@korajs/store 1.0.0-beta.1 → 1.0.0-beta.11

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 (71) hide show
  1. package/dist/adapters/better-sqlite3.cjs.map +1 -1
  2. package/dist/adapters/better-sqlite3.d.cts +1 -1
  3. package/dist/adapters/better-sqlite3.d.ts +1 -1
  4. package/dist/adapters/better-sqlite3.js +1 -1
  5. package/dist/adapters/indexeddb.cjs +523 -148
  6. package/dist/adapters/indexeddb.cjs.map +1 -1
  7. package/dist/adapters/indexeddb.d.cts +4 -2
  8. package/dist/adapters/indexeddb.d.ts +4 -2
  9. package/dist/adapters/indexeddb.js +55 -11
  10. package/dist/adapters/indexeddb.js.map +1 -1
  11. package/dist/adapters/sqlite-wasm-worker.cjs +207 -187
  12. package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
  13. package/dist/adapters/sqlite-wasm-worker.js +208 -188
  14. package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
  15. package/dist/adapters/sqlite-wasm.cjs +474 -140
  16. package/dist/adapters/sqlite-wasm.cjs.map +1 -1
  17. package/dist/adapters/sqlite-wasm.d.cts +45 -8
  18. package/dist/adapters/sqlite-wasm.d.ts +45 -8
  19. package/dist/adapters/sqlite-wasm.js +3 -3
  20. package/dist/{backup-ZV4Y424B.js → backup-5S7K2Z35.js} +3 -3
  21. package/dist/{chunk-FFYA7J5H.js → chunk-CYO3YKFL.js} +4 -3
  22. package/dist/chunk-CYO3YKFL.js.map +1 -0
  23. package/dist/{chunk-6NKLDBTY.js → chunk-GSJ7EEUC.js} +2 -1
  24. package/dist/chunk-GSJ7EEUC.js.map +1 -0
  25. package/dist/{chunk-X57MWW35.js → chunk-HS6DBMST.js} +13 -10
  26. package/dist/chunk-HS6DBMST.js.map +1 -0
  27. package/dist/chunk-RJIEKEN4.js +751 -0
  28. package/dist/chunk-RJIEKEN4.js.map +1 -0
  29. package/dist/{chunk-QL2XVZRN.js → chunk-TUR7RGEP.js} +12 -1
  30. package/dist/{chunk-QL2XVZRN.js.map → chunk-TUR7RGEP.js.map} +1 -1
  31. package/dist/{chunk-IOEFNHHP.js → chunk-VDBJQ75K.js} +2 -2
  32. package/dist/chunk-VDBJQ75K.js.map +1 -0
  33. package/dist/{chunk-ZLWAYQEQ.js → chunk-YT7MRFCP.js} +36 -32
  34. package/dist/chunk-YT7MRFCP.js.map +1 -0
  35. package/dist/{export-audit-AJ7RORNK.js → export-audit-ODGQTQIK.js} +3 -3
  36. package/dist/index.cjs +313 -144
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +51 -5
  39. package/dist/index.d.ts +51 -5
  40. package/dist/index.js +212 -59
  41. package/dist/index.js.map +1 -1
  42. package/dist/internal.cjs +46 -40
  43. package/dist/internal.cjs.map +1 -1
  44. package/dist/internal.d.cts +3 -3
  45. package/dist/internal.d.ts +3 -3
  46. package/dist/internal.js +3 -3
  47. package/dist/sqlite-wasm-channel-GGHA2BXU.js +12 -0
  48. package/dist/{sqlite-wasm-channel-DUDPclTE.d.cts → sqlite-wasm-channel-L6o3bWQK.d.cts} +1 -1
  49. package/dist/{sqlite-wasm-channel-DUDPclTE.d.ts → sqlite-wasm-channel-L6o3bWQK.d.ts} +1 -1
  50. package/dist/{types-5h4Hqcwc.d.ts → types-BOO9EPt1.d.ts} +1 -1
  51. package/dist/{types-k6AZgiH4.d.ts → types-BslDOTk0.d.cts} +26 -1
  52. package/dist/{types-k6AZgiH4.d.cts → types-BslDOTk0.d.ts} +26 -1
  53. package/dist/{types-DfPiPwKr.d.cts → types-C_GDavG-.d.cts} +1 -1
  54. package/package.json +2 -12
  55. package/dist/adapters/sqlite-wasm-shared-host.cjs +0 -68
  56. package/dist/adapters/sqlite-wasm-shared-host.cjs.map +0 -1
  57. package/dist/adapters/sqlite-wasm-shared-host.d.cts +0 -2
  58. package/dist/adapters/sqlite-wasm-shared-host.d.ts +0 -2
  59. package/dist/adapters/sqlite-wasm-shared-host.js +0 -66
  60. package/dist/adapters/sqlite-wasm-shared-host.js.map +0 -1
  61. package/dist/chunk-6NKLDBTY.js.map +0 -1
  62. package/dist/chunk-FFYA7J5H.js.map +0 -1
  63. package/dist/chunk-IOEFNHHP.js.map +0 -1
  64. package/dist/chunk-RBPVEAVM.js +0 -425
  65. package/dist/chunk-RBPVEAVM.js.map +0 -1
  66. package/dist/chunk-X57MWW35.js.map +0 -1
  67. package/dist/chunk-ZLWAYQEQ.js.map +0 -1
  68. package/dist/sqlite-wasm-channel-H43KEZLM.js +0 -12
  69. /package/dist/{backup-ZV4Y424B.js.map → backup-5S7K2Z35.js.map} +0 -0
  70. /package/dist/{export-audit-AJ7RORNK.js.map → export-audit-ODGQTQIK.js.map} +0 -0
  71. /package/dist/{sqlite-wasm-channel-H43KEZLM.js.map → sqlite-wasm-channel-GGHA2BXU.js.map} +0 -0
@@ -1,425 +0,0 @@
1
- import {
2
- Mutex
3
- } from "./chunk-TVJEC5S2.js";
4
- import {
5
- AdapterError,
6
- StoreNotOpenError,
7
- WorkerTimeoutError
8
- } from "./chunk-QL2XVZRN.js";
9
-
10
- // src/adapters/sqlite-wasm-adapter.ts
11
- import { generateFullDDL } from "@korajs/core";
12
-
13
- // src/multi-tab/shared-worker-bridge.ts
14
- var SW_REQUEST = "kora-sw-request";
15
- var SW_RESPONSE = "kora-sw-response";
16
- var SharedWorkerClientBridge = class {
17
- constructor(sharedWorker, dbName, workerUrl, timeoutMs = 3e4) {
18
- this.dbName = dbName;
19
- this.workerUrl = workerUrl;
20
- this.timeoutMs = timeoutMs;
21
- this.port = sharedWorker.port;
22
- this.port.start();
23
- this.port.addEventListener("message", (event) => {
24
- const data = event.data;
25
- if (data?.type !== SW_RESPONSE) {
26
- return;
27
- }
28
- const entry = this.pending.get(data.requestId);
29
- if (entry) {
30
- this.pending.delete(data.requestId);
31
- entry.resolve(data.response);
32
- }
33
- });
34
- }
35
- dbName;
36
- workerUrl;
37
- port;
38
- pending = /* @__PURE__ */ new Map();
39
- timeoutMs;
40
- terminated = false;
41
- async send(request) {
42
- if (this.terminated) {
43
- return {
44
- id: request.id,
45
- type: "error",
46
- message: "SharedWorker bridge terminated",
47
- code: "BRIDGE_TERMINATED"
48
- };
49
- }
50
- const requestId = crypto.randomUUID();
51
- const msg = {
52
- type: SW_REQUEST,
53
- requestId,
54
- dbName: this.dbName,
55
- workerUrl: this.workerUrl,
56
- request
57
- };
58
- return new Promise((resolve, reject) => {
59
- const timer = setTimeout(() => {
60
- this.pending.delete(requestId);
61
- reject(new WorkerTimeoutError(`shared-worker:${request.type}`, this.timeoutMs));
62
- }, this.timeoutMs);
63
- this.pending.set(requestId, {
64
- resolve: (response) => {
65
- clearTimeout(timer);
66
- resolve(response);
67
- },
68
- reject: (error) => {
69
- clearTimeout(timer);
70
- reject(error);
71
- }
72
- });
73
- this.port.postMessage(msg);
74
- });
75
- }
76
- terminate() {
77
- if (this.terminated) {
78
- return;
79
- }
80
- this.terminated = true;
81
- this.port.close();
82
- for (const [, entry] of this.pending) {
83
- entry.reject(new Error("SharedWorker bridge terminated"));
84
- }
85
- this.pending.clear();
86
- }
87
- };
88
-
89
- // src/multi-tab/tab-storage.ts
90
- var RPC_REQUEST = "kora-worker-request";
91
- var RPC_RESPONSE = "kora-worker-response";
92
- function isSharedWorkerStorageSupported() {
93
- return typeof globalThis !== "undefined" && typeof SharedWorker !== "undefined";
94
- }
95
- function isMultiTabStorageSupported() {
96
- return typeof globalThis !== "undefined" && typeof BroadcastChannel !== "undefined" && typeof navigator !== "undefined" && typeof navigator.locks?.request === "function";
97
- }
98
- async function acquireTabStorageSession(dbName) {
99
- const channelName = `kora-storage-${dbName}`;
100
- if (!isMultiTabStorageSupported()) {
101
- return { role: "leader", channelName };
102
- }
103
- return new Promise((resolve) => {
104
- let releaseHeld;
105
- void navigator.locks.request(
106
- `kora-leader-${dbName}`,
107
- { mode: "exclusive", ifAvailable: true },
108
- (lock) => {
109
- if (lock === null) {
110
- resolve({ role: "follower", channelName });
111
- return;
112
- }
113
- resolve({
114
- role: "leader",
115
- channelName,
116
- releaseLock: async () => {
117
- releaseHeld?.();
118
- }
119
- });
120
- return new Promise((release) => {
121
- releaseHeld = release;
122
- });
123
- }
124
- );
125
- });
126
- }
127
- function startLeaderRpcRelay(channelName, bridge) {
128
- const channel = new BroadcastChannel(channelName);
129
- const onMessage = (event) => {
130
- const data = event.data;
131
- if (data?.type !== RPC_REQUEST) {
132
- return;
133
- }
134
- void bridge.send(data.request).then((response) => {
135
- const msg = {
136
- type: RPC_RESPONSE,
137
- requestId: data.requestId,
138
- response
139
- };
140
- channel.postMessage(msg);
141
- }).catch((error) => {
142
- const message = error instanceof Error ? error.message : "Worker RPC failed";
143
- const msg = {
144
- type: RPC_RESPONSE,
145
- requestId: data.requestId,
146
- response: {
147
- id: data.request.id,
148
- type: "error",
149
- message,
150
- code: "LEADER_RPC_ERROR"
151
- }
152
- };
153
- channel.postMessage(msg);
154
- });
155
- };
156
- channel.addEventListener("message", onMessage);
157
- return () => {
158
- channel.removeEventListener("message", onMessage);
159
- channel.close();
160
- };
161
- }
162
- var FollowerBroadcastBridge = class {
163
- channel;
164
- pending = /* @__PURE__ */ new Map();
165
- timeoutMs;
166
- terminated = false;
167
- constructor(channelName, timeoutMs = 3e4) {
168
- this.timeoutMs = timeoutMs;
169
- this.channel = new BroadcastChannel(channelName);
170
- this.channel.addEventListener("message", (event) => {
171
- const data = event.data;
172
- if (data?.type !== RPC_RESPONSE) {
173
- return;
174
- }
175
- const entry = this.pending.get(data.requestId);
176
- if (entry) {
177
- this.pending.delete(data.requestId);
178
- entry.resolve(data.response);
179
- }
180
- });
181
- }
182
- async send(request) {
183
- if (this.terminated) {
184
- return {
185
- id: request.id,
186
- type: "error",
187
- message: "Follower bridge terminated",
188
- code: "BRIDGE_TERMINATED"
189
- };
190
- }
191
- const requestId = crypto.randomUUID();
192
- const msg = { type: RPC_REQUEST, requestId, request };
193
- return new Promise((resolve, reject) => {
194
- const timer = setTimeout(() => {
195
- this.pending.delete(requestId);
196
- reject(new WorkerTimeoutError(`follower-rpc:${request.type}`, this.timeoutMs));
197
- }, this.timeoutMs);
198
- this.pending.set(requestId, {
199
- resolve: (response) => {
200
- clearTimeout(timer);
201
- resolve(response);
202
- },
203
- reject: (error) => {
204
- clearTimeout(timer);
205
- reject(error);
206
- }
207
- });
208
- this.channel.postMessage(msg);
209
- });
210
- }
211
- terminate() {
212
- if (this.terminated) {
213
- return;
214
- }
215
- this.terminated = true;
216
- this.channel.close();
217
- for (const [, entry] of this.pending) {
218
- entry.reject(new Error("Follower bridge terminated"));
219
- }
220
- this.pending.clear();
221
- }
222
- };
223
-
224
- // src/adapters/sqlite-wasm-adapter.ts
225
- var SqliteWasmAdapter = class {
226
- bridge = null;
227
- opened = false;
228
- mutex = new Mutex();
229
- injectedBridge;
230
- workerUrl;
231
- sharedWorkerUrl;
232
- workerResponseTimeoutMs;
233
- dbName;
234
- tabSession = null;
235
- sharedWorker = null;
236
- constructor(options = {}) {
237
- this.injectedBridge = options.bridge;
238
- this.workerUrl = options.workerUrl;
239
- this.sharedWorkerUrl = options.sharedWorkerUrl;
240
- this.workerResponseTimeoutMs = options.workerResponseTimeoutMs ?? 3e4;
241
- this.dbName = options.dbName ?? "kora-db";
242
- }
243
- async open(schema) {
244
- if (this.opened) return;
245
- if (this.injectedBridge) {
246
- this.bridge = this.injectedBridge;
247
- } else if (this.sharedWorkerUrl && this.workerUrl && isSharedWorkerStorageSupported()) {
248
- const workerUrlString = typeof this.workerUrl === "string" ? this.workerUrl : this.workerUrl.href;
249
- const sharedUrl = typeof this.sharedWorkerUrl === "string" ? this.sharedWorkerUrl : this.sharedWorkerUrl.href;
250
- this.sharedWorker = new SharedWorker(sharedUrl, { name: `kora-sw-${this.dbName}` });
251
- this.bridge = new SharedWorkerClientBridge(this.sharedWorker, this.dbName, workerUrlString);
252
- } else if (this.workerUrl) {
253
- this.tabSession = await acquireTabStorageSession(this.dbName);
254
- const { WebWorkerBridge } = await import("./sqlite-wasm-channel-H43KEZLM.js");
255
- if (this.tabSession.role === "leader") {
256
- const workerBridge = new WebWorkerBridge(this.workerUrl, this.workerResponseTimeoutMs);
257
- this.tabSession.stopRelay = startLeaderRpcRelay(this.tabSession.channelName, workerBridge);
258
- this.bridge = workerBridge;
259
- } else {
260
- this.bridge = new FollowerBroadcastBridge(
261
- this.tabSession.channelName,
262
- this.workerResponseTimeoutMs
263
- );
264
- }
265
- } else {
266
- throw new AdapterError(
267
- 'SqliteWasmAdapter requires either a bridge (for testing) or a workerUrl (for browsers). Pass { bridge: new MockWorkerBridge() } for tests, or { workerUrl: "/worker.js" } for browsers.'
268
- );
269
- }
270
- const ddlStatements = generateFullDDL(schema);
271
- const response = await this.sendRequest({
272
- id: 0,
273
- type: "open",
274
- ddlStatements,
275
- dbName: this.dbName
276
- });
277
- if (response.type === "error") {
278
- throw new AdapterError(`Failed to open database: ${response.message}`, {
279
- code: response.code,
280
- dbName: this.dbName
281
- });
282
- }
283
- this.opened = true;
284
- }
285
- async close() {
286
- if (!this.bridge) return;
287
- try {
288
- await this.sendRequest({ id: 0, type: "close" });
289
- } finally {
290
- this.tabSession?.stopRelay?.();
291
- if (this.tabSession?.releaseLock) {
292
- await this.tabSession.releaseLock();
293
- }
294
- this.tabSession = null;
295
- this.sharedWorker = null;
296
- this.bridge.terminate();
297
- this.bridge = null;
298
- this.opened = false;
299
- }
300
- }
301
- async execute(sql, params) {
302
- this.guardOpen();
303
- const response = await this.sendRequest({ id: 0, type: "execute", sql, params });
304
- if (response.type === "error") {
305
- throw new AdapterError(`Execute failed: ${response.message}`, { sql, params });
306
- }
307
- }
308
- async query(sql, params) {
309
- this.guardOpen();
310
- const response = await this.sendRequest({ id: 0, type: "query", sql, params });
311
- if (response.type === "error") {
312
- throw new AdapterError(`Query failed: ${response.message}`, { sql, params });
313
- }
314
- return response.data ?? [];
315
- }
316
- async transaction(fn) {
317
- this.guardOpen();
318
- const release = await this.mutex.acquire();
319
- try {
320
- await this.sendChecked({ id: 0, type: "begin" }, "BEGIN transaction");
321
- const tx = {
322
- execute: async (sql, params) => {
323
- const response = await this.sendRequest({ id: 0, type: "execute", sql, params });
324
- if (response.type === "error") {
325
- throw new AdapterError(`Transaction execute failed: ${response.message}`, {
326
- sql,
327
- params
328
- });
329
- }
330
- },
331
- query: async (sql, params) => {
332
- const response = await this.sendRequest({ id: 0, type: "query", sql, params });
333
- if (response.type === "error") {
334
- throw new AdapterError(`Transaction query failed: ${response.message}`, { sql, params });
335
- }
336
- return response.data ?? [];
337
- }
338
- };
339
- await fn(tx);
340
- await this.sendChecked({ id: 0, type: "commit" }, "COMMIT transaction");
341
- } catch (error) {
342
- try {
343
- await this.sendRequest({ id: 0, type: "rollback" });
344
- } catch {
345
- }
346
- throw error;
347
- } finally {
348
- release();
349
- }
350
- }
351
- async migrate(from, to, migration) {
352
- this.guardOpen();
353
- const release = await this.mutex.acquire();
354
- try {
355
- await this.sendChecked({ id: 0, type: "begin" }, "BEGIN migration");
356
- for (const sql of migration.statements) {
357
- const response = await this.sendRequest({ id: 0, type: "execute", sql });
358
- if (response.type === "error") {
359
- throw new AdapterError(`Migration from v${from} to v${to} failed: ${response.message}`, {
360
- from,
361
- to
362
- });
363
- }
364
- }
365
- await this.sendChecked({ id: 0, type: "commit" }, "COMMIT migration");
366
- } catch (error) {
367
- try {
368
- await this.sendRequest({ id: 0, type: "rollback" });
369
- } catch {
370
- }
371
- if (error instanceof AdapterError) throw error;
372
- throw new AdapterError(
373
- `Migration from v${from} to v${to} failed: ${error.message}`,
374
- { from, to }
375
- );
376
- } finally {
377
- release();
378
- }
379
- }
380
- /**
381
- * Export the database as a Uint8Array (for IndexedDB persistence).
382
- * Only available when the database is open.
383
- */
384
- async exportDatabase() {
385
- this.guardOpen();
386
- const response = await this.sendRequest({ id: 0, type: "export" });
387
- if (response.type === "error") {
388
- throw new AdapterError(`Export failed: ${response.message}`);
389
- }
390
- return response.data;
391
- }
392
- /**
393
- * Import a serialized database snapshot.
394
- */
395
- async importDatabase(data) {
396
- this.guardOpen();
397
- const response = await this.sendRequest({ id: 0, type: "import", data });
398
- if (response.type === "error") {
399
- throw new AdapterError(`Import failed: ${response.message}`);
400
- }
401
- }
402
- guardOpen() {
403
- if (!this.opened || !this.bridge) {
404
- throw new StoreNotOpenError();
405
- }
406
- }
407
- async sendRequest(request) {
408
- const bridge = this.bridge;
409
- if (!bridge) {
410
- throw new StoreNotOpenError();
411
- }
412
- return bridge.send(request);
413
- }
414
- async sendChecked(request, description) {
415
- const response = await this.sendRequest(request);
416
- if (response.type === "error") {
417
- throw new AdapterError(`${description} failed: ${response.message}`);
418
- }
419
- }
420
- };
421
-
422
- export {
423
- SqliteWasmAdapter
424
- };
425
- //# sourceMappingURL=chunk-RBPVEAVM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/sqlite-wasm-adapter.ts","../src/multi-tab/shared-worker-bridge.ts","../src/multi-tab/tab-storage.ts"],"sourcesContent":["import { generateFullDDL } from '@korajs/core'\nimport type { SchemaDefinition } from '@korajs/core'\nimport { AdapterError, StoreNotOpenError } from '../errors'\nimport { SharedWorkerClientBridge } from '../multi-tab/shared-worker-bridge'\nimport {\n\tFollowerBroadcastBridge,\n\tacquireTabStorageSession,\n\tisSharedWorkerStorageSupported,\n\tstartLeaderRpcRelay,\n} from '../multi-tab/tab-storage'\nimport type { MigrationPlan, StorageAdapter, Transaction } from '../types'\nimport { Mutex } from './sqlite-wasm-channel'\nimport type { WorkerBridge, WorkerRequest, WorkerResponse } from './sqlite-wasm-channel'\n\n/**\n * Options for creating a SqliteWasmAdapter.\n */\nexport interface SqliteWasmAdapterOptions {\n\t/**\n\t * Injected WorkerBridge for testing. If omitted, a WebWorkerBridge is created\n\t * in browser environments.\n\t */\n\tbridge?: WorkerBridge\n\n\t/**\n\t * Database name for persistence. Used as the OPFS file name or IDB key.\n\t */\n\tdbName?: string\n\n\t/**\n\t * URL to the sqlite-wasm-worker script. Required in browsers if no bridge is provided.\n\t */\n\tworkerUrl?: string | URL\n\n\t/** Timeout for worker / follower RPC responses. Defaults to 30000ms. */\n\tworkerResponseTimeoutMs?: number\n\n\t/**\n\t * Optional SharedWorker host script (`sqlite-wasm-shared-host`). When set and\n\t * {@link isSharedWorkerStorageSupported}, one DedicatedWorker per `dbName` is pooled per origin.\n\t * Requires `workerUrl` for the inner SQLite worker. Falls back to leader election when omitted.\n\t */\n\tsharedWorkerUrl?: string | URL\n}\n\n/**\n * SQLite WASM adapter that communicates with a SQLite instance through a WorkerBridge.\n *\n * In browsers, the bridge is backed by a Web Worker running SQLite WASM with OPFS persistence.\n * In Node.js tests, the bridge is backed by MockWorkerBridge wrapping better-sqlite3.\n *\n * @example\n * ```typescript\n * // Browser usage\n * const adapter = new SqliteWasmAdapter({ workerUrl: '/sqlite-wasm-worker.js' })\n *\n * // Test usage with MockWorkerBridge\n * import { MockWorkerBridge } from './sqlite-wasm-mock-bridge'\n * const adapter = new SqliteWasmAdapter({ bridge: new MockWorkerBridge() })\n * ```\n */\nexport class SqliteWasmAdapter implements StorageAdapter {\n\tprivate bridge: WorkerBridge | null = null\n\tprivate opened = false\n\tprivate readonly mutex = new Mutex()\n\tprivate readonly injectedBridge: WorkerBridge | undefined\n\tprivate readonly workerUrl: string | URL | undefined\n\tprivate readonly sharedWorkerUrl: string | URL | undefined\n\tprivate readonly workerResponseTimeoutMs: number\n\tprivate readonly dbName: string\n\tprivate tabSession: Awaited<ReturnType<typeof acquireTabStorageSession>> | null = null\n\tprivate sharedWorker: SharedWorker | null = null\n\n\tconstructor(options: SqliteWasmAdapterOptions = {}) {\n\t\tthis.injectedBridge = options.bridge\n\t\tthis.workerUrl = options.workerUrl\n\t\tthis.sharedWorkerUrl = options.sharedWorkerUrl\n\t\tthis.workerResponseTimeoutMs = options.workerResponseTimeoutMs ?? 30_000\n\t\tthis.dbName = options.dbName ?? 'kora-db'\n\t}\n\n\tasync open(schema: SchemaDefinition): Promise<void> {\n\t\tif (this.opened) return\n\n\t\tif (this.injectedBridge) {\n\t\t\tthis.bridge = this.injectedBridge\n\t\t} else if (this.sharedWorkerUrl && this.workerUrl && isSharedWorkerStorageSupported()) {\n\t\t\tconst workerUrlString =\n\t\t\t\ttypeof this.workerUrl === 'string' ? this.workerUrl : this.workerUrl.href\n\t\t\tconst sharedUrl =\n\t\t\t\ttypeof this.sharedWorkerUrl === 'string' ? this.sharedWorkerUrl : this.sharedWorkerUrl.href\n\t\t\tthis.sharedWorker = new SharedWorker(sharedUrl, { name: `kora-sw-${this.dbName}` })\n\t\t\tthis.bridge = new SharedWorkerClientBridge(this.sharedWorker, this.dbName, workerUrlString)\n\t\t} else if (this.workerUrl) {\n\t\t\tthis.tabSession = await acquireTabStorageSession(this.dbName)\n\t\t\tconst { WebWorkerBridge } = await import('./sqlite-wasm-channel')\n\n\t\t\tif (this.tabSession.role === 'leader') {\n\t\t\t\tconst workerBridge = new WebWorkerBridge(this.workerUrl, this.workerResponseTimeoutMs)\n\t\t\t\tthis.tabSession.stopRelay = startLeaderRpcRelay(this.tabSession.channelName, workerBridge)\n\t\t\t\tthis.bridge = workerBridge\n\t\t\t} else {\n\t\t\t\tthis.bridge = new FollowerBroadcastBridge(\n\t\t\t\t\tthis.tabSession.channelName,\n\t\t\t\t\tthis.workerResponseTimeoutMs,\n\t\t\t\t)\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new AdapterError(\n\t\t\t\t'SqliteWasmAdapter requires either a bridge (for testing) or a workerUrl (for browsers). ' +\n\t\t\t\t\t'Pass { bridge: new MockWorkerBridge() } for tests, or { workerUrl: \"/worker.js\" } for browsers.',\n\t\t\t)\n\t\t}\n\n\t\tconst ddlStatements = generateFullDDL(schema)\n\t\tconst response = await this.sendRequest({\n\t\t\tid: 0,\n\t\t\ttype: 'open',\n\t\t\tddlStatements,\n\t\t\tdbName: this.dbName,\n\t\t})\n\t\tif (response.type === 'error') {\n\t\t\tthrow new AdapterError(`Failed to open database: ${response.message}`, {\n\t\t\t\tcode: response.code,\n\t\t\t\tdbName: this.dbName,\n\t\t\t})\n\t\t}\n\t\tthis.opened = true\n\t}\n\n\tasync close(): Promise<void> {\n\t\tif (!this.bridge) return\n\n\t\ttry {\n\t\t\tawait this.sendRequest({ id: 0, type: 'close' })\n\t\t} finally {\n\t\t\tthis.tabSession?.stopRelay?.()\n\t\t\tif (this.tabSession?.releaseLock) {\n\t\t\t\tawait this.tabSession.releaseLock()\n\t\t\t}\n\t\t\tthis.tabSession = null\n\t\t\tthis.sharedWorker = null\n\t\t\tthis.bridge.terminate()\n\t\t\tthis.bridge = null\n\t\t\tthis.opened = false\n\t\t}\n\t}\n\n\tasync execute(sql: string, params?: unknown[]): Promise<void> {\n\t\tthis.guardOpen()\n\t\tconst response = await this.sendRequest({ id: 0, type: 'execute', sql, params })\n\t\tif (response.type === 'error') {\n\t\t\tthrow new AdapterError(`Execute failed: ${response.message}`, { sql, params })\n\t\t}\n\t}\n\n\tasync query<T>(sql: string, params?: unknown[]): Promise<T[]> {\n\t\tthis.guardOpen()\n\t\tconst response = await this.sendRequest({ id: 0, type: 'query', sql, params })\n\t\tif (response.type === 'error') {\n\t\t\tthrow new AdapterError(`Query failed: ${response.message}`, { sql, params })\n\t\t}\n\t\treturn (response.data as T[]) ?? []\n\t}\n\n\tasync transaction(fn: (tx: Transaction) => Promise<void>): Promise<void> {\n\t\tthis.guardOpen()\n\n\t\tconst release = await this.mutex.acquire()\n\t\ttry {\n\t\t\tawait this.sendChecked({ id: 0, type: 'begin' }, 'BEGIN transaction')\n\n\t\t\tconst tx: Transaction = {\n\t\t\t\texecute: async (sql: string, params?: unknown[]): Promise<void> => {\n\t\t\t\t\tconst response = await this.sendRequest({ id: 0, type: 'execute', sql, params })\n\t\t\t\t\tif (response.type === 'error') {\n\t\t\t\t\t\tthrow new AdapterError(`Transaction execute failed: ${response.message}`, {\n\t\t\t\t\t\t\tsql,\n\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tquery: async <T>(sql: string, params?: unknown[]): Promise<T[]> => {\n\t\t\t\t\tconst response = await this.sendRequest({ id: 0, type: 'query', sql, params })\n\t\t\t\t\tif (response.type === 'error') {\n\t\t\t\t\t\tthrow new AdapterError(`Transaction query failed: ${response.message}`, { sql, params })\n\t\t\t\t\t}\n\t\t\t\t\treturn (response.data as T[]) ?? []\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tawait fn(tx)\n\t\t\tawait this.sendChecked({ id: 0, type: 'commit' }, 'COMMIT transaction')\n\t\t} catch (error) {\n\t\t\t// Attempt rollback, but don't mask the original error\n\t\t\ttry {\n\t\t\t\tawait this.sendRequest({ id: 0, type: 'rollback' })\n\t\t\t} catch {\n\t\t\t\t// Rollback failure is secondary to the original error\n\t\t\t}\n\t\t\tthrow error\n\t\t} finally {\n\t\t\trelease()\n\t\t}\n\t}\n\n\tasync migrate(from: number, to: number, migration: MigrationPlan): Promise<void> {\n\t\tthis.guardOpen()\n\n\t\tconst release = await this.mutex.acquire()\n\t\ttry {\n\t\t\tawait this.sendChecked({ id: 0, type: 'begin' }, 'BEGIN migration')\n\n\t\t\tfor (const sql of migration.statements) {\n\t\t\t\tconst response = await this.sendRequest({ id: 0, type: 'execute', sql })\n\t\t\t\tif (response.type === 'error') {\n\t\t\t\t\tthrow new AdapterError(`Migration from v${from} to v${to} failed: ${response.message}`, {\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.sendChecked({ id: 0, type: 'commit' }, 'COMMIT migration')\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait this.sendRequest({ id: 0, type: 'rollback' })\n\t\t\t} catch {\n\t\t\t\t// Rollback failure is secondary\n\t\t\t}\n\t\t\tif (error instanceof AdapterError) throw error\n\t\t\tthrow new AdapterError(\n\t\t\t\t`Migration from v${from} to v${to} failed: ${(error as Error).message}`,\n\t\t\t\t{ from, to },\n\t\t\t)\n\t\t} finally {\n\t\t\trelease()\n\t\t}\n\t}\n\n\t/**\n\t * Export the database as a Uint8Array (for IndexedDB persistence).\n\t * Only available when the database is open.\n\t */\n\tasync exportDatabase(): Promise<Uint8Array> {\n\t\tthis.guardOpen()\n\t\tconst response = await this.sendRequest({ id: 0, type: 'export' })\n\t\tif (response.type === 'error') {\n\t\t\tthrow new AdapterError(`Export failed: ${response.message}`)\n\t\t}\n\t\treturn response.data as Uint8Array\n\t}\n\n\t/**\n\t * Import a serialized database snapshot.\n\t */\n\tasync importDatabase(data: Uint8Array): Promise<void> {\n\t\tthis.guardOpen()\n\t\tconst response = await this.sendRequest({ id: 0, type: 'import', data })\n\t\tif (response.type === 'error') {\n\t\t\tthrow new AdapterError(`Import failed: ${response.message}`)\n\t\t}\n\t}\n\n\tprivate guardOpen(): void {\n\t\tif (!this.opened || !this.bridge) {\n\t\t\tthrow new StoreNotOpenError()\n\t\t}\n\t}\n\n\tprivate async sendRequest(request: WorkerRequest): Promise<WorkerResponse> {\n\t\t// guardOpen() is always called before sendRequest, so bridge is guaranteed non-null\n\t\tconst bridge = this.bridge\n\t\tif (!bridge) {\n\t\t\tthrow new StoreNotOpenError()\n\t\t}\n\t\treturn bridge.send(request)\n\t}\n\n\tprivate async sendChecked(request: WorkerRequest, description: string): Promise<void> {\n\t\tconst response = await this.sendRequest(request)\n\t\tif (response.type === 'error') {\n\t\t\tthrow new AdapterError(`${description} failed: ${response.message}`)\n\t\t}\n\t}\n}\n","/// <reference lib=\"dom\" />\nimport type { WorkerBridge, WorkerRequest, WorkerResponse } from '../adapters/sqlite-wasm-channel'\nimport { WorkerTimeoutError } from '../errors'\n\nconst SW_REQUEST = 'kora-sw-request'\nconst SW_RESPONSE = 'kora-sw-response'\n\nexport interface SharedWorkerRpcRequest {\n\ttype: typeof SW_REQUEST\n\trequestId: string\n\tdbName: string\n\tworkerUrl: string\n\trequest: WorkerRequest\n}\n\nexport interface SharedWorkerRpcResponse {\n\ttype: typeof SW_RESPONSE\n\trequestId: string\n\tresponse: WorkerResponse\n}\n\n/**\n * Forwards {@link WorkerBridge} RPC to a SharedWorker that hosts one DedicatedWorker per `dbName`.\n * Pair with the bundled `sqlite-wasm-shared-host` worker script.\n */\nexport class SharedWorkerClientBridge implements WorkerBridge {\n\tprivate readonly port: MessagePort\n\tprivate readonly pending = new Map<\n\t\tstring,\n\t\t{ resolve: (r: WorkerResponse) => void; reject: (e: Error) => void }\n\t>()\n\tprivate readonly timeoutMs: number\n\tprivate terminated = false\n\n\tconstructor(\n\t\tsharedWorker: SharedWorker,\n\t\tprivate readonly dbName: string,\n\t\tprivate readonly workerUrl: string,\n\t\ttimeoutMs = 30000,\n\t) {\n\t\tthis.timeoutMs = timeoutMs\n\t\tthis.port = sharedWorker.port\n\t\tthis.port.start()\n\t\tthis.port.addEventListener('message', (event: MessageEvent<SharedWorkerRpcResponse>) => {\n\t\t\tconst data = event.data\n\t\t\tif (data?.type !== SW_RESPONSE) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst entry = this.pending.get(data.requestId)\n\t\t\tif (entry) {\n\t\t\t\tthis.pending.delete(data.requestId)\n\t\t\t\tentry.resolve(data.response)\n\t\t\t}\n\t\t})\n\t}\n\n\tasync send(request: WorkerRequest): Promise<WorkerResponse> {\n\t\tif (this.terminated) {\n\t\t\treturn {\n\t\t\t\tid: request.id,\n\t\t\t\ttype: 'error',\n\t\t\t\tmessage: 'SharedWorker bridge terminated',\n\t\t\t\tcode: 'BRIDGE_TERMINATED',\n\t\t\t}\n\t\t}\n\n\t\tconst requestId = crypto.randomUUID()\n\t\tconst msg: SharedWorkerRpcRequest = {\n\t\t\ttype: SW_REQUEST,\n\t\t\trequestId,\n\t\t\tdbName: this.dbName,\n\t\t\tworkerUrl: this.workerUrl,\n\t\t\trequest,\n\t\t}\n\n\t\treturn new Promise<WorkerResponse>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.pending.delete(requestId)\n\t\t\t\treject(new WorkerTimeoutError(`shared-worker:${request.type}`, this.timeoutMs))\n\t\t\t}, this.timeoutMs)\n\n\t\t\tthis.pending.set(requestId, {\n\t\t\t\tresolve: (response) => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\tresolve(response)\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\treject(error)\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tthis.port.postMessage(msg)\n\t\t})\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) {\n\t\t\treturn\n\t\t}\n\t\tthis.terminated = true\n\t\tthis.port.close()\n\t\tfor (const [, entry] of this.pending) {\n\t\t\tentry.reject(new Error('SharedWorker bridge terminated'))\n\t\t}\n\t\tthis.pending.clear()\n\t}\n}\n","/**\n * Multi-tab SQLite storage coordination via `navigator.locks` and `BroadcastChannel`.\n *\n * One tab holds the exclusive `kora-leader-${dbName}` lock and owns the SQLite worker.\n * Other tabs send worker RPC over a named broadcast channel.\n */\n\nimport type { WorkerBridge, WorkerRequest, WorkerResponse } from '../adapters/sqlite-wasm-channel'\nimport { WorkerTimeoutError } from '../errors'\n\nconst RPC_REQUEST = 'kora-worker-request'\nconst RPC_RESPONSE = 'kora-worker-response'\n\ninterface RpcRequestMessage {\n\ttype: typeof RPC_REQUEST\n\trequestId: string\n\trequest: WorkerRequest\n}\n\ninterface RpcResponseMessage {\n\ttype: typeof RPC_RESPONSE\n\trequestId: string\n\tresponse: WorkerResponse\n}\n\nexport type TabStorageRole = 'leader' | 'follower'\n\nexport interface TabStorageSession {\n\trole: TabStorageRole\n\tchannelName: string\n\t/** Leader only: release the navigator lock when closing the database. */\n\treleaseLock?: () => Promise<void>\n\t/** Leader only: stop the broadcast RPC relay. */\n\tstopRelay?: () => void\n}\n\n/**\n * Returns whether a SharedWorker could host a single SQLite WASM instance per origin.\n * Not implemented yet — use {@link isMultiTabStorageSupported} + leader election today.\n */\nexport function isSharedWorkerStorageSupported(): boolean {\n\treturn typeof globalThis !== 'undefined' && typeof SharedWorker !== 'undefined'\n}\n\n/**\n * Returns whether multi-tab coordination APIs exist in this runtime.\n */\nexport function isMultiTabStorageSupported(): boolean {\n\treturn (\n\t\ttypeof globalThis !== 'undefined' &&\n\t\ttypeof BroadcastChannel !== 'undefined' &&\n\t\ttypeof navigator !== 'undefined' &&\n\t\ttypeof navigator.locks?.request === 'function'\n\t)\n}\n\n/**\n * Resolve leader vs follower for a database name.\n * Without lock APIs, every instance is treated as leader (single-tab / Node).\n */\nexport async function acquireTabStorageSession(dbName: string): Promise<TabStorageSession> {\n\tconst channelName = `kora-storage-${dbName}`\n\n\tif (!isMultiTabStorageSupported()) {\n\t\treturn { role: 'leader', channelName }\n\t}\n\n\treturn new Promise<TabStorageSession>((resolve) => {\n\t\tlet releaseHeld: (() => void) | undefined\n\n\t\tvoid navigator.locks.request(\n\t\t\t`kora-leader-${dbName}`,\n\t\t\t{ mode: 'exclusive', ifAvailable: true },\n\t\t\t(lock) => {\n\t\t\t\tif (lock === null) {\n\t\t\t\t\tresolve({ role: 'follower', channelName })\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tresolve({\n\t\t\t\t\trole: 'leader',\n\t\t\t\t\tchannelName,\n\t\t\t\t\treleaseLock: async () => {\n\t\t\t\t\t\treleaseHeld?.()\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t\treturn new Promise<void>((release) => {\n\t\t\t\t\treleaseHeld = release\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\t})\n}\n\n/**\n * Leader tab: forward follower RPC to the real worker bridge.\n */\nexport function startLeaderRpcRelay(channelName: string, bridge: WorkerBridge): () => void {\n\tconst channel = new BroadcastChannel(channelName)\n\n\tconst onMessage = (event: MessageEvent<RpcRequestMessage>): void => {\n\t\tconst data = event.data\n\t\tif (data?.type !== RPC_REQUEST) {\n\t\t\treturn\n\t\t}\n\n\t\tvoid bridge\n\t\t\t.send(data.request)\n\t\t\t.then((response) => {\n\t\t\t\tconst msg: RpcResponseMessage = {\n\t\t\t\t\ttype: RPC_RESPONSE,\n\t\t\t\t\trequestId: data.requestId,\n\t\t\t\t\tresponse,\n\t\t\t\t}\n\t\t\t\tchannel.postMessage(msg)\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tconst message = error instanceof Error ? error.message : 'Worker RPC failed'\n\t\t\t\tconst msg: RpcResponseMessage = {\n\t\t\t\t\ttype: RPC_RESPONSE,\n\t\t\t\t\trequestId: data.requestId,\n\t\t\t\t\tresponse: {\n\t\t\t\t\t\tid: data.request.id,\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t\tcode: 'LEADER_RPC_ERROR',\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tchannel.postMessage(msg)\n\t\t\t})\n\t}\n\n\tchannel.addEventListener('message', onMessage)\n\treturn () => {\n\t\tchannel.removeEventListener('message', onMessage)\n\t\tchannel.close()\n\t}\n}\n\n/**\n * Follower tab: proxy {@link WorkerBridge} over BroadcastChannel to the leader.\n */\nexport class FollowerBroadcastBridge implements WorkerBridge {\n\tprivate readonly channel: BroadcastChannel\n\tprivate readonly pending = new Map<\n\t\tstring,\n\t\t{ resolve: (r: WorkerResponse) => void; reject: (e: Error) => void }\n\t>()\n\tprivate readonly timeoutMs: number\n\tprivate terminated = false\n\n\tconstructor(channelName: string, timeoutMs = 30000) {\n\t\tthis.timeoutMs = timeoutMs\n\t\tthis.channel = new BroadcastChannel(channelName)\n\t\tthis.channel.addEventListener('message', (event: MessageEvent<RpcResponseMessage>) => {\n\t\t\tconst data = event.data\n\t\t\tif (data?.type !== RPC_RESPONSE) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst entry = this.pending.get(data.requestId)\n\t\t\tif (entry) {\n\t\t\t\tthis.pending.delete(data.requestId)\n\t\t\t\tentry.resolve(data.response)\n\t\t\t}\n\t\t})\n\t}\n\n\tasync send(request: WorkerRequest): Promise<WorkerResponse> {\n\t\tif (this.terminated) {\n\t\t\treturn {\n\t\t\t\tid: request.id,\n\t\t\t\ttype: 'error',\n\t\t\t\tmessage: 'Follower bridge terminated',\n\t\t\t\tcode: 'BRIDGE_TERMINATED',\n\t\t\t}\n\t\t}\n\n\t\tconst requestId = crypto.randomUUID()\n\t\tconst msg: RpcRequestMessage = { type: RPC_REQUEST, requestId, request }\n\n\t\treturn new Promise<WorkerResponse>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.pending.delete(requestId)\n\t\t\t\treject(new WorkerTimeoutError(`follower-rpc:${request.type}`, this.timeoutMs))\n\t\t\t}, this.timeoutMs)\n\n\t\t\tthis.pending.set(requestId, {\n\t\t\t\tresolve: (response) => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\tresolve(response)\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\treject(error)\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tthis.channel.postMessage(msg)\n\t\t})\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) {\n\t\t\treturn\n\t\t}\n\t\tthis.terminated = true\n\t\tthis.channel.close()\n\t\tfor (const [, entry] of this.pending) {\n\t\t\tentry.reject(new Error('Follower bridge terminated'))\n\t\t}\n\t\tthis.pending.clear()\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/backup/backup.ts"],"sourcesContent":["import { generateUUIDv7 } from '@korajs/core'\nimport type { Operation, SchemaDefinition, VersionVector } from '@korajs/core'\nimport { deserializeOperationWithCollection } from '../serialization/serializer'\nimport type { OperationRow, StorageAdapter } from '../types'\nimport type {\n\tBackupManifest,\n\tBackupOptions,\n\tBackupProgress,\n\tRestoreOptions,\n\tRestoreResult,\n} from './types'\n\n// ── Section I/O helpers ──────────────────────────────────────────────────────\n\nfunction encodeSection(name: string, content: Uint8Array): Uint8Array {\n\tconst nameBytes = new TextEncoder().encode(name)\n\tconst header = new Uint8Array(8)\n\tconst dv = new DataView(header.buffer)\n\tdv.setUint32(0, nameBytes.length, true)\n\tdv.setUint32(4, content.length, true)\n\n\tconst result = new Uint8Array(header.length + nameBytes.length + content.length)\n\tresult.set(header, 0)\n\tresult.set(nameBytes, 8)\n\tresult.set(content, 8 + nameBytes.length)\n\treturn result\n}\n\nfunction encodeJsonSection(name: string, data: unknown): Uint8Array {\n\tconst json = JSON.stringify(data)\n\treturn encodeSection(name, new TextEncoder().encode(json))\n}\n\nfunction encodeNdjsonSection(name: string, records: unknown[]): Uint8Array {\n\tconst lines = `${records.map((r) => JSON.stringify(r)).join('\\n')}\\n`\n\treturn encodeSection(name, new TextEncoder().encode(lines))\n}\n\nfunction readUint32(view: DataView, offset: number): number {\n\treturn view.getUint32(offset, true)\n}\n\ninterface Section {\n\tname: string\n\tcontent: Uint8Array\n}\n\nfunction parseSections(data: Uint8Array): Section[] {\n\tconst sections: Section[] = []\n\tconst dv = new DataView(data.buffer, data.byteOffset, data.byteLength)\n\tlet offset = 0\n\n\twhile (offset + 8 <= data.byteLength) {\n\t\tconst nameLen = readUint32(dv, offset)\n\t\tconst contentLen = readUint32(dv, offset + 4)\n\t\toffset += 8\n\n\t\tif (offset + nameLen + contentLen > data.byteLength) break\n\n\t\tconst name = new TextDecoder().decode(data.slice(offset, offset + nameLen))\n\t\toffset += nameLen\n\n\t\tconst content = data.slice(offset, offset + contentLen)\n\t\toffset += contentLen\n\n\t\tsections.push({ name, content })\n\t}\n\n\treturn sections\n}\n\nfunction findSection(sections: Section[], name: string): Uint8Array | null {\n\tfor (const s of sections) {\n\t\tif (s.name === name) return s.content\n\t}\n\treturn null\n}\n\nfunction parseJsonSection<T>(sections: Section[], name: string): T | null {\n\tconst content = findSection(sections, name)\n\tif (!content) return null\n\treturn JSON.parse(new TextDecoder().decode(content)) as T\n}\n\n/**\n * Export format version. Bump on breaking changes.\n */\nconst BACKUP_VERSION = 1\n\n/**\n * Export a backup from a store.\n *\n * Reads all data via the adapter and produces a portable binary backup.\n *\n * @param adapter - The storage adapter\n * @param schema - The schema definition\n * @param nodeId - Current node ID\n * @param schemaVersion - Schema version\n * @param options - Backup options\n * @returns Backup as a Uint8Array\n */\nexport async function exportBackup(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\tnodeId: string,\n\tschemaVersion: number,\n\toptions?: BackupOptions,\n): Promise<Uint8Array> {\n\tconst onProgress = options?.onProgress ?? (() => {})\n\tconst includeRecords = options?.includeRecords ?? true\n\tconst collectionFilter = options?.collections\n\tconst collections = collectionFilter\n\t\t? Object.keys(schema.collections).filter((c) => collectionFilter.includes(c))\n\t\t: Object.keys(schema.collections)\n\n\tonProgress({ phase: 'reading', progress: 0, message: 'Reading version vector' })\n\tconst versionVector = await readVersionVector(adapter)\n\tonProgress({ phase: 'reading', progress: 0.1, message: 'Reading metadata' })\n\tconst meta = await readMeta(adapter)\n\tonProgress({ phase: 'reading', progress: 0.2, message: 'Reading operations' })\n\tconst operations = await readAllOperations(adapter, schema)\n\tonProgress({ phase: 'reading', progress: 0.5, message: 'Reading records' })\n\n\tconst sections: Uint8Array[] = []\n\tlet allContentForChecksum = new Uint8Array(0)\n\n\t// Helper: add a section and update running checksum content\n\tconst addSection = (name: string, data: Uint8Array) => {\n\t\tsections.push(data)\n\t\tconst newLen = allContentForChecksum.length + data.length\n\t\tconst combined = new Uint8Array(newLen)\n\t\tcombined.set(allContentForChecksum, 0)\n\t\tcombined.set(data, allContentForChecksum.length)\n\t\tallContentForChecksum = combined\n\t}\n\n\t// Version vector section\n\tconst vvObj: Record<string, number> = {}\n\tfor (const [nid, seq] of versionVector) {\n\t\tvvObj[nid] = seq\n\t}\n\taddSection('version_vector', encodeJsonSection('version_vector', vvObj))\n\n\t// Meta section\n\tconst metaObj: Record<string, string> = {}\n\tfor (const row of meta) {\n\t\tmetaObj[row.key] = row.value\n\t}\n\taddSection('meta', encodeJsonSection('meta', metaObj))\n\n\t// Operations section\n\tconst opLines = `${operations.map((op) => JSON.stringify(op)).join('\\n')}\\n`\n\taddSection('operations', encodeSection('operations', new TextEncoder().encode(opLines)))\n\n\t// Records sections (optional)\n\tlet totalRecords = 0\n\tif (includeRecords) {\n\t\tfor (const col of collections) {\n\t\t\tconst records = await readCollectionRecords(adapter, col)\n\t\t\tif (records.length > 0) {\n\t\t\t\tconst lines = `${records.map((r) => JSON.stringify(r)).join('\\n')}\\n`\n\t\t\t\tconst sectionName = `records:${col}`\n\t\t\t\taddSection(sectionName, encodeSection(sectionName, new TextEncoder().encode(lines)))\n\t\t\t\ttotalRecords += records.length\n\t\t\t}\n\t\t}\n\t}\n\tonProgress({ phase: 'reading', progress: 0.9, message: 'Computing checksum' })\n\n\t// Compute SHA-256 checksum over all content sections\n\tconst checksumHex = await computeSha256(allContentForChecksum)\n\tonProgress({ phase: 'writing', progress: 1, message: 'Finalizing' })\n\n\t// Build manifest\n\tconst manifest: BackupManifest = {\n\t\tversion: BACKUP_VERSION,\n\t\tcreatedAt: Date.now(),\n\t\tnodeId,\n\t\tschemaVersion,\n\t\toperationCount: operations.length,\n\t\tcollections,\n\t\tincludesRecords: includeRecords,\n\t\tchecksum: checksumHex,\n\t}\n\n\t// Final output: header + manifest + all content sections + checksum section\n\tconst header = new Uint8Array(0)\n\n\t// Merge manifest + all sections + checksum section\n\tconst manifestSection = encodeJsonSection('manifest', manifest)\n\tconst checksumSection = encodeSection('checksum', new TextEncoder().encode(checksumHex))\n\n\tconst totalLen = manifestSection.length + allContentForChecksum.length + checksumSection.length\n\tconst result = new Uint8Array(totalLen)\n\tlet pos = 0\n\tresult.set(manifestSection, pos)\n\tpos += manifestSection.length\n\tresult.set(allContentForChecksum, pos)\n\tpos += allContentForChecksum.length\n\tresult.set(checksumSection, pos)\n\n\treturn result\n}\n\n/**\n * Read backup manifest without loading the entire backup.\n * Parses only the first section (which is always the manifest).\n *\n * @param data - The raw backup data\n * @returns The backup manifest\n */\nexport function readBackupManifest(data: Uint8Array): BackupManifest {\n\tconst sections = parseSections(data)\n\tconst manifest = parseJsonSection<BackupManifest>(sections, 'manifest')\n\tif (!manifest) {\n\t\tthrow new Error('Invalid backup: manifest section not found')\n\t}\n\treturn manifest\n}\n\n/**\n * Validate the backup checksum.\n *\n * @param data - The raw backup data\n * @returns True if the checksum is valid\n */\nexport async function verifyBackupChecksum(data: Uint8Array): Promise<boolean> {\n\tconst sections = parseSections(data)\n\tconst manifest = parseJsonSection<BackupManifest>(sections, 'manifest')\n\tif (!manifest) return false\n\n\tconst storedChecksum = manifest.checksum\n\tif (!storedChecksum) return false\n\n\t// Recompute checksum over content sections (everything after manifest, before checksum)\n\tconst manifestSection = findSection(sections, 'manifest')\n\tif (!manifestSection) return false\n\n\t// Find the checksum section\n\tconst checksumSection = findSection(sections, 'checksum')\n\n\t// The content spans from end of manifest section to start of checksum section\n\tconst checksumBytes = checksumSection\n\t\t? new TextEncoder().encode(manifest.checksum)\n\t\t: new Uint8Array(0)\n\n\t// Rebuild all content sections and hash them\n\tconst contentSections = sections.filter((s) => s.name !== 'manifest' && s.name !== 'checksum')\n\n\tlet contentForHash = new Uint8Array(0)\n\tfor (const section of contentSections) {\n\t\tconst sectionBytes = encodeSection(section.name, section.content)\n\t\tconst newLen = contentForHash.length + sectionBytes.length\n\t\tconst combined = new Uint8Array(newLen)\n\t\tcombined.set(contentForHash, 0)\n\t\tcombined.set(sectionBytes, contentForHash.length)\n\t\tcontentForHash = combined\n\t}\n\n\tconst computed = await computeSha256(contentForHash)\n\treturn computed === storedChecksum\n}\n\n/**\n * Restore a backup into a store.\n *\n * @param adapter - The storage adapter\n * @param schema - The schema definition\n * @param data - The backup data\n * @param options - Restore options\n * @returns Result of the restore operation\n */\nexport async function restoreBackup(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n\tdata: Uint8Array,\n\toptions?: RestoreOptions,\n): Promise<RestoreResult> {\n\tconst startTime = Date.now()\n\tconst onProgress = options?.onProgress ?? (() => {})\n\tconst collectionFilter = options?.collections\n\n\tonProgress({ phase: 'verifying', progress: 0, message: 'Parsing backup' })\n\n\tconst sections = parseSections(data)\n\tconst manifest = parseJsonSection<BackupManifest>(sections, 'manifest')\n\tif (!manifest) {\n\t\treturn {\n\t\t\toperationsRestored: 0,\n\t\t\trecordsRestored: 0,\n\t\t\tsuccess: false,\n\t\t\terror: 'Invalid backup: manifest section not found',\n\t\t\tduration: Date.now() - startTime,\n\t\t}\n\t}\n\n\t// Validate format version\n\tif (manifest.version !== BACKUP_VERSION) {\n\t\treturn {\n\t\t\toperationsRestored: 0,\n\t\t\trecordsRestored: 0,\n\t\t\tsuccess: false,\n\t\t\terror: `Unsupported backup version: ${manifest.version}`,\n\t\t\tduration: Date.now() - startTime,\n\t\t}\n\t}\n\n\tonProgress({ phase: 'verifying', progress: 0.2, message: 'Verifying checksum' })\n\n\t// Verify checksum\n\tconst valid = await verifyBackupChecksum(data)\n\tif (!valid) {\n\t\treturn {\n\t\t\toperationsRestored: 0,\n\t\t\trecordsRestored: 0,\n\t\t\tsuccess: false,\n\t\t\terror: 'Backup checksum mismatch: data may be corrupted',\n\t\t\tduration: Date.now() - startTime,\n\t\t}\n\t}\n\n\tonProgress({ phase: 'restoring', progress: 0.3, message: 'Loading operations' })\n\n\t// Parse operations\n\tconst opsContent = findSection(sections, 'operations')\n\tlet operations: Operation[] = []\n\tif (opsContent) {\n\t\tconst text = new TextDecoder().decode(opsContent)\n\t\tconst lines = text\n\t\t\t.trim()\n\t\t\t.split('\\n')\n\t\t\t.filter((l) => l.length > 0)\n\t\toperations = lines.map((line) => JSON.parse(line) as Operation)\n\t}\n\n\t// Filter collections if requested\n\tif (collectionFilter) {\n\t\toperations = operations.filter((op) => collectionFilter.includes(op.collection))\n\t}\n\n\t// Load version vector\n\tconst vvData = parseJsonSection<Record<string, number>>(sections, 'version_vector')\n\n\t// Load meta\n\tconst metaData = parseJsonSection<Record<string, string>>(sections, 'meta')\n\n\tonProgress({ phase: 'restoring', progress: 0.4, message: 'Applying operations' })\n\n\tif (options?.merge) {\n\t\t// Merge mode: replay operations through applyRemoteOperation.\n\t\t// This won't work directly since adapter doesn't have applyRemoteOperation.\n\t\t// Instead, we import the raw data into the adapter.\n\t\tawait adapter.transaction(async (tx) => {\n\t\t\t// Import version vector\n\t\t\tif (vvData) {\n\t\t\t\tfor (const [nid, seq] of Object.entries(vvData)) {\n\t\t\t\t\tawait tx.execute(\n\t\t\t\t\t\t'INSERT OR REPLACE INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\t\t[nid, seq],\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Import meta\n\t\t\tif (metaData) {\n\t\t\t\tfor (const [key, value] of Object.entries(metaData)) {\n\t\t\t\t\tawait tx.execute('INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)', [\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t])\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Import operations into _kora_ops_ tables\n\t\t\tfor (const op of operations) {\n\t\t\t\tconst collection = op.collection\n\t\t\t\tconst opRow = {\n\t\t\t\t\tid: op.id,\n\t\t\t\t\tnode_id: op.nodeId,\n\t\t\t\t\ttype: op.type,\n\t\t\t\t\trecord_id: op.recordId,\n\t\t\t\t\tdata: op.data !== null ? JSON.stringify(op.data) : null,\n\t\t\t\t\tprevious_data: op.previousData !== null ? JSON.stringify(op.previousData) : null,\n\t\t\t\t\ttimestamp: JSON.stringify(op.timestamp),\n\t\t\t\t\tsequence_number: op.sequenceNumber,\n\t\t\t\t\tcausal_deps: JSON.stringify(op.causalDeps),\n\t\t\t\t\tschema_version: op.schemaVersion,\n\t\t\t\t}\n\n\t\t\t\tawait tx.execute(\n\t\t\t\t\t`INSERT OR IGNORE INTO _kora_ops_${collection} (id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n\t\t\t\t\t[\n\t\t\t\t\t\topRow.id,\n\t\t\t\t\t\topRow.node_id,\n\t\t\t\t\t\topRow.type,\n\t\t\t\t\t\topRow.record_id,\n\t\t\t\t\t\topRow.data,\n\t\t\t\t\t\topRow.previous_data,\n\t\t\t\t\t\topRow.timestamp,\n\t\t\t\t\t\topRow.sequence_number,\n\t\t\t\t\t\topRow.causal_deps,\n\t\t\t\t\t\topRow.schema_version,\n\t\t\t\t\t],\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t} else {\n\t\t// Replace mode: clear existing data and bulk import\n\t\tawait adapter.transaction(async (tx) => {\n\t\t\t// Clear existing data\n\t\t\tfor (const collection of Object.keys(schema.collections)) {\n\t\t\t\tawait tx.execute(`DELETE FROM _kora_ops_${collection}`)\n\t\t\t\tawait tx.execute(`DELETE FROM ${collection}`)\n\t\t\t}\n\t\t\tawait tx.execute('DELETE FROM _kora_version_vector')\n\t\t\tawait tx.execute('DELETE FROM _kora_meta')\n\n\t\t\t// Import version vector\n\t\t\tif (vvData) {\n\t\t\t\tfor (const [nid, seq] of Object.entries(vvData)) {\n\t\t\t\t\tawait tx.execute(\n\t\t\t\t\t\t'INSERT INTO _kora_version_vector (node_id, sequence_number) VALUES (?, ?)',\n\t\t\t\t\t\t[nid, seq],\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Import meta\n\t\t\tif (metaData) {\n\t\t\t\tfor (const [key, value] of Object.entries(metaData)) {\n\t\t\t\t\tawait tx.execute('INSERT INTO _kora_meta (key, value) VALUES (?, ?)', [key, value])\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Import operations\n\t\t\tfor (const op of operations) {\n\t\t\t\tconst collection = op.collection\n\t\t\t\tawait tx.execute(\n\t\t\t\t\t`INSERT INTO _kora_ops_${collection} (id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n\t\t\t\t\t[\n\t\t\t\t\t\top.id,\n\t\t\t\t\t\top.nodeId,\n\t\t\t\t\t\top.type,\n\t\t\t\t\t\top.recordId,\n\t\t\t\t\t\top.data !== null ? JSON.stringify(op.data) : null,\n\t\t\t\t\t\top.previousData !== null ? JSON.stringify(op.previousData) : null,\n\t\t\t\t\t\tJSON.stringify(op.timestamp),\n\t\t\t\t\t\top.sequenceNumber,\n\t\t\t\t\t\tJSON.stringify(op.causalDeps),\n\t\t\t\t\t\top.schemaVersion,\n\t\t\t\t\t],\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n\n\tonProgress({ phase: 'restoring', progress: 0.8, message: 'Restoring records' })\n\n\t// Restore records sections (optional)\n\tlet recordsRestored = 0\n\tif (manifest.includesRecords) {\n\t\tfor (const col of manifest.collections) {\n\t\t\tif (collectionFilter && !collectionFilter.includes(col)) continue\n\n\t\t\tconst sectionContent = findSection(sections, `records:${col}`)\n\t\t\tif (!sectionContent) continue\n\n\t\t\tconst text = new TextDecoder().decode(sectionContent)\n\t\t\tconst lines = text\n\t\t\t\t.trim()\n\t\t\t\t.split('\\n')\n\t\t\t\t.filter((l) => l.length > 0)\n\t\t\tconst records = lines.map((line) => JSON.parse(line) as Record<string, unknown>)\n\n\t\t\tif (records.length === 0) continue\n\n\t\t\tawait adapter.transaction(async (tx) => {\n\t\t\t\tfor (const record of records) {\n\t\t\t\t\tconst keys = Object.keys(record)\n\t\t\t\t\tconst placeholders = keys.map(() => '?').join(', ')\n\t\t\t\t\tconst values = keys.map((k) => {\n\t\t\t\t\t\tconst v = record[k]\n\t\t\t\t\t\tif (typeof v === 'boolean') return v ? 1 : 0\n\t\t\t\t\t\tif (Array.isArray(v) || (typeof v === 'object' && v !== null)) return JSON.stringify(v)\n\t\t\t\t\t\treturn v\n\t\t\t\t\t})\n\n\t\t\t\t\tawait tx.execute(\n\t\t\t\t\t\t`INSERT OR REPLACE INTO ${col} (${keys.join(', ')}) VALUES (${placeholders})`,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\trecordsRestored += records.length\n\t\t}\n\t}\n\n\tonProgress({ phase: 'restoring', progress: 1, message: 'Done' })\n\n\treturn {\n\t\toperationsRestored: operations.length,\n\t\trecordsRestored,\n\t\tsuccess: true,\n\t\tduration: Date.now() - startTime,\n\t}\n}\n\n// ── Reading helpers ──────────────────────────────────────────────────────────\n\nasync function readVersionVector(adapter: StorageAdapter): Promise<Map<string, number>> {\n\tconst rows = await adapter.query<{ node_id: string; sequence_number: number }>(\n\t\t'SELECT node_id, sequence_number FROM _kora_version_vector',\n\t)\n\tconst vv = new Map<string, number>()\n\tfor (const row of rows) {\n\t\tvv.set(row.node_id, row.sequence_number)\n\t}\n\treturn vv\n}\n\ninterface MetaRow {\n\tkey: string\n\tvalue: string\n}\n\nasync function readMeta(adapter: StorageAdapter): Promise<MetaRow[]> {\n\treturn adapter.query<MetaRow>('SELECT key, value FROM _kora_meta')\n}\n\nasync function readAllOperations(\n\tadapter: StorageAdapter,\n\tschema: SchemaDefinition,\n): Promise<Operation[]> {\n\tconst allOps: Operation[] = []\n\n\tfor (const collectionName of Object.keys(schema.collections)) {\n\t\tconst rows = await adapter.query<OperationRow>(\n\t\t\t`SELECT * FROM _kora_ops_${collectionName} ORDER BY sequence_number ASC`,\n\t\t)\n\n\t\tfor (const row of rows) {\n\t\t\tallOps.push(deserializeOperationWithCollection(row, collectionName))\n\t\t}\n\t}\n\n\treturn allOps\n}\n\nasync function readCollectionRecords(\n\tadapter: StorageAdapter,\n\tcollection: string,\n): Promise<Record<string, unknown>[]> {\n\treturn adapter.query<Record<string, unknown>>(`SELECT * FROM ${collection} WHERE _deleted = 0`)\n}\n\n// ── Crypto helpers ───────────────────────────────────────────────────────────\n\nasync function computeSha256(data: Uint8Array<ArrayBuffer>): Promise<string> {\n\tconst hashBuffer = await crypto.subtle.digest('SHA-256', data)\n\tconst hashArray = Array.from(new Uint8Array(hashBuffer))\n\treturn hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n"],"mappings":"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","names":[]}