@weasel-js/storage 1.9.4 → 1.10.1

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 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 `createRecordCache` and `openRecords`. */
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
- type CreateOptions = RecordCacheOptions & {
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: CreateOptions): OwnedRecordCache;
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
@@ -1,3 +1,5 @@
1
+ import { createEmitter } from '@weasel-js/registry';
2
+
1
3
  // src/indexedDb.ts
2
4
  function createIndexedDbAdapter({
3
5
  database = "weasel",
@@ -388,48 +390,21 @@ var urlHashAdapter = {
388
390
  }
389
391
  };
390
392
 
391
- // src/records.ts
393
+ // src/writeQueue.ts
392
394
  var DELETED = /* @__PURE__ */ Symbol("deleted");
393
- function createRecordCache(options) {
394
- return buildCache(options, false).cache;
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 ?? []);
395
+ function createWriteQueue(options) {
396
+ const { storage, prefix, debounceMs, maxWaitMs, retryMs, retryMaxMs, writable, closed, stopped } = options;
403
397
  const queued = /* @__PURE__ */ new Map();
404
398
  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
399
  let timer = null;
412
400
  let firstQueuedAt = null;
413
- let retryTimer = null;
414
401
  const firstRetryWait = retryMs === false ? 0 : retryMs;
402
+ let retryTimer = null;
415
403
  let retryWait = firstRetryWait;
416
- let reading = null;
417
404
  let warned = false;
418
- let writeRetryTimer = null;
419
- let writeRetryWait = retryWait;
420
- let writeWarned = false;
421
405
  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
406
  const schedule = () => {
432
- if (!writable() || closed) return;
407
+ if (!writable() || closed()) return;
433
408
  const now = Date.now();
434
409
  firstQueuedAt ??= now;
435
410
  if (timer) clearTimeout(timer);
@@ -450,62 +425,119 @@ function buildCache(options, startUnread) {
450
425
  });
451
426
  return mine;
452
427
  }
428
+ async function write(name, value) {
429
+ const key = prefix + name;
430
+ try {
431
+ if (value === DELETED) await storage.delete(key);
432
+ else await storage.set(key, value);
433
+ return true;
434
+ } catch (error) {
435
+ if (!warned) {
436
+ warned = true;
437
+ console.warn(`[storage] could not write "${key}"; trying again`, error);
438
+ }
439
+ if (!queued.has(name) && !stopped()) queued.set(name, value);
440
+ return false;
441
+ } finally {
442
+ const count = inFlight.get(name) ?? 1;
443
+ if (count > 1) inFlight.set(name, count - 1);
444
+ else inFlight.delete(name);
445
+ }
446
+ }
453
447
  async function send() {
454
448
  if (queued.size === 0) return true;
455
449
  if (!writable()) return false;
456
- stopRetryingWrites();
450
+ stopRetrying();
457
451
  const batch = [...queued];
458
452
  queued.clear();
459
453
  for (const [name] of batch) inFlight.set(name, (inFlight.get(name) ?? 0) + 1);
460
- const landed2 = await Promise.all(
461
- batch.map(async ([name, value]) => {
462
- const key = prefix + name;
463
- try {
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;
454
+ const landed = await Promise.all(batch.map(([name, value]) => write(name, value)));
455
+ if (landed.every(Boolean)) {
456
+ warned = false;
457
+ retryWait = firstRetryWait;
484
458
  return true;
485
459
  }
486
- retryWrites();
460
+ retry();
487
461
  return false;
488
462
  }
489
- function stopRetryingWrites() {
490
- if (writeRetryTimer) clearTimeout(writeRetryTimer);
491
- writeRetryTimer = null;
463
+ function stopRetrying() {
464
+ if (retryTimer) clearTimeout(retryTimer);
465
+ retryTimer = null;
492
466
  }
493
- function retryWrites() {
494
- stopRetryingWrites();
495
- if (retryMs === false || closed || stopped || queued.size === 0) return;
496
- writeRetryTimer = setTimeout(() => {
497
- writeRetryTimer = null;
467
+ function retry() {
468
+ stopRetrying();
469
+ if (retryMs === false || closed() || stopped() || queued.size === 0) return;
470
+ retryTimer = setTimeout(() => {
471
+ retryTimer = null;
498
472
  void flush();
499
- }, writeRetryWait);
500
- writeRetryWait = Math.min(writeRetryWait * 2, retryMaxMs);
473
+ }, retryWait);
474
+ retryWait = Math.min(retryWait * 2, retryMaxMs);
501
475
  }
476
+ return {
477
+ get size() {
478
+ return queued.size;
479
+ },
480
+ has: (name) => queued.has(name),
481
+ owns: (name) => queued.has(name) || inFlight.has(name),
482
+ add: (name, value) => {
483
+ queued.set(name, value);
484
+ },
485
+ schedule,
486
+ flush,
487
+ stopRetrying,
488
+ discard: () => {
489
+ queued.clear();
490
+ if (timer) clearTimeout(timer);
491
+ timer = null;
492
+ stopRetrying();
493
+ }
494
+ };
495
+ }
496
+
497
+ // src/records.ts
498
+ function createRecordCache(options) {
499
+ return buildCache(options, false).cache;
500
+ }
501
+ function buildCache(options, startUnread) {
502
+ const { storage, prefix } = options;
503
+ const retryMs = options.retryMs ?? 1e3;
504
+ const retryMaxMs = options.retryMaxMs ?? 3e4;
505
+ const values = new Map(options.initial ?? []);
506
+ const changed = createEmitter();
507
+ const overruledEmitter = createEmitter();
508
+ let unread = startUnread;
509
+ let stopped = !(options.writable ?? true);
510
+ const writable = () => !unread && !stopped;
511
+ let closed = false;
512
+ let retryTimer = null;
513
+ let retryWait = retryMs === false ? 0 : retryMs;
514
+ let reading = null;
515
+ let warned = false;
516
+ let landed = () => {
517
+ };
518
+ const hasRead = new Promise((resolve) => {
519
+ if (startUnread) landed = resolve;
520
+ else resolve();
521
+ });
522
+ const emit = changed.emit;
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 (queued.has(name) || inFlight.has(name)) {
540
+ if (queue.owns(name)) {
509
541
  overruled.push([name, value]);
510
542
  continue;
511
543
  }
@@ -517,7 +549,7 @@ function buildCache(options, startUnread) {
517
549
  }
518
550
  applied.push({ name, value, origin: "remote" });
519
551
  }
520
- if (overruled.length > 0) for (const listener of [...overruledListeners]) listener(overruled);
552
+ if (overruled.length > 0) overruledEmitter.emit(overruled);
521
553
  if (applied.length > 0) emit(applied);
522
554
  };
523
555
  let unsubscribe = writable() ? storage.subscribe?.(prefix, applyRemote) : void 0;
@@ -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 (queued.size > 0) schedule();
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) && !queued.has(name)) return;
617
+ if (!unread && !values.has(name) && !queue.has(name)) return;
586
618
  values.delete(name);
587
- queued.set(name, DELETED);
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,48 +631,35 @@ 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
- queued.set(name, value);
634
+ queue.add(name, value);
603
635
  emit([{ name, value, origin: "local" }]);
604
- schedule();
636
+ queue.schedule();
605
637
  },
606
638
  delete: remove,
607
- subscribe: (listener) => {
608
- listeners.add(listener);
609
- return () => {
610
- listeners.delete(listener);
611
- };
612
- },
613
- flush,
639
+ subscribe: changed.subscribe,
640
+ flush: queue.flush,
614
641
  read,
615
642
  whenRead: () => hasRead,
616
643
  close: async () => {
617
644
  if (closed) return;
618
645
  stopRetrying();
619
- await flush();
646
+ await queue.flush();
620
647
  closed = true;
621
- stopRetryingWrites();
648
+ queue.stopRetrying();
622
649
  unsubscribe?.();
623
650
  if (typeof window !== "undefined") {
624
651
  window.removeEventListener("pagehide", onPageHide);
625
652
  document.removeEventListener("visibilitychange", onVisibility);
626
653
  }
627
654
  },
628
- onOverruled: (listener) => {
629
- overruledListeners.add(listener);
630
- return () => {
631
- overruledListeners.delete(listener);
632
- };
633
- },
655
+ onOverruled: overruledEmitter.subscribe,
634
656
  seed: (entries) => {
635
657
  for (const [name, value] of entries) values.set(name, value);
636
658
  },
637
659
  stopWriting: () => {
638
660
  stopped = true;
639
- queued.clear();
640
- if (timer) clearTimeout(timer);
641
- timer = null;
661
+ queue.discard();
642
662
  stopRetrying();
643
- stopRetryingWrites();
644
663
  unsubscribe?.();
645
664
  }
646
665
  };
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 { createEmitter } from '@weasel-js/registry';\nimport 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 changed = createEmitter<[RecordChange[]]>();\n const overruledEmitter = createEmitter<[[string, unknown][]]>();\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 = changed.emit;\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) overruledEmitter.emit(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: changed.subscribe,\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: overruledEmitter.subscribe,\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,7 +1,7 @@
1
1
  {
2
2
  "name": "@weasel-js/storage",
3
- "version": "1.9.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.",
3
+ "version": "1.10.1",
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.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -15,6 +15,9 @@
15
15
  },
16
16
  "./package.json": "./package.json"
17
17
  },
18
+ "dependencies": {
19
+ "@weasel-js/registry": "1.10.1"
20
+ },
18
21
  "author": "orochi235",
19
22
  "homepage": "https://orochi235.github.io/weasel/",
20
23
  "repository": {