fix: a popup save no longer undoes a network switch the background saved during it (closes #641)
The popup's saveState() and the background's updateState() each read the stored record, change it and write it back, and each was ordered only within its own context, so a write by one could land between the other's read and write and be lost. Both now hold the browser's lock (navigator.locks, shared by every page and the background except a page in a Firefox private window) from the read to the write, through withLock() in src/shared/browserApi.js; the recovery screen's reset takes it too. The lock also orders a page's own saves, so both per-context queues are gone. The unit tests get a small lock from a Jest setup file. Model: opus-5-5
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
// `navigator.locks` for the unit tests, which run on node, where there is none.
|
||||
//
|
||||
// One lock per name: granted in the order it was asked for, and let go when
|
||||
// the callback settles, whether it resolved or rejected. That is what the
|
||||
// browser's own does for the one call the extension makes,
|
||||
// `navigator.locks.request(name, callback)`. Every module a test file loads
|
||||
// shares it, as every page of the extension and its background share the
|
||||
// browser's.
|
||||
//
|
||||
// Run before each test file by `setupFiles` in package.json.
|
||||
|
||||
// For each name, a promise that settles once the last request for it has
|
||||
// let the lock go.
|
||||
const released = new Map();
|
||||
|
||||
function request(name, callback) {
|
||||
const previous = released.get(name) || Promise.resolve();
|
||||
const result = previous.then(() => callback({ name, mode: "exclusive" }));
|
||||
released.set(
|
||||
name,
|
||||
result.catch(() => {}),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
globalThis.navigator = { locks: { request } };
|
||||
Reference in New Issue
Block a user