@vielzeug/vault 1.0.2

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 (96) hide show
  1. package/README.md +74 -0
  2. package/dist/_dev.cjs +2 -0
  3. package/dist/_dev.cjs.map +1 -0
  4. package/dist/_dev.d.ts +2 -0
  5. package/dist/_dev.d.ts.map +1 -0
  6. package/dist/_dev.js +12 -0
  7. package/dist/_dev.js.map +1 -0
  8. package/dist/adapter-core.cjs +2 -0
  9. package/dist/adapter-core.cjs.map +1 -0
  10. package/dist/adapter-core.d.ts +8 -0
  11. package/dist/adapter-core.d.ts.map +1 -0
  12. package/dist/adapter-core.js +269 -0
  13. package/dist/adapter-core.js.map +1 -0
  14. package/dist/adapters/indexeddb.cjs +2 -0
  15. package/dist/adapters/indexeddb.cjs.map +1 -0
  16. package/dist/adapters/indexeddb.d.ts +13 -0
  17. package/dist/adapters/indexeddb.d.ts.map +1 -0
  18. package/dist/adapters/indexeddb.js +336 -0
  19. package/dist/adapters/indexeddb.js.map +1 -0
  20. package/dist/adapters/memory.cjs +2 -0
  21. package/dist/adapters/memory.cjs.map +1 -0
  22. package/dist/adapters/memory.d.ts +14 -0
  23. package/dist/adapters/memory.d.ts.map +1 -0
  24. package/dist/adapters/memory.js +200 -0
  25. package/dist/adapters/memory.js.map +1 -0
  26. package/dist/adapters/webstorage.cjs +2 -0
  27. package/dist/adapters/webstorage.cjs.map +1 -0
  28. package/dist/adapters/webstorage.d.ts +14 -0
  29. package/dist/adapters/webstorage.d.ts.map +1 -0
  30. package/dist/adapters/webstorage.js +182 -0
  31. package/dist/adapters/webstorage.js.map +1 -0
  32. package/dist/errors.cjs +2 -0
  33. package/dist/errors.cjs.map +1 -0
  34. package/dist/errors.d.ts +22 -0
  35. package/dist/errors.d.ts.map +1 -0
  36. package/dist/errors.js +17 -0
  37. package/dist/errors.js.map +1 -0
  38. package/dist/index.cjs +1 -0
  39. package/dist/index.d.ts +17 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +11 -0
  42. package/dist/internal.cjs +2 -0
  43. package/dist/internal.cjs.map +1 -0
  44. package/dist/internal.d.ts +50 -0
  45. package/dist/internal.d.ts.map +1 -0
  46. package/dist/internal.js +125 -0
  47. package/dist/internal.js.map +1 -0
  48. package/dist/migration.cjs +2 -0
  49. package/dist/migration.cjs.map +1 -0
  50. package/dist/migration.d.ts +37 -0
  51. package/dist/migration.d.ts.map +1 -0
  52. package/dist/migration.js +27 -0
  53. package/dist/migration.js.map +1 -0
  54. package/dist/prune.cjs +2 -0
  55. package/dist/prune.cjs.map +1 -0
  56. package/dist/prune.d.ts +32 -0
  57. package/dist/prune.d.ts.map +1 -0
  58. package/dist/prune.js +20 -0
  59. package/dist/prune.js.map +1 -0
  60. package/dist/query.cjs +2 -0
  61. package/dist/query.cjs.map +1 -0
  62. package/dist/query.d.ts +113 -0
  63. package/dist/query.d.ts.map +1 -0
  64. package/dist/query.js +126 -0
  65. package/dist/query.js.map +1 -0
  66. package/dist/streaming.cjs +2 -0
  67. package/dist/streaming.cjs.map +1 -0
  68. package/dist/streaming.d.ts +22 -0
  69. package/dist/streaming.d.ts.map +1 -0
  70. package/dist/streaming.js +21 -0
  71. package/dist/streaming.js.map +1 -0
  72. package/dist/ttl.cjs +2 -0
  73. package/dist/ttl.cjs.map +1 -0
  74. package/dist/ttl.d.ts +74 -0
  75. package/dist/ttl.d.ts.map +1 -0
  76. package/dist/ttl.js +32 -0
  77. package/dist/ttl.js.map +1 -0
  78. package/dist/types.cjs +2 -0
  79. package/dist/types.cjs.map +1 -0
  80. package/dist/types.d.ts +409 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +27 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/vault.cjs +2 -0
  85. package/dist/vault.cjs.map +1 -0
  86. package/dist/vault.iife.js +2 -0
  87. package/dist/vault.iife.js.map +1 -0
  88. package/dist/vault.js +2 -0
  89. package/dist/vault.js.map +1 -0
  90. package/dist/versioned-codec.cjs +2 -0
  91. package/dist/versioned-codec.cjs.map +1 -0
  92. package/dist/versioned-codec.d.ts +44 -0
  93. package/dist/versioned-codec.d.ts.map +1 -0
  94. package/dist/versioned-codec.js +32 -0
  95. package/dist/versioned-codec.js.map +1 -0
  96. package/package.json +41 -0
@@ -0,0 +1,200 @@
1
+ import { VaultDisposedError as e } from "../errors.js";
2
+ import { getRecordKey as t } from "../internal.js";
3
+ import { defaultCodec as n, isExpired as r } from "../ttl.js";
4
+ import { buildAdapterOps as i } from "../adapter-core.js";
5
+ //#region src/adapters/memory.ts
6
+ function a(e) {
7
+ return function(t) {
8
+ if (typeof t != "object" || !t) return !1;
9
+ let n = t;
10
+ if (typeof n.table != "string" || typeof n.type != "string" || n.table === "__proto__" || n.table === "constructor" || n.table === "prototype") return !1;
11
+ switch (n.type) {
12
+ case "clear": return !0;
13
+ case "delete": return typeof n.key == "string";
14
+ case "deleteMany": return Array.isArray(n.keys) && n.keys.every((e) => typeof e == "string");
15
+ case "put": return typeof n.key == "string" && e.decode(n.stored) !== void 0;
16
+ case "putAll": return Array.isArray(n.entries) && n.entries.every((t) => typeof t == "object" && !!t && typeof t.key == "string" && e.decode(t.stored) !== void 0);
17
+ default: return !1;
18
+ }
19
+ };
20
+ }
21
+ function o(o) {
22
+ let { codec: s = n, logger: c, name: l, onMetrics: u, schema: d, signals: f, validators: p } = o, m = new Map(Object.keys(d).map((e) => [e, /* @__PURE__ */ new Map()])), h = (e) => m.get(e), g = a(s), _ = l !== void 0 && typeof BroadcastChannel < "u" ? new BroadcastChannel(`vault-memory:${l}`) : void 0, v = i(d, {
23
+ async clear(e) {
24
+ h(e).clear(), _?.postMessage({
25
+ table: e,
26
+ type: "clear"
27
+ });
28
+ },
29
+ async count(e) {
30
+ let t = h(e), n = 0, i = [];
31
+ for (let [e, a] of t) {
32
+ let t = s.decode(a);
33
+ !t || r(t.expiresAt) ? i.push(e) : n += 1;
34
+ }
35
+ for (let e of i) t.delete(e);
36
+ return n;
37
+ },
38
+ async delete(e, t) {
39
+ let n = h(e), i = n.get(String(t));
40
+ if (!i) return !1;
41
+ let a = s.decode(i), o = a !== void 0 && !r(a.expiresAt);
42
+ return n.delete(String(t)), o && _?.postMessage({
43
+ key: String(t),
44
+ table: e,
45
+ type: "delete"
46
+ }), o;
47
+ },
48
+ async deleteMany(e, t) {
49
+ let n = h(e), i = [];
50
+ for (let e of t) {
51
+ let t = String(e), a = n.get(t);
52
+ if (a) {
53
+ let e = s.decode(a);
54
+ e !== void 0 && !r(e.expiresAt) && i.push(t), n.delete(t);
55
+ }
56
+ }
57
+ return i.length > 0 && _?.postMessage({
58
+ keys: i,
59
+ table: e,
60
+ type: "deleteMany"
61
+ }), i.length;
62
+ },
63
+ dispose: _ ? async () => _.close() : void 0,
64
+ async get(e, t) {
65
+ let n = h(e), i = n.get(String(t));
66
+ if (!i) return;
67
+ let a = s.decode(i);
68
+ if (!a || r(a.expiresAt)) {
69
+ n.delete(String(t));
70
+ return;
71
+ }
72
+ return a.value;
73
+ },
74
+ async getAll(e) {
75
+ let t = h(e), n = [], i = [];
76
+ for (let [e, a] of t) {
77
+ let t = s.decode(a);
78
+ !t || r(t.expiresAt) ? i.push(e) : n.push(t.value);
79
+ }
80
+ for (let e of i) t.delete(e);
81
+ return n;
82
+ },
83
+ async getRawCount(e) {
84
+ return h(e).size;
85
+ },
86
+ async has(e, t) {
87
+ let n = h(e), i = n.get(String(t));
88
+ if (!i) return !1;
89
+ let a = s.decode(i), o = a !== void 0 && !r(a.expiresAt);
90
+ return o || n.delete(String(t)), o;
91
+ },
92
+ async pruneExpiredInTable(e) {
93
+ let t = h(e), n = 0;
94
+ for (let [e, i] of t) {
95
+ let a = s.decode(i);
96
+ (!a || r(a.expiresAt)) && (t.delete(e), n += 1);
97
+ }
98
+ return n;
99
+ },
100
+ async put(e, n, r) {
101
+ let i = String(t(d, e, n)), a = r === void 0 ? void 0 : Date.now() + r, o = s.encode(n, a);
102
+ h(e).set(i, o), _?.postMessage({
103
+ key: i,
104
+ stored: o,
105
+ table: e,
106
+ type: "put"
107
+ });
108
+ },
109
+ async putAll(e, n, r) {
110
+ let i = h(e), a = [], o = r === void 0 ? void 0 : Date.now() + r;
111
+ for (let r of n) {
112
+ let n = String(t(d, e, r)), c = s.encode(r, o);
113
+ i.set(n, c), a.push({
114
+ key: n,
115
+ stored: c
116
+ });
117
+ }
118
+ a.length > 0 && _?.postMessage({
119
+ entries: a,
120
+ table: e,
121
+ type: "putAll"
122
+ });
123
+ }
124
+ }, {
125
+ logger: c,
126
+ onCrossTabMessage: _ ? (e) => (_.onmessage = (t) => {
127
+ let n;
128
+ try {
129
+ if (!g(t.data)) return;
130
+ n = t.data;
131
+ } catch {
132
+ return;
133
+ }
134
+ let r = m.get(n.table);
135
+ if (!r) return;
136
+ let i = p?.[n.table], a = d[n.table]?.key, o = (e, t) => {
137
+ try {
138
+ let n = s.decode(t);
139
+ if (!n) return !1;
140
+ let o = i ? i.parse(n.value) : n.value;
141
+ if (a && String(o[a]) !== e) return !1;
142
+ let c = n.expiresAt === void 0 ? { value: o } : {
143
+ expiresAt: n.expiresAt,
144
+ value: o
145
+ };
146
+ return r.set(e, c), !0;
147
+ } catch {
148
+ return !1;
149
+ }
150
+ };
151
+ switch (n.type) {
152
+ case "clear":
153
+ r.clear(), e(n.table);
154
+ return;
155
+ case "delete":
156
+ r.delete(n.key), e(n.table);
157
+ return;
158
+ case "deleteMany":
159
+ for (let e of n.keys) r.delete(e);
160
+ e(n.table);
161
+ return;
162
+ case "put":
163
+ o(n.key, n.stored) && e(n.table);
164
+ return;
165
+ case "putAll":
166
+ {
167
+ let t = !1;
168
+ for (let { key: e, stored: r } of n.entries) o(e, r) && (t = !0);
169
+ t && e(n.table);
170
+ }
171
+ return;
172
+ }
173
+ }, () => {
174
+ _.onmessage = null;
175
+ }) : void 0,
176
+ onMetrics: u,
177
+ schema: d,
178
+ signals: f,
179
+ validators: p
180
+ });
181
+ return {
182
+ ...v,
183
+ iterate(t) {
184
+ let n = h(String(t));
185
+ return { async *[Symbol.asyncIterator]() {
186
+ if (v.disposed) throw new e();
187
+ let t = [];
188
+ for (let [e, i] of n) {
189
+ let n = s.decode(i);
190
+ !n || r(n.expiresAt) ? t.push(e) : yield n.value;
191
+ }
192
+ for (let e of t) n.delete(e);
193
+ } };
194
+ }
195
+ };
196
+ }
197
+ //#endregion
198
+ export { o as createMemory };
199
+
200
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +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":"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"}
@@ -0,0 +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;
2
+ //# sourceMappingURL=webstorage.cjs.map
@@ -0,0 +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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"}
@@ -0,0 +1,14 @@
1
+ import type { Adapter, AnySchema, BaseAdapterOptions } from '../types';
2
+ import { VaultQuotaError } from '../errors';
3
+ type WebStorageOptions<S extends AnySchema> = BaseAdapterOptions<S> & {
4
+ name: string;
5
+ /**
6
+ * Called when localStorage/sessionStorage quota is exceeded on a write.
7
+ * Return `'ignore'` to silently drop the write, or `'throw'` (default) to rethrow the error.
8
+ */
9
+ onQuotaExceeded?: (table: keyof S, error: VaultQuotaError) => 'ignore' | 'throw';
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>;
13
+ export {};
14
+ //# sourceMappingURL=webstorage.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,182 @@
1
+ import { VaultError as e, VaultQuotaError as t } from "../errors.js";
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";
4
+ import { buildAdapterOps as l } from "../adapter-core.js";
5
+ //#region src/adapters/webstorage.ts
6
+ var u = /* @__PURE__ */ new Set(["QuotaExceededError", "NS_ERROR_DOM_QUOTA_REACHED"]);
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;
9
+ try {
10
+ S = p();
11
+ } catch (t) {
12
+ throw new e(`${b} is not available in this environment (private browsing or sandboxed iframe?)`, { cause: t });
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);
16
+ if (!n) throw new e(`table "${t}" not in schema`);
17
+ return n;
18
+ }, E = (e, n, r) => {
19
+ try {
20
+ C().setItem(n, JSON.stringify(r));
21
+ } catch (n) {
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;
25
+ throw r;
26
+ }
27
+ throw n;
28
+ }
29
+ }, D = /* @__PURE__ */ new Set();
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);
35
+ }
36
+ })();
37
+ let O = (e) => {
38
+ let t = C().getItem(e);
39
+ if (t) try {
40
+ let e = f.decode(JSON.parse(t));
41
+ return !e || c(e.expiresAt) ? void 0 : e.value;
42
+ } catch {
43
+ return;
44
+ }
45
+ }, k = (e) => {
46
+ C().removeItem(e), D.delete(e);
47
+ };
48
+ return l(v, {
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);
53
+ },
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);
58
+ return r;
59
+ },
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);
63
+ },
64
+ async deleteMany(e, t) {
65
+ let n = 0;
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);
69
+ }
70
+ return n;
71
+ },
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;
75
+ },
76
+ async getAll(e) {
77
+ let t = [], n = [], r = T(e);
78
+ for (let e of D) {
79
+ if (!e.startsWith(r)) continue;
80
+ let i = O(e);
81
+ if (i === void 0) {
82
+ n.push(e);
83
+ continue;
84
+ }
85
+ t.push(i);
86
+ }
87
+ for (let e of n) k(e);
88
+ return t;
89
+ },
90
+ async getAllKeys(e) {
91
+ let t = T(e), n = [], r = [];
92
+ for (let i of D) {
93
+ if (!i.startsWith(t)) continue;
94
+ let a = O(i);
95
+ if (a === void 0) {
96
+ r.push(i);
97
+ continue;
98
+ }
99
+ n.push(a[v[e].key]);
100
+ }
101
+ for (let e of r) k(e);
102
+ return n;
103
+ },
104
+ async getRawCount(e) {
105
+ let t = T(e), n = 0;
106
+ for (let e of D) e.startsWith(t) && (n += 1);
107
+ return n;
108
+ },
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;
112
+ },
113
+ async pruneExpiredInTable(e) {
114
+ let t = T(e), n = [];
115
+ for (let e of D) {
116
+ if (!e.startsWith(t)) continue;
117
+ let r = C().getItem(e);
118
+ if (r === null) {
119
+ n.push(e);
120
+ continue;
121
+ }
122
+ try {
123
+ let t = f.decode(JSON.parse(r));
124
+ (!t || c(t.expiresAt)) && n.push(e);
125
+ } catch {
126
+ n.push(e);
127
+ }
128
+ }
129
+ for (let e of n) k(e);
130
+ return n.length;
131
+ },
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);
135
+ },
136
+ async putAll(e, t, n) {
137
+ let r = n === void 0 ? void 0 : Date.now() + n;
138
+ 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);
141
+ }
142
+ }
143
+ }, {
144
+ logger: m,
145
+ onCrossTabMessage(e) {
146
+ if (typeof window > "u" || typeof window.addEventListener != "function") return;
147
+ let t = (t) => {
148
+ if (t.storageArea && t.storageArea !== S) return;
149
+ if (t.key === null) {
150
+ D.clear();
151
+ for (let t of Object.keys(v)) e(t);
152
+ return;
153
+ }
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));
156
+ };
157
+ return window.addEventListener("storage", t), () => window.removeEventListener("storage", t);
158
+ },
159
+ onMetrics: g,
160
+ schema: v,
161
+ signals: y,
162
+ validators: x
163
+ });
164
+ }
165
+ function f(e) {
166
+ return d({
167
+ ...e,
168
+ getStorage: () => typeof window < "u" ? window.localStorage : localStorage,
169
+ storageLabel: "localStorage"
170
+ });
171
+ }
172
+ function p(e) {
173
+ return d({
174
+ ...e,
175
+ getStorage: () => typeof window < "u" ? window.sessionStorage : sessionStorage,
176
+ storageLabel: "sessionStorage"
177
+ });
178
+ }
179
+ //#endregion
180
+ export { f as createLocalStorage, p as createSessionStorage };
181
+
182
+ //# sourceMappingURL=webstorage.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,2 @@
1
+ var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{constructor(e=`adapter is disposed`,t){super(e,t)}},n=class extends e{},r=class extends e{},i=class extends e{};exports.VaultDisposedError=t,exports.VaultError=e,exports.VaultMigrationError=i,exports.VaultQuotaError=r,exports.VaultScopeError=n;
2
+ //# sourceMappingURL=errors.cjs.map
@@ -0,0 +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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Base class for all vault errors. Catch with `instanceof VaultError` to
3
+ * handle any vault-originated error regardless of its specific subtype.
4
+ */
5
+ export declare class VaultError extends Error {
6
+ constructor(message: string, opts?: ErrorOptions);
7
+ static is(err: unknown): err is VaultError;
8
+ }
9
+ /** Thrown when an operation is attempted on a disposed adapter or observer hub. */
10
+ export declare class VaultDisposedError extends VaultError {
11
+ constructor(message?: string, opts?: ErrorOptions);
12
+ }
13
+ /** Thrown when a `batch()` callback accesses a table not declared in the scope. */
14
+ export declare class VaultScopeError extends VaultError {
15
+ }
16
+ /** Thrown when a WebStorage write exceeds the storage quota. */
17
+ export declare class VaultQuotaError extends VaultError {
18
+ }
19
+ /** Thrown when an IndexedDB `onupgradeneeded` migration callback throws. */
20
+ export declare class VaultMigrationError extends VaultError {
21
+ }
22
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAOhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU;CAG3C;AAED,mFAAmF;AACnF,qBAAa,kBAAmB,SAAQ,UAAU;gBACpC,OAAO,SAAwB,EAAE,IAAI,CAAC,EAAE,YAAY;CAGjE;AAED,mFAAmF;AACnF,qBAAa,eAAgB,SAAQ,UAAU;CAAG;AAElD,gEAAgE;AAChE,qBAAa,eAAgB,SAAQ,UAAU;CAAG;AAElD,4EAA4E;AAC5E,qBAAa,mBAAoB,SAAQ,UAAU;CAAG"}
package/dist/errors.js ADDED
@@ -0,0 +1,17 @@
1
+ //#region src/errors.ts
2
+ var e = class e extends Error {
3
+ constructor(e, t) {
4
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ static is(t) {
7
+ return t instanceof e;
8
+ }
9
+ }, t = class extends e {
10
+ constructor(e = "adapter is disposed", t) {
11
+ super(e, t);
12
+ }
13
+ }, n = class extends e {}, r = class extends e {}, i = class extends e {};
14
+ //#endregion
15
+ export { t as VaultDisposedError, e as VaultError, i as VaultMigrationError, r as VaultQuotaError, n as VaultScopeError };
16
+
17
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +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"}
package/dist/index.cjs ADDED
@@ -0,0 +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;
@@ -0,0 +1,17 @@
1
+ export { createIndexedDB } from './adapters/indexeddb';
2
+ export type { IndexedDbAdapter } from './adapters/indexeddb';
3
+ export { createMemory } from './adapters/memory';
4
+ export type { MemoryAdapter } from './adapters/memory';
5
+ export { createLocalStorage, createSessionStorage } from './adapters/webstorage';
6
+ export { VaultDisposedError, VaultError, VaultMigrationError, VaultQuotaError, VaultScopeError } from './errors';
7
+ export { defineMigration } from './migration';
8
+ export type { MigrationStep } from './migration';
9
+ export type { QueryBuilder } from './query';
10
+ 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';
15
+ 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';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ import { VaultDisposedError as e, VaultError as t, VaultMigrationError as n, VaultQuotaError as r, VaultScopeError as i } from "./errors.js";
2
+ import { defaultCodec as a, isExpired as o, ttl as s } from "./ttl.js";
3
+ import { createIndexedDB as c } from "./adapters/indexeddb.js";
4
+ import { createMemory as l } from "./adapters/memory.js";
5
+ import { createLocalStorage as u, createSessionStorage as d } from "./adapters/webstorage.js";
6
+ import { defineMigration as f } from "./migration.js";
7
+ import { scheduleExpiredPrune as p } from "./prune.js";
8
+ import { toReadableStream as m } from "./streaming.js";
9
+ import { createVersionedCodec as h } from "./versioned-codec.js";
10
+ import { table as g } from "./types.js";
11
+ export { e as VaultDisposedError, t as VaultError, n as VaultMigrationError, r as VaultQuotaError, i as VaultScopeError, c as createIndexedDB, u as createLocalStorage, l as createMemory, d as createSessionStorage, h as createVersionedCodec, a as defaultCodec, f as defineMigration, o as isExpired, p as scheduleExpiredPrune, g as table, m as toReadableStream, s as ttl };