@weasel-js/storage 1.9.4 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -5
- package/dist/index.js +113 -84
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ interface OwnedRecordCache extends RecordCache {
|
|
|
120
120
|
onOverruled(listener: (changes: [string, unknown][]) => void): () => void;
|
|
121
121
|
stopWriting(): void;
|
|
122
122
|
}
|
|
123
|
-
/** Options for `
|
|
123
|
+
/** Options for `openRecords`, and the part of `createRecordCache`'s the two share. */
|
|
124
124
|
interface RecordCacheOptions {
|
|
125
125
|
storage: StorageAdapter;
|
|
126
126
|
prefix: string;
|
|
@@ -135,12 +135,15 @@ interface RecordCacheOptions {
|
|
|
135
135
|
/** The longest wait between those tries. Default 30000 ms. */
|
|
136
136
|
retryMaxMs?: number;
|
|
137
137
|
}
|
|
138
|
-
|
|
138
|
+
/** Options for `createRecordCache`. */
|
|
139
|
+
interface CreateRecordCacheOptions extends RecordCacheOptions {
|
|
140
|
+
/** The records the cache opens holding, each a name and its value. Default none. */
|
|
139
141
|
initial?: Iterable<[string, unknown]>;
|
|
142
|
+
/** False opens the cache with writing off for good. Default true. */
|
|
140
143
|
writable?: boolean;
|
|
141
|
-
}
|
|
144
|
+
}
|
|
142
145
|
/** A cache holding `initial`, with nothing read from storage. */
|
|
143
|
-
declare function createRecordCache(options:
|
|
146
|
+
declare function createRecordCache(options: CreateRecordCacheOptions): OwnedRecordCache;
|
|
144
147
|
/** Read every record under `prefix` and hold them. A failed read opens the
|
|
145
148
|
* cache empty with writing off, so it never overwrites what it could not
|
|
146
149
|
* read, and tries again on a backoff. When a read lands, the cache holds it,
|
|
@@ -160,4 +163,4 @@ declare function encodeUrlHash(value: string): string;
|
|
|
160
163
|
* malformed. */
|
|
161
164
|
declare function decodeUrlHash(hash: string): string | null;
|
|
162
165
|
|
|
163
|
-
export { type IndexedDbAdapterOptions, type OwnedRecordCache, type RecordCache, type RecordCacheOptions, type RecordChange, type StorageAdapter, type StorageChange, type SyncStorageAdapter, createDefaultStorage, createIndexedDbAdapter, createMemoryAdapter, createRecordCache, decodeUrlHash, defaultStorage, encodeUrlHash, fallbackStorage, indexedDbAdapter, localStorageAdapter, noneAdapter, openRecords, openRecordsSync, sessionStorageAdapter, urlHashAdapter };
|
|
166
|
+
export { type CreateRecordCacheOptions, type IndexedDbAdapterOptions, type OwnedRecordCache, type RecordCache, type RecordCacheOptions, type RecordChange, type StorageAdapter, type StorageChange, type SyncStorageAdapter, createDefaultStorage, createIndexedDbAdapter, createMemoryAdapter, createRecordCache, decodeUrlHash, defaultStorage, encodeUrlHash, fallbackStorage, indexedDbAdapter, localStorageAdapter, noneAdapter, openRecords, openRecordsSync, sessionStorageAdapter, urlHashAdapter };
|
package/dist/index.js
CHANGED
|
@@ -388,48 +388,21 @@ var urlHashAdapter = {
|
|
|
388
388
|
}
|
|
389
389
|
};
|
|
390
390
|
|
|
391
|
-
// src/
|
|
391
|
+
// src/writeQueue.ts
|
|
392
392
|
var DELETED = /* @__PURE__ */ Symbol("deleted");
|
|
393
|
-
function
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
function buildCache(options, startUnread) {
|
|
397
|
-
const { storage, prefix } = options;
|
|
398
|
-
const debounceMs = options.debounceMs ?? 300;
|
|
399
|
-
const maxWaitMs = options.maxWaitMs ?? 1e3;
|
|
400
|
-
const retryMs = options.retryMs ?? 1e3;
|
|
401
|
-
const retryMaxMs = options.retryMaxMs ?? 3e4;
|
|
402
|
-
const values = new Map(options.initial ?? []);
|
|
393
|
+
function createWriteQueue(options) {
|
|
394
|
+
const { storage, prefix, debounceMs, maxWaitMs, retryMs, retryMaxMs, writable, closed, stopped } = options;
|
|
403
395
|
const queued = /* @__PURE__ */ new Map();
|
|
404
396
|
const inFlight = /* @__PURE__ */ new Map();
|
|
405
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
406
|
-
const overruledListeners = /* @__PURE__ */ new Set();
|
|
407
|
-
let unread = startUnread;
|
|
408
|
-
let stopped = !(options.writable ?? true);
|
|
409
|
-
const writable = () => !unread && !stopped;
|
|
410
|
-
let closed = false;
|
|
411
397
|
let timer = null;
|
|
412
398
|
let firstQueuedAt = null;
|
|
413
|
-
let retryTimer = null;
|
|
414
399
|
const firstRetryWait = retryMs === false ? 0 : retryMs;
|
|
400
|
+
let retryTimer = null;
|
|
415
401
|
let retryWait = firstRetryWait;
|
|
416
|
-
let reading = null;
|
|
417
402
|
let warned = false;
|
|
418
|
-
let writeRetryTimer = null;
|
|
419
|
-
let writeRetryWait = retryWait;
|
|
420
|
-
let writeWarned = false;
|
|
421
403
|
let sending = null;
|
|
422
|
-
let landed = () => {
|
|
423
|
-
};
|
|
424
|
-
const hasRead = new Promise((resolve) => {
|
|
425
|
-
if (startUnread) landed = resolve;
|
|
426
|
-
else resolve();
|
|
427
|
-
});
|
|
428
|
-
const emit = (changes) => {
|
|
429
|
-
for (const listener of [...listeners]) listener(changes);
|
|
430
|
-
};
|
|
431
404
|
const schedule = () => {
|
|
432
|
-
if (!writable() || closed) return;
|
|
405
|
+
if (!writable() || closed()) return;
|
|
433
406
|
const now = Date.now();
|
|
434
407
|
firstQueuedAt ??= now;
|
|
435
408
|
if (timer) clearTimeout(timer);
|
|
@@ -450,62 +423,121 @@ function buildCache(options, startUnread) {
|
|
|
450
423
|
});
|
|
451
424
|
return mine;
|
|
452
425
|
}
|
|
426
|
+
async function write(name, value) {
|
|
427
|
+
const key = prefix + name;
|
|
428
|
+
try {
|
|
429
|
+
if (value === DELETED) await storage.delete(key);
|
|
430
|
+
else await storage.set(key, value);
|
|
431
|
+
return true;
|
|
432
|
+
} catch (error) {
|
|
433
|
+
if (!warned) {
|
|
434
|
+
warned = true;
|
|
435
|
+
console.warn(`[storage] could not write "${key}"; trying again`, error);
|
|
436
|
+
}
|
|
437
|
+
if (!queued.has(name) && !stopped()) queued.set(name, value);
|
|
438
|
+
return false;
|
|
439
|
+
} finally {
|
|
440
|
+
const count = inFlight.get(name) ?? 1;
|
|
441
|
+
if (count > 1) inFlight.set(name, count - 1);
|
|
442
|
+
else inFlight.delete(name);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
453
445
|
async function send() {
|
|
454
446
|
if (queued.size === 0) return true;
|
|
455
447
|
if (!writable()) return false;
|
|
456
|
-
|
|
448
|
+
stopRetrying();
|
|
457
449
|
const batch = [...queued];
|
|
458
450
|
queued.clear();
|
|
459
451
|
for (const [name] of batch) inFlight.set(name, (inFlight.get(name) ?? 0) + 1);
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (value === DELETED) await storage.delete(key);
|
|
465
|
-
else await storage.set(key, value);
|
|
466
|
-
return true;
|
|
467
|
-
} catch (error) {
|
|
468
|
-
if (!writeWarned) {
|
|
469
|
-
writeWarned = true;
|
|
470
|
-
console.warn(`[storage] could not write "${key}"; trying again`, error);
|
|
471
|
-
}
|
|
472
|
-
if (!queued.has(name) && !stopped) queued.set(name, value);
|
|
473
|
-
return false;
|
|
474
|
-
} finally {
|
|
475
|
-
const count = inFlight.get(name) ?? 1;
|
|
476
|
-
if (count > 1) inFlight.set(name, count - 1);
|
|
477
|
-
else inFlight.delete(name);
|
|
478
|
-
}
|
|
479
|
-
})
|
|
480
|
-
);
|
|
481
|
-
if (landed2.every(Boolean)) {
|
|
482
|
-
writeWarned = false;
|
|
483
|
-
writeRetryWait = firstRetryWait;
|
|
452
|
+
const landed = await Promise.all(batch.map(([name, value]) => write(name, value)));
|
|
453
|
+
if (landed.every(Boolean)) {
|
|
454
|
+
warned = false;
|
|
455
|
+
retryWait = firstRetryWait;
|
|
484
456
|
return true;
|
|
485
457
|
}
|
|
486
|
-
|
|
458
|
+
retry();
|
|
487
459
|
return false;
|
|
488
460
|
}
|
|
489
|
-
function
|
|
490
|
-
if (
|
|
491
|
-
|
|
461
|
+
function stopRetrying() {
|
|
462
|
+
if (retryTimer) clearTimeout(retryTimer);
|
|
463
|
+
retryTimer = null;
|
|
492
464
|
}
|
|
493
|
-
function
|
|
494
|
-
|
|
495
|
-
if (retryMs === false || closed || stopped || queued.size === 0) return;
|
|
496
|
-
|
|
497
|
-
|
|
465
|
+
function retry() {
|
|
466
|
+
stopRetrying();
|
|
467
|
+
if (retryMs === false || closed() || stopped() || queued.size === 0) return;
|
|
468
|
+
retryTimer = setTimeout(() => {
|
|
469
|
+
retryTimer = null;
|
|
498
470
|
void flush();
|
|
499
|
-
},
|
|
500
|
-
|
|
471
|
+
}, retryWait);
|
|
472
|
+
retryWait = Math.min(retryWait * 2, retryMaxMs);
|
|
501
473
|
}
|
|
474
|
+
return {
|
|
475
|
+
get size() {
|
|
476
|
+
return queued.size;
|
|
477
|
+
},
|
|
478
|
+
has: (name) => queued.has(name),
|
|
479
|
+
owns: (name) => queued.has(name) || inFlight.has(name),
|
|
480
|
+
add: (name, value) => {
|
|
481
|
+
queued.set(name, value);
|
|
482
|
+
},
|
|
483
|
+
schedule,
|
|
484
|
+
flush,
|
|
485
|
+
stopRetrying,
|
|
486
|
+
discard: () => {
|
|
487
|
+
queued.clear();
|
|
488
|
+
if (timer) clearTimeout(timer);
|
|
489
|
+
timer = null;
|
|
490
|
+
stopRetrying();
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/records.ts
|
|
496
|
+
function createRecordCache(options) {
|
|
497
|
+
return buildCache(options, false).cache;
|
|
498
|
+
}
|
|
499
|
+
function buildCache(options, startUnread) {
|
|
500
|
+
const { storage, prefix } = options;
|
|
501
|
+
const retryMs = options.retryMs ?? 1e3;
|
|
502
|
+
const retryMaxMs = options.retryMaxMs ?? 3e4;
|
|
503
|
+
const values = new Map(options.initial ?? []);
|
|
504
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
505
|
+
const overruledListeners = /* @__PURE__ */ new Set();
|
|
506
|
+
let unread = startUnread;
|
|
507
|
+
let stopped = !(options.writable ?? true);
|
|
508
|
+
const writable = () => !unread && !stopped;
|
|
509
|
+
let closed = false;
|
|
510
|
+
let retryTimer = null;
|
|
511
|
+
let retryWait = retryMs === false ? 0 : retryMs;
|
|
512
|
+
let reading = null;
|
|
513
|
+
let warned = false;
|
|
514
|
+
let landed = () => {
|
|
515
|
+
};
|
|
516
|
+
const hasRead = new Promise((resolve) => {
|
|
517
|
+
if (startUnread) landed = resolve;
|
|
518
|
+
else resolve();
|
|
519
|
+
});
|
|
520
|
+
const emit = (changes) => {
|
|
521
|
+
for (const listener of [...listeners]) listener(changes);
|
|
522
|
+
};
|
|
523
|
+
const queue = createWriteQueue({
|
|
524
|
+
storage,
|
|
525
|
+
prefix,
|
|
526
|
+
debounceMs: options.debounceMs ?? 300,
|
|
527
|
+
maxWaitMs: options.maxWaitMs ?? 1e3,
|
|
528
|
+
retryMs,
|
|
529
|
+
retryMaxMs,
|
|
530
|
+
writable,
|
|
531
|
+
closed: () => closed,
|
|
532
|
+
stopped: () => stopped
|
|
533
|
+
});
|
|
502
534
|
const applyRemote = (changes) => {
|
|
503
535
|
const applied = [];
|
|
504
536
|
const overruled = [];
|
|
505
537
|
for (const [key, value] of changes) {
|
|
506
538
|
if (!key.startsWith(prefix)) continue;
|
|
507
539
|
const name = key.slice(prefix.length);
|
|
508
|
-
if (
|
|
540
|
+
if (queue.owns(name)) {
|
|
509
541
|
overruled.push([name, value]);
|
|
510
542
|
continue;
|
|
511
543
|
}
|
|
@@ -560,7 +592,7 @@ function buildCache(options, startUnread) {
|
|
|
560
592
|
unsubscribe = storage.subscribe?.(prefix, applyRemote);
|
|
561
593
|
stopEarly?.();
|
|
562
594
|
applyRemote([...listed, ...early]);
|
|
563
|
-
if (
|
|
595
|
+
if (queue.size > 0) queue.schedule();
|
|
564
596
|
landed();
|
|
565
597
|
return true;
|
|
566
598
|
}
|
|
@@ -572,21 +604,21 @@ function buildCache(options, startUnread) {
|
|
|
572
604
|
return reading;
|
|
573
605
|
}
|
|
574
606
|
const onPageHide = () => {
|
|
575
|
-
void flush();
|
|
607
|
+
void queue.flush();
|
|
576
608
|
};
|
|
577
609
|
const onVisibility = () => {
|
|
578
|
-
if (document.visibilityState === "hidden") void flush();
|
|
610
|
+
if (document.visibilityState === "hidden") void queue.flush();
|
|
579
611
|
};
|
|
580
612
|
if (typeof window !== "undefined") {
|
|
581
613
|
window.addEventListener("pagehide", onPageHide);
|
|
582
614
|
document.addEventListener("visibilitychange", onVisibility);
|
|
583
615
|
}
|
|
584
616
|
const remove = (name) => {
|
|
585
|
-
if (!unread && !values.has(name) && !
|
|
617
|
+
if (!unread && !values.has(name) && !queue.has(name)) return;
|
|
586
618
|
values.delete(name);
|
|
587
|
-
|
|
619
|
+
queue.add(name, DELETED);
|
|
588
620
|
emit([{ name, value: void 0, origin: "local" }]);
|
|
589
|
-
schedule();
|
|
621
|
+
queue.schedule();
|
|
590
622
|
};
|
|
591
623
|
const cache = {
|
|
592
624
|
prefix,
|
|
@@ -599,9 +631,9 @@ function buildCache(options, startUnread) {
|
|
|
599
631
|
set: (name, value) => {
|
|
600
632
|
if (value === void 0) return remove(name);
|
|
601
633
|
values.set(name, value);
|
|
602
|
-
|
|
634
|
+
queue.add(name, value);
|
|
603
635
|
emit([{ name, value, origin: "local" }]);
|
|
604
|
-
schedule();
|
|
636
|
+
queue.schedule();
|
|
605
637
|
},
|
|
606
638
|
delete: remove,
|
|
607
639
|
subscribe: (listener) => {
|
|
@@ -610,15 +642,15 @@ function buildCache(options, startUnread) {
|
|
|
610
642
|
listeners.delete(listener);
|
|
611
643
|
};
|
|
612
644
|
},
|
|
613
|
-
flush,
|
|
645
|
+
flush: queue.flush,
|
|
614
646
|
read,
|
|
615
647
|
whenRead: () => hasRead,
|
|
616
648
|
close: async () => {
|
|
617
649
|
if (closed) return;
|
|
618
650
|
stopRetrying();
|
|
619
|
-
await flush();
|
|
651
|
+
await queue.flush();
|
|
620
652
|
closed = true;
|
|
621
|
-
|
|
653
|
+
queue.stopRetrying();
|
|
622
654
|
unsubscribe?.();
|
|
623
655
|
if (typeof window !== "undefined") {
|
|
624
656
|
window.removeEventListener("pagehide", onPageHide);
|
|
@@ -636,11 +668,8 @@ function buildCache(options, startUnread) {
|
|
|
636
668
|
},
|
|
637
669
|
stopWriting: () => {
|
|
638
670
|
stopped = true;
|
|
639
|
-
|
|
640
|
-
if (timer) clearTimeout(timer);
|
|
641
|
-
timer = null;
|
|
671
|
+
queue.discard();
|
|
642
672
|
stopRetrying();
|
|
643
|
-
stopRetryingWrites();
|
|
644
673
|
unsubscribe?.();
|
|
645
674
|
}
|
|
646
675
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/indexedDb.ts","../src/json.ts","../src/webStorage.ts","../src/defaultStorage.ts","../src/memory.ts","../src/urlHash.ts","../src/urlHashAdapter.ts","../src/records.ts"],"names":["landed"],"mappings":"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","file":"index.js","sourcesContent":["import type { StorageAdapter, StorageChange } from './types';\n\n/** Options for `createIndexedDbAdapter`. */\nexport interface IndexedDbAdapterOptions {\n /** Default `'weasel'`. */\n database?: string;\n /** Default `'records'`. One object store per database: a store added to a\n * database that already exists is not created. */\n store?: string;\n}\n\ninterface NodeChannel extends BroadcastChannel {\n unref?: () => void;\n}\n\n/** Persist to IndexedDB, which stores structured-clone values natively — typed\n * arrays, `Map`s, `Blob`s — and holds far more than localStorage. Other tabs\n * hear writes through a `BroadcastChannel`. The database opens on first use. */\nexport function createIndexedDbAdapter({\n database = 'weasel',\n store = 'records',\n}: IndexedDbAdapterOptions = {}): StorageAdapter {\n let opened: Promise<IDBDatabase> | null = null;\n let connection: IDBDatabase | null = null;\n const forget = (db: IDBDatabase): void => {\n if (connection !== db) return;\n connection = null;\n opened = null;\n };\n const open = (): Promise<IDBDatabase> => {\n if (opened) return opened;\n const mine = new Promise<IDBDatabase>((resolve, reject) => {\n if (typeof indexedDB === 'undefined') {\n reject(new Error('[storage] IndexedDB is not available here'));\n return;\n }\n // No `onblocked`: a blocked open is still pending, and lands once the\n // connections in its way close.\n const request = indexedDB.open(database, 1);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(store)) {\n request.result.createObjectStore(store);\n }\n };\n request.onsuccess = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(store)) {\n db.close();\n reject(new Error(`[storage] IndexedDB database \"${database}\" has no store \"${store}\"`));\n return;\n }\n connection = db;\n // The browser closing the connection: site data cleared, or evicted.\n db.onclose = () => forget(db);\n // Another connection wants to delete or upgrade the database, and\n // waits for as long as this one stays open.\n db.onversionchange = () => {\n db.close();\n forget(db);\n };\n resolve(db);\n };\n request.onerror = () => reject(request.error);\n });\n opened = mine;\n // A failed open is not kept, so the next call tries again.\n mine.catch(() => {\n if (opened === mine) opened = null;\n });\n return mine;\n };\n\n const run = async <T>(\n mode: IDBTransactionMode,\n body: (s: IDBObjectStore) => () => T,\n ): Promise<T> => {\n let db = await open();\n let tx: IDBTransaction;\n try {\n tx = db.transaction(store, mode);\n } catch {\n // A connection that closed without saying so. One more, on a new one.\n forget(db);\n db = await open();\n tx = db.transaction(store, mode);\n }\n return new Promise<T>((resolve, reject) => {\n const result = body(tx.objectStore(store));\n tx.oncomplete = () => resolve(result());\n tx.onerror = () => reject(tx.error);\n tx.onabort = () => reject(tx.error);\n });\n };\n\n let channel: NodeChannel | null = null;\n const getChannel = (): NodeChannel | null => {\n if (typeof BroadcastChannel === 'undefined') return null;\n if (!channel) {\n channel = new BroadcastChannel(`weasel-storage:${database}:${store}`) as NodeChannel;\n // Node keeps its event loop alive for an open channel; a browser has no unref.\n channel.unref?.();\n }\n return channel;\n };\n const announce = (changes: StorageChange[]): void => {\n getChannel()?.postMessage(changes);\n };\n\n const adapter: StorageAdapter = {\n get: (key) =>\n run('readonly', (s) => {\n const request = s.get(key);\n return () => request.result as unknown;\n }),\n list: (prefix) =>\n run('readonly', (s) => {\n const range = IDBKeyRange.bound(prefix, `${prefix}`);\n const keys = s.getAllKeys(range);\n const values = s.getAll(range);\n return () =>\n keys.result.map((key, i): [string, unknown] => [String(key), values.result[i]]);\n }),\n set: async (key, value) => {\n await run('readwrite', (s) => {\n s.put(value, key);\n return () => undefined;\n });\n announce([[key, value]]);\n },\n delete: async (key) => {\n await run('readwrite', (s) => {\n s.delete(key);\n return () => undefined;\n });\n announce([[key, undefined]]);\n },\n };\n if (typeof BroadcastChannel !== 'undefined') {\n adapter.subscribe = (prefix, on) => {\n const ch = getChannel();\n if (!ch) return () => {};\n const handler = (e: MessageEvent<StorageChange[]>): void => {\n const mine = e.data.filter(([key]) => key.startsWith(prefix));\n if (mine.length > 0) on(mine);\n };\n ch.addEventListener('message', handler);\n return () => ch.removeEventListener('message', handler);\n };\n }\n return adapter;\n}\n\n/** IndexedDB under the default database and store. */\nexport const indexedDbAdapter: StorageAdapter = createIndexedDbAdapter();\n","/** Raw strings written before records existed come back as the string they\n * are. */\nexport function parse(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** Whether `JSON.stringify` would keep `value` exactly. An object key holding\n * `undefined` counts as kept: JSON drops the key, and reading back an absent\n * key yields the same `undefined`. */\nexport function isJsonSafe(value: unknown, seen: Set<object> = new Set()): boolean {\n if (value === null) return true;\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return true;\n case 'number':\n return Number.isFinite(value);\n case 'object': {\n if (seen.has(value)) return false;\n seen.add(value);\n const proto = Object.getPrototypeOf(value);\n const ok = Array.isArray(value)\n ? value.every((v) => isJsonSafe(v, seen))\n : (proto === Object.prototype || proto === null) &&\n Object.values(value).every((v) => v === undefined || isJsonSafe(v, seen));\n seen.delete(value);\n return ok;\n }\n default:\n return false;\n }\n}\n","import { isJsonSafe, parse } from './json';\nimport type { SyncStorageAdapter } from './types';\n\nfunction webStorageAdapter(area: () => Storage, name: string, crossTab: boolean): SyncStorageAdapter {\n const warned = new Set<string>();\n const keysNow = (prefix: string): string[] => {\n const store = area();\n const out: string[] = [];\n for (let i = 0; i < store.length; i++) {\n const key = store.key(i);\n if (key?.startsWith(prefix)) out.push(key);\n }\n return out;\n };\n const listNow = (prefix: string): [string, unknown][] => {\n const store = area();\n const out: [string, unknown][] = [];\n for (const key of keysNow(prefix)) {\n const raw = store.getItem(key);\n if (raw !== null) out.push([key, parse(raw)]);\n }\n return out;\n };\n // The keys each live subscription knows to exist. `clear()` in another tab\n // arrives as one event naming no key, so this is what says what went.\n const subscribers = new Set<{ prefix: string; keys: Set<string> }>();\n const note = (key: string, held: boolean): void => {\n for (const sub of subscribers) {\n if (!key.startsWith(sub.prefix)) continue;\n if (held) sub.keys.add(key);\n else sub.keys.delete(key);\n }\n };\n const adapter: SyncStorageAdapter = {\n get: async (key) => {\n const raw = area().getItem(key);\n return raw === null ? undefined : parse(raw);\n },\n list: async (prefix) => listNow(prefix),\n listSync: listNow,\n set: async (key, value) => {\n if (!warned.has(key) && !isJsonSafe(value)) {\n warned.add(key);\n console.warn(\n `[storage] \"${key}\" holds a value JSON cannot keep exactly; ${name} stores what JSON keeps. Use IndexedDB for binary or non-JSON state.`,\n );\n }\n area().setItem(key, JSON.stringify(value));\n note(key, true);\n },\n delete: async (key) => {\n area().removeItem(key);\n note(key, false);\n },\n };\n if (crossTab) {\n adapter.subscribe = (prefix, on) => {\n if (typeof window === 'undefined') return () => {};\n const sub = { prefix, keys: new Set(keysNow(prefix)) };\n subscribers.add(sub);\n const handler = (e: StorageEvent): void => {\n const store = area();\n if (e.storageArea !== store) return;\n if (e.key === null) {\n const gone = [...sub.keys].filter((key) => store.getItem(key) === null);\n for (const key of gone) sub.keys.delete(key);\n if (gone.length > 0) on(gone.map((key): [string, unknown] => [key, undefined]));\n return;\n }\n if (!e.key.startsWith(prefix)) return;\n if (e.newValue === null) sub.keys.delete(e.key);\n else sub.keys.add(e.key);\n on([[e.key, e.newValue === null ? undefined : parse(e.newValue)]]);\n };\n window.addEventListener('storage', handler);\n return () => {\n subscribers.delete(sub);\n window.removeEventListener('storage', handler);\n };\n };\n }\n return adapter;\n}\n\n/** Persist to `localStorage`, one JSON value per record. Survives a reload and\n * reaches other tabs through the `storage` event. */\nexport const localStorageAdapter: SyncStorageAdapter = webStorageAdapter(\n () => localStorage,\n 'localStorage',\n true,\n);\n\n/** Persist to `sessionStorage` — survives a reload but not a new tab. */\nexport const sessionStorageAdapter: SyncStorageAdapter = webStorageAdapter(\n () => sessionStorage,\n 'sessionStorage',\n false,\n);\n","import { indexedDbAdapter } from './indexedDb';\nimport type { StorageAdapter } from './types';\nimport { localStorageAdapter } from './webStorage';\n\n/** `preferred` if it opens, otherwise `fallback` — with a warning. */\nexport async function fallbackStorage(\n preferred: StorageAdapter,\n fallback: StorageAdapter = localStorageAdapter,\n label = 'preferred storage',\n): Promise<StorageAdapter> {\n try {\n await preferred.list(' ');\n return preferred;\n } catch (error) {\n console.warn(`[storage] ${label} would not open; using the fallback instead`, error);\n return fallback;\n }\n}\n\n/** A page-wide default: `preferred`, or localStorage where it will not open,\n * chosen on first call and kept until `resetDefaultStorage` (tests only). */\nexport function createDefaultStorage(\n preferred: StorageAdapter,\n label?: string,\n): { defaultStorage: () => Promise<StorageAdapter>; resetDefaultStorage: () => void } {\n let resolved: Promise<StorageAdapter> | null = null;\n return {\n defaultStorage: () => (resolved ??= fallbackStorage(preferred, localStorageAdapter, label)),\n resetDefaultStorage: () => {\n resolved = null;\n },\n };\n}\n\n/** IndexedDB under the default database, 'weasel', or localStorage where it\n * will not open. Resolved once per page. */\nexport const { defaultStorage, resetDefaultStorage } = createDefaultStorage(indexedDbAdapter, 'IndexedDB');\n","import type { StorageAdapter, StorageChange, SyncStorageAdapter } from './types';\n\ninterface MemorySubscriber {\n owner: StorageAdapter;\n prefix: string;\n on: (changes: StorageChange[]) => void;\n}\n\nconst memorySubscribers = new WeakMap<Map<string, unknown>, Set<MemorySubscriber>>();\n\n/** An in-memory store, discarded on reload. Values are copied in and out, as a\n * real substrate would. Adapters built over one shared `backing` hear each\n * other's writes — two tabs, for a test. */\nexport function createMemoryAdapter(backing: Map<string, unknown> = new Map()): SyncStorageAdapter {\n let subscribers = memorySubscribers.get(backing);\n if (!subscribers) {\n subscribers = new Set();\n memorySubscribers.set(backing, subscribers);\n }\n const peers = subscribers;\n const notify = (key: string, value: unknown): void => {\n for (const sub of peers) {\n if (sub.owner === adapter || !key.startsWith(sub.prefix)) continue;\n const copy = value === undefined ? undefined : structuredClone(value);\n queueMicrotask(() => sub.on([[key, copy]]));\n }\n };\n const listNow = (prefix: string): [string, unknown][] =>\n [...backing]\n .filter(([key]) => key.startsWith(prefix))\n .map(([key, value]): [string, unknown] => [key, structuredClone(value)]);\n const adapter: SyncStorageAdapter = {\n get: async (key) => (backing.has(key) ? structuredClone(backing.get(key)) : undefined),\n list: async (prefix) => listNow(prefix),\n listSync: listNow,\n set: async (key, value) => {\n const copy = structuredClone(value);\n backing.set(key, copy);\n notify(key, copy);\n },\n delete: async (key) => {\n backing.delete(key);\n notify(key, undefined);\n },\n subscribe: (prefix, on) => {\n const sub = { owner: adapter, prefix, on };\n peers.add(sub);\n return () => {\n peers.delete(sub);\n };\n },\n };\n return adapter;\n}\n\n/** Persists nothing and reads back nothing. */\nexport const noneAdapter: SyncStorageAdapter = {\n get: async () => undefined,\n list: async () => [],\n listSync: () => [],\n set: async () => {},\n delete: async () => {},\n};\n","/** Encode a string for the URL fragment. */\nexport function encodeUrlHash(value: string): string {\n return btoa(encodeURIComponent(value));\n}\n\n/** Decode a URL fragment written by `encodeUrlHash`, or `null` if it is\n * malformed. */\nexport function decodeUrlHash(hash: string): string | null {\n if (!hash) return null;\n try {\n return decodeURIComponent(atob(hash));\n } catch {\n return null;\n }\n}\n","import { parse } from './json';\nimport type { StorageAdapter, StorageChange } from './types';\nimport { decodeUrlHash, encodeUrlHash } from './urlHash';\n\nconst URL_HASH_GUARD = typeof window !== 'undefined';\n\n/** The fragment's records, each still the JSON text it is stored as. Anyone\n * can write a fragment, so whatever is not a map of strings reads as absent.\n * No prototype, so a record may be named for anything an object inherits. */\nfunction readHashMap(): Record<string, string> {\n const map = Object.create(null) as Record<string, string>;\n if (!URL_HASH_GUARD) return map;\n const raw = decodeUrlHash(window.location.hash.replace(/^#/, ''));\n if (!raw) return map;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return map;\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return map;\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value === 'string') map[key] = value;\n }\n return map;\n}\n\n/** What each live subscription last saw, refreshed on this page's own writes\n * so `hashchange` reports only somebody else's. */\nconst hashSubscribers = new Set<{ last: Record<string, string> }>();\n\nfunction writeHashMap(map: Record<string, string>): void {\n if (!URL_HASH_GUARD) return;\n const encoded = encodeUrlHash(JSON.stringify(map));\n window.history.replaceState(window.history.state, '', `#${encoded}`);\n for (const sub of hashSubscribers) sub.last = Object.assign(Object.create(null), map);\n}\n\n/** Persist into the URL fragment, so the page's link carries its state and can\n * be shared or bookmarked. Changes to the fragment made elsewhere — a pasted\n * link, back and forward — arrive through `hashchange`. */\nexport const urlHashAdapter: StorageAdapter = {\n get: async (key) => {\n const raw = readHashMap()[key];\n return raw === undefined ? undefined : parse(raw);\n },\n list: async (prefix) =>\n Object.entries(readHashMap())\n .filter(([key]) => key.startsWith(prefix))\n .map(([key, raw]): [string, unknown] => [key, parse(raw)]),\n set: async (key, value) => {\n const map = readHashMap();\n map[key] = JSON.stringify(value);\n writeHashMap(map);\n },\n delete: async (key) => {\n const map = readHashMap();\n delete map[key];\n writeHashMap(map);\n },\n subscribe: (prefix, on) => {\n if (!URL_HASH_GUARD) return () => {};\n const sub = { last: readHashMap() };\n hashSubscribers.add(sub);\n const handler = (): void => {\n const next = readHashMap();\n const changes: StorageChange[] = [];\n for (const key of new Set([...Object.keys(sub.last), ...Object.keys(next)])) {\n if (!key.startsWith(prefix) || sub.last[key] === next[key]) continue;\n const raw = next[key];\n changes.push([key, raw === undefined ? undefined : parse(raw)]);\n }\n sub.last = next;\n if (changes.length > 0) on(changes);\n };\n window.addEventListener('hashchange', handler);\n return () => {\n hashSubscribers.delete(sub);\n window.removeEventListener('hashchange', handler);\n };\n },\n};\n","import type { StorageAdapter, StorageChange, SyncStorageAdapter } from './types';\n\n/** One record changing, as a cache listener hears it. `value` is `undefined`\n * for a delete. `local` changes were made through this cache; `remote` ones\n * came from another writer. */\nexport interface RecordChange {\n name: string;\n value: unknown;\n origin: 'local' | 'remote';\n}\n\n/**\n * Every record under one prefix, held in memory: the only thing that talks to\n * a `StorageAdapter`. Names are keys with the prefix removed.\n *\n * Writes land in memory at once and reach storage on a debounce. The newest\n * write to a record wins: another writer's change to a record with a write\n * still queued or on its way here is ignored, since that write lands after\n * it. A write storage rejects stays queued and is sent again on a backoff.\n */\nexport interface RecordCache {\n readonly prefix: string;\n /** False while writing is off, so nothing here can overwrite the records:\n * until a first read that failed lands on a later try, and for good once\n * the opener marks them read-only. */\n readonly writable: boolean;\n has(name: string): boolean;\n get(name: string): unknown;\n /** Every record whose name starts with `namePrefix`. */\n entries(namePrefix?: string): [string, unknown][];\n /** `undefined` is no value a record can hold: setting it deletes. */\n set(name: string, value: unknown): void;\n delete(name: string): void;\n subscribe(listener: (changes: RecordChange[]) => void): () => void;\n /** Send queued writes now. Resolves true when every queued write landed or\n * none was queued; false when a write threw (it stays queued) or writing\n * is off and writes were queued. */\n flush(): Promise<boolean>;\n /** Try a failed first read again now, ahead of the backoff. Resolves\n * whether the records have been read. */\n read(): Promise<boolean>;\n /** Resolves once the records have been read: at once for a cache that\n * opened with them, and when a later read lands for one whose first read\n * failed. Never resolves for a cache closed or stopped before that. */\n whenRead(): Promise<void>;\n /** Send queued writes, stop hearing other writers, and stop retrying. */\n close(): Promise<void>;\n}\n\n/** The parts of a cache only its opener uses. */\nexport interface OwnedRecordCache extends RecordCache {\n /** Hold these records without writing them back. */\n seed(entries: Iterable<[string, unknown]>): void;\n /** Hear another writer's changes this cache did not take, because its own\n * write to the record was queued or on its way: each a name and the value\n * the other writer set, `undefined` for a delete. */\n onOverruled(listener: (changes: [string, unknown][]) => void): () => void;\n stopWriting(): void;\n}\n\n/** Options for `createRecordCache` and `openRecords`. */\nexport interface RecordCacheOptions {\n storage: StorageAdapter;\n prefix: string;\n /** Trailing debounce on writes. Default 300 ms. */\n debounceMs?: number;\n /** The longest a write waits under continuous change. Default 1000 ms. */\n maxWaitMs?: number;\n /** The wait before a failed first read, or a write storage rejected, is\n * tried again, doubling after each failure. Default 1000 ms; `false` never\n * tries again on its own, leaving a rejected write for the next flush. */\n retryMs?: number | false;\n /** The longest wait between those tries. Default 30000 ms. */\n retryMaxMs?: number;\n}\n\ntype CreateOptions = RecordCacheOptions & {\n initial?: Iterable<[string, unknown]>;\n writable?: boolean;\n};\n\nconst DELETED = Symbol('deleted');\n\n/** A cache holding `initial`, with nothing read from storage. */\nexport function createRecordCache(options: CreateOptions): OwnedRecordCache {\n return buildCache(options, false).cache;\n}\n\n/** `startUnread` leaves the cache waiting on a first read: `cache.read()`\n * makes it, and `failed` reports one made elsewhere that threw. */\nfunction buildCache(\n options: CreateOptions,\n startUnread: boolean,\n): { cache: OwnedRecordCache; failed: (error: unknown) => void } {\n const { storage, prefix } = options;\n const debounceMs = options.debounceMs ?? 300;\n const maxWaitMs = options.maxWaitMs ?? 1000;\n const retryMs = options.retryMs ?? 1000;\n const retryMaxMs = options.retryMaxMs ?? 30_000;\n const values = new Map<string, unknown>(options.initial ?? []);\n const queued = new Map<string, unknown>();\n // How many writes to each name are on their way to storage.\n const inFlight = new Map<string, number>();\n const listeners = new Set<(changes: RecordChange[]) => void>();\n const overruledListeners = new Set<(changes: [string, unknown][]) => void>();\n // Two reasons writing is off. A read landing clears `unread`; nothing\n // clears `stopped`, which is the opener's choice.\n let unread = startUnread;\n let stopped = !(options.writable ?? true);\n const writable = (): boolean => !unread && !stopped;\n let closed = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let firstQueuedAt: number | null = null;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n const firstRetryWait = retryMs === false ? 0 : retryMs;\n let retryWait = firstRetryWait;\n let reading: Promise<boolean> | null = null;\n let warned = false;\n let writeRetryTimer: ReturnType<typeof setTimeout> | null = null;\n let writeRetryWait = retryWait;\n let writeWarned = false;\n let sending: Promise<boolean> | null = null;\n let landed = (): void => {};\n const hasRead = new Promise<void>((resolve) => {\n if (startUnread) landed = resolve;\n else resolve();\n });\n\n const emit = (changes: RecordChange[]): void => {\n for (const listener of [...listeners]) listener(changes);\n };\n\n const schedule = (): void => {\n if (!writable() || closed) return;\n const now = Date.now();\n firstQueuedAt ??= now;\n if (timer) clearTimeout(timer);\n const wait = Math.max(0, Math.min(debounceMs, firstQueuedAt + maxWaitMs - now));\n timer = setTimeout(() => {\n timer = null;\n void flush();\n }, wait);\n };\n\n // One batch is on its way at a time. A rejected write is back in the queue\n // before the next batch is taken, so a newer write to its record stands.\n function flush(): Promise<boolean> {\n if (timer) clearTimeout(timer);\n timer = null;\n firstQueuedAt = null;\n // With nothing on its way the batch leaves in this tick, which a flush\n // on `pagehide` depends on.\n const mine = sending ? sending.then(send) : send();\n sending = mine;\n void mine.finally(() => {\n if (sending === mine) sending = null;\n });\n return mine;\n }\n\n async function send(): Promise<boolean> {\n if (queued.size === 0) return true;\n if (!writable()) return false;\n stopRetryingWrites();\n const batch = [...queued];\n queued.clear();\n for (const [name] of batch) inFlight.set(name, (inFlight.get(name) ?? 0) + 1);\n const landed = await Promise.all(\n batch.map(async ([name, value]) => {\n const key = prefix + name;\n try {\n if (value === DELETED) await storage.delete(key);\n else await storage.set(key, value);\n return true;\n } catch (error) {\n if (!writeWarned) {\n writeWarned = true;\n console.warn(`[storage] could not write \"${key}\"; trying again`, error);\n }\n // A write queued since is newer, and stands.\n if (!queued.has(name) && !stopped) queued.set(name, value);\n return false;\n } finally {\n const count = inFlight.get(name) ?? 1;\n if (count > 1) inFlight.set(name, count - 1);\n else inFlight.delete(name);\n }\n }),\n );\n if (landed.every(Boolean)) {\n writeWarned = false;\n writeRetryWait = firstRetryWait;\n return true;\n }\n retryWrites();\n return false;\n }\n\n function stopRetryingWrites(): void {\n if (writeRetryTimer) clearTimeout(writeRetryTimer);\n writeRetryTimer = null;\n }\n\n function retryWrites(): void {\n stopRetryingWrites();\n if (retryMs === false || closed || stopped || queued.size === 0) return;\n writeRetryTimer = setTimeout(() => {\n writeRetryTimer = null;\n void flush();\n }, writeRetryWait);\n writeRetryWait = Math.min(writeRetryWait * 2, retryMaxMs);\n }\n\n const applyRemote = (changes: StorageChange[]): void => {\n const applied: RecordChange[] = [];\n const overruled: [string, unknown][] = [];\n for (const [key, value] of changes) {\n if (!key.startsWith(prefix)) continue;\n const name = key.slice(prefix.length);\n if (queued.has(name) || inFlight.has(name)) {\n overruled.push([name, value]);\n continue;\n }\n if (value === undefined) {\n if (!values.has(name)) continue;\n values.delete(name);\n } else {\n values.set(name, value);\n }\n applied.push({ name, value, origin: 'remote' });\n }\n if (overruled.length > 0) for (const listener of [...overruledListeners]) listener(overruled);\n if (applied.length > 0) emit(applied);\n };\n\n let unsubscribe = writable() ? storage.subscribe?.(prefix, applyRemote) : undefined;\n\n const stopRetrying = (): void => {\n if (retryTimer) clearTimeout(retryTimer);\n retryTimer = null;\n };\n\n const failed = (error: unknown): void => {\n if (!warned) {\n warned = true;\n console.warn(\n `[storage] could not read \"${prefix}\"; opening empty and holding writes until a read lands`,\n error,\n );\n }\n if (retryMs === false || closed || stopped) return;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void read();\n }, retryWait);\n retryWait = Math.min(retryWait * 2, retryMaxMs);\n };\n\n async function attempt(): Promise<boolean> {\n stopRetrying();\n // Listen before listing, so a change landing between the two is not lost.\n const early: StorageChange[] = [];\n const stopEarly = storage.subscribe?.(prefix, (c) => early.push(...c));\n let listed: StorageChange[];\n try {\n listed = await storage.list(prefix);\n } catch (error) {\n stopEarly?.();\n failed(error);\n return false;\n }\n if (closed || stopped) {\n stopEarly?.();\n return false;\n }\n unread = false;\n unsubscribe = storage.subscribe?.(prefix, applyRemote);\n stopEarly?.();\n // Skips every name with a write queued while unread, so those win.\n applyRemote([...listed, ...early]);\n if (queued.size > 0) schedule();\n landed();\n return true;\n }\n\n function read(): Promise<boolean> {\n if (!unread || stopped || closed) return Promise.resolve(!unread);\n reading ??= attempt().finally(() => {\n reading = null;\n });\n return reading;\n }\n\n const onPageHide = (): void => {\n void flush();\n };\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') void flush();\n };\n if (typeof window !== 'undefined') {\n window.addEventListener('pagehide', onPageHide);\n document.addEventListener('visibilitychange', onVisibility);\n }\n\n const remove = (name: string): void => {\n // An unread cache cannot tell what storage holds, so it queues the delete.\n if (!unread && !values.has(name) && !queued.has(name)) return;\n values.delete(name);\n queued.set(name, DELETED);\n emit([{ name, value: undefined, origin: 'local' }]);\n schedule();\n };\n\n const cache: OwnedRecordCache = {\n prefix,\n get writable() {\n return writable();\n },\n has: (name) => values.has(name),\n get: (name) => values.get(name),\n entries: (namePrefix = '') => [...values].filter(([name]) => name.startsWith(namePrefix)),\n set: (name, value) => {\n if (value === undefined) return remove(name);\n values.set(name, value);\n queued.set(name, value);\n emit([{ name, value, origin: 'local' }]);\n schedule();\n },\n delete: remove,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n flush,\n read,\n whenRead: () => hasRead,\n close: async () => {\n if (closed) return;\n stopRetrying();\n await flush();\n closed = true;\n stopRetryingWrites();\n unsubscribe?.();\n if (typeof window !== 'undefined') {\n window.removeEventListener('pagehide', onPageHide);\n document.removeEventListener('visibilitychange', onVisibility);\n }\n },\n onOverruled: (listener) => {\n overruledListeners.add(listener);\n return () => {\n overruledListeners.delete(listener);\n };\n },\n seed: (entries) => {\n for (const [name, value] of entries) values.set(name, value);\n },\n stopWriting: () => {\n stopped = true;\n queued.clear();\n if (timer) clearTimeout(timer);\n timer = null;\n stopRetrying();\n stopRetryingWrites();\n unsubscribe?.();\n },\n };\n return { cache, failed };\n}\n\n/** Read every record under `prefix` and hold them. A failed read opens the\n * cache empty with writing off, so it never overwrites what it could not\n * read, and tries again on a backoff. When a read lands, the cache holds it,\n * reports it as remote changes, and starts writing, sending first whatever\n * was written meanwhile. */\nexport async function openRecords(options: RecordCacheOptions): Promise<OwnedRecordCache> {\n const { cache } = buildCache(options, true);\n await cache.read();\n return cache;\n}\n\n/** `openRecords` for an adapter that reads synchronously: the cache is ready\n * on return. A failed read opens it empty with writing off, and it recovers\n * the way `openRecords` does. */\nexport function openRecordsSync(\n options: RecordCacheOptions & { storage: SyncStorageAdapter },\n): OwnedRecordCache {\n let listed: [string, unknown][];\n try {\n listed = options.storage.listSync(options.prefix);\n } catch (error) {\n const { cache, failed } = buildCache(options, true);\n failed(error);\n return cache;\n }\n const initial = listed.map(([key, value]): [string, unknown] => [\n key.slice(options.prefix.length),\n value,\n ]);\n return createRecordCache({ ...options, initial });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/indexedDb.ts","../src/json.ts","../src/webStorage.ts","../src/defaultStorage.ts","../src/memory.ts","../src/urlHash.ts","../src/urlHashAdapter.ts","../src/writeQueue.ts","../src/records.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { StorageAdapter, StorageChange } from './types';\n\n/** Options for `createIndexedDbAdapter`. */\nexport interface IndexedDbAdapterOptions {\n /** Default `'weasel'`. */\n database?: string;\n /** Default `'records'`. One object store per database: a store added to a\n * database that already exists is not created. */\n store?: string;\n}\n\ninterface NodeChannel extends BroadcastChannel {\n unref?: () => void;\n}\n\n/** Persist to IndexedDB, which stores structured-clone values natively — typed\n * arrays, `Map`s, `Blob`s — and holds far more than localStorage. Other tabs\n * hear writes through a `BroadcastChannel`. The database opens on first use. */\nexport function createIndexedDbAdapter({\n database = 'weasel',\n store = 'records',\n}: IndexedDbAdapterOptions = {}): StorageAdapter {\n let opened: Promise<IDBDatabase> | null = null;\n let connection: IDBDatabase | null = null;\n const forget = (db: IDBDatabase): void => {\n if (connection !== db) return;\n connection = null;\n opened = null;\n };\n const open = (): Promise<IDBDatabase> => {\n if (opened) return opened;\n const mine = new Promise<IDBDatabase>((resolve, reject) => {\n if (typeof indexedDB === 'undefined') {\n reject(new Error('[storage] IndexedDB is not available here'));\n return;\n }\n // No `onblocked`: a blocked open is still pending, and lands once the\n // connections in its way close.\n const request = indexedDB.open(database, 1);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(store)) {\n request.result.createObjectStore(store);\n }\n };\n request.onsuccess = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(store)) {\n db.close();\n reject(new Error(`[storage] IndexedDB database \"${database}\" has no store \"${store}\"`));\n return;\n }\n connection = db;\n // The browser closing the connection: site data cleared, or evicted.\n db.onclose = () => forget(db);\n // Another connection wants to delete or upgrade the database, and\n // waits for as long as this one stays open.\n db.onversionchange = () => {\n db.close();\n forget(db);\n };\n resolve(db);\n };\n request.onerror = () => reject(request.error);\n });\n opened = mine;\n // A failed open is not kept, so the next call tries again.\n mine.catch(() => {\n if (opened === mine) opened = null;\n });\n return mine;\n };\n\n const run = async <T>(\n mode: IDBTransactionMode,\n body: (s: IDBObjectStore) => () => T,\n ): Promise<T> => {\n let db = await open();\n let tx: IDBTransaction;\n try {\n tx = db.transaction(store, mode);\n } catch {\n // A connection that closed without saying so. One more, on a new one.\n forget(db);\n db = await open();\n tx = db.transaction(store, mode);\n }\n return new Promise<T>((resolve, reject) => {\n const result = body(tx.objectStore(store));\n tx.oncomplete = () => resolve(result());\n tx.onerror = () => reject(tx.error);\n tx.onabort = () => reject(tx.error);\n });\n };\n\n let channel: NodeChannel | null = null;\n const getChannel = (): NodeChannel | null => {\n if (typeof BroadcastChannel === 'undefined') return null;\n if (!channel) {\n channel = new BroadcastChannel(`weasel-storage:${database}:${store}`) as NodeChannel;\n // Node keeps its event loop alive for an open channel; a browser has no unref.\n channel.unref?.();\n }\n return channel;\n };\n const announce = (changes: StorageChange[]): void => {\n getChannel()?.postMessage(changes);\n };\n\n const adapter: StorageAdapter = {\n get: (key) =>\n run('readonly', (s) => {\n const request = s.get(key);\n return () => request.result as unknown;\n }),\n list: (prefix) =>\n run('readonly', (s) => {\n const range = IDBKeyRange.bound(prefix, `${prefix}`);\n const keys = s.getAllKeys(range);\n const values = s.getAll(range);\n return () =>\n keys.result.map((key, i): [string, unknown] => [String(key), values.result[i]]);\n }),\n set: async (key, value) => {\n await run('readwrite', (s) => {\n s.put(value, key);\n return () => undefined;\n });\n announce([[key, value]]);\n },\n delete: async (key) => {\n await run('readwrite', (s) => {\n s.delete(key);\n return () => undefined;\n });\n announce([[key, undefined]]);\n },\n };\n if (typeof BroadcastChannel !== 'undefined') {\n adapter.subscribe = (prefix, on) => {\n const ch = getChannel();\n if (!ch) return () => {};\n const handler = (e: MessageEvent<StorageChange[]>): void => {\n const mine = e.data.filter(([key]) => key.startsWith(prefix));\n if (mine.length > 0) on(mine);\n };\n ch.addEventListener('message', handler);\n return () => ch.removeEventListener('message', handler);\n };\n }\n return adapter;\n}\n\n/** IndexedDB under the default database and store. */\nexport const indexedDbAdapter: StorageAdapter = createIndexedDbAdapter();\n","/** Raw strings written before records existed come back as the string they\n * are. */\nexport function parse(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** Whether `JSON.stringify` would keep `value` exactly. An object key holding\n * `undefined` counts as kept: JSON drops the key, and reading back an absent\n * key yields the same `undefined`. */\nexport function isJsonSafe(value: unknown, seen: Set<object> = new Set()): boolean {\n if (value === null) return true;\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return true;\n case 'number':\n return Number.isFinite(value);\n case 'object': {\n if (seen.has(value)) return false;\n seen.add(value);\n const proto = Object.getPrototypeOf(value);\n const ok = Array.isArray(value)\n ? value.every((v) => isJsonSafe(v, seen))\n : (proto === Object.prototype || proto === null) &&\n Object.values(value).every((v) => v === undefined || isJsonSafe(v, seen));\n seen.delete(value);\n return ok;\n }\n default:\n return false;\n }\n}\n","import { isJsonSafe, parse } from './json';\nimport type { SyncStorageAdapter } from './types';\n\nfunction webStorageAdapter(area: () => Storage, name: string, crossTab: boolean): SyncStorageAdapter {\n const warned = new Set<string>();\n const keysNow = (prefix: string): string[] => {\n const store = area();\n const out: string[] = [];\n for (let i = 0; i < store.length; i++) {\n const key = store.key(i);\n if (key?.startsWith(prefix)) out.push(key);\n }\n return out;\n };\n const listNow = (prefix: string): [string, unknown][] => {\n const store = area();\n const out: [string, unknown][] = [];\n for (const key of keysNow(prefix)) {\n const raw = store.getItem(key);\n if (raw !== null) out.push([key, parse(raw)]);\n }\n return out;\n };\n // The keys each live subscription knows to exist. `clear()` in another tab\n // arrives as one event naming no key, so this is what says what went.\n const subscribers = new Set<{ prefix: string; keys: Set<string> }>();\n const note = (key: string, held: boolean): void => {\n for (const sub of subscribers) {\n if (!key.startsWith(sub.prefix)) continue;\n if (held) sub.keys.add(key);\n else sub.keys.delete(key);\n }\n };\n const adapter: SyncStorageAdapter = {\n get: async (key) => {\n const raw = area().getItem(key);\n return raw === null ? undefined : parse(raw);\n },\n list: async (prefix) => listNow(prefix),\n listSync: listNow,\n set: async (key, value) => {\n if (!warned.has(key) && !isJsonSafe(value)) {\n warned.add(key);\n console.warn(\n `[storage] \"${key}\" holds a value JSON cannot keep exactly; ${name} stores what JSON keeps. Use IndexedDB for binary or non-JSON state.`,\n );\n }\n area().setItem(key, JSON.stringify(value));\n note(key, true);\n },\n delete: async (key) => {\n area().removeItem(key);\n note(key, false);\n },\n };\n if (crossTab) {\n adapter.subscribe = (prefix, on) => {\n if (typeof window === 'undefined') return () => {};\n const sub = { prefix, keys: new Set(keysNow(prefix)) };\n subscribers.add(sub);\n const handler = (e: StorageEvent): void => {\n const store = area();\n if (e.storageArea !== store) return;\n if (e.key === null) {\n const gone = [...sub.keys].filter((key) => store.getItem(key) === null);\n for (const key of gone) sub.keys.delete(key);\n if (gone.length > 0) on(gone.map((key): [string, unknown] => [key, undefined]));\n return;\n }\n if (!e.key.startsWith(prefix)) return;\n if (e.newValue === null) sub.keys.delete(e.key);\n else sub.keys.add(e.key);\n on([[e.key, e.newValue === null ? undefined : parse(e.newValue)]]);\n };\n window.addEventListener('storage', handler);\n return () => {\n subscribers.delete(sub);\n window.removeEventListener('storage', handler);\n };\n };\n }\n return adapter;\n}\n\n/** Persist to `localStorage`, one JSON value per record. Survives a reload and\n * reaches other tabs through the `storage` event. */\nexport const localStorageAdapter: SyncStorageAdapter = webStorageAdapter(\n () => localStorage,\n 'localStorage',\n true,\n);\n\n/** Persist to `sessionStorage` — survives a reload but not a new tab. */\nexport const sessionStorageAdapter: SyncStorageAdapter = webStorageAdapter(\n () => sessionStorage,\n 'sessionStorage',\n false,\n);\n","import { indexedDbAdapter } from './indexedDb';\nimport type { StorageAdapter } from './types';\nimport { localStorageAdapter } from './webStorage';\n\n/** `preferred` if it opens, otherwise `fallback` — with a warning. */\nexport async function fallbackStorage(\n preferred: StorageAdapter,\n fallback: StorageAdapter = localStorageAdapter,\n label = 'preferred storage',\n): Promise<StorageAdapter> {\n try {\n await preferred.list(' ');\n return preferred;\n } catch (error) {\n console.warn(`[storage] ${label} would not open; using the fallback instead`, error);\n return fallback;\n }\n}\n\n/** A page-wide default: `preferred`, or localStorage where it will not open,\n * chosen on first call and kept until `resetDefaultStorage` (tests only). */\nexport function createDefaultStorage(\n preferred: StorageAdapter,\n label?: string,\n): { defaultStorage: () => Promise<StorageAdapter>; resetDefaultStorage: () => void } {\n let resolved: Promise<StorageAdapter> | null = null;\n return {\n defaultStorage: () => (resolved ??= fallbackStorage(preferred, localStorageAdapter, label)),\n resetDefaultStorage: () => {\n resolved = null;\n },\n };\n}\n\n/** IndexedDB under the default database, 'weasel', or localStorage where it\n * will not open. Resolved once per page. */\nexport const { defaultStorage, resetDefaultStorage } = createDefaultStorage(indexedDbAdapter, 'IndexedDB');\n","import type { StorageAdapter, StorageChange, SyncStorageAdapter } from './types';\n\ninterface MemorySubscriber {\n owner: StorageAdapter;\n prefix: string;\n on: (changes: StorageChange[]) => void;\n}\n\nconst memorySubscribers = new WeakMap<Map<string, unknown>, Set<MemorySubscriber>>();\n\n/** An in-memory store, discarded on reload. Values are copied in and out, as a\n * real substrate would. Adapters built over one shared `backing` hear each\n * other's writes — two tabs, for a test. */\nexport function createMemoryAdapter(backing: Map<string, unknown> = new Map()): SyncStorageAdapter {\n let subscribers = memorySubscribers.get(backing);\n if (!subscribers) {\n subscribers = new Set();\n memorySubscribers.set(backing, subscribers);\n }\n const peers = subscribers;\n const notify = (key: string, value: unknown): void => {\n for (const sub of peers) {\n if (sub.owner === adapter || !key.startsWith(sub.prefix)) continue;\n const copy = value === undefined ? undefined : structuredClone(value);\n queueMicrotask(() => sub.on([[key, copy]]));\n }\n };\n const listNow = (prefix: string): [string, unknown][] =>\n [...backing]\n .filter(([key]) => key.startsWith(prefix))\n .map(([key, value]): [string, unknown] => [key, structuredClone(value)]);\n const adapter: SyncStorageAdapter = {\n get: async (key) => (backing.has(key) ? structuredClone(backing.get(key)) : undefined),\n list: async (prefix) => listNow(prefix),\n listSync: listNow,\n set: async (key, value) => {\n const copy = structuredClone(value);\n backing.set(key, copy);\n notify(key, copy);\n },\n delete: async (key) => {\n backing.delete(key);\n notify(key, undefined);\n },\n subscribe: (prefix, on) => {\n const sub = { owner: adapter, prefix, on };\n peers.add(sub);\n return () => {\n peers.delete(sub);\n };\n },\n };\n return adapter;\n}\n\n/** Persists nothing and reads back nothing. */\nexport const noneAdapter: SyncStorageAdapter = {\n get: async () => undefined,\n list: async () => [],\n listSync: () => [],\n set: async () => {},\n delete: async () => {},\n};\n","/** Encode a string for the URL fragment. */\nexport function encodeUrlHash(value: string): string {\n return btoa(encodeURIComponent(value));\n}\n\n/** Decode a URL fragment written by `encodeUrlHash`, or `null` if it is\n * malformed. */\nexport function decodeUrlHash(hash: string): string | null {\n if (!hash) return null;\n try {\n return decodeURIComponent(atob(hash));\n } catch {\n return null;\n }\n}\n","import { parse } from './json';\nimport type { StorageAdapter, StorageChange } from './types';\nimport { decodeUrlHash, encodeUrlHash } from './urlHash';\n\nconst URL_HASH_GUARD = typeof window !== 'undefined';\n\n/** The fragment's records, each still the JSON text it is stored as. Anyone\n * can write a fragment, so whatever is not a map of strings reads as absent.\n * No prototype, so a record may be named for anything an object inherits. */\nfunction readHashMap(): Record<string, string> {\n const map = Object.create(null) as Record<string, string>;\n if (!URL_HASH_GUARD) return map;\n const raw = decodeUrlHash(window.location.hash.replace(/^#/, ''));\n if (!raw) return map;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return map;\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return map;\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value === 'string') map[key] = value;\n }\n return map;\n}\n\n/** What each live subscription last saw, refreshed on this page's own writes\n * so `hashchange` reports only somebody else's. */\nconst hashSubscribers = new Set<{ last: Record<string, string> }>();\n\nfunction writeHashMap(map: Record<string, string>): void {\n if (!URL_HASH_GUARD) return;\n const encoded = encodeUrlHash(JSON.stringify(map));\n window.history.replaceState(window.history.state, '', `#${encoded}`);\n for (const sub of hashSubscribers) sub.last = Object.assign(Object.create(null), map);\n}\n\n/** Persist into the URL fragment, so the page's link carries its state and can\n * be shared or bookmarked. Changes to the fragment made elsewhere — a pasted\n * link, back and forward — arrive through `hashchange`. */\nexport const urlHashAdapter: StorageAdapter = {\n get: async (key) => {\n const raw = readHashMap()[key];\n return raw === undefined ? undefined : parse(raw);\n },\n list: async (prefix) =>\n Object.entries(readHashMap())\n .filter(([key]) => key.startsWith(prefix))\n .map(([key, raw]): [string, unknown] => [key, parse(raw)]),\n set: async (key, value) => {\n const map = readHashMap();\n map[key] = JSON.stringify(value);\n writeHashMap(map);\n },\n delete: async (key) => {\n const map = readHashMap();\n delete map[key];\n writeHashMap(map);\n },\n subscribe: (prefix, on) => {\n if (!URL_HASH_GUARD) return () => {};\n const sub = { last: readHashMap() };\n hashSubscribers.add(sub);\n const handler = (): void => {\n const next = readHashMap();\n const changes: StorageChange[] = [];\n for (const key of new Set([...Object.keys(sub.last), ...Object.keys(next)])) {\n if (!key.startsWith(prefix) || sub.last[key] === next[key]) continue;\n const raw = next[key];\n changes.push([key, raw === undefined ? undefined : parse(raw)]);\n }\n sub.last = next;\n if (changes.length > 0) on(changes);\n };\n window.addEventListener('hashchange', handler);\n return () => {\n hashSubscribers.delete(sub);\n window.removeEventListener('hashchange', handler);\n };\n },\n};\n","import type { StorageAdapter } from './types';\n\n/** What the queue holds for a record to delete. */\nexport const DELETED = Symbol('deleted');\n\n/** What a write queue reads from the cache it writes for. */\nexport interface WriteQueueOptions {\n storage: StorageAdapter;\n prefix: string;\n debounceMs: number;\n maxWaitMs: number;\n retryMs: number | false;\n retryMaxMs: number;\n /** Whether a batch may leave now. */\n writable(): boolean;\n closed(): boolean;\n stopped(): boolean;\n}\n\n/** A cache's writes on their way to storage: the newest per record, sent on a\n * debounce, and sent again on a backoff when storage rejects one. */\nexport interface WriteQueue {\n /** How many records have a write waiting to leave. */\n readonly size: number;\n /** Whether a write to `name` is waiting to leave. */\n has(name: string): boolean;\n /** Whether a write to `name` is waiting or on its way. */\n owns(name: string): boolean;\n /** Queue `value` for `name`, replacing a write still waiting. */\n add(name: string, value: unknown): void;\n /** Send what is queued after the debounce. */\n schedule(): void;\n /** Send what is queued now. Resolves as `RecordCache.flush` does. */\n flush(): Promise<boolean>;\n /** Stop sending rejected writes again on a timer. */\n stopRetrying(): void;\n /** Drop every queued write and every timer. */\n discard(): void;\n}\n\nexport function createWriteQueue(options: WriteQueueOptions): WriteQueue {\n const { storage, prefix, debounceMs, maxWaitMs, retryMs, retryMaxMs, writable, closed, stopped } = options;\n const queued = new Map<string, unknown>();\n // How many writes to each name are on their way to storage.\n const inFlight = new Map<string, number>();\n let timer: ReturnType<typeof setTimeout> | null = null;\n let firstQueuedAt: number | null = null;\n const firstRetryWait = retryMs === false ? 0 : retryMs;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n let retryWait = firstRetryWait;\n let warned = false;\n let sending: Promise<boolean> | null = null;\n\n const schedule = (): void => {\n if (!writable() || closed()) return;\n const now = Date.now();\n firstQueuedAt ??= now;\n if (timer) clearTimeout(timer);\n const wait = Math.max(0, Math.min(debounceMs, firstQueuedAt + maxWaitMs - now));\n timer = setTimeout(() => {\n timer = null;\n void flush();\n }, wait);\n };\n\n // One batch is on its way at a time. A rejected write is back in the queue\n // before the next batch is taken, so a newer write to its record stands.\n function flush(): Promise<boolean> {\n if (timer) clearTimeout(timer);\n timer = null;\n firstQueuedAt = null;\n // With nothing on its way the batch leaves in this tick, which a flush\n // on `pagehide` depends on.\n const mine = sending ? sending.then(send) : send();\n sending = mine;\n void mine.finally(() => {\n if (sending === mine) sending = null;\n });\n return mine;\n }\n\n async function write(name: string, value: unknown): Promise<boolean> {\n const key = prefix + name;\n try {\n if (value === DELETED) await storage.delete(key);\n else await storage.set(key, value);\n return true;\n } catch (error) {\n if (!warned) {\n warned = true;\n console.warn(`[storage] could not write \"${key}\"; trying again`, error);\n }\n // A write queued since is newer, and stands.\n if (!queued.has(name) && !stopped()) queued.set(name, value);\n return false;\n } finally {\n const count = inFlight.get(name) ?? 1;\n if (count > 1) inFlight.set(name, count - 1);\n else inFlight.delete(name);\n }\n }\n\n async function send(): Promise<boolean> {\n if (queued.size === 0) return true;\n if (!writable()) return false;\n stopRetrying();\n const batch = [...queued];\n queued.clear();\n for (const [name] of batch) inFlight.set(name, (inFlight.get(name) ?? 0) + 1);\n const landed = await Promise.all(batch.map(([name, value]) => write(name, value)));\n if (landed.every(Boolean)) {\n warned = false;\n retryWait = firstRetryWait;\n return true;\n }\n retry();\n return false;\n }\n\n function stopRetrying(): void {\n if (retryTimer) clearTimeout(retryTimer);\n retryTimer = null;\n }\n\n function retry(): void {\n stopRetrying();\n if (retryMs === false || closed() || stopped() || queued.size === 0) return;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void flush();\n }, retryWait);\n retryWait = Math.min(retryWait * 2, retryMaxMs);\n }\n\n return {\n get size() {\n return queued.size;\n },\n has: (name) => queued.has(name),\n owns: (name) => queued.has(name) || inFlight.has(name),\n add: (name, value) => {\n queued.set(name, value);\n },\n schedule,\n flush,\n stopRetrying,\n discard: () => {\n queued.clear();\n if (timer) clearTimeout(timer);\n timer = null;\n stopRetrying();\n },\n };\n}\n","import type { StorageAdapter, StorageChange, SyncStorageAdapter } from './types';\nimport { DELETED, createWriteQueue } from './writeQueue';\n\n/** One record changing, as a cache listener hears it. `value` is `undefined`\n * for a delete. `local` changes were made through this cache; `remote` ones\n * came from another writer. */\nexport interface RecordChange {\n name: string;\n value: unknown;\n origin: 'local' | 'remote';\n}\n\n/**\n * Every record under one prefix, held in memory: the only thing that talks to\n * a `StorageAdapter`. Names are keys with the prefix removed.\n *\n * Writes land in memory at once and reach storage on a debounce. The newest\n * write to a record wins: another writer's change to a record with a write\n * still queued or on its way here is ignored, since that write lands after\n * it. A write storage rejects stays queued and is sent again on a backoff.\n */\nexport interface RecordCache {\n readonly prefix: string;\n /** False while writing is off, so nothing here can overwrite the records:\n * until a first read that failed lands on a later try, and for good once\n * the opener marks them read-only. */\n readonly writable: boolean;\n has(name: string): boolean;\n get(name: string): unknown;\n /** Every record whose name starts with `namePrefix`. */\n entries(namePrefix?: string): [string, unknown][];\n /** `undefined` is no value a record can hold: setting it deletes. */\n set(name: string, value: unknown): void;\n delete(name: string): void;\n subscribe(listener: (changes: RecordChange[]) => void): () => void;\n /** Send queued writes now. Resolves true when every queued write landed or\n * none was queued; false when a write threw (it stays queued) or writing\n * is off and writes were queued. */\n flush(): Promise<boolean>;\n /** Try a failed first read again now, ahead of the backoff. Resolves\n * whether the records have been read. */\n read(): Promise<boolean>;\n /** Resolves once the records have been read: at once for a cache that\n * opened with them, and when a later read lands for one whose first read\n * failed. Never resolves for a cache closed or stopped before that. */\n whenRead(): Promise<void>;\n /** Send queued writes, stop hearing other writers, and stop retrying. */\n close(): Promise<void>;\n}\n\n/** The parts of a cache only its opener uses. */\nexport interface OwnedRecordCache extends RecordCache {\n /** Hold these records without writing them back. */\n seed(entries: Iterable<[string, unknown]>): void;\n /** Hear another writer's changes this cache did not take, because its own\n * write to the record was queued or on its way: each a name and the value\n * the other writer set, `undefined` for a delete. */\n onOverruled(listener: (changes: [string, unknown][]) => void): () => void;\n stopWriting(): void;\n}\n\n/** Options for `openRecords`, and the part of `createRecordCache`'s the two share. */\nexport interface RecordCacheOptions {\n storage: StorageAdapter;\n prefix: string;\n /** Trailing debounce on writes. Default 300 ms. */\n debounceMs?: number;\n /** The longest a write waits under continuous change. Default 1000 ms. */\n maxWaitMs?: number;\n /** The wait before a failed first read, or a write storage rejected, is\n * tried again, doubling after each failure. Default 1000 ms; `false` never\n * tries again on its own, leaving a rejected write for the next flush. */\n retryMs?: number | false;\n /** The longest wait between those tries. Default 30000 ms. */\n retryMaxMs?: number;\n}\n\n/** Options for `createRecordCache`. */\nexport interface CreateRecordCacheOptions extends RecordCacheOptions {\n /** The records the cache opens holding, each a name and its value. Default none. */\n initial?: Iterable<[string, unknown]>;\n /** False opens the cache with writing off for good. Default true. */\n writable?: boolean;\n}\n\n/** A cache holding `initial`, with nothing read from storage. */\nexport function createRecordCache(options: CreateRecordCacheOptions): OwnedRecordCache {\n return buildCache(options, false).cache;\n}\n\n/** `startUnread` leaves the cache waiting on a first read: `cache.read()`\n * makes it, and `failed` reports one made elsewhere that threw. */\nfunction buildCache(\n options: CreateRecordCacheOptions,\n startUnread: boolean,\n): { cache: OwnedRecordCache; failed: (error: unknown) => void } {\n const { storage, prefix } = options;\n const retryMs = options.retryMs ?? 1000;\n const retryMaxMs = options.retryMaxMs ?? 30_000;\n const values = new Map<string, unknown>(options.initial ?? []);\n const listeners = new Set<(changes: RecordChange[]) => void>();\n const overruledListeners = new Set<(changes: [string, unknown][]) => void>();\n // Two reasons writing is off. A read landing clears `unread`; nothing\n // clears `stopped`, which is the opener's choice.\n let unread = startUnread;\n let stopped = !(options.writable ?? true);\n const writable = (): boolean => !unread && !stopped;\n let closed = false;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n let retryWait = retryMs === false ? 0 : retryMs;\n let reading: Promise<boolean> | null = null;\n let warned = false;\n let landed = (): void => {};\n const hasRead = new Promise<void>((resolve) => {\n if (startUnread) landed = resolve;\n else resolve();\n });\n\n const emit = (changes: RecordChange[]): void => {\n for (const listener of [...listeners]) listener(changes);\n };\n\n const queue = createWriteQueue({\n storage,\n prefix,\n debounceMs: options.debounceMs ?? 300,\n maxWaitMs: options.maxWaitMs ?? 1000,\n retryMs,\n retryMaxMs,\n writable,\n closed: () => closed,\n stopped: () => stopped,\n });\n\n const applyRemote = (changes: StorageChange[]): void => {\n const applied: RecordChange[] = [];\n const overruled: [string, unknown][] = [];\n for (const [key, value] of changes) {\n if (!key.startsWith(prefix)) continue;\n const name = key.slice(prefix.length);\n if (queue.owns(name)) {\n overruled.push([name, value]);\n continue;\n }\n if (value === undefined) {\n if (!values.has(name)) continue;\n values.delete(name);\n } else {\n values.set(name, value);\n }\n applied.push({ name, value, origin: 'remote' });\n }\n if (overruled.length > 0) for (const listener of [...overruledListeners]) listener(overruled);\n if (applied.length > 0) emit(applied);\n };\n\n let unsubscribe = writable() ? storage.subscribe?.(prefix, applyRemote) : undefined;\n\n const stopRetrying = (): void => {\n if (retryTimer) clearTimeout(retryTimer);\n retryTimer = null;\n };\n\n const failed = (error: unknown): void => {\n if (!warned) {\n warned = true;\n console.warn(\n `[storage] could not read \"${prefix}\"; opening empty and holding writes until a read lands`,\n error,\n );\n }\n if (retryMs === false || closed || stopped) return;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void read();\n }, retryWait);\n retryWait = Math.min(retryWait * 2, retryMaxMs);\n };\n\n async function attempt(): Promise<boolean> {\n stopRetrying();\n // Listen before listing, so a change landing between the two is not lost.\n const early: StorageChange[] = [];\n const stopEarly = storage.subscribe?.(prefix, (c) => early.push(...c));\n let listed: StorageChange[];\n try {\n listed = await storage.list(prefix);\n } catch (error) {\n stopEarly?.();\n failed(error);\n return false;\n }\n if (closed || stopped) {\n stopEarly?.();\n return false;\n }\n unread = false;\n unsubscribe = storage.subscribe?.(prefix, applyRemote);\n stopEarly?.();\n // Skips every name with a write queued while unread, so those win.\n applyRemote([...listed, ...early]);\n if (queue.size > 0) queue.schedule();\n landed();\n return true;\n }\n\n function read(): Promise<boolean> {\n if (!unread || stopped || closed) return Promise.resolve(!unread);\n reading ??= attempt().finally(() => {\n reading = null;\n });\n return reading;\n }\n\n const onPageHide = (): void => {\n void queue.flush();\n };\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') void queue.flush();\n };\n if (typeof window !== 'undefined') {\n window.addEventListener('pagehide', onPageHide);\n document.addEventListener('visibilitychange', onVisibility);\n }\n\n const remove = (name: string): void => {\n // An unread cache cannot tell what storage holds, so it queues the delete.\n if (!unread && !values.has(name) && !queue.has(name)) return;\n values.delete(name);\n queue.add(name, DELETED);\n emit([{ name, value: undefined, origin: 'local' }]);\n queue.schedule();\n };\n\n const cache: OwnedRecordCache = {\n prefix,\n get writable() {\n return writable();\n },\n has: (name) => values.has(name),\n get: (name) => values.get(name),\n entries: (namePrefix = '') => [...values].filter(([name]) => name.startsWith(namePrefix)),\n set: (name, value) => {\n if (value === undefined) return remove(name);\n values.set(name, value);\n queue.add(name, value);\n emit([{ name, value, origin: 'local' }]);\n queue.schedule();\n },\n delete: remove,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n flush: queue.flush,\n read,\n whenRead: () => hasRead,\n close: async () => {\n if (closed) return;\n stopRetrying();\n await queue.flush();\n closed = true;\n queue.stopRetrying();\n unsubscribe?.();\n if (typeof window !== 'undefined') {\n window.removeEventListener('pagehide', onPageHide);\n document.removeEventListener('visibilitychange', onVisibility);\n }\n },\n onOverruled: (listener) => {\n overruledListeners.add(listener);\n return () => {\n overruledListeners.delete(listener);\n };\n },\n seed: (entries) => {\n for (const [name, value] of entries) values.set(name, value);\n },\n stopWriting: () => {\n stopped = true;\n queue.discard();\n stopRetrying();\n unsubscribe?.();\n },\n };\n return { cache, failed };\n}\n\n/** Read every record under `prefix` and hold them. A failed read opens the\n * cache empty with writing off, so it never overwrites what it could not\n * read, and tries again on a backoff. When a read lands, the cache holds it,\n * reports it as remote changes, and starts writing, sending first whatever\n * was written meanwhile. */\nexport async function openRecords(options: RecordCacheOptions): Promise<OwnedRecordCache> {\n const { cache } = buildCache(options, true);\n await cache.read();\n return cache;\n}\n\n/** `openRecords` for an adapter that reads synchronously: the cache is ready\n * on return. A failed read opens it empty with writing off, and it recovers\n * the way `openRecords` does. */\nexport function openRecordsSync(\n options: RecordCacheOptions & { storage: SyncStorageAdapter },\n): OwnedRecordCache {\n let listed: [string, unknown][];\n try {\n listed = options.storage.listSync(options.prefix);\n } catch (error) {\n const { cache, failed } = buildCache(options, true);\n failed(error);\n return cache;\n }\n const initial = listed.map(([key, value]): [string, unknown] => [\n key.slice(options.prefix.length),\n value,\n ]);\n return createRecordCache({ ...options, initial });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/storage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Keyed async storage behind one adapter interface — IndexedDB, localStorage, the URL hash, memory — and an in-memory record cache that writes behind and hears other tabs. No React, no weasel deps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|