@vielzeug/vault 1.0.3 → 2.0.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.
Files changed (86) hide show
  1. package/README.md +18 -59
  2. package/dist/_dev.cjs +1 -1
  3. package/dist/_dev.cjs.map +1 -1
  4. package/dist/_dev.js +3 -8
  5. package/dist/_dev.js.map +1 -1
  6. package/dist/adapter-core.cjs +1 -1
  7. package/dist/adapter-core.cjs.map +1 -1
  8. package/dist/adapter-core.d.ts +6 -3
  9. package/dist/adapter-core.d.ts.map +1 -1
  10. package/dist/adapter-core.js +138 -148
  11. package/dist/adapter-core.js.map +1 -1
  12. package/dist/adapters/indexeddb.cjs +1 -1
  13. package/dist/adapters/indexeddb.cjs.map +1 -1
  14. package/dist/adapters/indexeddb.d.ts +2 -5
  15. package/dist/adapters/indexeddb.d.ts.map +1 -1
  16. package/dist/adapters/indexeddb.js +113 -127
  17. package/dist/adapters/indexeddb.js.map +1 -1
  18. package/dist/adapters/memory.cjs +1 -1
  19. package/dist/adapters/memory.cjs.map +1 -1
  20. package/dist/adapters/memory.d.ts +3 -9
  21. package/dist/adapters/memory.d.ts.map +1 -1
  22. package/dist/adapters/memory.js +104 -140
  23. package/dist/adapters/memory.js.map +1 -1
  24. package/dist/adapters/webstorage.cjs +1 -1
  25. package/dist/adapters/webstorage.cjs.map +1 -1
  26. package/dist/adapters/webstorage.d.ts +3 -3
  27. package/dist/adapters/webstorage.d.ts.map +1 -1
  28. package/dist/adapters/webstorage.js +72 -67
  29. package/dist/adapters/webstorage.js.map +1 -1
  30. package/dist/errors.cjs.map +1 -1
  31. package/dist/errors.js.map +1 -1
  32. package/dist/index.cjs +1 -1
  33. package/dist/index.d.ts +2 -7
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +8 -10
  36. package/dist/internal.cjs +1 -1
  37. package/dist/internal.cjs.map +1 -1
  38. package/dist/internal.d.ts +8 -37
  39. package/dist/internal.d.ts.map +1 -1
  40. package/dist/internal.js +48 -98
  41. package/dist/internal.js.map +1 -1
  42. package/dist/migration.cjs +1 -1
  43. package/dist/migration.cjs.map +1 -1
  44. package/dist/migration.js +1 -3
  45. package/dist/migration.js.map +1 -1
  46. package/dist/prune.cjs +1 -1
  47. package/dist/prune.cjs.map +1 -1
  48. package/dist/prune.d.ts +2 -2
  49. package/dist/prune.d.ts.map +1 -1
  50. package/dist/prune.js +13 -13
  51. package/dist/prune.js.map +1 -1
  52. package/dist/query.cjs +1 -1
  53. package/dist/query.cjs.map +1 -1
  54. package/dist/query.d.ts +6 -6
  55. package/dist/query.d.ts.map +1 -1
  56. package/dist/query.js +1 -1
  57. package/dist/query.js.map +1 -1
  58. package/dist/streaming.d.ts +1 -21
  59. package/dist/streaming.d.ts.map +1 -1
  60. package/dist/ttl.cjs +1 -1
  61. package/dist/ttl.cjs.map +1 -1
  62. package/dist/ttl.d.ts +2 -47
  63. package/dist/ttl.d.ts.map +1 -1
  64. package/dist/ttl.js +1 -8
  65. package/dist/ttl.js.map +1 -1
  66. package/dist/types.cjs.map +1 -1
  67. package/dist/types.d.ts +29 -316
  68. package/dist/types.d.ts.map +1 -1
  69. package/dist/types.js.map +1 -1
  70. package/dist/vault.cjs +1 -1
  71. package/dist/vault.cjs.map +1 -1
  72. package/dist/vault.iife.js +1 -1
  73. package/dist/vault.iife.js.map +1 -1
  74. package/dist/vault.js +1 -1
  75. package/dist/vault.js.map +1 -1
  76. package/dist/versioned-codec.d.ts +1 -43
  77. package/dist/versioned-codec.d.ts.map +1 -1
  78. package/package.json +7 -7
  79. package/dist/streaming.cjs +0 -2
  80. package/dist/streaming.cjs.map +0 -1
  81. package/dist/streaming.js +0 -21
  82. package/dist/streaming.js.map +0 -1
  83. package/dist/versioned-codec.cjs +0 -2
  84. package/dist/versioned-codec.cjs.map +0 -1
  85. package/dist/versioned-codec.js +0 -32
  86. package/dist/versioned-codec.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import type { Adapter, AnySchema, BaseAdapterOptions, KeyOf, RecordOf, TtlMs } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { VaultDisposedError } from '../errors';\nimport { getRecordKey } from '../internal';\nimport { defaultCodec, isExpired, type StoredRecord } from '../ttl';\n\ntype MemoryBroadcastMsg =\n | { table: string; type: 'clear' }\n | { key: string; table: string; type: 'delete' }\n | { keys: string[]; table: string; type: 'deleteMany' }\n | { key: string; stored: StoredRecord<unknown>; table: string; type: 'put' }\n | { entries: Array<{ key: string; stored: StoredRecord<unknown> }>; table: string; type: 'putAll' };\n\n/** Runtime type guard — rejects malformed or unknown BroadcastChannel messages. */\nfunction makeBroadcastMsgGuard(codec: { decode<T>(raw: unknown): (StoredRecord<T> & { value: T }) | undefined }) {\n return function isBroadcastMsg(data: unknown): data is MemoryBroadcastMsg {\n if (typeof data !== 'object' || data === null) return false;\n\n const d = data as Record<string, unknown>;\n\n if (typeof d['table'] !== 'string' || typeof d['type'] !== 'string') return false;\n\n // Guard against prototype-polluting table names from crafted cross-tab messages.\n if (d['table'] === '__proto__' || d['table'] === 'constructor' || d['table'] === 'prototype') return false;\n\n switch (d['type']) {\n case 'clear':\n return true;\n case 'delete':\n return typeof d['key'] === 'string';\n case 'deleteMany':\n return Array.isArray(d['keys']) && (d['keys'] as unknown[]).every((k) => typeof k === 'string');\n case 'put':\n return typeof d['key'] === 'string' && codec.decode(d['stored']) !== undefined;\n case 'putAll':\n return (\n Array.isArray(d['entries']) &&\n (d['entries'] as unknown[]).every(\n (e) =>\n typeof e === 'object' &&\n e !== null &&\n typeof (e as Record<string, unknown>)['key'] === 'string' &&\n codec.decode((e as Record<string, unknown>)['stored']) !== undefined,\n )\n );\n default:\n return false;\n }\n };\n}\n\ntype MemoryOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n /**\n * When provided and BroadcastChannel is available, enables cross-tab state sync.\n * All `createMemory` instances with the same `name` will replicate mutations to each other.\n */\n name?: string;\n};\n\nexport type MemoryAdapter<S extends AnySchema> = Adapter<S> & {\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>>;\n};\n\nexport function createMemory<S extends AnySchema>(options: MemoryOptions<S>): MemoryAdapter<S> {\n const { codec = defaultCodec, logger, name, onMetrics, schema, signals, validators } = options;\n const tables = new Map(Object.keys(schema).map((k) => [k, new Map<string, StoredRecord<unknown>>()]));\n const getTableStore = (table: string) => tables.get(table)!;\n const isBroadcastMsg = makeBroadcastMsgGuard(codec);\n\n const channel =\n name !== undefined && typeof BroadcastChannel !== 'undefined'\n ? new BroadcastChannel(`vault-memory:${name}`)\n : undefined;\n\n const core: StorageBackend<S> = {\n async clear<K extends keyof S & string>(table: K): Promise<void> {\n getTableStore(table).clear();\n channel?.postMessage({ table, type: 'clear' });\n },\n\n async count<K extends keyof S & string>(table: K): Promise<number> {\n const store = getTableStore(table);\n let liveCount = 0;\n const expiredKeys: string[] = [];\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n expiredKeys.push(key);\n } else {\n liveCount += 1;\n }\n }\n\n for (const key of expiredKeys) store.delete(key);\n\n return liveCount;\n },\n\n async delete<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const store = getTableStore(table);\n const raw = store.get(String(key));\n\n if (!raw) return false;\n\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n const isLive = decoded !== undefined && !isExpired(decoded.expiresAt);\n\n store.delete(String(key));\n\n if (isLive) channel?.postMessage({ key: String(key), table, type: 'delete' });\n\n return isLive;\n },\n\n async deleteMany<K extends keyof S & string>(table: K, keys: KeyOf<S, K>[]): Promise<number> {\n const store = getTableStore(table);\n const deletedKeys: string[] = [];\n\n for (const key of keys) {\n const strKey = String(key);\n const raw = store.get(strKey);\n\n if (raw) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (decoded !== undefined && !isExpired(decoded.expiresAt)) deletedKeys.push(strKey);\n\n store.delete(strKey);\n }\n }\n\n if (deletedKeys.length > 0) channel?.postMessage({ keys: deletedKeys, table, type: 'deleteMany' });\n\n return deletedKeys.length;\n },\n\n dispose: channel ? async () => channel.close() : undefined,\n\n async get<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<RecordOf<S, K> | undefined> {\n const store = getTableStore(table);\n const raw = store.get(String(key));\n\n if (!raw) return undefined;\n\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n store.delete(String(key));\n\n return undefined;\n }\n\n return decoded.value;\n },\n\n async getAll<K extends keyof S & string>(table: K): Promise<RecordOf<S, K>[]> {\n const store = getTableStore(table);\n const records: RecordOf<S, K>[] = [];\n const expiredKeys: string[] = [];\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n expiredKeys.push(key);\n } else {\n records.push(decoded.value);\n }\n }\n\n for (const key of expiredKeys) store.delete(key);\n\n return records;\n },\n\n async getRawCount<K extends keyof S & string>(table: K): Promise<number> {\n return getTableStore(table).size;\n },\n\n async has<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const store = getTableStore(table);\n const raw = store.get(String(key));\n\n if (!raw) return false;\n\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n const live = decoded !== undefined && !isExpired(decoded.expiresAt);\n\n if (!live) store.delete(String(key));\n\n return live;\n },\n\n async pruneExpiredInTable<K extends keyof S & string>(table: K): Promise<number> {\n const store = getTableStore(table);\n let pruned = 0;\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n store.delete(key);\n pruned += 1;\n }\n }\n\n return pruned;\n },\n\n async put<K extends keyof S & string>(table: K, value: RecordOf<S, K>, ttl?: TtlMs): Promise<void> {\n const key = String(getRecordKey(schema, table, value));\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n const stored = codec.encode(value, expiresAt) as StoredRecord<unknown>;\n\n getTableStore(table).set(key, stored);\n channel?.postMessage({ key, stored, table, type: 'put' });\n },\n\n async putAll<K extends keyof S & string>(table: K, values: RecordOf<S, K>[], ttl?: TtlMs): Promise<void> {\n const store = getTableStore(table);\n const entries: Array<{ key: string; stored: StoredRecord<unknown> }> = [];\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n for (const value of values) {\n const key = String(getRecordKey(schema, table, value));\n const stored = codec.encode(value, expiresAt) as StoredRecord<unknown>;\n\n store.set(key, stored);\n entries.push({ key, stored });\n }\n\n if (entries.length > 0) channel?.postMessage({ entries, table, type: 'putAll' });\n },\n };\n\n const adapter = buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage: channel\n ? (notify) => {\n channel.onmessage = (event: MessageEvent<unknown>) => {\n let msg: MemoryBroadcastMsg;\n\n try {\n if (!isBroadcastMsg(event.data)) return;\n\n msg = event.data;\n } catch {\n return;\n }\n\n const store = tables.get(msg.table);\n\n if (!store) return;\n\n const validator = validators?.[msg.table as keyof S];\n\n const keyField = schema[msg.table as keyof S & string]?.key;\n\n const applyStoredWithValidation = (key: string, stored: StoredRecord<unknown>): boolean => {\n try {\n const parsed = codec.decode(stored as unknown);\n\n if (!parsed) return false;\n\n const rawValue = validator ? validator.parse(parsed.value) : parsed.value;\n\n // Security: verify the record's own primary key matches the broadcast envelope key.\n // Prevents a rogue same-origin sender from inserting records with mismatched keys.\n if (keyField && String((rawValue as Record<string, unknown>)[keyField]) !== key) return false;\n\n const validated: StoredRecord<unknown> =\n parsed.expiresAt !== undefined\n ? { expiresAt: parsed.expiresAt, value: rawValue }\n : { value: rawValue };\n\n store.set(key, validated);\n\n return true;\n } catch {\n return false;\n }\n };\n\n switch (msg.type) {\n case 'clear':\n store.clear();\n notify(msg.table as keyof S & string);\n\n return;\n case 'delete':\n store.delete(msg.key);\n notify(msg.table as keyof S & string);\n\n return;\n case 'deleteMany':\n for (const key of msg.keys) store.delete(key);\n notify(msg.table as keyof S & string);\n\n return;\n case 'put':\n if (applyStoredWithValidation(msg.key, msg.stored)) {\n notify(msg.table as keyof S & string);\n }\n\n return;\n case 'putAll':\n {\n let anyApplied = false;\n\n for (const { key, stored } of msg.entries) {\n if (applyStoredWithValidation(key, stored)) anyApplied = true;\n }\n\n if (anyApplied) notify(msg.table as keyof S & string);\n }\n\n return;\n }\n };\n\n return () => {\n channel.onmessage = null;\n };\n }\n : undefined,\n onMetrics,\n schema,\n signals,\n validators,\n });\n\n return {\n ...adapter,\n iterate<K extends keyof S>(table: K): AsyncIterable<RecordOf<S, K>> {\n const store = getTableStore(String(table));\n\n return {\n async *[Symbol.asyncIterator]() {\n if (adapter.disposed) throw new VaultDisposedError();\n\n const expiredKeys: string[] = [];\n\n for (const [key, raw] of store) {\n const decoded = codec.decode<RecordOf<S, K>>(raw);\n\n if (!decoded || isExpired(decoded.expiresAt)) {\n expiredKeys.push(key);\n } else {\n yield decoded.value;\n }\n }\n\n for (const key of expiredKeys) store.delete(key);\n },\n };\n },\n };\n}\n"],"mappings":";;;;;AAeA,SAAS,EAAsB,GAAkF;CAC/G,OAAO,SAAwB,GAA2C;EACxE,IAAI,OAAO,KAAS,aAAY,GAAe,OAAO;EAEtD,IAAM,IAAI;EAKV,IAHI,OAAO,EAAE,SAAa,YAAY,OAAO,EAAE,QAAY,YAGvD,EAAE,UAAa,eAAe,EAAE,UAAa,iBAAiB,EAAE,UAAa,aAAa,OAAO;EAErG,QAAQ,EAAE,MAAV;GACE,KAAK,SACH,OAAO;GACT,KAAK,UACH,OAAO,OAAO,EAAE,OAAW;GAC7B,KAAK,cACH,OAAO,MAAM,QAAQ,EAAE,IAAO,KAAM,EAAE,KAAsB,OAAO,MAAM,OAAO,KAAM,QAAQ;GAChG,KAAK,OACH,OAAO,OAAO,EAAE,OAAW,YAAY,EAAM,OAAO,EAAE,MAAS,MAAM,KAAA;GACvE,KAAK,UACH,OACE,MAAM,QAAQ,EAAE,OAAU,KACzB,EAAE,QAAyB,OACzB,MACC,OAAO,KAAM,cACb,KACA,OAAQ,EAA8B,OAAW,YACjD,EAAM,OAAQ,EAA8B,MAAS,MAAM,KAAA,CAC/D;GAEJ,SACE,OAAO;EACX;CACF;AACF;AAcA,SAAgB,EAAkC,GAA6C;CAC7F,IAAM,EAAE,WAAQ,GAAc,WAAQ,SAAM,cAAW,WAAQ,YAAS,kBAAe,GACjF,IAAS,IAAI,IAAI,OAAO,KAAK,CAAM,CAAC,CAAC,KAAK,MAAM,CAAC,mBAAG,IAAI,IAAmC,CAAC,CAAC,CAAC,GAC9F,KAAiB,MAAkB,EAAO,IAAI,CAAK,GACnD,IAAiB,EAAsB,CAAK,GAE5C,IACJ,MAAS,KAAA,KAAa,OAAO,mBAAqB,MAC9C,IAAI,iBAAiB,gBAAgB,GAAM,IAC3C,KAAA,GAqKA,IAAU,EAAgB,GAAQ;EAlKtC,MAAM,MAAkC,GAAyB;GAE/D,AADA,EAAc,CAAK,CAAC,CAAC,MAAM,GAC3B,GAAS,YAAY;IAAE;IAAO,MAAM;GAAQ,CAAC;EAC/C;EAEA,MAAM,MAAkC,GAA2B;GACjE,IAAM,IAAQ,EAAc,CAAK,GAC7B,IAAY,GACV,IAAwB,CAAC;GAE/B,KAAK,IAAM,CAAC,GAAK,MAAQ,GAAO;IAC9B,IAAM,IAAU,EAAM,OAAuB,CAAG;IAEhD,AAAI,CAAC,KAAW,EAAU,EAAQ,SAAS,IACzC,EAAY,KAAK,CAAG,IAEpB,KAAa;GAEjB;GAEA,KAAK,IAAM,KAAO,GAAa,EAAM,OAAO,CAAG;GAE/C,OAAO;EACT;EAEA,MAAM,OAAmC,GAAU,GAAoC;GACrF,IAAM,IAAQ,EAAc,CAAK,GAC3B,IAAM,EAAM,IAAI,OAAO,CAAG,CAAC;GAEjC,IAAI,CAAC,GAAK,OAAO;GAEjB,IAAM,IAAU,EAAM,OAAuB,CAAG,GAC1C,IAAS,MAAY,KAAA,KAAa,CAAC,EAAU,EAAQ,SAAS;GAMpE,OAJA,EAAM,OAAO,OAAO,CAAG,CAAC,GAEpB,KAAQ,GAAS,YAAY;IAAE,KAAK,OAAO,CAAG;IAAG;IAAO,MAAM;GAAS,CAAC,GAErE;EACT;EAEA,MAAM,WAAuC,GAAU,GAAsC;GAC3F,IAAM,IAAQ,EAAc,CAAK,GAC3B,IAAwB,CAAC;GAE/B,KAAK,IAAM,KAAO,GAAM;IACtB,IAAM,IAAS,OAAO,CAAG,GACnB,IAAM,EAAM,IAAI,CAAM;IAE5B,IAAI,GAAK;KACP,IAAM,IAAU,EAAM,OAAuB,CAAG;KAIhD,AAFI,MAAY,KAAA,KAAa,CAAC,EAAU,EAAQ,SAAS,KAAG,EAAY,KAAK,CAAM,GAEnF,EAAM,OAAO,CAAM;IACrB;GACF;GAIA,OAFI,EAAY,SAAS,KAAG,GAAS,YAAY;IAAE,MAAM;IAAa;IAAO,MAAM;GAAa,CAAC,GAE1F,EAAY;EACrB;EAEA,SAAS,IAAU,YAAY,EAAQ,MAAM,IAAI,KAAA;EAEjD,MAAM,IAAgC,GAAU,GAAuD;GACrG,IAAM,IAAQ,EAAc,CAAK,GAC3B,IAAM,EAAM,IAAI,OAAO,CAAG,CAAC;GAEjC,IAAI,CAAC,GAAK;GAEV,IAAM,IAAU,EAAM,OAAuB,CAAG;GAEhD,IAAI,CAAC,KAAW,EAAU,EAAQ,SAAS,GAAG;IAC5C,EAAM,OAAO,OAAO,CAAG,CAAC;IAExB;GACF;GAEA,OAAO,EAAQ;EACjB;EAEA,MAAM,OAAmC,GAAqC;GAC5E,IAAM,IAAQ,EAAc,CAAK,GAC3B,IAA4B,CAAC,GAC7B,IAAwB,CAAC;GAE/B,KAAK,IAAM,CAAC,GAAK,MAAQ,GAAO;IAC9B,IAAM,IAAU,EAAM,OAAuB,CAAG;IAEhD,AAAI,CAAC,KAAW,EAAU,EAAQ,SAAS,IACzC,EAAY,KAAK,CAAG,IAEpB,EAAQ,KAAK,EAAQ,KAAK;GAE9B;GAEA,KAAK,IAAM,KAAO,GAAa,EAAM,OAAO,CAAG;GAE/C,OAAO;EACT;EAEA,MAAM,YAAwC,GAA2B;GACvE,OAAO,EAAc,CAAK,CAAC,CAAC;EAC9B;EAEA,MAAM,IAAgC,GAAU,GAAoC;GAClF,IAAM,IAAQ,EAAc,CAAK,GAC3B,IAAM,EAAM,IAAI,OAAO,CAAG,CAAC;GAEjC,IAAI,CAAC,GAAK,OAAO;GAEjB,IAAM,IAAU,EAAM,OAAuB,CAAG,GAC1C,IAAO,MAAY,KAAA,KAAa,CAAC,EAAU,EAAQ,SAAS;GAIlE,OAFK,KAAM,EAAM,OAAO,OAAO,CAAG,CAAC,GAE5B;EACT;EAEA,MAAM,oBAAgD,GAA2B;GAC/E,IAAM,IAAQ,EAAc,CAAK,GAC7B,IAAS;GAEb,KAAK,IAAM,CAAC,GAAK,MAAQ,GAAO;IAC9B,IAAM,IAAU,EAAM,OAAuB,CAAG;IAEhD,CAAI,CAAC,KAAW,EAAU,EAAQ,SAAS,OACzC,EAAM,OAAO,CAAG,GAChB,KAAU;GAEd;GAEA,OAAO;EACT;EAEA,MAAM,IAAgC,GAAU,GAAuB,GAA4B;GACjG,IAAM,IAAM,OAAO,EAAa,GAAQ,GAAO,CAAK,CAAC,GAC/C,IAAY,MAAQ,KAAA,IAA+B,KAAA,IAAnB,KAAK,IAAI,IAAI,GAC7C,IAAS,EAAM,OAAO,GAAO,CAAS;GAG5C,AADA,EAAc,CAAK,CAAC,CAAC,IAAI,GAAK,CAAM,GACpC,GAAS,YAAY;IAAE;IAAK;IAAQ;IAAO,MAAM;GAAM,CAAC;EAC1D;EAEA,MAAM,OAAmC,GAAU,GAA0B,GAA4B;GACvG,IAAM,IAAQ,EAAc,CAAK,GAC3B,IAAiE,CAAC,GAClE,IAAY,MAAQ,KAAA,IAA+B,KAAA,IAAnB,KAAK,IAAI,IAAI;GAEnD,KAAK,IAAM,KAAS,GAAQ;IAC1B,IAAM,IAAM,OAAO,EAAa,GAAQ,GAAO,CAAK,CAAC,GAC/C,IAAS,EAAM,OAAO,GAAO,CAAS;IAG5C,AADA,EAAM,IAAI,GAAK,CAAM,GACrB,EAAQ,KAAK;KAAE;KAAK;IAAO,CAAC;GAC9B;GAEA,AAAI,EAAQ,SAAS,KAAG,GAAS,YAAY;IAAE;IAAS;IAAO,MAAM;GAAS,CAAC;EACjF;CAGsC,GAAM;EAC5C;EACA,mBAAmB,KACd,OACC,EAAQ,aAAa,MAAiC;GACpD,IAAI;GAEJ,IAAI;IACF,IAAI,CAAC,EAAe,EAAM,IAAI,GAAG;IAEjC,IAAM,EAAM;GACd,QAAQ;IACN;GACF;GAEA,IAAM,IAAQ,EAAO,IAAI,EAAI,KAAK;GAElC,IAAI,CAAC,GAAO;GAEZ,IAAM,IAAY,IAAa,EAAI,QAE7B,IAAW,EAAO,EAAI,MAA0B,EAAE,KAElD,KAA6B,GAAa,MAA2C;IACzF,IAAI;KACF,IAAM,IAAS,EAAM,OAAO,CAAiB;KAE7C,IAAI,CAAC,GAAQ,OAAO;KAEpB,IAAM,IAAW,IAAY,EAAU,MAAM,EAAO,KAAK,IAAI,EAAO;KAIpE,IAAI,KAAY,OAAQ,EAAqC,EAAS,MAAM,GAAK,OAAO;KAExF,IAAM,IACJ,EAAO,cAAc,KAAA,IAEjB,EAAE,OAAO,EAAS,IADlB;MAAE,WAAW,EAAO;MAAW,OAAO;KAAS;KAKrD,OAFA,EAAM,IAAI,GAAK,CAAS,GAEjB;IACT,QAAQ;KACN,OAAO;IACT;GACF;GAEA,QAAQ,EAAI,MAAZ;IACE,KAAK;KAEH,AADA,EAAM,MAAM,GACZ,EAAO,EAAI,KAAyB;KAEpC;IACF,KAAK;KAEH,AADA,EAAM,OAAO,EAAI,GAAG,GACpB,EAAO,EAAI,KAAyB;KAEpC;IACF,KAAK;KACH,KAAK,IAAM,KAAO,EAAI,MAAM,EAAM,OAAO,CAAG;KAC5C,EAAO,EAAI,KAAyB;KAEpC;IACF,KAAK;KACH,AAAI,EAA0B,EAAI,KAAK,EAAI,MAAM,KAC/C,EAAO,EAAI,KAAyB;KAGtC;IACF,KAAK;KACH;MACE,IAAI,IAAa;MAEjB,KAAK,IAAM,EAAE,QAAK,eAAY,EAAI,SAChC,AAAI,EAA0B,GAAK,CAAM,MAAG,IAAa;MAG3D,AAAI,KAAY,EAAO,EAAI,KAAyB;KACtD;KAEA;GACJ;EACF,SAEa;GACX,EAAQ,YAAY;EACtB,KAEF,KAAA;EACJ;EACA;EACA;EACA;CACF,CAAC;CAED,OAAO;EACL,GAAG;EACH,QAA2B,GAAyC;GAClE,IAAM,IAAQ,EAAc,OAAO,CAAK,CAAC;GAEzC,OAAO,EACL,QAAQ,OAAO,iBAAiB;IAC9B,IAAI,EAAQ,UAAU,MAAM,IAAI,EAAmB;IAEnD,IAAM,IAAwB,CAAC;IAE/B,KAAK,IAAM,CAAC,GAAK,MAAQ,GAAO;KAC9B,IAAM,IAAU,EAAM,OAAuB,CAAG;KAEhD,AAAI,CAAC,KAAW,EAAU,EAAQ,SAAS,IACzC,EAAY,KAAK,CAAG,IAEpB,MAAM,EAAQ;IAElB;IAEA,KAAK,IAAM,KAAO,GAAa,EAAM,OAAO,CAAG;GACjD,EACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"memory.js","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import type { AnySchema, BaseAdapterOptions, KeyOf, RecordOf, VaultStore } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { encodeVaultKey, getRecordKey } from '../internal';\nimport { isExpired, parseStored, type StoredRecord } from '../ttl';\n\ntype MemoryBroadcastMsg =\n | { table: string; type: 'clear' }\n | { key: string; table: string; type: 'delete' }\n | { keys: string[]; table: string; type: 'deleteMany' }\n | { key: string; stored: StoredRecord<unknown>; table: string; type: 'put' }\n | { entries: Array<{ key: string; stored: StoredRecord<unknown> }>; table: string; type: 'putAll' };\n\ntype MemoryOptions<S extends AnySchema> = BaseAdapterOptions<S> & { name?: string };\n\nfunction isBroadcastMessage(value: unknown): value is MemoryBroadcastMsg {\n if (typeof value !== 'object' || value === null) return false;\n\n const message = value as Record<string, unknown>;\n\n if (typeof message['table'] !== 'string' || typeof message['type'] !== 'string') return false;\n\n if (message['table'] === '__proto__' || message['table'] === 'constructor' || message['table'] === 'prototype') {\n return false;\n }\n\n switch (message['type']) {\n case 'clear':\n return true;\n case 'delete':\n return typeof message['key'] === 'string';\n case 'deleteMany':\n return Array.isArray(message['keys']) && message['keys'].every((key) => typeof key === 'string');\n case 'put':\n return typeof message['key'] === 'string' && parseStored(message['stored']) !== undefined;\n case 'putAll':\n return (\n Array.isArray(message['entries']) &&\n message['entries'].every(\n (entry) =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as Record<string, unknown>)['key'] === 'string' &&\n parseStored((entry as Record<string, unknown>)['stored']) !== undefined,\n )\n );\n default:\n return false;\n }\n}\n\n/** Memory uses tagged Map keys so numeric and string primary keys never collide. */\nexport function createMemory<S extends AnySchema>(options: MemoryOptions<S>): VaultStore<S> {\n const { logger, name, onMetrics, schema, validators } = options;\n const tables = new Map(Object.keys(schema).map((table) => [table, new Map<string, StoredRecord<unknown>>()]));\n const getTable = (table: string): Map<string, StoredRecord<unknown>> => tables.get(table)!;\n const channel =\n name !== undefined && typeof BroadcastChannel !== 'undefined'\n ? new BroadcastChannel(`vault-memory:${name}`)\n : undefined;\n\n const core: StorageBackend<S> = {\n async clear(table) {\n getTable(table).clear();\n channel?.postMessage({ table, type: 'clear' });\n },\n async count(table) {\n const store = getTable(table);\n let count = 0;\n\n for (const [key, stored] of store) {\n const record = parseStored(stored);\n\n if (!record || isExpired(record.expiresAt)) store.delete(key);\n else count += 1;\n }\n\n return count;\n },\n async delete(table, key) {\n const store = getTable(table);\n const encodedKey = encodeVaultKey(key);\n const record = parseStored(store.get(encodedKey));\n\n store.delete(encodedKey);\n\n const deleted = record !== undefined && !isExpired(record.expiresAt);\n\n if (deleted) channel?.postMessage({ key: encodedKey, table, type: 'delete' });\n\n return deleted;\n },\n async deleteMany(table, keys) {\n let deleted = 0;\n const deletedKeys: string[] = [];\n\n for (const key of keys) {\n const encodedKey = encodeVaultKey(key);\n const record = parseStored(getTable(table).get(encodedKey));\n\n getTable(table).delete(encodedKey);\n\n if (record !== undefined && !isExpired(record.expiresAt)) {\n deleted += 1;\n deletedKeys.push(encodedKey);\n }\n }\n\n if (deletedKeys.length > 0) channel?.postMessage({ keys: deletedKeys, table, type: 'deleteMany' });\n\n return deleted;\n },\n dispose: channel ? async () => channel.close() : undefined,\n async get(table, key) {\n const store = getTable(table);\n const encodedKey = encodeVaultKey(key);\n const record = parseStored<RecordOf<S, typeof table>>(store.get(encodedKey));\n\n if (!record || isExpired(record.expiresAt)) {\n store.delete(encodedKey);\n\n return undefined;\n }\n\n return record.value;\n },\n async getAll(table) {\n const store = getTable(table);\n const values: RecordOf<S, typeof table>[] = [];\n\n for (const [key, stored] of store) {\n const record = parseStored<RecordOf<S, typeof table>>(stored);\n\n if (!record || isExpired(record.expiresAt)) store.delete(key);\n else values.push(record.value);\n }\n\n return values;\n },\n async getRawCount(table) {\n return getTable(table).size;\n },\n async has(table, key) {\n return (await core.get(table, key)) !== undefined;\n },\n async pruneExpiredInTable(table) {\n const store = getTable(table);\n let pruned = 0;\n\n for (const [key, stored] of store) {\n const record = parseStored(stored);\n\n if (!record || isExpired(record.expiresAt)) {\n store.delete(key);\n pruned += 1;\n }\n }\n\n return pruned;\n },\n async put(table, value, ttl) {\n const key = encodeVaultKey(getRecordKey(schema, table, value));\n const stored: StoredRecord<unknown> = ttl === undefined ? { value } : { expiresAt: Date.now() + ttl, value };\n\n getTable(table).set(key, stored);\n channel?.postMessage({ key, stored, table, type: 'put' });\n },\n async putAll(table, values, ttl) {\n const expiresAt = ttl === undefined ? undefined : Date.now() + ttl;\n const entries: Array<{ key: string; stored: StoredRecord<unknown> }> = [];\n\n for (const value of values) {\n const key = encodeVaultKey(getRecordKey(schema, table, value));\n const stored: StoredRecord<unknown> = expiresAt === undefined ? { value } : { expiresAt, value };\n\n getTable(table).set(key, stored);\n entries.push({ key, stored });\n }\n\n if (entries.length > 0) channel?.postMessage({ entries, table, type: 'putAll' });\n },\n };\n\n return buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage: channel\n ? (notify) => {\n channel.onmessage = (event: MessageEvent<unknown>) => {\n if (!isBroadcastMessage(event.data)) return;\n\n const message = event.data;\n\n if (!tables.has(message.table)) return;\n\n const store = getTable(message.table);\n const validateStored = (key: string, stored: StoredRecord<unknown>): boolean => {\n const parsed = parseStored(stored);\n const keyField = schema[message.table as keyof S & string]?.key;\n const validator = validators?.[message.table as keyof S];\n\n if (!parsed || !keyField) return false;\n\n try {\n const value = validator ? validator.parse(parsed.value) : parsed.value;\n\n if (encodeVaultKey((value as Record<string, unknown>)[keyField] as KeyOf<S, keyof S>) !== key)\n return false;\n\n store.set(key, parsed.expiresAt === undefined ? { value } : { expiresAt: parsed.expiresAt, value });\n\n return true;\n } catch {\n return false;\n }\n };\n\n switch (message.type) {\n case 'clear':\n store.clear();\n notify(message.table as keyof S & string);\n break;\n case 'delete':\n store.delete(message.key);\n notify(message.table as keyof S & string);\n break;\n case 'deleteMany':\n for (const key of message.keys) store.delete(key);\n notify(message.table as keyof S & string);\n break;\n case 'put':\n if (validateStored(message.key, message.stored)) notify(message.table as keyof S & string);\n\n break;\n case 'putAll':\n if (message.entries.some((entry) => validateStored(entry.key, entry.stored))) {\n notify(message.table as keyof S & string);\n }\n\n break;\n }\n };\n\n return () => {\n channel.onmessage = null;\n };\n }\n : undefined,\n onMetrics,\n schema,\n validators,\n });\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../errors.cjs"),t=require("../internal.cjs"),n=require("../ttl.cjs"),r=require("../adapter-core.cjs");var i=new Set([`QuotaExceededError`,`NS_ERROR_DOM_QUOTA_REACHED`]);function a(a){let{codec:o=n.defaultCodec,getStorage:s,logger:c,name:l,onMetrics:u,onQuotaExceeded:d,schema:f,signals:p,storageLabel:m,validators:h}=a,g;try{g=s()}catch(t){throw new e.VaultError(`${m} is not available in this environment (private browsing or sandboxed iframe?)`,{cause:t})}let _=()=>g,v=new Map(Object.keys(f).map(e=>[e,t.encodeStorageTablePrefix(l,e)])),y=t=>{let n=v.get(t);if(!n)throw new e.VaultError(`table "${t}" not in schema`);return n},b=(t,n,r)=>{try{_().setItem(n,JSON.stringify(r))}catch(n){if(n instanceof DOMException&&i.has(n.name)){let r=new e.VaultQuotaError(`${m} quota exceeded while writing record`,{cause:n});if(d?.(t,r)===`ignore`)return;throw r}throw n}},x=new Set;(()=>{let e=t.encodeDbPrefix(l);for(let t=0;t<g.length;t++){let n=g.key(t);n!==null&&n.startsWith(e)&&x.add(n)}})();let S=e=>{let t=_().getItem(e);if(t)try{let e=o.decode(JSON.parse(t));return!e||n.isExpired(e.expiresAt)?void 0:e.value}catch{return}},C=e=>{_().removeItem(e),x.delete(e)};return r.buildAdapterOps(f,{async clear(e){let t=_(),n=y(e),r=[];for(let e of x)e.startsWith(n)&&r.push(e);for(let e of r)t.removeItem(e),x.delete(e)},async count(e){let t=y(e),n=[],r=0;for(let e of x)e.startsWith(t)&&(S(e)===void 0?n.push(e):r+=1);for(let e of n)C(e);return r},async delete(e,n){let r=t.encodeStorageKey(l,e,String(n));return S(r)===void 0?(x.has(r)&&C(r),!1):(C(r),!0)},async deleteMany(e,n){let r=0;for(let i of n){let n=t.encodeStorageKey(l,e,String(i));S(n)===void 0?x.has(n)&&C(n):(C(n),r+=1)}return r},async get(e,n){let r=t.encodeStorageKey(l,e,String(n)),i=S(r);return i===void 0&&x.has(r)&&C(r),i},async getAll(e){let t=[],n=[],r=y(e);for(let e of x){if(!e.startsWith(r))continue;let i=S(e);if(i===void 0){n.push(e);continue}t.push(i)}for(let e of n)C(e);return t},async getAllKeys(e){let t=y(e),n=[],r=[];for(let i of x){if(!i.startsWith(t))continue;let a=S(i);if(a===void 0){r.push(i);continue}n.push(a[f[e].key])}for(let e of r)C(e);return n},async getRawCount(e){let t=y(e),n=0;for(let e of x)e.startsWith(t)&&(n+=1);return n},async has(e,n){let r=t.encodeStorageKey(l,e,String(n)),i=S(r);return i===void 0&&x.has(r)&&C(r),i!==void 0},async pruneExpiredInTable(e){let t=y(e),r=[];for(let e of x){if(!e.startsWith(t))continue;let i=_().getItem(e);if(i===null){r.push(e);continue}try{let t=o.decode(JSON.parse(i));(!t||n.isExpired(t.expiresAt))&&r.push(e)}catch{r.push(e)}}for(let e of r)C(e);return r.length},async put(e,n,r){let i=t.encodeStorageKey(l,e,String(t.getRecordKey(f,e,n))),a=r===void 0?void 0:Date.now()+r;b(e,i,o.encode(n,a)),x.add(i)},async putAll(e,n,r){let i=r===void 0?void 0:Date.now()+r;for(let r of n){let n=t.encodeStorageKey(l,e,String(t.getRecordKey(f,e,r)));b(e,n,o.encode(r,i)),x.add(n)}}},{logger:c,onCrossTabMessage(e){if(typeof window>`u`||typeof window.addEventListener!=`function`)return;let n=n=>{if(n.storageArea&&n.storageArea!==g)return;if(n.key===null){x.clear();for(let t of Object.keys(f))e(t);return}let r=t.decodeStorageTableFromKey(l,n.key);r&&Object.hasOwn(f,r)&&(n.newValue===null?x.delete(n.key):x.add(n.key),e(r))};return window.addEventListener(`storage`,n),()=>window.removeEventListener(`storage`,n)},onMetrics:u,schema:f,signals:p,validators:h})}function o(e){return a({...e,getStorage:()=>typeof window<`u`?window.localStorage:localStorage,storageLabel:`localStorage`})}function s(e){return a({...e,getStorage:()=>typeof window<`u`?window.sessionStorage:sessionStorage,storageLabel:`sessionStorage`})}exports.createLocalStorage=o,exports.createSessionStorage=s;
1
+ const e=require("../errors.cjs"),t=require("../internal.cjs"),n=require("../ttl.cjs"),r=require("../adapter-core.cjs");var i=new Set([`QuotaExceededError`,`NS_ERROR_DOM_QUOTA_REACHED`]);function a(a){let{getStorage:o,logger:s,name:c,onMetrics:l,onQuotaExceeded:u,schema:d,storageLabel:f,validators:p}=a,m;try{m=o()}catch(t){throw new e.VaultError(`${f} is not available in this environment (private browsing or sandboxed iframe?)`,{cause:t})}let h=()=>m,g=new Map(Object.keys(d).map(e=>[e,t.encodeStorageTablePrefix(c,e)])),_=t=>{let n=g.get(t);if(!n)throw new e.VaultError(`table "${t}" not in schema`);return n},v=(t,n,r)=>{try{h().setItem(n,JSON.stringify(r))}catch(n){if(n instanceof DOMException&&i.has(n.name)){let r=new e.VaultQuotaError(`${f} quota exceeded while writing record`,{cause:n});if(u?.(t,r)===`ignore`)return;throw r}throw n}},y=new Set;(()=>{let e=t.encodeDbPrefix(c);for(let t=0;t<m.length;t++){let n=m.key(t);n!==null&&n.startsWith(e)&&y.add(n)}})();let b=e=>{let t=h().getItem(e);if(t)try{let e=n.parseStored(JSON.parse(t));return!e||n.isExpired(e.expiresAt)?void 0:e.value}catch{return}},x=e=>{h().removeItem(e),y.delete(e)};return r.buildAdapterOps(d,{async clear(e){let t=h(),n=_(e),r=[];for(let e of y)e.startsWith(n)&&r.push(e);for(let e of r)t.removeItem(e),y.delete(e)},async count(e){let t=_(e),n=[],r=0;for(let e of y)e.startsWith(t)&&(b(e)===void 0?n.push(e):r+=1);for(let e of n)x(e);return r},async delete(e,n){let r=t.encodeStorageKey(c,e,n);return b(r)===void 0?(y.has(r)&&x(r),!1):(x(r),!0)},async deleteMany(e,n){let r=0;for(let i of n){let n=t.encodeStorageKey(c,e,i);b(n)===void 0?y.has(n)&&x(n):(x(n),r+=1)}return r},async get(e,n){let r=t.encodeStorageKey(c,e,n),i=b(r);return i===void 0&&y.has(r)&&x(r),i},async getAll(e){let t=[],n=[],r=_(e);for(let e of y){if(!e.startsWith(r))continue;let i=b(e);if(i===void 0){n.push(e);continue}t.push(i)}for(let e of n)x(e);return t},async getAllKeys(e){let t=_(e),n=[],r=[];for(let i of y){if(!i.startsWith(t))continue;let a=b(i);if(a===void 0){r.push(i);continue}n.push(a[d[e].key])}for(let e of r)x(e);return n},async getRawCount(e){let t=_(e),n=0;for(let e of y)e.startsWith(t)&&(n+=1);return n},async has(e,n){let r=t.encodeStorageKey(c,e,n),i=b(r);return i===void 0&&y.has(r)&&x(r),i!==void 0},async pruneExpiredInTable(e){let t=_(e),r=[];for(let e of y){if(!e.startsWith(t))continue;let i=h().getItem(e);if(i===null){r.push(e);continue}try{let t=n.parseStored(JSON.parse(i));(!t||n.isExpired(t.expiresAt))&&r.push(e)}catch{r.push(e)}}for(let e of r)x(e);return r.length},async put(e,n,r){let i=t.encodeStorageKey(c,e,t.getRecordKey(d,e,n)),a=r===void 0?void 0:Date.now()+r;v(e,i,a===void 0?{value:n}:{expiresAt:a,value:n}),y.add(i)},async putAll(e,n,r){let i=r===void 0?void 0:Date.now()+r;for(let r of n){let n=t.encodeStorageKey(c,e,t.getRecordKey(d,e,r));v(e,n,i===void 0?{value:r}:{expiresAt:i,value:r}),y.add(n)}}},{logger:s,onCrossTabMessage(e){if(typeof window>`u`||typeof window.addEventListener!=`function`)return;let n=n=>{if(n.storageArea&&n.storageArea!==m)return;if(n.key===null){y.clear();for(let t of Object.keys(d))e(t);return}let r=t.decodeStorageTableFromKey(c,n.key);r&&Object.hasOwn(d,r)&&(n.newValue===null?y.delete(n.key):y.add(n.key),e(r))};return window.addEventListener(`storage`,n),()=>window.removeEventListener(`storage`,n)},onMetrics:l,schema:d,validators:p})}function o(e){return a({...e,getStorage:()=>typeof window<`u`?window.localStorage:localStorage,storageLabel:`localStorage`})}function s(e){return a({...e,getStorage:()=>typeof window<`u`?window.sessionStorage:sessionStorage,storageLabel:`sessionStorage`})}exports.createLocalStorage=o,exports.createSessionStorage=s;
2
2
  //# sourceMappingURL=webstorage.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"webstorage.cjs","names":[],"sources":["../../src/adapters/webstorage.ts"],"sourcesContent":["import type { Adapter, AnySchema, BaseAdapterOptions, KeyOf, RecordOf, TtlMs } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { VaultError, VaultQuotaError } from '../errors';\nimport {\n decodeStorageTableFromKey,\n encodeDbPrefix,\n encodeStorageKey,\n encodeStorageTablePrefix,\n getRecordKey,\n} from '../internal';\nimport { defaultCodec, isExpired } from '../ttl';\n\n// Firefox historically threw 'NS_ERROR_DOM_QUOTA_REACHED'; modern browsers use the standard name.\nconst QUOTA_ERROR_NAMES = new Set(['QuotaExceededError', 'NS_ERROR_DOM_QUOTA_REACHED']);\n\ntype WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n name: string;\n /**\n * Called when localStorage/sessionStorage quota is exceeded on a write.\n * Return `'ignore'` to silently drop the write, or `'throw'` (default) to rethrow the error.\n */\n onQuotaExceeded?: (table: keyof S, error: VaultQuotaError) => 'ignore' | 'throw';\n};\n\nfunction createWebStorageAdapter<S extends AnySchema>(\n options: WebStorageOptions<S> & {\n getStorage: () => Storage;\n storageLabel: string;\n },\n): Adapter<S> {\n const {\n codec = defaultCodec,\n getStorage,\n logger,\n name,\n onMetrics,\n onQuotaExceeded,\n schema,\n signals,\n storageLabel,\n validators,\n } = options;\n\n let resolvedStorage: Storage;\n\n try {\n resolvedStorage = getStorage();\n } catch (cause) {\n throw new VaultError(\n `${storageLabel} is not available in this environment (private browsing or sandboxed iframe?)`,\n {\n cause,\n },\n );\n }\n\n const storage = (): Storage => resolvedStorage;\n\n const prefixMap = new Map(Object.keys(schema).map((table) => [table, encodeStorageTablePrefix(name, table)]));\n const getPrefix = (table: string): string => {\n const cached = prefixMap.get(table);\n\n if (!cached) throw new VaultError(`table \"${table}\" not in schema`);\n\n return cached;\n };\n\n const writeItem = (table: keyof S, storageKey: string, value: unknown): void => {\n try {\n storage().setItem(storageKey, JSON.stringify(value));\n } catch (error) {\n if (error instanceof DOMException && QUOTA_ERROR_NAMES.has(error.name)) {\n const wrappedError = new VaultQuotaError(`${storageLabel} quota exceeded while writing record`, {\n cause: error,\n });\n\n if (onQuotaExceeded?.(table, wrappedError) === 'ignore') return;\n\n throw wrappedError;\n }\n\n throw error;\n }\n };\n\n // Per-instance registry of all storage keys owned by this adapter instance.\n // Populated once at construction; kept current by every mutation.\n const ownedKeys = new Set<string>();\n\n const initOwnedKeys = (): void => {\n const dbPrefix = encodeDbPrefix(name);\n\n for (let i = 0; i < resolvedStorage.length; i++) {\n const key = resolvedStorage.key(i);\n\n if (key !== null && key.startsWith(dbPrefix)) ownedKeys.add(key);\n }\n };\n\n initOwnedKeys();\n\n /**\n * Reads a single entry without side effects. Returns the live value,\n * or `undefined` if missing/expired/corrupt.\n *\n * Callers that want to evict stale entries must call `evict(storageKey)` explicitly.\n * This design avoids the `{ cleanup?: boolean }` flag that required callers to remember\n * to pass `{ cleanup: false }` inside loops.\n */\n const parseEntry = <T extends Record<string, unknown>>(storageKey: string): T | undefined => {\n const raw = storage().getItem(storageKey);\n\n if (!raw) return undefined;\n\n try {\n const stored = codec.decode<T>(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) return undefined;\n\n return stored.value;\n } catch {\n return undefined;\n }\n };\n\n /** Removes a stale/expired/corrupt entry from storage and the owned-keys registry. */\n const evict = (storageKey: string): void => {\n storage().removeItem(storageKey);\n ownedKeys.delete(storageKey);\n };\n\n const core: StorageBackend<S> = {\n async clear<K extends keyof S & string>(table: K): Promise<void> {\n const target = storage();\n const prefix = getPrefix(table);\n const toRemove: string[] = [];\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) toRemove.push(key);\n }\n\n for (const key of toRemove) {\n target.removeItem(key);\n ownedKeys.delete(key);\n }\n },\n\n async count<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n let liveCount = 0;\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n } else {\n liveCount += 1;\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return liveCount;\n },\n\n async delete<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n\n return true;\n }\n\n if (ownedKeys.has(storageKey)) evict(storageKey);\n\n return false;\n },\n\n async deleteMany<K extends keyof S & string>(table: K, keys: KeyOf<S, K>[]): Promise<number> {\n let deleted = 0;\n\n for (const key of keys) {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n deleted += 1;\n } else if (ownedKeys.has(storageKey)) {\n evict(storageKey);\n }\n }\n\n return deleted;\n },\n\n async get<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<RecordOf<S, K> | undefined> {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value;\n },\n\n async getAll<K extends keyof S & string>(table: K): Promise<RecordOf<S, K>[]> {\n const records: RecordOf<S, K>[] = [];\n const expiredKeys: string[] = [];\n const prefix = getPrefix(table);\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n records.push(value);\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return records;\n },\n\n async getAllKeys<K extends keyof S & string>(table: K): Promise<KeyOf<S, K>[]> {\n const prefix = getPrefix(table);\n const keys: KeyOf<S, K>[] = [];\n const expiredStorageKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredStorageKeys.push(storageKey);\n continue;\n }\n\n // Extract the record key from the already-decoded value (avoids a second parse).\n keys.push((value as Record<string, unknown>)[schema[table].key] as KeyOf<S, K>);\n }\n\n for (const storageKey of expiredStorageKeys) {\n evict(storageKey);\n }\n\n return keys;\n },\n\n async getRawCount<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n let count = 0;\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) count += 1;\n }\n\n return count;\n },\n\n async has<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value !== undefined;\n },\n\n async pruneExpiredInTable<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const raw = storage().getItem(storageKey);\n\n if (raw === null) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n try {\n const stored = codec.decode(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n expiredKeys.push(storageKey);\n }\n } catch {\n expiredKeys.push(storageKey);\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return expiredKeys.length;\n },\n\n async put<K extends keyof S & string>(table: K, value: RecordOf<S, K>, ttl?: TtlMs): Promise<void> {\n const storageKey = encodeStorageKey(name, table, String(getRecordKey(schema, table, value)));\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n writeItem(table, storageKey, codec.encode(value, expiresAt));\n ownedKeys.add(storageKey);\n },\n\n async putAll<K extends keyof S & string>(table: K, values: RecordOf<S, K>[], ttl?: TtlMs): Promise<void> {\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n for (const value of values) {\n const storageKey = encodeStorageKey(name, table, String(getRecordKey(schema, table, value)));\n\n writeItem(table, storageKey, codec.encode(value, expiresAt));\n ownedKeys.add(storageKey);\n }\n },\n };\n\n return buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage(notify) {\n if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {\n return undefined;\n }\n\n const listener = (event: StorageEvent) => {\n if (event.storageArea && event.storageArea !== resolvedStorage) return;\n\n if (event.key === null) {\n // storage.clear() from another tab — all keys are gone; purge ownedKeys\n ownedKeys.clear();\n\n for (const table of Object.keys(schema)) {\n notify(table as keyof S & string);\n }\n\n return;\n }\n\n const tableName = decodeStorageTableFromKey(name, event.key);\n\n if (tableName && Object.hasOwn(schema, tableName)) {\n if (event.newValue === null) {\n ownedKeys.delete(event.key);\n } else {\n ownedKeys.add(event.key);\n }\n\n notify(tableName as keyof S & string);\n }\n };\n\n window.addEventListener('storage', listener);\n\n return () => window.removeEventListener('storage', listener);\n },\n onMetrics,\n schema,\n signals,\n validators,\n });\n}\n\nexport function createLocalStorage<S extends AnySchema>(options: WebStorageOptions<S>): Adapter<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.localStorage : localStorage),\n storageLabel: 'localStorage',\n });\n}\n\nexport function createSessionStorage<S extends AnySchema>(options: WebStorageOptions<S>): Adapter<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.sessionStorage : sessionStorage),\n storageLabel: 'sessionStorage',\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"webstorage.cjs","names":[],"sources":["../../src/adapters/webstorage.ts"],"sourcesContent":["import type { AnySchema, BaseAdapterOptions, KeyOf, RecordOf, TtlMs, VaultStore } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { VaultError, VaultQuotaError } from '../errors';\nimport {\n decodeStorageTableFromKey,\n encodeDbPrefix,\n encodeStorageKey,\n encodeStorageTablePrefix,\n getRecordKey,\n} from '../internal';\nimport { isExpired, parseStored } from '../ttl';\n\n// Firefox historically threw 'NS_ERROR_DOM_QUOTA_REACHED'; modern browsers use the standard name.\nconst QUOTA_ERROR_NAMES = new Set(['QuotaExceededError', 'NS_ERROR_DOM_QUOTA_REACHED']);\n\ntype WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n name: string;\n /**\n * Called when localStorage/sessionStorage quota is exceeded on a write.\n * Return `'ignore'` to silently drop the write, or `'throw'` (default) to rethrow the error.\n */\n onQuotaExceeded?: (table: keyof S, error: VaultQuotaError) => 'ignore' | 'throw';\n};\n\nfunction createWebStorageAdapter<S extends AnySchema>(\n options: WebStorageOptions<S> & {\n getStorage: () => Storage;\n storageLabel: string;\n },\n): VaultStore<S> {\n const { getStorage, logger, name, onMetrics, onQuotaExceeded, schema, storageLabel, validators } = options;\n\n let resolvedStorage: Storage;\n\n try {\n resolvedStorage = getStorage();\n } catch (cause) {\n throw new VaultError(\n `${storageLabel} is not available in this environment (private browsing or sandboxed iframe?)`,\n {\n cause,\n },\n );\n }\n\n const storage = (): Storage => resolvedStorage;\n\n const prefixMap = new Map(Object.keys(schema).map((table) => [table, encodeStorageTablePrefix(name, table)]));\n const getPrefix = (table: string): string => {\n const cached = prefixMap.get(table);\n\n if (!cached) throw new VaultError(`table \"${table}\" not in schema`);\n\n return cached;\n };\n\n const writeItem = (table: keyof S, storageKey: string, value: unknown): void => {\n try {\n storage().setItem(storageKey, JSON.stringify(value));\n } catch (error) {\n if (error instanceof DOMException && QUOTA_ERROR_NAMES.has(error.name)) {\n const wrappedError = new VaultQuotaError(`${storageLabel} quota exceeded while writing record`, {\n cause: error,\n });\n\n if (onQuotaExceeded?.(table, wrappedError) === 'ignore') return;\n\n throw wrappedError;\n }\n\n throw error;\n }\n };\n\n // Per-instance registry of all storage keys owned by this adapter instance.\n // Populated once at construction; kept current by every mutation.\n const ownedKeys = new Set<string>();\n\n const initOwnedKeys = (): void => {\n const dbPrefix = encodeDbPrefix(name);\n\n for (let i = 0; i < resolvedStorage.length; i++) {\n const key = resolvedStorage.key(i);\n\n if (key !== null && key.startsWith(dbPrefix)) ownedKeys.add(key);\n }\n };\n\n initOwnedKeys();\n\n /**\n * Reads a single entry without side effects. Returns the live value,\n * or `undefined` if missing/expired/corrupt.\n *\n * Callers that want to evict stale entries must call `evict(storageKey)` explicitly.\n * This design avoids the `{ cleanup?: boolean }` flag that required callers to remember\n * to pass `{ cleanup: false }` inside loops.\n */\n const parseEntry = <T extends object>(storageKey: string): T | undefined => {\n const raw = storage().getItem(storageKey);\n\n if (!raw) return undefined;\n\n try {\n const stored = parseStored<T>(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) return undefined;\n\n return stored.value;\n } catch {\n return undefined;\n }\n };\n\n /** Removes a stale/expired/corrupt entry from storage and the owned-keys registry. */\n const evict = (storageKey: string): void => {\n storage().removeItem(storageKey);\n ownedKeys.delete(storageKey);\n };\n\n const core: StorageBackend<S> = {\n async clear<K extends keyof S & string>(table: K): Promise<void> {\n const target = storage();\n const prefix = getPrefix(table);\n const toRemove: string[] = [];\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) toRemove.push(key);\n }\n\n for (const key of toRemove) {\n target.removeItem(key);\n ownedKeys.delete(key);\n }\n },\n\n async count<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n let liveCount = 0;\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n } else {\n liveCount += 1;\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return liveCount;\n },\n\n async delete<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n\n return true;\n }\n\n if (ownedKeys.has(storageKey)) evict(storageKey);\n\n return false;\n },\n\n async deleteMany<K extends keyof S & string>(table: K, keys: KeyOf<S, K>[]): Promise<number> {\n let deleted = 0;\n\n for (const key of keys) {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n deleted += 1;\n } else if (ownedKeys.has(storageKey)) {\n evict(storageKey);\n }\n }\n\n return deleted;\n },\n\n async get<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<RecordOf<S, K> | undefined> {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value;\n },\n\n async getAll<K extends keyof S & string>(table: K): Promise<RecordOf<S, K>[]> {\n const records: RecordOf<S, K>[] = [];\n const expiredKeys: string[] = [];\n const prefix = getPrefix(table);\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n records.push(value);\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return records;\n },\n\n async getAllKeys<K extends keyof S & string>(table: K): Promise<KeyOf<S, K>[]> {\n const prefix = getPrefix(table);\n const keys: KeyOf<S, K>[] = [];\n const expiredStorageKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredStorageKeys.push(storageKey);\n continue;\n }\n\n // Extract the record key from the already-decoded value (avoids a second parse).\n keys.push((value as Record<string, unknown>)[schema[table].key] as KeyOf<S, K>);\n }\n\n for (const storageKey of expiredStorageKeys) {\n evict(storageKey);\n }\n\n return keys;\n },\n\n async getRawCount<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n let count = 0;\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) count += 1;\n }\n\n return count;\n },\n\n async has<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value !== undefined;\n },\n\n async pruneExpiredInTable<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const raw = storage().getItem(storageKey);\n\n if (raw === null) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n try {\n const stored = parseStored(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n expiredKeys.push(storageKey);\n }\n } catch {\n expiredKeys.push(storageKey);\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return expiredKeys.length;\n },\n\n async put<K extends keyof S & string>(table: K, value: RecordOf<S, K>, ttl?: TtlMs): Promise<void> {\n const storageKey = encodeStorageKey(name, table, getRecordKey(schema, table, value));\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n writeItem(table, storageKey, expiresAt === undefined ? { value } : { expiresAt, value });\n ownedKeys.add(storageKey);\n },\n\n async putAll<K extends keyof S & string>(table: K, values: RecordOf<S, K>[], ttl?: TtlMs): Promise<void> {\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n for (const value of values) {\n const storageKey = encodeStorageKey(name, table, getRecordKey(schema, table, value));\n\n writeItem(table, storageKey, expiresAt === undefined ? { value } : { expiresAt, value });\n ownedKeys.add(storageKey);\n }\n },\n };\n\n return buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage(notify) {\n if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {\n return undefined;\n }\n\n const listener = (event: StorageEvent) => {\n if (event.storageArea && event.storageArea !== resolvedStorage) return;\n\n if (event.key === null) {\n // storage.clear() from another tab — all keys are gone; purge ownedKeys\n ownedKeys.clear();\n\n for (const table of Object.keys(schema)) {\n notify(table as keyof S & string);\n }\n\n return;\n }\n\n const tableName = decodeStorageTableFromKey(name, event.key);\n\n if (tableName && Object.hasOwn(schema, tableName)) {\n if (event.newValue === null) {\n ownedKeys.delete(event.key);\n } else {\n ownedKeys.add(event.key);\n }\n\n notify(tableName as keyof S & string);\n }\n };\n\n window.addEventListener('storage', listener);\n\n return () => window.removeEventListener('storage', listener);\n },\n onMetrics,\n schema,\n validators,\n });\n}\n\nexport function createLocalStorage<S extends AnySchema>(options: WebStorageOptions<S>): VaultStore<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.localStorage : localStorage),\n storageLabel: 'localStorage',\n });\n}\n\nexport function createSessionStorage<S extends AnySchema>(options: WebStorageOptions<S>): VaultStore<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.sessionStorage : sessionStorage),\n storageLabel: 'sessionStorage',\n });\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Adapter, AnySchema, BaseAdapterOptions } from '../types';
1
+ import type { AnySchema, BaseAdapterOptions, VaultStore } from '../types';
2
2
  import { VaultQuotaError } from '../errors';
3
3
  type WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {
4
4
  name: string;
@@ -8,7 +8,7 @@ type WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {
8
8
  */
9
9
  onQuotaExceeded?: (table: keyof S, error: VaultQuotaError) => 'ignore' | 'throw';
10
10
  };
11
- export declare function createLocalStorage<S extends AnySchema>(options: WebStorageOptions<S>): Adapter<S>;
12
- export declare function createSessionStorage<S extends AnySchema>(options: WebStorageOptions<S>): Adapter<S>;
11
+ export declare function createLocalStorage<S extends AnySchema>(options: WebStorageOptions<S>): VaultStore<S>;
12
+ export declare function createSessionStorage<S extends AnySchema>(options: WebStorageOptions<S>): VaultStore<S>;
13
13
  export {};
14
14
  //# sourceMappingURL=webstorage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webstorage.d.ts","sourceRoot":"","sources":["../../src/adapters/webstorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAA0B,MAAM,UAAU,CAAC;AAG/F,OAAO,EAAc,eAAe,EAAE,MAAM,WAAW,CAAC;AAaxD,KAAK,iBAAiB,CAAC,CAAC,SAAS,SAAS,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG;IACpE,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,eAAe,KAAK,QAAQ,GAAG,OAAO,CAAC;CAClF,CAAC;AAuWF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMjG;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMnG"}
1
+ {"version":3,"file":"webstorage.d.ts","sourceRoot":"","sources":["../../src/adapters/webstorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAA0B,UAAU,EAAE,MAAM,UAAU,CAAC;AAGlG,OAAO,EAAc,eAAe,EAAE,MAAM,WAAW,CAAC;AAaxD,KAAK,iBAAiB,CAAC,CAAC,SAAS,SAAS,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG;IACpE,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,eAAe,KAAK,QAAQ,GAAG,OAAO,CAAC;CAClF,CAAC;AA2VF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAMpG;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAMtG"}
@@ -1,165 +1,170 @@
1
1
  import { VaultError as e, VaultQuotaError as t } from "../errors.js";
2
2
  import { decodeStorageTableFromKey as n, encodeDbPrefix as r, encodeStorageKey as i, encodeStorageTablePrefix as a, getRecordKey as o } from "../internal.js";
3
- import { defaultCodec as s, isExpired as c } from "../ttl.js";
3
+ import { isExpired as s, parseStored as c } from "../ttl.js";
4
4
  import { buildAdapterOps as l } from "../adapter-core.js";
5
5
  //#region src/adapters/webstorage.ts
6
6
  var u = /* @__PURE__ */ new Set(["QuotaExceededError", "NS_ERROR_DOM_QUOTA_REACHED"]);
7
7
  function d(d) {
8
- let { codec: f = s, getStorage: p, logger: m, name: h, onMetrics: g, onQuotaExceeded: _, schema: v, signals: y, storageLabel: b, validators: x } = d, S;
8
+ let { getStorage: f, logger: p, name: m, onMetrics: h, onQuotaExceeded: g, schema: _, storageLabel: v, validators: y } = d, b;
9
9
  try {
10
- S = p();
10
+ b = f();
11
11
  } catch (t) {
12
- throw new e(`${b} is not available in this environment (private browsing or sandboxed iframe?)`, { cause: t });
12
+ throw new e(`${v} is not available in this environment (private browsing or sandboxed iframe?)`, { cause: t });
13
13
  }
14
- let C = () => S, w = new Map(Object.keys(v).map((e) => [e, a(h, e)])), T = (t) => {
15
- let n = w.get(t);
14
+ let x = () => b, S = new Map(Object.keys(_).map((e) => [e, a(m, e)])), C = (t) => {
15
+ let n = S.get(t);
16
16
  if (!n) throw new e(`table "${t}" not in schema`);
17
17
  return n;
18
- }, E = (e, n, r) => {
18
+ }, w = (e, n, r) => {
19
19
  try {
20
- C().setItem(n, JSON.stringify(r));
20
+ x().setItem(n, JSON.stringify(r));
21
21
  } catch (n) {
22
22
  if (n instanceof DOMException && u.has(n.name)) {
23
- let r = new t(`${b} quota exceeded while writing record`, { cause: n });
24
- if (_?.(e, r) === "ignore") return;
23
+ let r = new t(`${v} quota exceeded while writing record`, { cause: n });
24
+ if (g?.(e, r) === "ignore") return;
25
25
  throw r;
26
26
  }
27
27
  throw n;
28
28
  }
29
- }, D = /* @__PURE__ */ new Set();
29
+ }, T = /* @__PURE__ */ new Set();
30
30
  (() => {
31
- let e = r(h);
32
- for (let t = 0; t < S.length; t++) {
33
- let n = S.key(t);
34
- n !== null && n.startsWith(e) && D.add(n);
31
+ let e = r(m);
32
+ for (let t = 0; t < b.length; t++) {
33
+ let n = b.key(t);
34
+ n !== null && n.startsWith(e) && T.add(n);
35
35
  }
36
36
  })();
37
- let O = (e) => {
38
- let t = C().getItem(e);
37
+ let E = (e) => {
38
+ let t = x().getItem(e);
39
39
  if (t) try {
40
- let e = f.decode(JSON.parse(t));
41
- return !e || c(e.expiresAt) ? void 0 : e.value;
40
+ let e = c(JSON.parse(t));
41
+ return !e || s(e.expiresAt) ? void 0 : e.value;
42
42
  } catch {
43
43
  return;
44
44
  }
45
- }, k = (e) => {
46
- C().removeItem(e), D.delete(e);
45
+ }, D = (e) => {
46
+ x().removeItem(e), T.delete(e);
47
47
  };
48
- return l(v, {
48
+ return l(_, {
49
49
  async clear(e) {
50
- let t = C(), n = T(e), r = [];
51
- for (let e of D) e.startsWith(n) && r.push(e);
52
- for (let e of r) t.removeItem(e), D.delete(e);
50
+ let t = x(), n = C(e), r = [];
51
+ for (let e of T) e.startsWith(n) && r.push(e);
52
+ for (let e of r) t.removeItem(e), T.delete(e);
53
53
  },
54
54
  async count(e) {
55
- let t = T(e), n = [], r = 0;
56
- for (let e of D) e.startsWith(t) && (O(e) === void 0 ? n.push(e) : r += 1);
57
- for (let e of n) k(e);
55
+ let t = C(e), n = [], r = 0;
56
+ for (let e of T) e.startsWith(t) && (E(e) === void 0 ? n.push(e) : r += 1);
57
+ for (let e of n) D(e);
58
58
  return r;
59
59
  },
60
60
  async delete(e, t) {
61
- let n = i(h, e, String(t));
62
- return O(n) === void 0 ? (D.has(n) && k(n), !1) : (k(n), !0);
61
+ let n = i(m, e, t);
62
+ return E(n) === void 0 ? (T.has(n) && D(n), !1) : (D(n), !0);
63
63
  },
64
64
  async deleteMany(e, t) {
65
65
  let n = 0;
66
66
  for (let r of t) {
67
- let t = i(h, e, String(r));
68
- O(t) === void 0 ? D.has(t) && k(t) : (k(t), n += 1);
67
+ let t = i(m, e, r);
68
+ E(t) === void 0 ? T.has(t) && D(t) : (D(t), n += 1);
69
69
  }
70
70
  return n;
71
71
  },
72
72
  async get(e, t) {
73
- let n = i(h, e, String(t)), r = O(n);
74
- return r === void 0 && D.has(n) && k(n), r;
73
+ let n = i(m, e, t), r = E(n);
74
+ return r === void 0 && T.has(n) && D(n), r;
75
75
  },
76
76
  async getAll(e) {
77
- let t = [], n = [], r = T(e);
78
- for (let e of D) {
77
+ let t = [], n = [], r = C(e);
78
+ for (let e of T) {
79
79
  if (!e.startsWith(r)) continue;
80
- let i = O(e);
80
+ let i = E(e);
81
81
  if (i === void 0) {
82
82
  n.push(e);
83
83
  continue;
84
84
  }
85
85
  t.push(i);
86
86
  }
87
- for (let e of n) k(e);
87
+ for (let e of n) D(e);
88
88
  return t;
89
89
  },
90
90
  async getAllKeys(e) {
91
- let t = T(e), n = [], r = [];
92
- for (let i of D) {
91
+ let t = C(e), n = [], r = [];
92
+ for (let i of T) {
93
93
  if (!i.startsWith(t)) continue;
94
- let a = O(i);
94
+ let a = E(i);
95
95
  if (a === void 0) {
96
96
  r.push(i);
97
97
  continue;
98
98
  }
99
- n.push(a[v[e].key]);
99
+ n.push(a[_[e].key]);
100
100
  }
101
- for (let e of r) k(e);
101
+ for (let e of r) D(e);
102
102
  return n;
103
103
  },
104
104
  async getRawCount(e) {
105
- let t = T(e), n = 0;
106
- for (let e of D) e.startsWith(t) && (n += 1);
105
+ let t = C(e), n = 0;
106
+ for (let e of T) e.startsWith(t) && (n += 1);
107
107
  return n;
108
108
  },
109
109
  async has(e, t) {
110
- let n = i(h, e, String(t)), r = O(n);
111
- return r === void 0 && D.has(n) && k(n), r !== void 0;
110
+ let n = i(m, e, t), r = E(n);
111
+ return r === void 0 && T.has(n) && D(n), r !== void 0;
112
112
  },
113
113
  async pruneExpiredInTable(e) {
114
- let t = T(e), n = [];
115
- for (let e of D) {
114
+ let t = C(e), n = [];
115
+ for (let e of T) {
116
116
  if (!e.startsWith(t)) continue;
117
- let r = C().getItem(e);
117
+ let r = x().getItem(e);
118
118
  if (r === null) {
119
119
  n.push(e);
120
120
  continue;
121
121
  }
122
122
  try {
123
- let t = f.decode(JSON.parse(r));
124
- (!t || c(t.expiresAt)) && n.push(e);
123
+ let t = c(JSON.parse(r));
124
+ (!t || s(t.expiresAt)) && n.push(e);
125
125
  } catch {
126
126
  n.push(e);
127
127
  }
128
128
  }
129
- for (let e of n) k(e);
129
+ for (let e of n) D(e);
130
130
  return n.length;
131
131
  },
132
132
  async put(e, t, n) {
133
- let r = i(h, e, String(o(v, e, t))), a = n === void 0 ? void 0 : Date.now() + n;
134
- E(e, r, f.encode(t, a)), D.add(r);
133
+ let r = i(m, e, o(_, e, t)), a = n === void 0 ? void 0 : Date.now() + n;
134
+ w(e, r, a === void 0 ? { value: t } : {
135
+ expiresAt: a,
136
+ value: t
137
+ }), T.add(r);
135
138
  },
136
139
  async putAll(e, t, n) {
137
140
  let r = n === void 0 ? void 0 : Date.now() + n;
138
141
  for (let n of t) {
139
- let t = i(h, e, String(o(v, e, n)));
140
- E(e, t, f.encode(n, r)), D.add(t);
142
+ let t = i(m, e, o(_, e, n));
143
+ w(e, t, r === void 0 ? { value: n } : {
144
+ expiresAt: r,
145
+ value: n
146
+ }), T.add(t);
141
147
  }
142
148
  }
143
149
  }, {
144
- logger: m,
150
+ logger: p,
145
151
  onCrossTabMessage(e) {
146
152
  if (typeof window > "u" || typeof window.addEventListener != "function") return;
147
153
  let t = (t) => {
148
- if (t.storageArea && t.storageArea !== S) return;
154
+ if (t.storageArea && t.storageArea !== b) return;
149
155
  if (t.key === null) {
150
- D.clear();
151
- for (let t of Object.keys(v)) e(t);
156
+ T.clear();
157
+ for (let t of Object.keys(_)) e(t);
152
158
  return;
153
159
  }
154
- let r = n(h, t.key);
155
- r && Object.hasOwn(v, r) && (t.newValue === null ? D.delete(t.key) : D.add(t.key), e(r));
160
+ let r = n(m, t.key);
161
+ r && Object.hasOwn(_, r) && (t.newValue === null ? T.delete(t.key) : T.add(t.key), e(r));
156
162
  };
157
163
  return window.addEventListener("storage", t), () => window.removeEventListener("storage", t);
158
164
  },
159
- onMetrics: g,
160
- schema: v,
161
- signals: y,
162
- validators: x
165
+ onMetrics: h,
166
+ schema: _,
167
+ validators: y
163
168
  });
164
169
  }
165
170
  function f(e) {
@@ -1 +1 @@
1
- {"version":3,"file":"webstorage.js","names":[],"sources":["../../src/adapters/webstorage.ts"],"sourcesContent":["import type { Adapter, AnySchema, BaseAdapterOptions, KeyOf, RecordOf, TtlMs } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { VaultError, VaultQuotaError } from '../errors';\nimport {\n decodeStorageTableFromKey,\n encodeDbPrefix,\n encodeStorageKey,\n encodeStorageTablePrefix,\n getRecordKey,\n} from '../internal';\nimport { defaultCodec, isExpired } from '../ttl';\n\n// Firefox historically threw 'NS_ERROR_DOM_QUOTA_REACHED'; modern browsers use the standard name.\nconst QUOTA_ERROR_NAMES = new Set(['QuotaExceededError', 'NS_ERROR_DOM_QUOTA_REACHED']);\n\ntype WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n name: string;\n /**\n * Called when localStorage/sessionStorage quota is exceeded on a write.\n * Return `'ignore'` to silently drop the write, or `'throw'` (default) to rethrow the error.\n */\n onQuotaExceeded?: (table: keyof S, error: VaultQuotaError) => 'ignore' | 'throw';\n};\n\nfunction createWebStorageAdapter<S extends AnySchema>(\n options: WebStorageOptions<S> & {\n getStorage: () => Storage;\n storageLabel: string;\n },\n): Adapter<S> {\n const {\n codec = defaultCodec,\n getStorage,\n logger,\n name,\n onMetrics,\n onQuotaExceeded,\n schema,\n signals,\n storageLabel,\n validators,\n } = options;\n\n let resolvedStorage: Storage;\n\n try {\n resolvedStorage = getStorage();\n } catch (cause) {\n throw new VaultError(\n `${storageLabel} is not available in this environment (private browsing or sandboxed iframe?)`,\n {\n cause,\n },\n );\n }\n\n const storage = (): Storage => resolvedStorage;\n\n const prefixMap = new Map(Object.keys(schema).map((table) => [table, encodeStorageTablePrefix(name, table)]));\n const getPrefix = (table: string): string => {\n const cached = prefixMap.get(table);\n\n if (!cached) throw new VaultError(`table \"${table}\" not in schema`);\n\n return cached;\n };\n\n const writeItem = (table: keyof S, storageKey: string, value: unknown): void => {\n try {\n storage().setItem(storageKey, JSON.stringify(value));\n } catch (error) {\n if (error instanceof DOMException && QUOTA_ERROR_NAMES.has(error.name)) {\n const wrappedError = new VaultQuotaError(`${storageLabel} quota exceeded while writing record`, {\n cause: error,\n });\n\n if (onQuotaExceeded?.(table, wrappedError) === 'ignore') return;\n\n throw wrappedError;\n }\n\n throw error;\n }\n };\n\n // Per-instance registry of all storage keys owned by this adapter instance.\n // Populated once at construction; kept current by every mutation.\n const ownedKeys = new Set<string>();\n\n const initOwnedKeys = (): void => {\n const dbPrefix = encodeDbPrefix(name);\n\n for (let i = 0; i < resolvedStorage.length; i++) {\n const key = resolvedStorage.key(i);\n\n if (key !== null && key.startsWith(dbPrefix)) ownedKeys.add(key);\n }\n };\n\n initOwnedKeys();\n\n /**\n * Reads a single entry without side effects. Returns the live value,\n * or `undefined` if missing/expired/corrupt.\n *\n * Callers that want to evict stale entries must call `evict(storageKey)` explicitly.\n * This design avoids the `{ cleanup?: boolean }` flag that required callers to remember\n * to pass `{ cleanup: false }` inside loops.\n */\n const parseEntry = <T extends Record<string, unknown>>(storageKey: string): T | undefined => {\n const raw = storage().getItem(storageKey);\n\n if (!raw) return undefined;\n\n try {\n const stored = codec.decode<T>(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) return undefined;\n\n return stored.value;\n } catch {\n return undefined;\n }\n };\n\n /** Removes a stale/expired/corrupt entry from storage and the owned-keys registry. */\n const evict = (storageKey: string): void => {\n storage().removeItem(storageKey);\n ownedKeys.delete(storageKey);\n };\n\n const core: StorageBackend<S> = {\n async clear<K extends keyof S & string>(table: K): Promise<void> {\n const target = storage();\n const prefix = getPrefix(table);\n const toRemove: string[] = [];\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) toRemove.push(key);\n }\n\n for (const key of toRemove) {\n target.removeItem(key);\n ownedKeys.delete(key);\n }\n },\n\n async count<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n let liveCount = 0;\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n } else {\n liveCount += 1;\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return liveCount;\n },\n\n async delete<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n\n return true;\n }\n\n if (ownedKeys.has(storageKey)) evict(storageKey);\n\n return false;\n },\n\n async deleteMany<K extends keyof S & string>(table: K, keys: KeyOf<S, K>[]): Promise<number> {\n let deleted = 0;\n\n for (const key of keys) {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n deleted += 1;\n } else if (ownedKeys.has(storageKey)) {\n evict(storageKey);\n }\n }\n\n return deleted;\n },\n\n async get<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<RecordOf<S, K> | undefined> {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value;\n },\n\n async getAll<K extends keyof S & string>(table: K): Promise<RecordOf<S, K>[]> {\n const records: RecordOf<S, K>[] = [];\n const expiredKeys: string[] = [];\n const prefix = getPrefix(table);\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n records.push(value);\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return records;\n },\n\n async getAllKeys<K extends keyof S & string>(table: K): Promise<KeyOf<S, K>[]> {\n const prefix = getPrefix(table);\n const keys: KeyOf<S, K>[] = [];\n const expiredStorageKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredStorageKeys.push(storageKey);\n continue;\n }\n\n // Extract the record key from the already-decoded value (avoids a second parse).\n keys.push((value as Record<string, unknown>)[schema[table].key] as KeyOf<S, K>);\n }\n\n for (const storageKey of expiredStorageKeys) {\n evict(storageKey);\n }\n\n return keys;\n },\n\n async getRawCount<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n let count = 0;\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) count += 1;\n }\n\n return count;\n },\n\n async has<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, String(key));\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value !== undefined;\n },\n\n async pruneExpiredInTable<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const raw = storage().getItem(storageKey);\n\n if (raw === null) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n try {\n const stored = codec.decode(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n expiredKeys.push(storageKey);\n }\n } catch {\n expiredKeys.push(storageKey);\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return expiredKeys.length;\n },\n\n async put<K extends keyof S & string>(table: K, value: RecordOf<S, K>, ttl?: TtlMs): Promise<void> {\n const storageKey = encodeStorageKey(name, table, String(getRecordKey(schema, table, value)));\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n writeItem(table, storageKey, codec.encode(value, expiresAt));\n ownedKeys.add(storageKey);\n },\n\n async putAll<K extends keyof S & string>(table: K, values: RecordOf<S, K>[], ttl?: TtlMs): Promise<void> {\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n for (const value of values) {\n const storageKey = encodeStorageKey(name, table, String(getRecordKey(schema, table, value)));\n\n writeItem(table, storageKey, codec.encode(value, expiresAt));\n ownedKeys.add(storageKey);\n }\n },\n };\n\n return buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage(notify) {\n if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {\n return undefined;\n }\n\n const listener = (event: StorageEvent) => {\n if (event.storageArea && event.storageArea !== resolvedStorage) return;\n\n if (event.key === null) {\n // storage.clear() from another tab — all keys are gone; purge ownedKeys\n ownedKeys.clear();\n\n for (const table of Object.keys(schema)) {\n notify(table as keyof S & string);\n }\n\n return;\n }\n\n const tableName = decodeStorageTableFromKey(name, event.key);\n\n if (tableName && Object.hasOwn(schema, tableName)) {\n if (event.newValue === null) {\n ownedKeys.delete(event.key);\n } else {\n ownedKeys.add(event.key);\n }\n\n notify(tableName as keyof S & string);\n }\n };\n\n window.addEventListener('storage', listener);\n\n return () => window.removeEventListener('storage', listener);\n },\n onMetrics,\n schema,\n signals,\n validators,\n });\n}\n\nexport function createLocalStorage<S extends AnySchema>(options: WebStorageOptions<S>): Adapter<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.localStorage : localStorage),\n storageLabel: 'localStorage',\n });\n}\n\nexport function createSessionStorage<S extends AnySchema>(options: WebStorageOptions<S>): Adapter<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.sessionStorage : sessionStorage),\n storageLabel: 'sessionStorage',\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"webstorage.js","names":[],"sources":["../../src/adapters/webstorage.ts"],"sourcesContent":["import type { AnySchema, BaseAdapterOptions, KeyOf, RecordOf, TtlMs, VaultStore } from '../types';\n\nimport { buildAdapterOps, type StorageBackend } from '../adapter-core';\nimport { VaultError, VaultQuotaError } from '../errors';\nimport {\n decodeStorageTableFromKey,\n encodeDbPrefix,\n encodeStorageKey,\n encodeStorageTablePrefix,\n getRecordKey,\n} from '../internal';\nimport { isExpired, parseStored } from '../ttl';\n\n// Firefox historically threw 'NS_ERROR_DOM_QUOTA_REACHED'; modern browsers use the standard name.\nconst QUOTA_ERROR_NAMES = new Set(['QuotaExceededError', 'NS_ERROR_DOM_QUOTA_REACHED']);\n\ntype WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {\n name: string;\n /**\n * Called when localStorage/sessionStorage quota is exceeded on a write.\n * Return `'ignore'` to silently drop the write, or `'throw'` (default) to rethrow the error.\n */\n onQuotaExceeded?: (table: keyof S, error: VaultQuotaError) => 'ignore' | 'throw';\n};\n\nfunction createWebStorageAdapter<S extends AnySchema>(\n options: WebStorageOptions<S> & {\n getStorage: () => Storage;\n storageLabel: string;\n },\n): VaultStore<S> {\n const { getStorage, logger, name, onMetrics, onQuotaExceeded, schema, storageLabel, validators } = options;\n\n let resolvedStorage: Storage;\n\n try {\n resolvedStorage = getStorage();\n } catch (cause) {\n throw new VaultError(\n `${storageLabel} is not available in this environment (private browsing or sandboxed iframe?)`,\n {\n cause,\n },\n );\n }\n\n const storage = (): Storage => resolvedStorage;\n\n const prefixMap = new Map(Object.keys(schema).map((table) => [table, encodeStorageTablePrefix(name, table)]));\n const getPrefix = (table: string): string => {\n const cached = prefixMap.get(table);\n\n if (!cached) throw new VaultError(`table \"${table}\" not in schema`);\n\n return cached;\n };\n\n const writeItem = (table: keyof S, storageKey: string, value: unknown): void => {\n try {\n storage().setItem(storageKey, JSON.stringify(value));\n } catch (error) {\n if (error instanceof DOMException && QUOTA_ERROR_NAMES.has(error.name)) {\n const wrappedError = new VaultQuotaError(`${storageLabel} quota exceeded while writing record`, {\n cause: error,\n });\n\n if (onQuotaExceeded?.(table, wrappedError) === 'ignore') return;\n\n throw wrappedError;\n }\n\n throw error;\n }\n };\n\n // Per-instance registry of all storage keys owned by this adapter instance.\n // Populated once at construction; kept current by every mutation.\n const ownedKeys = new Set<string>();\n\n const initOwnedKeys = (): void => {\n const dbPrefix = encodeDbPrefix(name);\n\n for (let i = 0; i < resolvedStorage.length; i++) {\n const key = resolvedStorage.key(i);\n\n if (key !== null && key.startsWith(dbPrefix)) ownedKeys.add(key);\n }\n };\n\n initOwnedKeys();\n\n /**\n * Reads a single entry without side effects. Returns the live value,\n * or `undefined` if missing/expired/corrupt.\n *\n * Callers that want to evict stale entries must call `evict(storageKey)` explicitly.\n * This design avoids the `{ cleanup?: boolean }` flag that required callers to remember\n * to pass `{ cleanup: false }` inside loops.\n */\n const parseEntry = <T extends object>(storageKey: string): T | undefined => {\n const raw = storage().getItem(storageKey);\n\n if (!raw) return undefined;\n\n try {\n const stored = parseStored<T>(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) return undefined;\n\n return stored.value;\n } catch {\n return undefined;\n }\n };\n\n /** Removes a stale/expired/corrupt entry from storage and the owned-keys registry. */\n const evict = (storageKey: string): void => {\n storage().removeItem(storageKey);\n ownedKeys.delete(storageKey);\n };\n\n const core: StorageBackend<S> = {\n async clear<K extends keyof S & string>(table: K): Promise<void> {\n const target = storage();\n const prefix = getPrefix(table);\n const toRemove: string[] = [];\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) toRemove.push(key);\n }\n\n for (const key of toRemove) {\n target.removeItem(key);\n ownedKeys.delete(key);\n }\n },\n\n async count<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n let liveCount = 0;\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n } else {\n liveCount += 1;\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return liveCount;\n },\n\n async delete<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n\n return true;\n }\n\n if (ownedKeys.has(storageKey)) evict(storageKey);\n\n return false;\n },\n\n async deleteMany<K extends keyof S & string>(table: K, keys: KeyOf<S, K>[]): Promise<number> {\n let deleted = 0;\n\n for (const key of keys) {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value !== undefined) {\n evict(storageKey);\n deleted += 1;\n } else if (ownedKeys.has(storageKey)) {\n evict(storageKey);\n }\n }\n\n return deleted;\n },\n\n async get<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<RecordOf<S, K> | undefined> {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value;\n },\n\n async getAll<K extends keyof S & string>(table: K): Promise<RecordOf<S, K>[]> {\n const records: RecordOf<S, K>[] = [];\n const expiredKeys: string[] = [];\n const prefix = getPrefix(table);\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n records.push(value);\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return records;\n },\n\n async getAllKeys<K extends keyof S & string>(table: K): Promise<KeyOf<S, K>[]> {\n const prefix = getPrefix(table);\n const keys: KeyOf<S, K>[] = [];\n const expiredStorageKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined) {\n expiredStorageKeys.push(storageKey);\n continue;\n }\n\n // Extract the record key from the already-decoded value (avoids a second parse).\n keys.push((value as Record<string, unknown>)[schema[table].key] as KeyOf<S, K>);\n }\n\n for (const storageKey of expiredStorageKeys) {\n evict(storageKey);\n }\n\n return keys;\n },\n\n async getRawCount<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n let count = 0;\n\n for (const key of ownedKeys) {\n if (key.startsWith(prefix)) count += 1;\n }\n\n return count;\n },\n\n async has<K extends keyof S & string>(table: K, key: KeyOf<S, K>): Promise<boolean> {\n const storageKey = encodeStorageKey(name, table, key);\n const value = parseEntry<RecordOf<S, K>>(storageKey);\n\n if (value === undefined && ownedKeys.has(storageKey)) evict(storageKey);\n\n return value !== undefined;\n },\n\n async pruneExpiredInTable<K extends keyof S & string>(table: K): Promise<number> {\n const prefix = getPrefix(table);\n const expiredKeys: string[] = [];\n\n for (const storageKey of ownedKeys) {\n if (!storageKey.startsWith(prefix)) continue;\n\n const raw = storage().getItem(storageKey);\n\n if (raw === null) {\n expiredKeys.push(storageKey);\n continue;\n }\n\n try {\n const stored = parseStored(JSON.parse(raw) as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n expiredKeys.push(storageKey);\n }\n } catch {\n expiredKeys.push(storageKey);\n }\n }\n\n for (const storageKey of expiredKeys) {\n evict(storageKey);\n }\n\n return expiredKeys.length;\n },\n\n async put<K extends keyof S & string>(table: K, value: RecordOf<S, K>, ttl?: TtlMs): Promise<void> {\n const storageKey = encodeStorageKey(name, table, getRecordKey(schema, table, value));\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n writeItem(table, storageKey, expiresAt === undefined ? { value } : { expiresAt, value });\n ownedKeys.add(storageKey);\n },\n\n async putAll<K extends keyof S & string>(table: K, values: RecordOf<S, K>[], ttl?: TtlMs): Promise<void> {\n const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;\n\n for (const value of values) {\n const storageKey = encodeStorageKey(name, table, getRecordKey(schema, table, value));\n\n writeItem(table, storageKey, expiresAt === undefined ? { value } : { expiresAt, value });\n ownedKeys.add(storageKey);\n }\n },\n };\n\n return buildAdapterOps(schema, core, {\n logger,\n onCrossTabMessage(notify) {\n if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {\n return undefined;\n }\n\n const listener = (event: StorageEvent) => {\n if (event.storageArea && event.storageArea !== resolvedStorage) return;\n\n if (event.key === null) {\n // storage.clear() from another tab — all keys are gone; purge ownedKeys\n ownedKeys.clear();\n\n for (const table of Object.keys(schema)) {\n notify(table as keyof S & string);\n }\n\n return;\n }\n\n const tableName = decodeStorageTableFromKey(name, event.key);\n\n if (tableName && Object.hasOwn(schema, tableName)) {\n if (event.newValue === null) {\n ownedKeys.delete(event.key);\n } else {\n ownedKeys.add(event.key);\n }\n\n notify(tableName as keyof S & string);\n }\n };\n\n window.addEventListener('storage', listener);\n\n return () => window.removeEventListener('storage', listener);\n },\n onMetrics,\n schema,\n validators,\n });\n}\n\nexport function createLocalStorage<S extends AnySchema>(options: WebStorageOptions<S>): VaultStore<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.localStorage : localStorage),\n storageLabel: 'localStorage',\n });\n}\n\nexport function createSessionStorage<S extends AnySchema>(options: WebStorageOptions<S>): VaultStore<S> {\n return createWebStorageAdapter({\n ...options,\n getStorage: () => (typeof window !== 'undefined' ? window.sessionStorage : sessionStorage),\n storageLabel: 'sessionStorage',\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base class for all vault errors. Catch with `instanceof VaultError` to\n * handle any vault-originated error regardless of its specific subtype.\n */\nexport class VaultError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n // Ensures `instanceof` works correctly when transpiled to ES5.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is VaultError {\n return err instanceof VaultError;\n }\n}\n\n/** Thrown when an operation is attempted on a disposed adapter or observer hub. */\nexport class VaultDisposedError extends VaultError {\n constructor(message = 'adapter is disposed', opts?: ErrorOptions) {\n super(message, opts);\n }\n}\n\n/** Thrown when a `batch()` callback accesses a table not declared in the scope. */\nexport class VaultScopeError extends VaultError {}\n\n/** Thrown when a WebStorage write exceeds the storage quota. */\nexport class VaultQuotaError extends VaultError {}\n\n/** Thrown when an IndexedDB `onupgradeneeded` migration callback throws. */\nexport class VaultMigrationError extends VaultError {}\n"],"mappings":"AAIA,IAAa,EAAb,MAAa,UAAmB,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KAEvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAiC,CACzC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAwC,CAAW,CACjD,YAAY,EAAU,sBAAuB,EAAqB,CAChE,MAAM,EAAS,CAAI,CACrB,CACF,EAGa,EAAb,cAAqC,CAAW,CAAC,EAGpC,EAAb,cAAqC,CAAW,CAAC,EAGpC,EAAb,cAAyC,CAAW,CAAC"}
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base class for all vault errors. Catch with `instanceof VaultError` to\n * handle any vault-originated error regardless of its specific subtype.\n */\nexport class VaultError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n // Ensures `instanceof` works correctly when transpiled to ES5.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is VaultError {\n return err instanceof VaultError;\n }\n}\n\n/** Thrown when an operation is attempted on a disposed adapter or observer hub. */\nexport class VaultDisposedError extends VaultError {\n constructor(message = 'adapter is disposed', opts?: ErrorOptions) {\n super(message, opts);\n }\n}\n\n/** Thrown when a `batch()` callback accesses a table not declared in the scope. */\nexport class VaultScopeError extends VaultError {}\n\n/** Thrown when a WebStorage write exceeds the storage quota. */\nexport class VaultQuotaError extends VaultError {}\n\n/** Thrown when an IndexedDB `onupgradeneeded` migration callback throws. */\nexport class VaultMigrationError extends VaultError {}\n"],"mappings":"AAIA,IAAa,EAAb,MAAa,UAAmB,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KAEvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CAEA,OAAO,GAAG,EAAiC,CACzC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAwC,CAAW,CACjD,YAAY,EAAU,sBAAuB,EAAqB,CAChE,MAAM,EAAS,CAAI,CACrB,CACF,EAGa,EAAb,cAAqC,CAAW,CAAC,EAGpC,EAAb,cAAqC,CAAW,CAAC,EAGpC,EAAb,cAAyC,CAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base class for all vault errors. Catch with `instanceof VaultError` to\n * handle any vault-originated error regardless of its specific subtype.\n */\nexport class VaultError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n // Ensures `instanceof` works correctly when transpiled to ES5.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is VaultError {\n return err instanceof VaultError;\n }\n}\n\n/** Thrown when an operation is attempted on a disposed adapter or observer hub. */\nexport class VaultDisposedError extends VaultError {\n constructor(message = 'adapter is disposed', opts?: ErrorOptions) {\n super(message, opts);\n }\n}\n\n/** Thrown when a `batch()` callback accesses a table not declared in the scope. */\nexport class VaultScopeError extends VaultError {}\n\n/** Thrown when a WebStorage write exceeds the storage quota. */\nexport class VaultQuotaError extends VaultError {}\n\n/** Thrown when an IndexedDB `onupgradeneeded` migration callback throws. */\nexport class VaultMigrationError extends VaultError {}\n"],"mappings":";AAIA,IAAa,IAAb,MAAa,UAAmB,MAAM;CACpC,YAAY,GAAiB,GAAqB;EAIhD,AAHA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,IAAI,OAAO,MAEvB,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS;CAClD;CAEA,OAAO,GAAG,GAAiC;EACzC,OAAO,aAAe;CACxB;AACF,GAGa,IAAb,cAAwC,EAAW;CACjD,YAAY,IAAU,uBAAuB,GAAqB;EAChE,MAAM,GAAS,CAAI;CACrB;AACF,GAGa,IAAb,cAAqC,EAAW,CAAC,GAGpC,IAAb,cAAqC,EAAW,CAAC,GAGpC,IAAb,cAAyC,EAAW,CAAC"}
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base class for all vault errors. Catch with `instanceof VaultError` to\n * handle any vault-originated error regardless of its specific subtype.\n */\nexport class VaultError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n // Ensures `instanceof` works correctly when transpiled to ES5.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is VaultError {\n return err instanceof VaultError;\n }\n}\n\n/** Thrown when an operation is attempted on a disposed adapter or observer hub. */\nexport class VaultDisposedError extends VaultError {\n constructor(message = 'adapter is disposed', opts?: ErrorOptions) {\n super(message, opts);\n }\n}\n\n/** Thrown when a `batch()` callback accesses a table not declared in the scope. */\nexport class VaultScopeError extends VaultError {}\n\n/** Thrown when a WebStorage write exceeds the storage quota. */\nexport class VaultQuotaError extends VaultError {}\n\n/** Thrown when an IndexedDB `onupgradeneeded` migration callback throws. */\nexport class VaultMigrationError extends VaultError {}\n"],"mappings":";AAIA,IAAa,IAAb,MAAa,UAAmB,MAAM;CACpC,YAAY,GAAiB,GAAqB;EAIhD,AAHA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,WAAW,MAEvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;CAEA,OAAO,GAAG,GAAiC;EACzC,OAAO,aAAe;CACxB;AACF,GAGa,IAAb,cAAwC,EAAW;CACjD,YAAY,IAAU,uBAAuB,GAAqB;EAChE,MAAM,GAAS,CAAI;CACrB;AACF,GAGa,IAAb,cAAqC,EAAW,CAAC,GAGpC,IAAb,cAAqC,EAAW,CAAC,GAGpC,IAAb,cAAyC,EAAW,CAAC"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./ttl.cjs"),n=require("./adapters/indexeddb.cjs"),r=require("./adapters/memory.cjs"),i=require("./adapters/webstorage.cjs"),a=require("./migration.cjs"),o=require("./prune.cjs"),s=require("./streaming.cjs"),c=require("./versioned-codec.cjs"),l=require("./types.cjs");exports.VaultDisposedError=e.VaultDisposedError,exports.VaultError=e.VaultError,exports.VaultMigrationError=e.VaultMigrationError,exports.VaultQuotaError=e.VaultQuotaError,exports.VaultScopeError=e.VaultScopeError,exports.createIndexedDB=n.createIndexedDB,exports.createLocalStorage=i.createLocalStorage,exports.createMemory=r.createMemory,exports.createSessionStorage=i.createSessionStorage,exports.createVersionedCodec=c.createVersionedCodec,exports.defaultCodec=t.defaultCodec,exports.defineMigration=a.defineMigration,exports.isExpired=t.isExpired,exports.scheduleExpiredPrune=o.scheduleExpiredPrune,exports.table=l.table,exports.toReadableStream=s.toReadableStream,exports.ttl=t.ttl;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./ttl.cjs"),n=require("./adapters/indexeddb.cjs"),r=require("./adapters/memory.cjs"),i=require("./adapters/webstorage.cjs"),a=require("./migration.cjs"),o=require("./prune.cjs"),s=require("./types.cjs");exports.VaultDisposedError=e.VaultDisposedError,exports.VaultError=e.VaultError,exports.VaultMigrationError=e.VaultMigrationError,exports.VaultQuotaError=e.VaultQuotaError,exports.VaultScopeError=e.VaultScopeError,exports.createIndexedDB=n.createIndexedDB,exports.createLocalStorage=i.createLocalStorage,exports.createMemory=r.createMemory,exports.createSessionStorage=i.createSessionStorage,exports.defineMigration=a.defineMigration,exports.isExpired=t.isExpired,exports.scheduleExpiredPrune=o.scheduleExpiredPrune,exports.table=s.table,exports.ttl=t.ttl;
package/dist/index.d.ts CHANGED
@@ -1,17 +1,12 @@
1
1
  export { createIndexedDB } from './adapters/indexeddb';
2
- export type { IndexedDbAdapter } from './adapters/indexeddb';
3
2
  export { createMemory } from './adapters/memory';
4
- export type { MemoryAdapter } from './adapters/memory';
5
3
  export { createLocalStorage, createSessionStorage } from './adapters/webstorage';
6
4
  export { VaultDisposedError, VaultError, VaultMigrationError, VaultQuotaError, VaultScopeError } from './errors';
7
5
  export { defineMigration } from './migration';
8
6
  export type { MigrationStep } from './migration';
9
7
  export type { QueryBuilder } from './query';
10
8
  export { scheduleExpiredPrune } from './prune';
11
- export { toReadableStream } from './streaming';
12
- export { defaultCodec, isExpired, ttl } from './ttl';
13
- export { createVersionedCodec } from './versioned-codec';
14
- export type { CodecVersion } from './versioned-codec';
9
+ export { isExpired, ttl } from './ttl';
15
10
  export { table } from './types';
16
- export type { Adapter, AnySchema, BaseAdapterOptions, DebugInfo, DebugStats, KeyOf, MetricsEvent, MigrationContext, MigrationFn, Observer, ReactiveSignal, RecordOf, RecordValidator, SchemaEntry, TableBuilder, TableSignals, TableValidators, TransactionContext, TtlMs, Unsubscribe, VaultCodec, VaultLogger, } from './types';
11
+ export type { AnySchema, BaseAdapterOptions, DebugInfo, DebugStats, IndexedDbVaultStore, KeyOf, MetricsEvent, MigrationContext, MigrationFn, Observer, RecordOf, RecordValidator, SchemaEntry, TableBuilder, TableValidators, TransactionContext, TtlMs, Unsubscribe, VaultKey, VaultLogger, VaultStore, } from './types';
17
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACjH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EACV,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,KAAK,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,KAAK,EACL,WAAW,EACX,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACjH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EACV,SAAS,EACT,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,KAAK,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,WAAW,EACX,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,KAAK,EACL,WAAW,EACX,QAAQ,EACR,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC"}