fix(library): read the catalogue the disk holds, not the version this build asks for
This commit is contained in:
@@ -270,6 +270,44 @@ export function onLibraryBlocked(fn: ((blocked: boolean) => void) | null): void
|
||||
blockedSink = fn;
|
||||
}
|
||||
|
||||
// The stores this build reads and writes. A catalogue that has been through the
|
||||
// newer build has all of them — it is only a version number that separates the
|
||||
// two.
|
||||
const STORES = [FOLDERS, PHOTOS, THUMBS, EDITS, DIRS];
|
||||
|
||||
// The catalogue as the disk already holds it, whatever version that is. Asked for
|
||||
// with no version on purpose: a build that names a version older than the one on
|
||||
// the disk — which is what a test server and a release server behind one domain
|
||||
// are, two builds against the one database the origin owns, with the reader moving
|
||||
// between them — is answered with `VersionError` and nothing else, every read of
|
||||
// the catalogue falls back on an empty list, and the LIBRARY draws the same empty
|
||||
// column a folder-less visit draws. No note, no error, nothing to read off the
|
||||
// screen. Taking the database as it stands is what lets the older build read what
|
||||
// the newer one wrote; a store it needs and does not find is the one case that is
|
||||
// still refused, and it is refused by name.
|
||||
function openAsIs(): Promise<IDBDatabase> {
|
||||
return new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const req = indexedDB.open(DB_NAME);
|
||||
req.onblocked = () => blockedSink?.(true);
|
||||
req.onsuccess = () => {
|
||||
blockedSink?.(false);
|
||||
const db = req.result;
|
||||
const missing = STORES.filter((s) => !db.objectStoreNames.contains(s));
|
||||
if (missing.length) {
|
||||
// A catalogue that is missing a store is not one this build can read, and
|
||||
// guessing at it is how a write lands on the wrong shape. The name goes to
|
||||
// the console; the screen keeps its own empty column, as before.
|
||||
console.error('catalogue: the database is missing', missing.join(', '));
|
||||
db.close();
|
||||
reject(new Error('catalogue-incomplete'));
|
||||
return;
|
||||
}
|
||||
resolve(db);
|
||||
};
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
}
|
||||
|
||||
function openDb(): Promise<IDBDatabase> {
|
||||
dbPromise ??= new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
@@ -300,7 +338,24 @@ function openDb(): Promise<IDBDatabase> {
|
||||
const db = req.result;
|
||||
void migrateLegacyDatabase(db).then(() => resolve(db));
|
||||
};
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onerror = () => {
|
||||
const err = req.error;
|
||||
// The one refusal that is not a failure: the catalogue on the disk was
|
||||
// written by a newer build of this app and this build is asking for an older
|
||||
// version of it. Every other way in is closed and this one is open.
|
||||
if (err && err.name === 'VersionError') {
|
||||
void openAsIs().then(resolve, reject);
|
||||
return;
|
||||
}
|
||||
reject(err);
|
||||
};
|
||||
}).catch((err: unknown) => {
|
||||
// A failed open is a fact about the ask, not about the visit: put nothing in
|
||||
// its place, so the read that follows the reader closing the other tab — or
|
||||
// reloading the build that holds the pen — opens the database again instead of
|
||||
// being answered forever by the one rejection.
|
||||
dbPromise = null;
|
||||
throw err;
|
||||
});
|
||||
return dbPromise;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user