mirror of
https://github.com/HeyPuter/puter.git
synced 2026-11-05 13:35:20 +00:00
fix(puter-js): push cleanup runs without the lock where Web Locks refuse
In a frame where navigator.locks.request rejects, such as a sandboxed frame, sign-out, disable(), the load-time check and syncs now run their step without the lock instead of rejecting, so signOut() still resolves and the subscription is still ended.
This commit is contained in:
1 parent
e15c242f5a
commit
d9fd40daed
2 files changed
+54
-6
No files matched your search
@@ -78,12 +78,19 @@ const warnStorage = (error) => {
|
||||
);
|
||||
};
|
||||
|
||||
/** Runs `run` alone among the site's tabs, where the browser has Web Locks. */
|
||||
const withPushLock = (run) => {
|
||||
const locks = globalThis.navigator?.locks;
|
||||
return typeof locks?.request === 'function'
|
||||
? locks.request(PUSH_LOCK, () => run())
|
||||
: run();
|
||||
/** Runs `run` alone among the site's tabs, or as is where Web Locks refuse. */
|
||||
const withPushLock = async (run) => {
|
||||
let started = false;
|
||||
const start = () => {
|
||||
started = true;
|
||||
return run();
|
||||
};
|
||||
try {
|
||||
return await globalThis.navigator.locks.request(PUSH_LOCK, start);
|
||||
} catch (error) {
|
||||
if (started) throw error;
|
||||
return await start();
|
||||
}
|
||||
};
|
||||
|
||||
/** Hidden, or in a window without focus. */
|
||||
|
||||
@@ -2250,6 +2250,47 @@ describe('sign-out', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('where the browser refuses Web Locks, as in a sandboxed frame', () => {
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(globalThis.navigator, 'locks', {
|
||||
value: {
|
||||
request: vi.fn(async () => {
|
||||
throw new Error('The request was denied');
|
||||
}),
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
delete globalThis.navigator.locks;
|
||||
});
|
||||
|
||||
it('signs out without rejecting and still ends the subscription', async () => {
|
||||
store.set(OPT_IN, true);
|
||||
store.set(SERVER_KEY, KEY);
|
||||
const subscription = makeSubscription();
|
||||
withBrowser(makeNav({ existing: subscription }));
|
||||
mockRequest.mockResolvedValue({ removed: true });
|
||||
const { module } = makeModule();
|
||||
await expect(
|
||||
module._forgetPush('leaving-token'),
|
||||
).resolves.toBeUndefined();
|
||||
expect(subscription.unsubscribe).toHaveBeenCalled();
|
||||
expect(store.has(OPT_IN)).toBe(false);
|
||||
});
|
||||
|
||||
it('still ends a subscription left here without an opt-in on load', async () => {
|
||||
store.set(SERVER_KEY, KEY);
|
||||
const subscription = makeSubscription();
|
||||
withBrowser(makeNav({ existing: subscription }));
|
||||
const { module } = makeModule();
|
||||
await module.onPush('chat', () => {}, { onError: () => {} });
|
||||
await vi.waitFor(() =>
|
||||
expect(subscription.unsubscribe).toHaveBeenCalled(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a different user signing in', () => {
|
||||
const USERS = { 'token-a': 'u-1', 'token-a2': 'u-1', 'token-b': 'u-2' };
|
||||
/** A page signed in as u-1, whose tokens name their user in `uu`. */
|
||||
|
||||
Reference in new issue
Block a user