From 2e973795383b71f63ae9e3bef0e5dfc7930b4c90 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 16 Sep 2026 11:52:03 +0200 Subject: playlists: the store, and putting it on nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit playlists.js is IndexedDB, WebCrypto and a transport, and node has no IndexedDB — so it is driven in Chrome against a node stubbed to record what it was handed, which is also how what leaves the browser is checked to be sealed. Sync asks the node what it holds (user_blob_list) rather than comparing against the merged watermark, which says nothing about that node: the first version pushed every body on every sync. A tombstoned playlist's body is deleted as each node is reached, or the quota fills with graves. The database version and its stores stay in hub-client.js — two modules opening one database at versions of their own is a VersionError thrown at whichever runs second. Co-Authored-By: Claude Opus 5 --- .../meshbay-hub/src/meshbay_hub/static/hub-client.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/hub-client.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js b/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js index 7ba6f92..dbd5037 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/hub-client.js @@ -12,8 +12,14 @@ const AUTH_KEY = 'mb_auth'; // should not cost a round trip before the first click works. const TOKEN_RENEW_MARGIN_S = 600; const IDB_NAME = 'meshbay'; -const IDB_VERSION = 1; +// **2**, for the `playlists` store (docs/playlists.md §14.2). The version and +// every store this database has live here, in one place, and `openDB` is +// exported so nothing else opens it at a version of its own — two modules +// disagreeing about the version is a `VersionError` thrown at whichever of +// them happens to run second. +const IDB_VERSION = 2; const IDB_STORE = 'group_indexes'; +const IDB_PLAYLISTS = 'playlists'; function navigate(path) { window.location.hash = path; @@ -29,6 +35,13 @@ function openDB() { if (!db.objectStoreNames.contains(IDB_STORE)) { db.createObjectStore(IDB_STORE, { keyPath: 'groupId' }); } + // Added at version 2. Out-of-line keys: the records are the playlist + // objects themselves, and the key is `userId|kind` — two accounts on one + // browser is ordinary, and so is a sign-out that never runs, so the + // separation belongs in the key rather than in a cleanup path. + if (!db.objectStoreNames.contains(IDB_PLAYLISTS)) { + db.createObjectStore(IDB_PLAYLISTS); + } }; req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); @@ -301,8 +314,11 @@ async function hubFetch(path, { method = 'GET', body, token, _retried } = {}) { return r.json(); } +// `openDB` and `IDB_PLAYLISTS` are exported so playlists.js reads and writes +// its own store without owning the database's version. export { HUB, navigate, session, + openDB, IDB_PLAYLISTS, cacheGroupIndex, getCachedGroupIndex, getAllCachedIndexes, clearAllCachedIndexes, _storeBundleKey, _loadBundleKey, _storeRecoveryKey, _loadRecoveryKey, _clearKeyDB, loadAuth, saveAuth, setAuth, setAuthChangeListener, -- cgit v1.2.3