Never let a share rewrite the Data Library entries remembered as on

Every restore wrote the selection it applied to browser storage, so
opening a link that switched no library entry on stored every saved
entry as off, and the next bare visit restored them off. Core layer
state never writes a recipient's preferences from a share. The library
now keeps what is remembered as on apart from what a share switches on
for the session: a share's entries still join the library, but only a
local restore and the viewer's own choices change what is remembered.
This commit is contained in:
Sameh Khamis committed 2026-11-12 15:58:22 -08:00
1 parent 53f0a32a1b
commit 2d5db9f63d
2 files changed
+60 -7

No files matched your search

+23 -6
View File
@@ -69,6 +69,10 @@ export function createDataLibrary({
let availability = new Map();
let serverPresent = false;
let selection = { added: [], on: [] };
// What this browser remembers as on. Like core layer state, a share
// decides what is on for the session but never rewrites it: only the
// viewer's explicit choices and a local restore do.
let savedOn = [];
let started = false;
// Set once availability is known; a share navigated to before then waits.
let loaded = false;
@@ -89,7 +93,11 @@ export function createDataLibrary({
const persist = () => {
selection = normalizeLibrarySelection(selection, switchable);
writeStoredLibrarySelection(storage, selection);
savedOn = savedOn.filter((id) => selection.added.includes(id));
writeStoredLibrarySelection(storage, {
added: selection.added,
on: savedOn,
});
shareLink?.onLibraryStateChange?.();
notify();
};
@@ -163,9 +171,16 @@ export function createDataLibrary({
return;
}
const on = new Set(selection.on);
if (change.enabled) on.add(id);
else on.delete(id);
const saved = new Set(savedOn);
if (change.enabled) {
on.add(id);
saved.add(id);
} else {
on.delete(id);
saved.delete(id);
}
selection = { ...selection, on: [...on] };
savedOn = [...saved];
persist();
});
@@ -217,9 +232,10 @@ export function createDataLibrary({
console.warn(`[Library] ${id} restore failed:`, error),
);
}
writeStoredLibrarySelection(storage, selection);
shareLink?.onLibraryStateChange?.();
notify();
// A share's entries join the library; only a local restore sets what
// is remembered as on.
if (origin !== 'share-restore') savedOn = selection.on;
persist();
}
/**
@@ -262,6 +278,7 @@ export function createDataLibrary({
availability = answer.availability;
serverPresent = answer.server;
const stored = readStoredLibrarySelection(storage, switchable);
savedOn = stored.on;
// A share opened in this tab while availability loaded wins over the
// opening one.
const linked = queuedShare ? idsForTokens(queuedShare) : openingShare();
+37 -1
View File
@@ -201,12 +201,48 @@ test('a link decides what is on and adds its entries to the library', async (t)
await manager.waitForLayerSettled?.('lib-sea-marks');
assert.equal(manager.isEnabled('lib-sea-marks'), true);
assert.equal(manager.isEnabled('lib-night-lights'), false);
// The link's entry joins the library; what is remembered as on stays
// the viewer's own.
assert.deepEqual(JSON.parse(storage.store.get(LIBRARY_STORAGE_KEY)), {
added: ['night-lights', 'sea-marks'],
on: ['sea-marks'],
on: ['night-lights'],
});
});
test('a share never rewrites what this browser remembers as on', async (t) => {
const saved = JSON.stringify({
added: ['night-lights', 'sea-marks'],
on: ['night-lights'],
});
const storage = memoryStorage(saved);
const manager = sealedManager(t);
const shareLink = fakeShareLink([]);
const library = createDataLibrary({
entries,
ledger,
dataManager: manager,
services: {},
storage,
shareLink,
source: source({}),
});
await library.start();
assert.equal(manager.isEnabled('lib-night-lights'), false);
shareLink.listener(['01']);
await manager.waitForLayerSettled?.('lib-sea-marks');
assert.equal(manager.isEnabled('lib-sea-marks'), true);
assert.deepEqual(JSON.parse(storage.store.get(LIBRARY_STORAGE_KEY)), {
added: ['night-lights', 'sea-marks'],
on: ['night-lights'],
});
// An explicit choice is remembered, and only that one.
await manager.setEnabled('lib-sea-marks', false, { origin: 'user' });
await manager.setEnabled('lib-night-lights', true, { origin: 'user' });
await manager.setEnabled('lib-night-lights', false, { origin: 'user' });
assert.deepEqual(JSON.parse(storage.store.get(LIBRARY_STORAGE_KEY)).on, []);
library.destroy();
});
/** A ShareLinkManager stand-in: the opening share and in-tab navigation. */
function fakeShareLink(initialLibraryTokens) {
const link = {