@vielzeug/vault 3.0.1 → 3.0.3

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 (78) hide show
  1. package/dist/adapter-core.cjs +1 -1
  2. package/dist/adapter-core.cjs.map +1 -1
  3. package/dist/adapter-core.d.ts +5 -34
  4. package/dist/adapter-core.d.ts.map +1 -1
  5. package/dist/adapter-core.js +1 -282
  6. package/dist/adapter-core.js.map +1 -1
  7. package/dist/adapters/indexeddb.cjs +1 -1
  8. package/dist/adapters/indexeddb.cjs.map +1 -1
  9. package/dist/adapters/indexeddb.d.ts +5 -35
  10. package/dist/adapters/indexeddb.d.ts.map +1 -1
  11. package/dist/adapters/indexeddb.js +1 -365
  12. package/dist/adapters/indexeddb.js.map +1 -1
  13. package/dist/adapters/memory.cjs +1 -1
  14. package/dist/adapters/memory.cjs.map +1 -1
  15. package/dist/adapters/memory.d.ts +8 -3
  16. package/dist/adapters/memory.d.ts.map +1 -1
  17. package/dist/adapters/memory.js +1 -60
  18. package/dist/adapters/memory.js.map +1 -1
  19. package/dist/adapters/sqlite.cjs +14 -32
  20. package/dist/adapters/sqlite.cjs.map +1 -1
  21. package/dist/adapters/sqlite.d.ts.map +1 -1
  22. package/dist/adapters/sqlite.js +14 -409
  23. package/dist/adapters/sqlite.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 +0 -6
  27. package/dist/adapters/webstorage.d.ts.map +1 -1
  28. package/dist/adapters/webstorage.js +1 -160
  29. package/dist/adapters/webstorage.js.map +1 -1
  30. package/dist/codec.cjs +1 -1
  31. package/dist/codec.cjs.map +1 -1
  32. package/dist/codec.js +1 -5
  33. package/dist/codec.js.map +1 -1
  34. package/dist/errors.cjs +1 -1
  35. package/dist/errors.cjs.map +1 -1
  36. package/dist/errors.d.ts +0 -5
  37. package/dist/errors.d.ts.map +1 -1
  38. package/dist/errors.js +1 -21
  39. package/dist/errors.js.map +1 -1
  40. package/dist/index.cjs +1 -1
  41. package/dist/index.d.ts +1 -3
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -5
  44. package/dist/indexeddb.cjs +1 -1
  45. package/dist/indexeddb.d.ts +2 -2
  46. package/dist/indexeddb.d.ts.map +1 -1
  47. package/dist/indexeddb.js +1 -2
  48. package/dist/internal.cjs +1 -1
  49. package/dist/internal.cjs.map +1 -1
  50. package/dist/internal.js +1 -72
  51. package/dist/internal.js.map +1 -1
  52. package/dist/local-storage.js +1 -2
  53. package/dist/memory.js +1 -2
  54. package/dist/session-storage.js +1 -2
  55. package/dist/sqlite.js +1 -2
  56. package/dist/ttl.cjs +1 -1
  57. package/dist/ttl.cjs.map +1 -1
  58. package/dist/ttl.js +1 -24
  59. package/dist/ttl.js.map +1 -1
  60. package/dist/types.cjs +1 -1
  61. package/dist/types.cjs.map +1 -1
  62. package/dist/types.d.ts +0 -2
  63. package/dist/types.d.ts.map +1 -1
  64. package/dist/types.js +1 -27
  65. package/dist/types.js.map +1 -1
  66. package/dist/vault.cjs +1 -1
  67. package/dist/vault.cjs.map +1 -1
  68. package/dist/vault.iife.js +1 -1
  69. package/dist/vault.iife.js.map +1 -1
  70. package/dist/vault.js +1 -1
  71. package/dist/vault.js.map +1 -1
  72. package/package.json +5 -5
  73. package/dist/query.cjs +0 -2
  74. package/dist/query.cjs.map +0 -1
  75. package/dist/query.d.ts +0 -23
  76. package/dist/query.d.ts.map +0 -1
  77. package/dist/query.js +0 -54
  78. package/dist/query.js.map +0 -1
@@ -1,366 +1,2 @@
1
- import { decodeRecord as e, encodeRecord as t } from "../codec.js";
2
- import { VaultDisposedError as n, VaultError as r, VaultMigrationError as i } from "../errors.js";
3
- import { encodeVaultKey as a, getRecordKey as o } from "../internal.js";
4
- import { isExpired as s, parseStored as c } from "../ttl.js";
5
- import { assertBatchTables as l, buildDocumentStore as u, buildTxContext as d, withBatch as f } from "../adapter-core.js";
6
- //#region src/adapters/indexeddb.ts
7
- function p(e) {
8
- return ({ db: t, tx: n }) => {
9
- for (let r of e) switch (r.type) {
10
- case "addIndex": {
11
- let e = n.objectStore(r.table);
12
- e.indexNames.contains(r.field) || e.createIndex(r.field, `value.${r.field}`);
13
- break;
14
- }
15
- case "addTable":
16
- t.objectStoreNames.contains(r.name) || t.createObjectStore(r.name);
17
- break;
18
- case "removeIndex": {
19
- let e = n.objectStore(r.table);
20
- e.indexNames.contains(r.field) && e.deleteIndex(r.field);
21
- break;
22
- }
23
- case "removeTable": t.objectStoreNames.contains(r.name) && t.deleteObjectStore(r.name);
24
- }
25
- };
26
- }
27
- function m(e) {
28
- return new Promise((t, n) => {
29
- e.onsuccess = () => t(e.result), e.onerror = () => n(e.error ?? new r("IndexedDB request failed"));
30
- });
31
- }
32
- function h(e, t, n) {
33
- let i = n instanceof Error && n.message ? `: ${n.message}` : "";
34
- return new r(`${t} on "${e}"${i}`, { cause: n });
35
- }
36
- function g(e, t, n) {
37
- return new Promise((r, i) => {
38
- let a, o;
39
- Promise.resolve().then(n).then((e) => {
40
- a = e;
41
- }).catch((t) => {
42
- o = t;
43
- try {
44
- e.abort();
45
- } catch {}
46
- });
47
- let s = (e, n = "transaction failed") => {
48
- o instanceof Error ? i(o) : i(h(t, n, o ?? e));
49
- };
50
- e.oncomplete = () => {
51
- if (o) {
52
- s(void 0);
53
- return;
54
- }
55
- r(a);
56
- }, e.onerror = () => i(h(t, "transaction error", e.error)), e.onabort = () => s(e.error, "transaction aborted");
57
- });
58
- }
59
- async function _(e, t, n) {
60
- let r = await m(e.getAll(n)), i = [];
61
- for (let e of r) {
62
- let n = t(e);
63
- n !== void 0 && i.push(n);
64
- }
65
- return i;
66
- }
67
- async function v(e, t, n) {
68
- let r = await m(e.get(t));
69
- if (r != null) return n(r);
70
- }
71
- async function y(e, t, n) {
72
- let r = await v(e, t, n) !== void 0;
73
- return await m(e.delete(t)), r;
74
- }
75
- async function b(e, t, n) {
76
- return (await Promise.all(t.map((t) => y(e, t, n)))).filter(Boolean).length;
77
- }
78
- function x(e) {
79
- return new Promise((t, n) => {
80
- let i = 0, a = e.openCursor();
81
- a.onerror = () => n(a.error ?? new r("IndexedDB cursor failed during prune")), a.onsuccess = () => {
82
- let e = a.result;
83
- if (!e) {
84
- t(i);
85
- return;
86
- }
87
- let n = c(e.value);
88
- (!n || s(n.expiresAt)) && (e.delete(), i += 1), e.continue();
89
- };
90
- });
91
- }
92
- function S(e, t) {
93
- return { [Symbol.asyncIterator]() {
94
- let n = e.openCursor(), i = { type: "idle" }, a = (e) => {
95
- if (i.type === "waiting") {
96
- let { resolve: t } = i;
97
- i = e.done ? { type: "done" } : { type: "idle" }, t(e);
98
- } else i.type === "buffered" ? i.results.push(e) : i = {
99
- results: [e],
100
- type: "buffered"
101
- };
102
- };
103
- return n.onerror = () => {
104
- let e = n.error ?? new r("IndexedDB cursor iteration failed");
105
- if (i.type === "waiting") {
106
- let { reject: t } = i;
107
- i = { type: "done" }, t(e);
108
- } else i = {
109
- error: e,
110
- type: "error"
111
- };
112
- }, n.onsuccess = () => {
113
- if (i.type === "done") return;
114
- let e = n.result;
115
- if (!e) {
116
- a({
117
- done: !0,
118
- value: void 0
119
- });
120
- return;
121
- }
122
- let r;
123
- try {
124
- r = t(e.value);
125
- } catch (e) {
126
- if (i.type === "waiting") {
127
- let { reject: t } = i;
128
- i = { type: "done" }, t(e);
129
- } else i = {
130
- error: e,
131
- type: "error"
132
- };
133
- return;
134
- }
135
- e.continue(), r !== void 0 && a({
136
- done: !1,
137
- value: r
138
- });
139
- }, {
140
- next() {
141
- if (i.type === "error") {
142
- let { error: e } = i;
143
- return i = { type: "done" }, Promise.reject(e);
144
- }
145
- if (i.type === "buffered") {
146
- let [e, ...t] = i.results;
147
- return i = e.done ? { type: "done" } : t.length > 0 ? {
148
- results: t,
149
- type: "buffered"
150
- } : { type: "idle" }, Promise.resolve(e);
151
- }
152
- return i.type === "done" ? Promise.resolve({
153
- done: !0,
154
- value: void 0
155
- }) : new Promise((e, t) => {
156
- i = {
157
- reject: t,
158
- resolve: e,
159
- type: "waiting"
160
- };
161
- });
162
- },
163
- return(e) {
164
- return i.type === "waiting" && i.resolve({
165
- done: !0,
166
- value: void 0
167
- }), i = { type: "done" }, Promise.resolve({
168
- done: !0,
169
- value: e
170
- });
171
- },
172
- throw(e) {
173
- return i.type === "waiting" && i.reject(e), i = { type: "done" }, Promise.reject(e);
174
- }
175
- };
176
- } };
177
- }
178
- function C(p) {
179
- let { migrate: h, name: C, schema: w, codecs: T, version: E = 1 } = p;
180
- if (!T) throw new r("createIndexedDB: codecs are required for durable persistence");
181
- if (!Number.isInteger(E) || E < 1) throw new r(`createIndexedDB: version must be a positive integer, got ${String(E)}`);
182
- let D = typeof BroadcastChannel < "u" ? new BroadcastChannel(`vault:${C}`) : void 0, O = null, k = null, A = !1, j = (e, t) => {
183
- for (let [n, r] of Object.entries(w)) {
184
- let i;
185
- i = e.objectStoreNames.contains(n) ? t.objectStore(n) : e.createObjectStore(n);
186
- let a = r.indexes ?? [];
187
- for (let e of a) i.indexNames.contains(e) || i.createIndex(e, `value.${e}`);
188
- }
189
- }, M = async () => (k ||= new Promise((e, t) => {
190
- let n = indexedDB.open(C, E);
191
- n.onupgradeneeded = (e) => {
192
- let r = n.result, a = n.transaction;
193
- if (h) try {
194
- h({
195
- db: r,
196
- newVersion: e.newVersion ?? null,
197
- oldVersion: e.oldVersion,
198
- tx: a
199
- });
200
- } catch (e) {
201
- try {
202
- a.abort();
203
- } catch {}
204
- t(new i(`migration failed for "${C}"`, { cause: e }));
205
- return;
206
- }
207
- j(r, a);
208
- }, n.onsuccess = () => {
209
- if (A) {
210
- n.result.close(), e();
211
- return;
212
- }
213
- let t = n.result;
214
- t.onversionchange = () => {
215
- t.close(), O = null, k = null;
216
- }, O = t, e();
217
- }, n.onerror = () => {
218
- k = null, t(new r(`failed to open "${C}"`, { cause: n.error }));
219
- };
220
- }), k), N = async (e, t, r) => {
221
- if (A || (O || await M(), !O)) throw new n(`"${C}" is disposed`);
222
- let i = String(e), a = O.transaction(i, t);
223
- return g(a, `${C}/${i}`, () => r(a.objectStore(i)));
224
- }, P = async () => {
225
- if (A || (O || await M(), !O)) throw new n(`"${C}" is disposed`);
226
- return O;
227
- }, F = (e) => {
228
- D?.postMessage({ table: String(e) });
229
- }, I = (t, n) => {
230
- let i = c(n);
231
- if (i && !s(i.expiresAt)) try {
232
- return e(T[t], i.value);
233
- } catch (e) {
234
- throw new r(`validation failed for table "${String(t)}"`, { cause: e });
235
- }
236
- }, L = (e, n, i) => {
237
- let a = n, o = t(T[e], a);
238
- for (let t of w[e].indexes ?? []) {
239
- let n = a[t];
240
- if (n !== void 0 && (typeof o != "object" || !o || !Object.hasOwn(o, t) || !Object.is(o[t], n))) throw new r(`codec output for table "${String(e)}" must preserve indexed field "${t}"`);
241
- }
242
- return i === void 0 ? { value: o } : {
243
- expiresAt: Date.now() + i,
244
- value: o
245
- };
246
- }, R = {
247
- clear: (e) => N(e, "readwrite", (e) => m(e.clear()).then(() => void 0)),
248
- delete: (e, t) => N(e, "readwrite", (n) => y(n, a(t), (t) => I(e, t))),
249
- deleteMany: (e, t) => N(e, "readwrite", (n) => b(n, t.map(a), (t) => I(e, t))),
250
- async dispose() {
251
- A = !0, D?.close(), k && await k.catch(() => {}), O?.close(), O = null, k = null;
252
- },
253
- get: (e, t) => N(e, "readonly", (n) => v(n, a(t), (t) => I(e, t))),
254
- getAll: (e) => N(e, "readonly", (t) => _(t, (t) => I(e, t))),
255
- getMany: (e, t) => N(e, "readonly", (n) => {
256
- let r = (t) => I(e, t);
257
- return Promise.all(t.map((e) => v(n, a(e), r)));
258
- }),
259
- iterate: (e) => {
260
- let t = async () => {
261
- if (A || (O || await M(), !O || A)) throw new n(`"${C}" is disposed`);
262
- return S(O.transaction(String(e), "readonly").objectStore(String(e)), (t) => I(e, t));
263
- }, r, i = () => t().then((e) => (r = e[Symbol.asyncIterator](), r));
264
- return { [Symbol.asyncIterator]() {
265
- return {
266
- next() {
267
- return r ? r.next() : i().then((e) => e.next());
268
- },
269
- return(e) {
270
- return r ? r.return?.(e) ?? Promise.resolve({
271
- done: !0,
272
- value: e
273
- }) : Promise.resolve({
274
- done: !0,
275
- value: e
276
- });
277
- },
278
- throw(e) {
279
- return r ? r.throw?.(e) ?? Promise.reject(e) : Promise.reject(e);
280
- }
281
- };
282
- } };
283
- },
284
- async pruneAllExpired() {
285
- let e = await P(), t = Object.keys(w), n = e.transaction(t, "readwrite"), r = await g(n, `${C}/pruneAll`, () => Promise.all(t.map(async (e) => [e, await x(n.objectStore(e))])));
286
- return Object.fromEntries(r);
287
- },
288
- pruneExpiredInTable: (e) => N(e, "readwrite", (e) => x(e)),
289
- put(e, t, n) {
290
- let r = a(o(w, e, t)), i = L(e, t, n);
291
- return N(e, "readwrite", (e) => m(e.put(i, r)).then(() => void 0));
292
- },
293
- putAll(e, t, n) {
294
- let r = t.map((t) => {
295
- let r = a(o(w, e, t));
296
- return {
297
- encoded: L(e, t, n),
298
- key: r
299
- };
300
- });
301
- return N(e, "readwrite", (e) => Promise.all(r.map(({ encoded: t, key: n }) => m(e.put(t, n)))).then(() => void 0));
302
- }
303
- }, z = async (e, t, n, r) => {
304
- l(e);
305
- let i = (await P()).transaction([...e], "readwrite"), s = /* @__PURE__ */ new Set(), c = (e) => i.objectStore(e), u = {
306
- clear: async (e) => {
307
- await m(c(e).clear());
308
- },
309
- delete: (e, t) => y(c(e), a(t), (t) => I(e, t)),
310
- deleteMany: (e, t) => b(c(e), t.map(a), (t) => I(e, t)),
311
- get: (e, t) => v(c(e), a(t), (t) => I(e, t)),
312
- getAll: (e) => _(c(e), (t) => I(e, t)),
313
- getMany: (e, t) => {
314
- let n = (t) => I(e, t), r = c(e);
315
- return Promise.all(t.map((e) => v(r, a(e), n)));
316
- },
317
- iterate(e) {
318
- return S(c(e), (t) => I(e, t));
319
- },
320
- pruneExpiredInTable: (e) => x(c(e)),
321
- put(e, t, n) {
322
- let r = a(o(w, e, t)), i = L(e, t, n);
323
- return m(c(e).put(i, r)).then(() => void 0);
324
- },
325
- putAll(e, t, n) {
326
- return Promise.all(t.map((t) => {
327
- let r = a(o(w, e, t)), i = L(e, t, n);
328
- return m(c(e).put(i, r));
329
- })).then(() => void 0);
330
- }
331
- }, f = new Set(e), p = !0, h = d(w, u, (e) => s.add(e), r, f, () => p);
332
- try {
333
- let e = await g(i, C, () => t(h));
334
- for (let e of s) n(e);
335
- return e;
336
- } finally {
337
- p = !1;
338
- }
339
- }, B, V = u(w, R, {
340
- codecs: T,
341
- onCrossTabMessage(e) {
342
- if (D) return D.onmessage = (t) => {
343
- let n = t.data?.table;
344
- n && Object.hasOwn(w, n) && e(n);
345
- }, () => {
346
- D.onmessage = null;
347
- };
348
- },
349
- onMutation: F,
350
- onTransactions: (e) => {
351
- B = (t, n) => z(t, n, e.notifyMutation, e.validate);
352
- },
353
- schema: w
354
- });
355
- if (!B) throw new r("IndexedDB transaction capability was not initialized");
356
- return Object.assign(f(V, B, w), { getAllByIndex(e, t, n) {
357
- return N(e, "readonly", (i) => {
358
- if (!i.indexNames.contains(t)) throw new r(`Table "${e}" has no index "${t}"`);
359
- return _(i.index(t), (t) => I(e, t), n);
360
- });
361
- } });
362
- }
363
- //#endregion
364
- export { C as createIndexedDB, p as defineMigration };
365
-
1
+ import{VaultDisposedError as e,VaultError as t,VaultMigrationError as n}from"../errors.js";import{isExpired as r,parseStored as i}from"../ttl.js";import{decodeRecord as a,encodeRecord as o}from"../codec.js";import{encodeVaultKey as s,getRecordKey as c}from"../internal.js";import{assertBatchTables as l,batchScopeGuard as u,buildDocumentStore as d,buildOperations as f}from"../adapter-core.js";function idbReq(e){return new Promise((n,r)=>{e.onsuccess=()=>n(e.result),e.onerror=()=>r(e.error??new t(`IndexedDB request failed`))})}function wrapTxError(e,n,r){let i=r instanceof Error&&r.message?`: ${r.message}`:``;return new t(`${n} on "${e}"${i}`,{cause:r})}function runIdbTx(e,t,n){return new Promise((r,i)=>{let a,o;Promise.resolve().then(n).then(e=>{a=e}).catch(t=>{o=t;try{e.abort()}catch{}});let rejectWithCallbackError=(e,n=`transaction failed`)=>{o instanceof Error?i(o):i(wrapTxError(t,n,o??e))};e.oncomplete=()=>{if(o){rejectWithCallbackError(void 0);return}r(a)},e.onerror=()=>i(wrapTxError(t,`transaction error`,e.error)),e.onabort=()=>rejectWithCallbackError(e.error,`transaction aborted`)})}async function getAllFromStore(e,t,n){let r=await idbReq(e.getAll(n)),i=[];for(let e of r){let n=t(e);n!==void 0&&i.push(n)}return i}async function storeGet(e,t,n){let r=await idbReq(e.get(t));if(r!=null)return n(r)}async function storeDelete(e,t,n){let r=await storeGet(e,t,n)!==void 0;return await idbReq(e.delete(t)),r}async function storeDeleteMany(e,t,n){return(await Promise.all(t.map(t=>storeDelete(e,t,n)))).filter(Boolean).length}function pruneExpiredInStore(e){return new Promise((n,a)=>{let o=0,s=e.openCursor();s.onerror=()=>a(s.error??new t(`IndexedDB cursor failed during prune`)),s.onsuccess=()=>{let e=s.result;if(!e){n(o);return}let t=i(e.value);(!t||r(t.expiresAt))&&(e.delete(),o+=1),e.continue()}})}function iterateStoreWithCursor(e,n){return{[Symbol.asyncIterator](){let r=e.openCursor(),i={type:`idle`},deliver=e=>{if(i.type===`waiting`){let{resolve:t}=i;i=e.done?{type:`done`}:{type:`idle`},t(e)}else i.type===`buffered`?i.results.push(e):i={results:[e],type:`buffered`}};return r.onerror=()=>{let e=r.error??new t(`IndexedDB cursor iteration failed`);if(i.type===`waiting`){let{reject:t}=i;i={type:`done`},t(e)}else i={error:e,type:`error`}},r.onsuccess=()=>{if(i.type===`done`)return;let e=r.result;if(!e){deliver({done:!0,value:void 0});return}let t;try{t=n(e.value)}catch(e){if(i.type===`waiting`){let{reject:t}=i;i={type:`done`},t(e)}else i={error:e,type:`error`};return}e.continue(),t!==void 0&&deliver({done:!1,value:t})},{next(){if(i.type===`error`){let{error:e}=i;return i={type:`done`},Promise.reject(e)}if(i.type===`buffered`){let[e,...t]=i.results;return i=e.done?{type:`done`}:t.length>0?{results:t,type:`buffered`}:{type:`idle`},Promise.resolve(e)}return i.type===`done`?Promise.resolve({done:!0,value:void 0}):new Promise((e,t)=>{i={reject:t,resolve:e,type:`waiting`}})},return(e){return i.type===`waiting`&&i.resolve({done:!0,value:void 0}),i={type:`done`},Promise.resolve({done:!0,value:e})},throw(e){return i.type===`waiting`&&i.reject(e),i={type:`done`},Promise.reject(e)}}}}}function createIndexedDB(p){let{migrate:m,name:h,schema:g,codecs:_,version:v=1}=p;if(!_)throw new t(`createIndexedDB: codecs are required for durable persistence`);if(!Number.isInteger(v)||v<1)throw new t(`createIndexedDB: version must be a positive integer, got ${String(v)}`);let y=typeof BroadcastChannel<`u`?new BroadcastChannel(`vault:${h}`):void 0,b=null,x=null,S=!1,createObjectStores=(e,t)=>{for(let[n,r]of Object.entries(g)){let i;i=e.objectStoreNames.contains(n)?t.objectStore(n):e.createObjectStore(n);let a=r.indexes??[];for(let e of a)i.indexNames.contains(e)||i.createIndex(e,`value.${e}`)}},connect=async()=>(x||=new Promise((e,r)=>{let i=indexedDB.open(h,v);i.onupgradeneeded=e=>{let t=i.result,a=i.transaction;if(m)try{m({db:t,newVersion:e.newVersion??null,oldVersion:e.oldVersion,tx:a})}catch(e){try{a.abort()}catch{}r(new n(`migration failed for "${h}"`,{cause:e}));return}createObjectStores(t,a)},i.onsuccess=()=>{if(S){i.result.close(),e();return}let t=i.result;t.onversionchange=()=>{t.close(),b=null,x=null},b=t,e()},i.onerror=()=>{x=null,r(new t(`failed to open "${h}"`,{cause:i.error}))}}),x),withStore=async(t,n,r)=>{if(S||(b||await connect(),!b))throw new e(`"${h}" is disposed`);let i=String(t),a=b.transaction(i,n);return runIdbTx(a,`${h}/${i}`,()=>r(a.objectStore(i)))},requireDb=async()=>{if(S||(b||await connect(),!b))throw new e(`"${h}" is disposed`);return b},publish=e=>{y?.postMessage({table:String(e)})},decodeWithCodec=(e,n)=>{let o=i(n);if(o&&!r(o.expiresAt))try{return a(_[e],o.value)}catch(n){throw new t(`validation failed for table "${String(e)}"`,{cause:n})}},encodeWithCodec=(e,n,r)=>{let i=n,a=o(_[e],i);for(let n of g[e].indexes??[]){let r=i[n];if(r!==void 0&&(typeof a!=`object`||!a||!Object.hasOwn(a,n)||!Object.is(a[n],r)))throw new t(`codec output for table "${String(e)}" must preserve indexed field "${n}"`)}return r===void 0?{value:a}:{expiresAt:Date.now()+r,value:a}},C={clear:e=>withStore(e,`readwrite`,e=>idbReq(e.clear()).then(()=>void 0)),delete:(e,t)=>withStore(e,`readwrite`,n=>{let decode=t=>decodeWithCodec(e,t);return storeDelete(n,s(t),decode)}),deleteMany:(e,t)=>withStore(e,`readwrite`,n=>{let decode=t=>decodeWithCodec(e,t);return storeDeleteMany(n,t.map(s),decode)}),async dispose(){S=!0,y?.close(),x&&await x.catch(()=>{}),b?.close(),b=null,x=null},get:(e,t)=>withStore(e,`readonly`,n=>{let decode=t=>decodeWithCodec(e,t);return storeGet(n,s(t),decode)}),getAll:e=>withStore(e,`readonly`,t=>{let decode=t=>decodeWithCodec(e,t);return getAllFromStore(t,decode)}),getMany:(e,t)=>withStore(e,`readonly`,n=>{let decode=t=>decodeWithCodec(e,t);return Promise.all(t.map(e=>storeGet(n,s(e),decode)))}),iterate:t=>{let getIterable=async()=>{if(S||(b||await connect(),!b||S))throw new e(`"${h}" is disposed`);let n=b.transaction(String(t),`readonly`).objectStore(String(t)),decode=e=>decodeWithCodec(t,e);return iterateStoreWithCursor(n,decode)},n,initInner=()=>getIterable().then(e=>(n=e[Symbol.asyncIterator](),n));return{[Symbol.asyncIterator](){return{next(){return n?n.next():initInner().then(e=>e.next())},return(e){return n?n.return?.(e)??Promise.resolve({done:!0,value:e}):Promise.resolve({done:!0,value:e})},throw(e){return n?n.throw?.(e)??Promise.reject(e):Promise.reject(e)}}}}},async pruneAllExpired(){let e=await requireDb(),t=Object.keys(g),n=e.transaction(t,`readwrite`),r=await runIdbTx(n,`${h}/pruneAll`,()=>Promise.all(t.map(async e=>[e,await pruneExpiredInStore(n.objectStore(e))])));return Object.fromEntries(r)},pruneExpiredInTable:e=>withStore(e,`readwrite`,e=>pruneExpiredInStore(e)),put(e,t,n){let r=s(c(g,e,t)),i=encodeWithCodec(e,t,n);return withStore(e,`readwrite`,e=>idbReq(e.put(i,r)).then(()=>void 0))},putAll(e,t,n){let r=t.map(t=>{let r=s(c(g,e,t));return{encoded:encodeWithCodec(e,t,n),key:r}});return withStore(e,`readwrite`,e=>Promise.all(r.map(({encoded:t,key:n})=>idbReq(e.put(t,n)))).then(()=>void 0))}},idbBatch=async(e,t,n,r)=>{l(e);let i=(await requireDb()).transaction([...e],`readwrite`),a=new Set,storeOf=e=>i.objectStore(e),o={clear:async e=>{await idbReq(storeOf(e).clear())},delete:(e,t)=>{let decode=t=>decodeWithCodec(e,t);return storeDelete(storeOf(e),s(t),decode)},deleteMany:(e,t)=>{let decode=t=>decodeWithCodec(e,t);return storeDeleteMany(storeOf(e),t.map(s),decode)},get:(e,t)=>{let decode=t=>decodeWithCodec(e,t);return storeGet(storeOf(e),s(t),decode)},getAll:e=>{let decode=t=>decodeWithCodec(e,t);return getAllFromStore(storeOf(e),decode)},getMany:(e,t)=>{let decode=t=>decodeWithCodec(e,t),n=storeOf(e);return Promise.all(t.map(e=>storeGet(n,s(e),decode)))},iterate(e){let decode=t=>decodeWithCodec(e,t);return iterateStoreWithCursor(storeOf(e),decode)},pruneExpiredInTable:e=>pruneExpiredInStore(storeOf(e)),put(e,t,n){let r=s(c(g,e,t)),i=encodeWithCodec(e,t,n);return idbReq(storeOf(e).put(i,r)).then(()=>void 0)},putAll(e,t,n){return Promise.all(t.map(t=>{let r=s(c(g,e,t)),i=encodeWithCodec(e,t,n);return idbReq(storeOf(e).put(i,r))})).then(()=>void 0)}},d=!0,p=f(g,o,e=>a.add(e),r,u(e,()=>d));try{let e=await runIdbTx(i,h,()=>t(p));for(let e of a)n(e);return e}finally{d=!1}},w=d(g,C,{codecs:_,createBatch:e=>(t,n)=>idbBatch(t,n,e.notifyMutation,e.validate),onCrossTabMessage(e){if(y)return y.onmessage=t=>{let n=t.data?.table;n&&Object.hasOwn(g,n)&&e(n)},()=>{y.onmessage=null}},onMutation:publish,schema:g});return Object.assign(w,{getAllByIndex(e,n,r){return withStore(e,`readonly`,i=>{if(!i.indexNames.contains(n))throw new t(`Table "${e}" has no index "${n}"`);let decode=t=>decodeWithCodec(e,t);return getAllFromStore(i.index(n),decode,r)})}})}export{createIndexedDB};
366
2
  //# sourceMappingURL=indexeddb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb.js","names":[],"sources":["../../src/adapters/indexeddb.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\n\nimport {\n assertBatchTables,\n type BatchImpl,\n buildDocumentStore,\n buildTxContext,\n type StorageBackend,\n withBatch,\n} from '../adapter-core';\nimport { decodeRecord, encodeRecord } from '../codec';\nimport { VaultDisposedError, VaultError, VaultMigrationError } from '../errors';\nimport { encodeVaultKey, getRecordKey } from '../internal';\nimport { isExpired, parseStored, type StoredRecord } from '../ttl';\nimport type { AnySchema, DocumentVaultStore, DurableStoreOptions, RecordOf, TransactionContext } from '../types';\n\n/** IndexedDB-only migration context supplied to `MigrationFn` during `onupgradeneeded`. */\nexport type MigrationContext = {\n db: IDBDatabase;\n newVersion: number | null;\n oldVersion: number;\n tx: IDBTransaction;\n};\n\n/** Synchronous IndexedDB schema upgrade callback. */\nexport type MigrationFn = (ctx: MigrationContext) => void;\n\n/**\n * A single step in a typed migration definition.\n * Compose multiple steps to describe the full schema change between two versions.\n */\nexport type MigrationStep =\n | { field: string; table: string; type: 'addIndex' }\n | { field: string; table: string; type: 'removeIndex' }\n | { name: string; type: 'addTable' }\n | { name: string; type: 'removeTable' };\n\n/**\n * Builds a typed `MigrationFn` from a declarative list of schema change steps.\n * Each step is applied in order and is idempotent (safe to run when the target\n * already exists or has already been removed).\n *\n * ```ts\n * const migrate = defineMigration([\n * { type: 'addTable', name: 'sessions' },\n * { type: 'addIndex', table: 'users', field: 'email' },\n * { type: 'removeTable', name: 'legacyTokens' },\n * ]);\n *\n * const db = createIndexedDB({ name: 'app', version: 2, schema, codecs, migrate });\n * ```\n */\nexport function defineMigration(steps: MigrationStep[]): MigrationFn {\n return ({ db, tx }) => {\n for (const step of steps) {\n switch (step.type) {\n case 'addIndex': {\n const store = tx.objectStore(step.table);\n\n // keyPath mirrors the vault storage envelope: { value: T, expiresAt?: number }\n if (!store.indexNames.contains(step.field)) {\n store.createIndex(step.field, `value.${step.field}`);\n }\n\n break;\n }\n case 'addTable':\n if (!db.objectStoreNames.contains(step.name)) {\n db.createObjectStore(step.name);\n }\n\n break;\n case 'removeIndex': {\n const store = tx.objectStore(step.table);\n\n if (store.indexNames.contains(step.field)) {\n store.deleteIndex(step.field);\n }\n\n break;\n }\n case 'removeTable':\n if (db.objectStoreNames.contains(step.name)) {\n db.deleteObjectStore(step.name);\n }\n\n break;\n }\n }\n };\n}\n\nfunction idbReq<R>(request: IDBRequest<R>): Promise<R> {\n return new Promise<R>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB request failed'));\n });\n}\n\nfunction wrapTxError(scope: string, message: string, cause: unknown): VaultError {\n const causeMessage = cause instanceof Error && cause.message ? `: ${cause.message}` : '';\n\n return new VaultError(`${message} on \"${scope}\"${causeMessage}`, { cause });\n}\n\nfunction runIdbTx<T>(tx: IDBTransaction, scope: string, work: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let result: T | undefined;\n let callbackError: unknown;\n\n Promise.resolve()\n .then(work)\n .then((value) => {\n result = value;\n })\n .catch((error) => {\n callbackError = error;\n\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n });\n\n const rejectWithCallbackError = (fallbackCause: unknown, message = 'transaction failed'): void => {\n if (callbackError instanceof Error) {\n reject(callbackError);\n } else {\n reject(wrapTxError(scope, message, callbackError ?? fallbackCause));\n }\n };\n\n tx.oncomplete = () => {\n if (callbackError) {\n rejectWithCallbackError(undefined);\n\n return;\n }\n\n resolve(result as T);\n };\n tx.onerror = () => reject(wrapTxError(scope, 'transaction error', tx.error));\n tx.onabort = () => rejectWithCallbackError(tx.error, 'transaction aborted');\n });\n}\n\nasync function getAllFromStore<T extends object>(\n store: IDBIndex | IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n query?: IDBValidKey | IDBKeyRange,\n): Promise<T[]> {\n const rawRecords = await idbReq<unknown[]>(store.getAll(query));\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function storeGet<T extends object>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<T | undefined> {\n const raw = await idbReq<unknown>(store.get(key));\n\n if (raw == null) return undefined;\n\n return decode(raw);\n}\n\nasync function storeDelete<T extends object>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<boolean> {\n const live = (await storeGet<T>(store, key, decode)) !== undefined;\n\n await idbReq(store.delete(key));\n\n return live;\n}\n\nasync function storeDeleteMany<T extends object>(\n store: IDBObjectStore,\n keys: readonly IDBValidKey[],\n decode: (raw: unknown) => T | undefined,\n): Promise<number> {\n const results = await Promise.all(keys.map((key) => storeDelete(store, key, decode)));\n return results.filter(Boolean).length;\n}\n\nfunction pruneExpiredInStore(store: IDBObjectStore): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n let deleted = 0;\n const request = store.openCursor();\n\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB cursor failed during prune'));\n request.onsuccess = () => {\n const cursor = request.result;\n\n if (!cursor) {\n resolve(deleted);\n\n return;\n }\n\n const stored = parseStored(cursor.value as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n cursor.delete();\n deleted += 1;\n }\n\n cursor.continue();\n };\n });\n}\n\n/**\n * Cursor state machine — a single discriminated union replaces five boolean/nullable variables.\n * Transitions: idle → waiting (next() before cursor fires) | buffered (cursor fires first) | done | error\n */\ntype CursorState<T> =\n | { type: 'idle' }\n | { reject: (e: unknown) => void; resolve: (r: IteratorResult<T>) => void; type: 'waiting' }\n | { results: IteratorResult<T>[]; type: 'buffered' }\n | { error: unknown; type: 'error' }\n | { type: 'done' };\n\n/**\n * F1: True cursor-based iteration for IndexedDB.\n * Yields live records one-by-one using an IDB cursor, avoiding materializing the full table.\n * This is memory-efficient for large tables — the cursor walks the store incrementally.\n *\n * Design: the cursor is opened *synchronously* in [Symbol.asyncIterator]() so that event\n * handlers are wired immediately (no queueMicrotask races). The cursor is advanced *eagerly*\n * before yielding — this keeps the IDB readonly transaction alive between consumer awaits,\n * because IDB auto-commits when there are no pending requests.\n */\nfunction iterateStoreWithCursor<T extends object>(\n store: IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<T> {\n const cursorRequest = store.openCursor();\n let state: CursorState<T> = { type: 'idle' };\n\n const deliver = (result: IteratorResult<T>): void => {\n if (state.type === 'waiting') {\n const { resolve } = state;\n\n state = result.done ? { type: 'done' } : { type: 'idle' };\n resolve(result);\n } else if (state.type === 'buffered') {\n state.results.push(result);\n } else {\n state = { results: [result], type: 'buffered' };\n }\n };\n\n cursorRequest.onerror = () => {\n const err = cursorRequest.error ?? new VaultError('IndexedDB cursor iteration failed');\n\n if (state.type === 'waiting') {\n const { reject } = state;\n\n state = { type: 'done' };\n reject(err);\n } else {\n state = { error: err, type: 'error' };\n }\n };\n\n cursorRequest.onsuccess = () => {\n if (state.type === 'done') return;\n const cursor = cursorRequest.result;\n\n if (!cursor) {\n deliver({ done: true, value: undefined });\n\n return;\n }\n\n let value: T | undefined;\n try {\n value = decode(cursor.value as unknown);\n } catch (error) {\n if (state.type === 'waiting') {\n const { reject } = state;\n state = { type: 'done' };\n reject(error);\n } else {\n state = { error, type: 'error' };\n }\n return;\n }\n\n // Advance eagerly BEFORE yielding to keep the IDB transaction alive.\n cursor.continue();\n\n if (value !== undefined) deliver({ done: false, value });\n };\n\n return {\n next(): Promise<IteratorResult<T>> {\n if (state.type === 'error') {\n const { error } = state;\n\n state = { type: 'done' };\n\n return Promise.reject(error);\n }\n\n if (state.type === 'buffered') {\n const [result, ...results] = state.results;\n\n state = result.done\n ? { type: 'done' }\n : results.length > 0\n ? { results, type: 'buffered' }\n : { type: 'idle' };\n\n return Promise.resolve(result);\n }\n\n if (state.type === 'done') return Promise.resolve({ done: true, value: undefined });\n\n return new Promise<IteratorResult<T>>((resolve, reject) => {\n state = { reject, resolve, type: 'waiting' };\n });\n },\n\n return(value?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.resolve({ done: true, value: undefined });\n\n state = { type: 'done' };\n\n return Promise.resolve({ done: true, value });\n },\n\n throw(err?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.reject(err);\n\n state = { type: 'done' };\n\n return Promise.reject(err);\n },\n };\n },\n };\n}\n\nexport interface IndexedDbVaultStore<S extends AnySchema> extends DocumentVaultStore<S> {\n getAllByIndex<K extends keyof S & string, Field extends keyof RecordOf<S, K> & string>(\n table: K,\n field: Field,\n value: RecordOf<S, K>[Field],\n ): Promise<RecordOf<S, K>[]>;\n}\n\ntype IndexedDbOptions<S extends AnySchema> = DurableStoreOptions<S> & {\n migrate?: MigrationFn;\n name: string;\n /** Schema version. Must be a positive integer. Increment when adding tables or changing the schema, then provide `migrate`. Defaults to 1. */\n version?: number;\n};\n\nexport function createIndexedDB<S extends AnySchema>(options: IndexedDbOptions<S>): IndexedDbVaultStore<S> {\n const { migrate, name, schema, codecs, version = 1 } = options;\n\n if (!codecs) {\n throw new VaultError('createIndexedDB: codecs are required for durable persistence');\n }\n\n if (!Number.isInteger(version) || version < 1) {\n throw new VaultError(`createIndexedDB: version must be a positive integer, got ${String(version)}`);\n }\n\n // Fixed envelopes keep IndexedDB records and `value.<field>` indexes portable across adapters.\n // Table-aware codec encode/decode is applied in the backend methods below.\n\n const channel = typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(`vault:${name}`) : undefined;\n\n let db: IDBDatabase | null = null;\n let connectPromise: Promise<void> | null = null;\n let disposed = false;\n\n const createObjectStores = (target: IDBDatabase, tx: IDBTransaction): void => {\n for (const [tableName, entry] of Object.entries(schema)) {\n let store: IDBObjectStore;\n\n if (!target.objectStoreNames.contains(tableName)) {\n store = target.createObjectStore(tableName);\n } else {\n store = tx.objectStore(tableName);\n }\n\n // F5: Create secondary indexes for fields declared via .index() on the table() builder.\n // Stored format is { value: T, expiresAt?: number } so IDB keyPath is `value.<field>`.\n const indexes = (entry as { indexes?: readonly string[] }).indexes ?? [];\n\n for (const field of indexes) {\n if (!store.indexNames.contains(field)) {\n store.createIndex(field, `value.${field}`);\n }\n }\n }\n };\n\n const connect = async (): Promise<void> => {\n if (!connectPromise) {\n connectPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(name, version);\n\n request.onupgradeneeded = (event) => {\n const target = request.result;\n const tx = request.transaction!;\n\n if (migrate) {\n try {\n migrate({\n db: target,\n newVersion: (event as IDBVersionChangeEvent).newVersion ?? null,\n oldVersion: event.oldVersion,\n tx,\n });\n } catch (error) {\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n\n reject(new VaultMigrationError(`migration failed for \"${name}\"`, { cause: error }));\n\n return;\n }\n }\n\n createObjectStores(target, tx);\n };\n\n request.onsuccess = () => {\n if (disposed) {\n request.result.close();\n resolve();\n\n return;\n }\n\n const connection = request.result;\n\n connection.onversionchange = () => {\n connection.close();\n db = null;\n connectPromise = null;\n };\n\n db = connection;\n resolve();\n };\n request.onerror = () => {\n connectPromise = null;\n reject(new VaultError(`failed to open \"${name}\"`, { cause: request.error }));\n };\n });\n }\n\n return connectPromise;\n };\n\n const withStore = async <T>(\n table: keyof S,\n mode: 'readonly' | 'readwrite',\n fn: (store: IDBObjectStore) => Promise<T>,\n ): Promise<T> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const tableName = String(table);\n const tx = db.transaction(tableName, mode);\n\n return runIdbTx(tx, `${name}/${tableName}`, () => fn(tx.objectStore(tableName)));\n };\n\n const requireDb = async (): Promise<IDBDatabase> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n return db;\n };\n\n const publish = <K extends keyof S>(table: K): void => {\n channel?.postMessage({ table: String(table) });\n };\n\n // Table-aware decode: unwrap envelope + apply codec.decode\n const decodeWithCodec = <T extends object>(table: keyof S, raw: unknown): T | undefined => {\n const stored = parseStored<unknown>(raw);\n\n if (!stored || isExpired(stored.expiresAt)) return undefined;\n\n try {\n return decodeRecord(codecs[table], stored.value) as unknown as T;\n } catch (err) {\n throw new VaultError(`validation failed for table \"${String(table)}\"`, { cause: err });\n }\n };\n\n // Table-aware encode: apply codec.encode + wrap in envelope\n const encodeWithCodec = <T>(table: keyof S, value: T, ttl?: number): StoredRecord<unknown> => {\n const record = value as RecordOf<S, typeof table>;\n const encoded = encodeRecord(codecs[table], record);\n\n for (const field of schema[table].indexes ?? []) {\n const indexedValue = (record as Record<string, unknown>)[field];\n if (indexedValue === undefined) continue;\n\n if (\n typeof encoded !== 'object' ||\n encoded === null ||\n !Object.hasOwn(encoded, field) ||\n !Object.is((encoded as Record<string, unknown>)[field], indexedValue)\n ) {\n throw new VaultError(`codec output for table \"${String(table)}\" must preserve indexed field \"${field}\"`);\n }\n }\n\n return ttl === undefined ? { value: encoded } : { expiresAt: Date.now() + ttl, value: encoded };\n };\n\n const core: StorageBackend<S> = {\n clear: (table) => withStore(table, 'readwrite', (s) => idbReq(s.clear()).then(() => undefined)),\n\n delete: (table, key) =>\n withStore(table, 'readwrite', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeDelete<RecordOf<S, typeof table>>(s, encodeVaultKey(key), decode);\n }),\n\n deleteMany: (table, keys) =>\n withStore(table, 'readwrite', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n return storeDeleteMany<RecordOf<S, typeof table>>(s, keys.map(encodeVaultKey), decode);\n }),\n\n async dispose(): Promise<void> {\n disposed = true;\n channel?.close();\n\n // F7: Wait for any in-progress connect before closing the DB to avoid\n // \"database connection is closing\" errors on in-flight requests.\n if (connectPromise) await connectPromise.catch(() => {});\n\n db?.close();\n db = null;\n connectPromise = null;\n },\n\n get: (table, key) =>\n withStore(table, 'readonly', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeGet<RecordOf<S, typeof table>>(s, encodeVaultKey(key), decode);\n }),\n\n getAll: (table) =>\n withStore(table, 'readonly', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return getAllFromStore<RecordOf<S, typeof table>>(s, decode);\n }),\n\n getMany: (table, keys) =>\n withStore(table, 'readonly', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n return Promise.all(keys.map((key) => storeGet<RecordOf<S, typeof table>>(s, encodeVaultKey(key), decode)));\n }),\n\n iterate: (table) => {\n // Each call opens a fresh transaction so iteration doesn't hold locks across awaits.\n const getIterable = async (): Promise<AsyncIterable<RecordOf<S, typeof table>>> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db || disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const idb = db;\n const tx = idb.transaction(String(table), 'readonly');\n const store = tx.objectStore(String(table));\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return iterateStoreWithCursor<RecordOf<S, typeof table>>(\n store,\n decode as (raw: unknown) => RecordOf<S, typeof table> | undefined,\n );\n };\n\n let inner: AsyncIterator<RecordOf<S, typeof table>> | undefined;\n\n const initInner = (): Promise<AsyncIterator<RecordOf<S, typeof table>>> =>\n getIterable().then((iterable) => {\n inner = iterable[Symbol.asyncIterator]();\n\n return inner;\n });\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<RecordOf<S, typeof table>> {\n return {\n next(): Promise<IteratorResult<RecordOf<S, typeof table>>> {\n if (inner) return inner.next();\n\n return initInner().then((it) => it.next());\n },\n return(value?: unknown): Promise<IteratorResult<RecordOf<S, typeof table>>> {\n if (inner) return inner.return?.(value) ?? Promise.resolve({ done: true, value });\n\n return Promise.resolve({ done: true, value });\n },\n throw(err?: unknown): Promise<IteratorResult<RecordOf<S, typeof table>>> {\n if (inner) return inner.throw?.(err) ?? Promise.reject(err);\n\n return Promise.reject(err);\n },\n };\n },\n };\n },\n\n async pruneAllExpired() {\n const idb = await requireDb();\n const tableNames = Object.keys(schema);\n const tx = idb.transaction(tableNames, 'readwrite');\n const results = await runIdbTx(tx, `${name}/pruneAll`, () =>\n Promise.all(tableNames.map(async (t) => [t, await pruneExpiredInStore(tx.objectStore(t))] as const)),\n );\n\n return Object.fromEntries(results);\n },\n\n pruneExpiredInTable: (table) => withStore(table, 'readwrite', (s) => pruneExpiredInStore(s)),\n\n put(table, value, ttl) {\n const key = encodeVaultKey(getRecordKey(schema, table, value));\n const encoded = encodeWithCodec(table, value, ttl);\n\n return withStore(table, 'readwrite', (s) => idbReq(s.put(encoded, key)).then(() => undefined));\n },\n\n putAll(table, values, ttl) {\n const encodedValues = values.map((v) => {\n const key = encodeVaultKey(getRecordKey(schema, table, v));\n\n return { encoded: encodeWithCodec(table, v, ttl), key };\n });\n\n return withStore(table, 'readwrite', (s) =>\n Promise.all(encodedValues.map(({ encoded, key }) => idbReq(s.put(encoded, key)))).then(() => undefined),\n );\n },\n };\n\n const idbBatch = async <K extends keyof S & string, R>(\n tables: readonly K[],\n fn: (tx: TransactionContext<S, K>) => Promise<R>,\n notifyMutation: (table: K) => void,\n validateFn: <T extends K>(table: T, value: RecordOf<S, T>) => RecordOf<S, T>,\n ): Promise<R> => {\n assertBatchTables(tables);\n\n const idb = await requireDb();\n const idbTx = idb.transaction([...tables] as string[], 'readwrite');\n const dirtyTables = new Set<K>();\n const storeOf = (table: K): IDBObjectStore => idbTx.objectStore(table);\n\n const batchCore: StorageBackend<S, K> = {\n clear: async (table) => {\n await idbReq(storeOf(table).clear());\n },\n delete: (table, key) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeDelete<RecordOf<S, K>>(storeOf(table), encodeVaultKey(key), decode);\n },\n deleteMany: (table, keys) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n return storeDeleteMany<RecordOf<S, K>>(storeOf(table), keys.map(encodeVaultKey), decode);\n },\n get: (table, key) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeGet<RecordOf<S, typeof table>>(storeOf(table), encodeVaultKey(key), decode);\n },\n getAll: (table) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return getAllFromStore<RecordOf<S, typeof table>>(storeOf(table), decode);\n },\n getMany: (table, keys) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n const store = storeOf(table);\n return Promise.all(keys.map((key) => storeGet<RecordOf<S, typeof table>>(store, encodeVaultKey(key), decode)));\n },\n iterate(table) {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return iterateStoreWithCursor<RecordOf<S, typeof table>>(\n storeOf(table),\n decode as (raw: unknown) => RecordOf<S, typeof table> | undefined,\n );\n },\n pruneExpiredInTable: (table) => pruneExpiredInStore(storeOf(table)),\n put(table, value, ttl) {\n const key = encodeVaultKey(getRecordKey(schema, table, value));\n const encoded = encodeWithCodec(table, value, ttl);\n\n return idbReq(storeOf(table).put(encoded, key)).then(() => undefined);\n },\n putAll(table, values, ttl) {\n return Promise.all(\n values.map((v) => {\n const key = encodeVaultKey(getRecordKey(schema, table, v));\n const encoded = encodeWithCodec(table, v, ttl);\n\n return idbReq(storeOf(table).put(encoded, key));\n }),\n ).then(() => undefined);\n },\n };\n\n const scope = new Set<string>(tables);\n let contextActive = true;\n const tx = buildTxContext<S, K>(\n schema,\n batchCore,\n (t) => dirtyTables.add(t),\n validateFn,\n scope,\n () => contextActive,\n );\n\n try {\n const result = await runIdbTx(idbTx, name, () => fn(tx));\n\n for (const table of dirtyTables) notifyMutation(table);\n\n return result;\n } finally {\n contextActive = false;\n }\n };\n\n let batch: BatchImpl<S> | undefined;\n const adapter = buildDocumentStore(schema, core, {\n codecs,\n onCrossTabMessage(notify) {\n if (!channel) {\n return undefined;\n }\n\n channel.onmessage = (event: MessageEvent<{ table?: string }>) => {\n const tableName = event.data?.table;\n\n if (!tableName || !Object.hasOwn(schema, tableName)) return;\n\n notify(tableName as keyof S & string);\n };\n\n return () => {\n channel.onmessage = null;\n };\n },\n onMutation: publish,\n onTransactions: (deps) => {\n batch = (tables, fn) => idbBatch(tables, fn, deps.notifyMutation, deps.validate);\n },\n schema,\n });\n\n if (!batch) throw new VaultError('IndexedDB transaction capability was not initialized');\n\n return Object.assign(withBatch(adapter, batch, schema), {\n getAllByIndex<K extends keyof S & string, Field extends keyof RecordOf<S, K> & string>(\n table: K,\n field: Field,\n value: RecordOf<S, K>[Field],\n ): Promise<RecordOf<S, K>[]> {\n return withStore(table, 'readonly', (store) => {\n if (!store.indexNames.contains(field)) throw new VaultError(`Table \"${table}\" has no index \"${field}\"`);\n\n const decode = (raw: unknown): RecordOf<S, K> | undefined => decodeWithCodec<RecordOf<S, K>>(table, raw);\n return getAllFromStore(store.index(field), decode, value as IDBValidKey);\n });\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"indexeddb.js","names":[],"sources":["../../src/adapters/indexeddb.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\n\nimport {\n assertBatchTables,\n batchScopeGuard,\n buildDocumentStore,\n buildOperations,\n type StorageBackend,\n} from '../adapter-core';\nimport { decodeRecord, encodeRecord } from '../codec';\nimport { VaultDisposedError, VaultError, VaultMigrationError } from '../errors';\nimport { encodeVaultKey, getRecordKey } from '../internal';\nimport { isExpired, parseStored, type StoredRecord } from '../ttl';\nimport type { AnySchema, DocumentVaultStore, DurableStoreOptions, RecordOf, TransactionContext } from '../types';\n\n/** IndexedDB-only migration context supplied to `MigrationFn` during `onupgradeneeded`. */\nexport type MigrationContext = {\n db: IDBDatabase;\n newVersion: number | null;\n oldVersion: number;\n tx: IDBTransaction;\n};\n\n/**\n * Synchronous IndexedDB schema upgrade callback, invoked from `onupgradeneeded`.\n * Tables and schema-declared indexes are created automatically; use the hook\n * only for work the schema cannot express, such as deleting a removed object\n * store or transforming records written by an older format.\n */\nexport type MigrationFn = (ctx: MigrationContext) => void;\n\nfunction idbReq<R>(request: IDBRequest<R>): Promise<R> {\n return new Promise<R>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB request failed'));\n });\n}\n\nfunction wrapTxError(scope: string, message: string, cause: unknown): VaultError {\n const causeMessage = cause instanceof Error && cause.message ? `: ${cause.message}` : '';\n\n return new VaultError(`${message} on \"${scope}\"${causeMessage}`, { cause });\n}\n\nfunction runIdbTx<T>(tx: IDBTransaction, scope: string, work: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let result: T | undefined;\n let callbackError: unknown;\n\n Promise.resolve()\n .then(work)\n .then((value) => {\n result = value;\n })\n .catch((error) => {\n callbackError = error;\n\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n });\n\n const rejectWithCallbackError = (fallbackCause: unknown, message = 'transaction failed'): void => {\n if (callbackError instanceof Error) {\n reject(callbackError);\n } else {\n reject(wrapTxError(scope, message, callbackError ?? fallbackCause));\n }\n };\n\n tx.oncomplete = () => {\n if (callbackError) {\n rejectWithCallbackError(undefined);\n\n return;\n }\n\n resolve(result as T);\n };\n tx.onerror = () => reject(wrapTxError(scope, 'transaction error', tx.error));\n tx.onabort = () => rejectWithCallbackError(tx.error, 'transaction aborted');\n });\n}\n\nasync function getAllFromStore<T extends object>(\n store: IDBIndex | IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n query?: IDBValidKey | IDBKeyRange,\n): Promise<T[]> {\n const rawRecords = await idbReq<unknown[]>(store.getAll(query));\n const records: T[] = [];\n\n for (const raw of rawRecords) {\n const value = decode(raw);\n\n if (value !== undefined) records.push(value);\n }\n\n return records;\n}\n\nasync function storeGet<T extends object>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<T | undefined> {\n const raw = await idbReq<unknown>(store.get(key));\n\n if (raw == null) return undefined;\n\n return decode(raw);\n}\n\nasync function storeDelete<T extends object>(\n store: IDBObjectStore,\n key: IDBValidKey,\n decode: (raw: unknown) => T | undefined,\n): Promise<boolean> {\n const live = (await storeGet<T>(store, key, decode)) !== undefined;\n\n await idbReq(store.delete(key));\n\n return live;\n}\n\nasync function storeDeleteMany<T extends object>(\n store: IDBObjectStore,\n keys: readonly IDBValidKey[],\n decode: (raw: unknown) => T | undefined,\n): Promise<number> {\n const results = await Promise.all(keys.map((key) => storeDelete(store, key, decode)));\n return results.filter(Boolean).length;\n}\n\nfunction pruneExpiredInStore(store: IDBObjectStore): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n let deleted = 0;\n const request = store.openCursor();\n\n request.onerror = () => reject(request.error ?? new VaultError('IndexedDB cursor failed during prune'));\n request.onsuccess = () => {\n const cursor = request.result;\n\n if (!cursor) {\n resolve(deleted);\n\n return;\n }\n\n const stored = parseStored(cursor.value as unknown);\n\n if (!stored || isExpired(stored.expiresAt)) {\n cursor.delete();\n deleted += 1;\n }\n\n cursor.continue();\n };\n });\n}\n\n/**\n * Cursor state machine — a single discriminated union replaces five boolean/nullable variables.\n * Transitions: idle → waiting (next() before cursor fires) | buffered (cursor fires first) | done | error\n */\ntype CursorState<T> =\n | { type: 'idle' }\n | { reject: (e: unknown) => void; resolve: (r: IteratorResult<T>) => void; type: 'waiting' }\n | { results: IteratorResult<T>[]; type: 'buffered' }\n | { error: unknown; type: 'error' }\n | { type: 'done' };\n\n/**\n * F1: True cursor-based iteration for IndexedDB.\n * Yields live records one-by-one using an IDB cursor, avoiding materializing the full table.\n * This is memory-efficient for large tables — the cursor walks the store incrementally.\n *\n * Design: the cursor is opened *synchronously* in [Symbol.asyncIterator]() so that event\n * handlers are wired immediately (no queueMicrotask races). The cursor is advanced *eagerly*\n * before yielding — this keeps the IDB readonly transaction alive between consumer awaits,\n * because IDB auto-commits when there are no pending requests.\n */\nfunction iterateStoreWithCursor<T extends object>(\n store: IDBObjectStore,\n decode: (raw: unknown) => T | undefined,\n): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<T> {\n const cursorRequest = store.openCursor();\n let state: CursorState<T> = { type: 'idle' };\n\n const deliver = (result: IteratorResult<T>): void => {\n if (state.type === 'waiting') {\n const { resolve } = state;\n\n state = result.done ? { type: 'done' } : { type: 'idle' };\n resolve(result);\n } else if (state.type === 'buffered') {\n state.results.push(result);\n } else {\n state = { results: [result], type: 'buffered' };\n }\n };\n\n cursorRequest.onerror = () => {\n const err = cursorRequest.error ?? new VaultError('IndexedDB cursor iteration failed');\n\n if (state.type === 'waiting') {\n const { reject } = state;\n\n state = { type: 'done' };\n reject(err);\n } else {\n state = { error: err, type: 'error' };\n }\n };\n\n cursorRequest.onsuccess = () => {\n if (state.type === 'done') return;\n const cursor = cursorRequest.result;\n\n if (!cursor) {\n deliver({ done: true, value: undefined });\n\n return;\n }\n\n let value: T | undefined;\n try {\n value = decode(cursor.value as unknown);\n } catch (error) {\n if (state.type === 'waiting') {\n const { reject } = state;\n state = { type: 'done' };\n reject(error);\n } else {\n state = { error, type: 'error' };\n }\n return;\n }\n\n // Advance eagerly BEFORE yielding to keep the IDB transaction alive.\n cursor.continue();\n\n if (value !== undefined) deliver({ done: false, value });\n };\n\n return {\n next(): Promise<IteratorResult<T>> {\n if (state.type === 'error') {\n const { error } = state;\n\n state = { type: 'done' };\n\n return Promise.reject(error);\n }\n\n if (state.type === 'buffered') {\n const [result, ...results] = state.results;\n\n state = result.done\n ? { type: 'done' }\n : results.length > 0\n ? { results, type: 'buffered' }\n : { type: 'idle' };\n\n return Promise.resolve(result);\n }\n\n if (state.type === 'done') return Promise.resolve({ done: true, value: undefined });\n\n return new Promise<IteratorResult<T>>((resolve, reject) => {\n state = { reject, resolve, type: 'waiting' };\n });\n },\n\n return(value?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.resolve({ done: true, value: undefined });\n\n state = { type: 'done' };\n\n return Promise.resolve({ done: true, value });\n },\n\n throw(err?: unknown): Promise<IteratorResult<T>> {\n if (state.type === 'waiting') state.reject(err);\n\n state = { type: 'done' };\n\n return Promise.reject(err);\n },\n };\n },\n };\n}\n\nexport interface IndexedDbVaultStore<S extends AnySchema> extends DocumentVaultStore<S> {\n getAllByIndex<K extends keyof S & string, Field extends keyof RecordOf<S, K> & string>(\n table: K,\n field: Field,\n value: RecordOf<S, K>[Field],\n ): Promise<RecordOf<S, K>[]>;\n}\n\ntype IndexedDbOptions<S extends AnySchema> = DurableStoreOptions<S> & {\n migrate?: MigrationFn;\n name: string;\n /** Schema version. Must be a positive integer. Increment when adding tables or changing the schema, then provide `migrate`. Defaults to 1. */\n version?: number;\n};\n\nexport function createIndexedDB<S extends AnySchema>(options: IndexedDbOptions<S>): IndexedDbVaultStore<S> {\n const { migrate, name, schema, codecs, version = 1 } = options;\n\n if (!codecs) {\n throw new VaultError('createIndexedDB: codecs are required for durable persistence');\n }\n\n if (!Number.isInteger(version) || version < 1) {\n throw new VaultError(`createIndexedDB: version must be a positive integer, got ${String(version)}`);\n }\n\n // Fixed envelopes keep IndexedDB records and `value.<field>` indexes portable across adapters.\n // Table-aware codec encode/decode is applied in the backend methods below.\n\n const channel = typeof BroadcastChannel !== 'undefined' ? new BroadcastChannel(`vault:${name}`) : undefined;\n\n let db: IDBDatabase | null = null;\n let connectPromise: Promise<void> | null = null;\n let disposed = false;\n\n const createObjectStores = (target: IDBDatabase, tx: IDBTransaction): void => {\n for (const [tableName, entry] of Object.entries(schema)) {\n let store: IDBObjectStore;\n\n if (!target.objectStoreNames.contains(tableName)) {\n store = target.createObjectStore(tableName);\n } else {\n store = tx.objectStore(tableName);\n }\n\n // F5: Create secondary indexes for fields declared via .index() on the table() builder.\n // Stored format is { value: T, expiresAt?: number } so IDB keyPath is `value.<field>`.\n const indexes = (entry as { indexes?: readonly string[] }).indexes ?? [];\n\n for (const field of indexes) {\n if (!store.indexNames.contains(field)) {\n store.createIndex(field, `value.${field}`);\n }\n }\n }\n };\n\n const connect = async (): Promise<void> => {\n if (!connectPromise) {\n connectPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(name, version);\n\n request.onupgradeneeded = (event) => {\n const target = request.result;\n const tx = request.transaction!;\n\n if (migrate) {\n try {\n migrate({\n db: target,\n newVersion: (event as IDBVersionChangeEvent).newVersion ?? null,\n oldVersion: event.oldVersion,\n tx,\n });\n } catch (error) {\n try {\n tx.abort();\n } catch {\n /* ignore */\n }\n\n reject(new VaultMigrationError(`migration failed for \"${name}\"`, { cause: error }));\n\n return;\n }\n }\n\n createObjectStores(target, tx);\n };\n\n request.onsuccess = () => {\n if (disposed) {\n request.result.close();\n resolve();\n\n return;\n }\n\n const connection = request.result;\n\n connection.onversionchange = () => {\n connection.close();\n db = null;\n connectPromise = null;\n };\n\n db = connection;\n resolve();\n };\n request.onerror = () => {\n connectPromise = null;\n reject(new VaultError(`failed to open \"${name}\"`, { cause: request.error }));\n };\n });\n }\n\n return connectPromise;\n };\n\n const withStore = async <T>(\n table: keyof S,\n mode: 'readonly' | 'readwrite',\n fn: (store: IDBObjectStore) => Promise<T>,\n ): Promise<T> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const tableName = String(table);\n const tx = db.transaction(tableName, mode);\n\n return runIdbTx(tx, `${name}/${tableName}`, () => fn(tx.objectStore(tableName)));\n };\n\n const requireDb = async (): Promise<IDBDatabase> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n return db;\n };\n\n const publish = <K extends keyof S>(table: K): void => {\n channel?.postMessage({ table: String(table) });\n };\n\n // Table-aware decode: unwrap envelope + apply codec.decode\n const decodeWithCodec = <T extends object>(table: keyof S, raw: unknown): T | undefined => {\n const stored = parseStored<unknown>(raw);\n\n if (!stored || isExpired(stored.expiresAt)) return undefined;\n\n try {\n return decodeRecord(codecs[table], stored.value) as unknown as T;\n } catch (err) {\n throw new VaultError(`validation failed for table \"${String(table)}\"`, { cause: err });\n }\n };\n\n // Table-aware encode: apply codec.encode + wrap in envelope\n const encodeWithCodec = <T>(table: keyof S, value: T, ttl?: number): StoredRecord<unknown> => {\n const record = value as RecordOf<S, typeof table>;\n const encoded = encodeRecord(codecs[table], record);\n\n for (const field of schema[table].indexes ?? []) {\n const indexedValue = (record as Record<string, unknown>)[field];\n if (indexedValue === undefined) continue;\n\n if (\n typeof encoded !== 'object' ||\n encoded === null ||\n !Object.hasOwn(encoded, field) ||\n !Object.is((encoded as Record<string, unknown>)[field], indexedValue)\n ) {\n throw new VaultError(`codec output for table \"${String(table)}\" must preserve indexed field \"${field}\"`);\n }\n }\n\n return ttl === undefined ? { value: encoded } : { expiresAt: Date.now() + ttl, value: encoded };\n };\n\n const core: StorageBackend<S> = {\n clear: (table) => withStore(table, 'readwrite', (s) => idbReq(s.clear()).then(() => undefined)),\n\n delete: (table, key) =>\n withStore(table, 'readwrite', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeDelete<RecordOf<S, typeof table>>(s, encodeVaultKey(key), decode);\n }),\n\n deleteMany: (table, keys) =>\n withStore(table, 'readwrite', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n return storeDeleteMany<RecordOf<S, typeof table>>(s, keys.map(encodeVaultKey), decode);\n }),\n\n async dispose(): Promise<void> {\n disposed = true;\n channel?.close();\n\n // F7: Wait for any in-progress connect before closing the DB to avoid\n // \"database connection is closing\" errors on in-flight requests.\n if (connectPromise) await connectPromise.catch(() => {});\n\n db?.close();\n db = null;\n connectPromise = null;\n },\n\n get: (table, key) =>\n withStore(table, 'readonly', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeGet<RecordOf<S, typeof table>>(s, encodeVaultKey(key), decode);\n }),\n\n getAll: (table) =>\n withStore(table, 'readonly', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return getAllFromStore<RecordOf<S, typeof table>>(s, decode);\n }),\n\n getMany: (table, keys) =>\n withStore(table, 'readonly', (s) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n return Promise.all(keys.map((key) => storeGet<RecordOf<S, typeof table>>(s, encodeVaultKey(key), decode)));\n }),\n\n iterate: (table) => {\n // Each call opens a fresh transaction so iteration doesn't hold locks across awaits.\n const getIterable = async (): Promise<AsyncIterable<RecordOf<S, typeof table>>> => {\n if (disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n if (!db) await connect();\n\n if (!db || disposed) throw new VaultDisposedError(`\"${name}\" is disposed`);\n\n const idb = db;\n const tx = idb.transaction(String(table), 'readonly');\n const store = tx.objectStore(String(table));\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return iterateStoreWithCursor<RecordOf<S, typeof table>>(\n store,\n decode as (raw: unknown) => RecordOf<S, typeof table> | undefined,\n );\n };\n\n let inner: AsyncIterator<RecordOf<S, typeof table>> | undefined;\n\n const initInner = (): Promise<AsyncIterator<RecordOf<S, typeof table>>> =>\n getIterable().then((iterable) => {\n inner = iterable[Symbol.asyncIterator]();\n\n return inner;\n });\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<RecordOf<S, typeof table>> {\n return {\n next(): Promise<IteratorResult<RecordOf<S, typeof table>>> {\n if (inner) return inner.next();\n\n return initInner().then((it) => it.next());\n },\n return(value?: unknown): Promise<IteratorResult<RecordOf<S, typeof table>>> {\n if (inner) return inner.return?.(value) ?? Promise.resolve({ done: true, value });\n\n return Promise.resolve({ done: true, value });\n },\n throw(err?: unknown): Promise<IteratorResult<RecordOf<S, typeof table>>> {\n if (inner) return inner.throw?.(err) ?? Promise.reject(err);\n\n return Promise.reject(err);\n },\n };\n },\n };\n },\n\n async pruneAllExpired() {\n const idb = await requireDb();\n const tableNames = Object.keys(schema);\n const tx = idb.transaction(tableNames, 'readwrite');\n const results = await runIdbTx(tx, `${name}/pruneAll`, () =>\n Promise.all(tableNames.map(async (t) => [t, await pruneExpiredInStore(tx.objectStore(t))] as const)),\n );\n\n return Object.fromEntries(results);\n },\n\n pruneExpiredInTable: (table) => withStore(table, 'readwrite', (s) => pruneExpiredInStore(s)),\n\n put(table, value, ttl) {\n const key = encodeVaultKey(getRecordKey(schema, table, value));\n const encoded = encodeWithCodec(table, value, ttl);\n\n return withStore(table, 'readwrite', (s) => idbReq(s.put(encoded, key)).then(() => undefined));\n },\n\n putAll(table, values, ttl) {\n const encodedValues = values.map((v) => {\n const key = encodeVaultKey(getRecordKey(schema, table, v));\n\n return { encoded: encodeWithCodec(table, v, ttl), key };\n });\n\n return withStore(table, 'readwrite', (s) =>\n Promise.all(encodedValues.map(({ encoded, key }) => idbReq(s.put(encoded, key)))).then(() => undefined),\n );\n },\n };\n\n const idbBatch = async <K extends keyof S & string, R>(\n tables: readonly K[],\n fn: (tx: TransactionContext<S, K>) => Promise<R>,\n notifyMutation: (table: K) => void,\n validateFn: <T extends K>(table: T, value: RecordOf<S, T>) => RecordOf<S, T>,\n ): Promise<R> => {\n assertBatchTables(tables);\n\n const idb = await requireDb();\n const idbTx = idb.transaction([...tables] as string[], 'readwrite');\n const dirtyTables = new Set<K>();\n const storeOf = (table: K): IDBObjectStore => idbTx.objectStore(table);\n\n const batchCore: StorageBackend<S, K> = {\n clear: async (table) => {\n await idbReq(storeOf(table).clear());\n },\n delete: (table, key) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeDelete<RecordOf<S, K>>(storeOf(table), encodeVaultKey(key), decode);\n },\n deleteMany: (table, keys) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n return storeDeleteMany<RecordOf<S, K>>(storeOf(table), keys.map(encodeVaultKey), decode);\n },\n get: (table, key) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return storeGet<RecordOf<S, typeof table>>(storeOf(table), encodeVaultKey(key), decode);\n },\n getAll: (table) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return getAllFromStore<RecordOf<S, typeof table>>(storeOf(table), decode);\n },\n getMany: (table, keys) => {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n const store = storeOf(table);\n return Promise.all(keys.map((key) => storeGet<RecordOf<S, typeof table>>(store, encodeVaultKey(key), decode)));\n },\n iterate(table) {\n const decode = <T extends object>(raw: unknown): T | undefined => decodeWithCodec<T>(table, raw);\n\n return iterateStoreWithCursor<RecordOf<S, typeof table>>(\n storeOf(table),\n decode as (raw: unknown) => RecordOf<S, typeof table> | undefined,\n );\n },\n pruneExpiredInTable: (table) => pruneExpiredInStore(storeOf(table)),\n put(table, value, ttl) {\n const key = encodeVaultKey(getRecordKey(schema, table, value));\n const encoded = encodeWithCodec(table, value, ttl);\n\n return idbReq(storeOf(table).put(encoded, key)).then(() => undefined);\n },\n putAll(table, values, ttl) {\n return Promise.all(\n values.map((v) => {\n const key = encodeVaultKey(getRecordKey(schema, table, v));\n const encoded = encodeWithCodec(table, v, ttl);\n\n return idbReq(storeOf(table).put(encoded, key));\n }),\n ).then(() => undefined);\n },\n };\n\n let contextActive = true;\n const tx = buildOperations<S, K>(\n schema,\n batchCore,\n (t) => dirtyTables.add(t),\n validateFn,\n batchScopeGuard(tables, () => contextActive),\n );\n\n try {\n const result = await runIdbTx(idbTx, name, () => fn(tx));\n\n for (const table of dirtyTables) notifyMutation(table);\n\n return result;\n } finally {\n contextActive = false;\n }\n };\n\n const adapter = buildDocumentStore(schema, core, {\n codecs,\n createBatch: (deps) => (tables, fn) => idbBatch(tables, fn, deps.notifyMutation, deps.validate),\n onCrossTabMessage(notify) {\n if (!channel) {\n return undefined;\n }\n\n channel.onmessage = (event: MessageEvent<{ table?: string }>) => {\n const tableName = event.data?.table;\n\n if (!tableName || !Object.hasOwn(schema, tableName)) return;\n\n notify(tableName as keyof S & string);\n };\n\n return () => {\n channel.onmessage = null;\n };\n },\n onMutation: publish,\n schema,\n });\n\n return Object.assign(adapter, {\n getAllByIndex<K extends keyof S & string, Field extends keyof RecordOf<S, K> & string>(\n table: K,\n field: Field,\n value: RecordOf<S, K>[Field],\n ): Promise<RecordOf<S, K>[]> {\n return withStore(table, 'readonly', (store) => {\n if (!store.indexNames.contains(field)) throw new VaultError(`Table \"${table}\" has no index \"${field}\"`);\n\n const decode = (raw: unknown): RecordOf<S, K> | undefined => decodeWithCodec<RecordOf<S, K>>(table, raw);\n return getAllFromStore(store.index(field), decode, value as IDBValidKey);\n });\n },\n });\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../internal.cjs"),t=require("../ttl.cjs"),n=require("../adapter-core.cjs");function r(r){let{schema:i}=r,a=new Map(Object.keys(i).map(e=>[e,new Map])),o=e=>a.get(e);return n.buildKeyValueStore(i,{async clear(e){o(e).clear()},async delete(n,r){let i=o(n),a=e.encodeVaultKey(r),s=t.parseStored(i.get(a));return i.delete(a),s!==void 0&&!t.isExpired(s.expiresAt)},async get(n,r){let i=o(n),a=e.encodeVaultKey(r),s=t.parseStored(i.get(a));if(!s||t.isExpired(s.expiresAt)){i.delete(a);return}return s.value},async getAll(e){let n=o(e),r=[];for(let[e,i]of n){let a=t.parseStored(i);!a||t.isExpired(a.expiresAt)?n.delete(e):r.push(a.value)}return r},async pruneExpiredInTable(e){let n=o(e),r=0;for(let[e,i]of n){let a=t.parseStored(i);(!a||t.isExpired(a.expiresAt))&&(n.delete(e),r+=1)}return r},async put(t,n,r){let a=e.encodeVaultKey(e.getRecordKey(i,t,n)),s=r===void 0?{value:n}:{expiresAt:Date.now()+r,value:n};o(t).set(a,s)},async putAll(t,n,r){let a=r===void 0?void 0:Date.now()+r;for(let r of n){let n=e.encodeVaultKey(e.getRecordKey(i,t,r)),s=a===void 0?{value:r}:{expiresAt:a,value:r};o(t).set(n,s)}}},r)}exports.createMemory=r;
1
+ const e=require("../ttl.cjs"),t=require("../internal.cjs"),n=require("../adapter-core.cjs");function createMemory(r){let{schema:i}=r,a=new Map(Object.keys(i).map(e=>[e,new Map])),getTable=e=>a.get(e),o={async clear(e){getTable(e).clear()},async delete(n,r){let i=getTable(n),a=t.encodeVaultKey(r),o=e.parseStored(i.get(a));return i.delete(a),o!==void 0&&!e.isExpired(o.expiresAt)},async get(n,r){let i=getTable(n),a=t.encodeVaultKey(r),o=e.parseStored(i.get(a));if(!o||e.isExpired(o.expiresAt)){i.delete(a);return}return o.value},async getAll(t){let n=getTable(t),r=[];for(let[t,i]of n){let a=e.parseStored(i);!a||e.isExpired(a.expiresAt)?n.delete(t):r.push(a.value)}return r},async pruneExpiredInTable(t){let n=getTable(t),r=0;for(let[t,i]of n){let a=e.parseStored(i);(!a||e.isExpired(a.expiresAt))&&(n.delete(t),r+=1)}return r},async put(e,n,r){let a=t.encodeVaultKey(t.getRecordKey(i,e,n)),o=r===void 0?{value:n}:{expiresAt:Date.now()+r,value:n};getTable(e).set(a,o)},async putAll(e,n,r){let a=r===void 0?void 0:Date.now()+r;for(let r of n){let n=t.encodeVaultKey(t.getRecordKey(i,e,r)),o=a===void 0?{value:r}:{expiresAt:a,value:r};getTable(e).set(n,o)}}};return n.buildDocumentStore(i,o,{...r,createBatch:e=>async(t,r)=>{n.assertBatchTables(t);let s=new Map(t.map(e=>[e,new Map(getTable(e))])),c=new Set,l=n.buildOperations(i,o,e=>{c.add(e)},e.validate,n.batchScopeGuard(t));try{let t=await r(l);for(let t of c)e.notifyMutation(t);return t}catch(e){for(let[e,t]of s)a.set(e,t);throw e}}})}exports.createMemory=createMemory;
2
2
  //# sourceMappingURL=memory.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.cjs","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import { buildKeyValueStore, type StorageBackend } from '../adapter-core';\nimport { encodeVaultKey, getRecordKey } from '../internal';\nimport { isExpired, parseStored, type StoredRecord } from '../ttl';\nimport type { AnySchema, KeyValueVaultStore, MemoryStoreOptions, RecordOf } from '../types';\n\n/** Memory uses tagged Map keys so numeric and string primary keys never collide. */\nexport function createMemory<S extends AnySchema>(options: MemoryStoreOptions<S>): KeyValueVaultStore<S> {\n const { schema } = 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\n const core: StorageBackend<S> = {\n async clear(table) {\n getTable(table).clear();\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 return record !== undefined && !isExpired(record.expiresAt);\n },\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 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 },\n async putAll(table, values, ttl) {\n const expiresAt = ttl === undefined ? undefined : Date.now() + ttl;\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 }\n },\n };\n\n return buildKeyValueStore(schema, core, options);\n}\n"],"mappings":"4FAMA,SAAgB,EAAkC,EAAuD,CACvG,GAAM,CAAE,UAAW,EACb,EAAS,IAAI,IAAI,OAAO,KAAK,CAAM,CAAC,CAAC,IAAK,GAAU,CAAC,EAAO,IAAI,GAAoC,CAAC,CAAC,EACtG,EAAY,GAAsD,EAAO,IAAI,CAAK,EA0ExF,OAAO,EAAA,mBAAmB,EAAQ,CAvEhC,MAAM,MAAM,EAAO,CACjB,EAAS,CAAK,CAAC,CAAC,MAAM,CACxB,EACA,MAAM,OAAO,EAAO,EAAK,CACvB,IAAM,EAAQ,EAAS,CAAK,EACtB,EAAa,EAAA,eAAe,CAAG,EAC/B,EAAS,EAAA,YAAY,EAAM,IAAI,CAAU,CAAC,EAIhD,OAFA,EAAM,OAAO,CAAU,EAEhB,IAAW,IAAA,IAAa,CAAC,EAAA,UAAU,EAAO,SAAS,CAC5D,EACA,MAAM,IAAI,EAAO,EAAK,CACpB,IAAM,EAAQ,EAAS,CAAK,EACtB,EAAa,EAAA,eAAe,CAAG,EAC/B,EAAS,EAAA,YAAuC,EAAM,IAAI,CAAU,CAAC,EAE3E,GAAI,CAAC,GAAU,EAAA,UAAU,EAAO,SAAS,EAAG,CAC1C,EAAM,OAAO,CAAU,EAEvB,MACF,CAEA,OAAO,EAAO,KAChB,EACA,MAAM,OAAO,EAAO,CAClB,IAAM,EAAQ,EAAS,CAAK,EACtB,EAAsC,CAAC,EAE7C,IAAK,GAAM,CAAC,EAAK,KAAW,EAAO,CACjC,IAAM,EAAS,EAAA,YAAuC,CAAM,EAExD,CAAC,GAAU,EAAA,UAAU,EAAO,SAAS,EAAG,EAAM,OAAO,CAAG,EACvD,EAAO,KAAK,EAAO,KAAK,CAC/B,CAEA,OAAO,CACT,EACA,MAAM,oBAAoB,EAAO,CAC/B,IAAM,EAAQ,EAAS,CAAK,EACxB,EAAS,EAEb,IAAK,GAAM,CAAC,EAAK,KAAW,EAAO,CACjC,IAAM,EAAS,EAAA,YAAY,CAAM,GAE7B,CAAC,GAAU,EAAA,UAAU,EAAO,SAAS,KACvC,EAAM,OAAO,CAAG,EAChB,GAAU,EAEd,CAEA,OAAO,CACT,EACA,MAAM,IAAI,EAAO,EAAO,EAAK,CAC3B,IAAM,EAAM,EAAA,eAAe,EAAA,aAAa,EAAQ,EAAO,CAAK,CAAC,EACvD,EAAgC,IAAQ,IAAA,GAAY,CAAE,OAAM,EAAI,CAAE,UAAW,KAAK,IAAI,EAAI,EAAK,OAAM,EAE3G,EAAS,CAAK,CAAC,CAAC,IAAI,EAAK,CAAM,CACjC,EACA,MAAM,OAAO,EAAO,EAAQ,EAAK,CAC/B,IAAM,EAAY,IAAQ,IAAA,GAAY,IAAA,GAAY,KAAK,IAAI,EAAI,EAE/D,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAM,EAAA,eAAe,EAAA,aAAa,EAAQ,EAAO,CAAK,CAAC,EACvD,EAAgC,IAAc,IAAA,GAAY,CAAE,OAAM,EAAI,CAAE,YAAW,OAAM,EAE/F,EAAS,CAAK,CAAC,CAAC,IAAI,EAAK,CAAM,CACjC,CACF,CAGgC,EAAM,CAAO,CACjD"}
1
+ {"version":3,"file":"memory.cjs","names":[],"sources":["../../src/adapters/memory.ts"],"sourcesContent":["import {\n assertBatchTables,\n batchScopeGuard,\n buildDocumentStore,\n buildOperations,\n type StorageBackend,\n} from '../adapter-core';\nimport { encodeVaultKey, getRecordKey } from '../internal';\nimport { isExpired, parseStored, type StoredRecord } from '../ttl';\nimport type { AnySchema, DocumentVaultStore, MemoryStoreOptions, RecordOf } from '../types';\n\n/**\n * Creates an in-memory document store. Memory uses tagged Map keys so numeric and string\n * primary keys never collide. `batch()` snapshots the declared tables and restores them when\n * the callback throws; because memory writes never await real I/O, the rollback is exact as\n * long as the callback does not interleave external writes between its `await`s.\n */\nexport function createMemory<S extends AnySchema>(options: MemoryStoreOptions<S>): DocumentVaultStore<S> {\n const { schema } = 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\n const core: StorageBackend<S> = {\n async clear(table) {\n getTable(table).clear();\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 return record !== undefined && !isExpired(record.expiresAt);\n },\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 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 },\n async putAll(table, values, ttl) {\n const expiresAt = ttl === undefined ? undefined : Date.now() + ttl;\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 }\n },\n };\n\n return buildDocumentStore(schema, core, {\n ...options,\n createBatch: (deps) => async (declaredTables, fn) => {\n assertBatchTables(declaredTables);\n\n const snapshots = new Map(declaredTables.map((tableName) => [tableName, new Map(getTable(tableName))]));\n const dirty = new Set<keyof S & string>();\n const tx = buildOperations(\n schema,\n core,\n (table) => {\n // Record the dirty table; observers are notified once at commit, not per operation.\n dirty.add(table);\n },\n deps.validate,\n batchScopeGuard(declaredTables),\n );\n\n try {\n const result = await fn(tx);\n\n for (const table of dirty) deps.notifyMutation(table);\n\n return result;\n } catch (error) {\n for (const [tableName, snapshot] of snapshots) tables.set(tableName, snapshot);\n\n throw error;\n }\n },\n });\n}\n"],"mappings":"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"}
@@ -1,4 +1,9 @@
1
- import type { AnySchema, KeyValueVaultStore, MemoryStoreOptions } from '../types';
2
- /** Memory uses tagged Map keys so numeric and string primary keys never collide. */
3
- export declare function createMemory<S extends AnySchema>(options: MemoryStoreOptions<S>): KeyValueVaultStore<S>;
1
+ import type { AnySchema, DocumentVaultStore, MemoryStoreOptions } from '../types';
2
+ /**
3
+ * Creates an in-memory document store. Memory uses tagged Map keys so numeric and string
4
+ * primary keys never collide. `batch()` snapshots the declared tables and restores them when
5
+ * the callback throws; because memory writes never await real I/O, the rollback is exact as
6
+ * long as the callback does not interleave external writes between its `await`s.
7
+ */
8
+ export declare function createMemory<S extends AnySchema>(options: MemoryStoreOptions<S>): DocumentVaultStore<S>;
4
9
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,kBAAkB,EAAY,MAAM,UAAU,CAAC;AAE5F,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CA8EvG"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,kBAAkB,EAAY,MAAM,UAAU,CAAC;AAE5F;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CA4GvG"}