@korajs/store 1.0.0-beta.0 → 1.0.0-beta.10

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 (81) 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-5XZ7THNJ.js → backup-5S7K2Z35.js} +3 -3
  21. package/dist/blob-fs.cjs +166 -0
  22. package/dist/blob-fs.cjs.map +1 -0
  23. package/dist/blob-fs.d.cts +29 -0
  24. package/dist/blob-fs.d.ts +29 -0
  25. package/dist/blob-fs.js +128 -0
  26. package/dist/blob-fs.js.map +1 -0
  27. package/dist/{chunk-EIVXWF4B.js → chunk-CYO3YKFL.js} +4 -3
  28. package/dist/chunk-CYO3YKFL.js.map +1 -0
  29. package/dist/{chunk-ETDJEH2I.js → chunk-GSJ7EEUC.js} +12 -1
  30. package/dist/chunk-GSJ7EEUC.js.map +1 -0
  31. package/dist/{chunk-5R4QMY3Z.js → chunk-HS6DBMST.js} +13 -10
  32. package/dist/chunk-HS6DBMST.js.map +1 -0
  33. package/dist/chunk-RJIEKEN4.js +751 -0
  34. package/dist/chunk-RJIEKEN4.js.map +1 -0
  35. package/dist/{chunk-QL2XVZRN.js → chunk-TUR7RGEP.js} +12 -1
  36. package/dist/{chunk-QL2XVZRN.js.map → chunk-TUR7RGEP.js.map} +1 -1
  37. package/dist/{chunk-IOEFNHHP.js → chunk-VDBJQ75K.js} +2 -2
  38. package/dist/chunk-VDBJQ75K.js.map +1 -0
  39. package/dist/chunk-W4MTTNEZ.js +55 -0
  40. package/dist/chunk-W4MTTNEZ.js.map +1 -0
  41. package/dist/{chunk-OUQDC5Z6.js → chunk-YT7MRFCP.js} +55 -35
  42. package/dist/chunk-YT7MRFCP.js.map +1 -0
  43. package/dist/content-addressed-blob-store-Dcj3SB9r.d.cts +60 -0
  44. package/dist/content-addressed-blob-store-Dcj3SB9r.d.ts +60 -0
  45. package/dist/{export-audit-VPGQWNR6.js → export-audit-ODGQTQIK.js} +3 -3
  46. package/dist/index.cjs +923 -131
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +443 -6
  49. package/dist/index.d.ts +443 -6
  50. package/dist/index.js +737 -49
  51. package/dist/index.js.map +1 -1
  52. package/dist/internal.cjs +69 -43
  53. package/dist/internal.cjs.map +1 -1
  54. package/dist/internal.d.cts +3 -3
  55. package/dist/internal.d.ts +3 -3
  56. package/dist/internal.js +3 -3
  57. package/dist/sqlite-wasm-channel-GGHA2BXU.js +12 -0
  58. package/dist/{sqlite-wasm-channel-DUDPclTE.d.cts → sqlite-wasm-channel-L6o3bWQK.d.cts} +1 -1
  59. package/dist/{sqlite-wasm-channel-DUDPclTE.d.ts → sqlite-wasm-channel-L6o3bWQK.d.ts} +1 -1
  60. package/dist/{types-CyjXwrjW.d.cts → types-BOO9EPt1.d.ts} +10 -3
  61. package/dist/{types-CJOVKxLw.d.ts → types-BslDOTk0.d.cts} +32 -2
  62. package/dist/{types-CJOVKxLw.d.cts → types-BslDOTk0.d.ts} +32 -2
  63. package/dist/{types-DAxCladl.d.ts → types-C_GDavG-.d.cts} +10 -3
  64. package/package.json +13 -12
  65. package/dist/adapters/sqlite-wasm-shared-host.cjs +0 -68
  66. package/dist/adapters/sqlite-wasm-shared-host.cjs.map +0 -1
  67. package/dist/adapters/sqlite-wasm-shared-host.d.cts +0 -2
  68. package/dist/adapters/sqlite-wasm-shared-host.d.ts +0 -2
  69. package/dist/adapters/sqlite-wasm-shared-host.js +0 -66
  70. package/dist/adapters/sqlite-wasm-shared-host.js.map +0 -1
  71. package/dist/chunk-5R4QMY3Z.js.map +0 -1
  72. package/dist/chunk-EIVXWF4B.js.map +0 -1
  73. package/dist/chunk-ETDJEH2I.js.map +0 -1
  74. package/dist/chunk-IOEFNHHP.js.map +0 -1
  75. package/dist/chunk-OUQDC5Z6.js.map +0 -1
  76. package/dist/chunk-RBPVEAVM.js +0 -425
  77. package/dist/chunk-RBPVEAVM.js.map +0 -1
  78. package/dist/sqlite-wasm-channel-H43KEZLM.js +0 -12
  79. /package/dist/{backup-5XZ7THNJ.js.map → backup-5S7K2Z35.js.map} +0 -0
  80. /package/dist/{export-audit-VPGQWNR6.js.map → export-audit-ODGQTQIK.js.map} +0 -0
  81. /package/dist/{sqlite-wasm-channel-H43KEZLM.js.map → sqlite-wasm-channel-GGHA2BXU.js.map} +0 -0
@@ -1,45 +1,5 @@
1
- // src/adapters/sqlite-wasm-worker.ts
2
- var db = null;
3
- var sqlite3Api = null;
4
- function sendResponse(response) {
5
- self.postMessage(response);
6
- }
7
- function handleExecute(id, sql, params) {
8
- if (!db) {
9
- sendResponse({ id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" });
10
- return;
11
- }
12
- try {
13
- db.exec({ sql, bind: params });
14
- sendResponse({ id, type: "success" });
15
- } catch (error) {
16
- sendResponse({ id, type: "error", message: error.message, code: "EXEC_ERROR" });
17
- }
18
- }
19
- function handleQuery(id, sql, params) {
20
- if (!db) {
21
- sendResponse({ id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" });
22
- return;
23
- }
24
- try {
25
- const rows = [];
26
- db.exec({
27
- sql,
28
- bind: params,
29
- rowMode: "object",
30
- callback: (row) => {
31
- rows.push({ ...row });
32
- }
33
- });
34
- sendResponse({ id, type: "success", data: rows });
35
- } catch (error) {
36
- sendResponse({ id, type: "error", message: error.message, code: "QUERY_ERROR" });
37
- }
38
- }
39
- function opfsDatabaseFilename(dbName) {
40
- const base = dbName.replace(/[^a-zA-Z0-9._-]/g, "_");
41
- return base.endsWith(".db") ? base : `${base}.db`;
42
- }
1
+ // src/adapters/sqlite-wasm-worker-core.ts
2
+ var OPFS_POOL_NAME = "kora-opfs";
43
3
  var OPFS_INIT_TIMEOUT_MS = 1e4;
44
4
  async function withTimeout(promise, timeoutMs, label) {
45
5
  let timer;
@@ -57,183 +17,243 @@ async function withTimeout(promise, timeoutMs, label) {
57
17
  if (timer !== void 0) clearTimeout(timer);
58
18
  }
59
19
  }
60
- async function handleOpen(id, ddlStatements, dbName) {
20
+ function opfsDatabaseFilename(dbName) {
21
+ const base = dbName.replace(/[^a-zA-Z0-9._-]/g, "_");
22
+ return base.endsWith(".db") ? base : `${base}.db`;
23
+ }
24
+ function classifyOpfsFailure(error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ if (/timed out|timeout/i.test(message)) {
27
+ return "timeout";
28
+ }
29
+ if (/lock|already|in use|in-use|NoModificationAllowed|acquire|SyncAccessHandle|being created/i.test(
30
+ message
31
+ )) {
32
+ return "lock-conflict";
33
+ }
34
+ return "unsupported";
35
+ }
36
+ var sqlite3Promise = null;
37
+ var opfsPoolPromise = null;
38
+ var opfsFallbackReason;
39
+ async function loadSqlite3() {
40
+ const sqlite3InitModule = (await import("@sqlite.org/sqlite-wasm")).default;
41
+ const wasmUrl = globalThis.__KORA_SQLITE_WASM_URL;
42
+ const initOptions = wasmUrl ? {
43
+ locateFile: (file) => file.endsWith(".wasm") ? wasmUrl : file
44
+ } : void 0;
45
+ const initFn = sqlite3InitModule;
46
+ return await withTimeout(initFn(initOptions), 6e4, "SQLite3 module init");
47
+ }
48
+ function getSqlite3() {
49
+ if (!sqlite3Promise) {
50
+ sqlite3Promise = loadSqlite3();
51
+ }
52
+ return sqlite3Promise;
53
+ }
54
+ async function installOpfsPool(sqlite3) {
55
+ if (!sqlite3.installOpfsSAHPoolVfs) {
56
+ opfsFallbackReason = "unsupported";
57
+ return null;
58
+ }
61
59
  try {
62
- const sqlite3InitModule = (await import("@sqlite.org/sqlite-wasm")).default;
63
- const wasmUrl = globalThis.__KORA_SQLITE_WASM_URL;
64
- const initOptions = wasmUrl ? {
65
- locateFile: (file) => {
66
- if (file.endsWith(".wasm")) return wasmUrl;
67
- return file;
68
- }
69
- } : void 0;
70
- const initFn = sqlite3InitModule;
71
- const sqlite3 = await withTimeout(
72
- initFn(initOptions),
73
- 6e4,
74
- "SQLite3 module init"
60
+ return await withTimeout(
61
+ sqlite3.installOpfsSAHPoolVfs({ name: OPFS_POOL_NAME }),
62
+ OPFS_INIT_TIMEOUT_MS,
63
+ "OPFS VFS install"
75
64
  );
76
- sqlite3Api = sqlite3;
77
- let useOpfs = false;
78
- if (sqlite3.installOpfsSAHPoolVfs) {
79
- try {
80
- const pool = await withTimeout(
81
- sqlite3.installOpfsSAHPoolVfs({ name: "kora-opfs" }),
82
- OPFS_INIT_TIMEOUT_MS,
83
- "OPFS VFS install"
84
- );
65
+ } catch (error) {
66
+ opfsFallbackReason = classifyOpfsFailure(error);
67
+ return null;
68
+ }
69
+ }
70
+ function getOpfsPool(sqlite3) {
71
+ if (!opfsPoolPromise) {
72
+ opfsPoolPromise = installOpfsPool(sqlite3);
73
+ }
74
+ return opfsPoolPromise;
75
+ }
76
+ function createSqliteWasmCore() {
77
+ let db = null;
78
+ let sqlite3Api = null;
79
+ let persistent = false;
80
+ async function open(id, ddlStatements, dbName) {
81
+ try {
82
+ if (db) {
83
+ applyDdl(db, ddlStatements);
84
+ return { id, type: "success", data: buildOpenData() };
85
+ }
86
+ const sqlite3 = await getSqlite3();
87
+ sqlite3Api = sqlite3;
88
+ const pool = await getOpfsPool(sqlite3);
89
+ if (pool) {
85
90
  db = new pool.OpfsSAHPoolDb(opfsDatabaseFilename(dbName ?? "kora-db"));
86
- useOpfs = true;
87
- } catch {
88
- console.warn("[kora] OPFS unavailable, falling back to in-memory SQLite");
91
+ persistent = true;
92
+ } else {
93
+ db = new sqlite3.oo1.DB({ filename: ":memory:" });
94
+ persistent = false;
89
95
  }
96
+ db.exec({ sql: "PRAGMA journal_mode = WAL" });
97
+ db.exec({ sql: "PRAGMA foreign_keys = ON" });
98
+ applyDdl(db, ddlStatements);
99
+ return { id, type: "success", data: buildOpenData() };
100
+ } catch (error) {
101
+ return { id, type: "error", message: error.message, code: "INIT_ERROR" };
90
102
  }
91
- if (!useOpfs) {
92
- db = new sqlite3.oo1.DB({ filename: ":memory:" });
93
- }
94
- db?.exec({ sql: "PRAGMA journal_mode = WAL" });
95
- db?.exec({ sql: "PRAGMA foreign_keys = ON" });
103
+ }
104
+ function buildOpenData() {
105
+ return {
106
+ persistent,
107
+ ...persistent ? {} : { fallbackReason: opfsFallbackReason ?? "unsupported" }
108
+ };
109
+ }
110
+ function applyDdl(target, ddlStatements) {
96
111
  for (const sql of ddlStatements) {
97
112
  if (sql.startsWith("--kora:safe-alter")) {
98
113
  try {
99
- db?.exec({ sql: sql.replace("--kora:safe-alter\n", "") });
100
- } catch (e) {
101
- const msg = e.message || "";
114
+ target.exec({ sql: sql.replace("--kora:safe-alter\n", "") });
115
+ } catch (error) {
116
+ const msg = error.message || "";
102
117
  if (!msg.includes("duplicate column name")) {
103
- throw e;
118
+ throw error;
104
119
  }
105
120
  }
106
121
  } else {
107
- db?.exec({ sql });
122
+ target.exec({ sql });
108
123
  }
109
124
  }
110
- sendResponse({ id, type: "success" });
111
- } catch (error) {
112
- sendResponse({
113
- id,
114
- type: "error",
115
- message: error.message,
116
- code: "INIT_ERROR"
117
- });
118
125
  }
119
- }
120
- function handleClose(id) {
121
- if (db) {
122
- db.close();
123
- db = null;
126
+ function execute(id, sql, params) {
127
+ if (!db) {
128
+ return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
129
+ }
130
+ try {
131
+ db.exec({ sql, bind: params });
132
+ return { id, type: "success" };
133
+ } catch (error) {
134
+ return { id, type: "error", message: error.message, code: "EXEC_ERROR" };
135
+ }
124
136
  }
125
- sendResponse({ id, type: "success" });
126
- }
127
- function handleImport(id, data) {
128
- if (!db) {
129
- sendResponse({ id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" });
130
- return;
137
+ function query(id, sql, params) {
138
+ if (!db) {
139
+ return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
140
+ }
141
+ try {
142
+ const rows = [];
143
+ db.exec({
144
+ sql,
145
+ bind: params,
146
+ rowMode: "object",
147
+ callback: (row) => {
148
+ rows.push({ ...row });
149
+ }
150
+ });
151
+ return { id, type: "success", data: rows };
152
+ } catch (error) {
153
+ return { id, type: "error", message: error.message, code: "QUERY_ERROR" };
154
+ }
131
155
  }
132
- const dbWithDeserialize = db;
133
- if (typeof dbWithDeserialize.deserialize === "function") {
156
+ function close(id) {
157
+ if (db) {
158
+ db.close();
159
+ db = null;
160
+ }
161
+ return { id, type: "success" };
162
+ }
163
+ function migrate(id, statements) {
164
+ if (!db) {
165
+ return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
166
+ }
134
167
  try {
135
- dbWithDeserialize.deserialize(data);
136
- sendResponse({ id, type: "success" });
137
- return;
168
+ for (const sql of statements) {
169
+ db.exec({ sql });
170
+ }
171
+ return { id, type: "success" };
138
172
  } catch (error) {
139
- sendResponse({ id, type: "error", message: error.message, code: "IMPORT_ERROR" });
140
- return;
173
+ return { id, type: "error", message: error.message, code: "MIGRATE_ERROR" };
141
174
  }
142
175
  }
143
- const sqlite3 = sqlite3Api;
144
- if (!sqlite3 || typeof sqlite3.capi?.sqlite3_deserialize === "undefined") {
145
- sendResponse({
176
+ function importData(id, data) {
177
+ if (!db) {
178
+ return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
179
+ }
180
+ const dbWithDeserialize = db;
181
+ if (typeof dbWithDeserialize.deserialize === "function") {
182
+ try {
183
+ dbWithDeserialize.deserialize(data);
184
+ return { id, type: "success" };
185
+ } catch (error) {
186
+ return { id, type: "error", message: error.message, code: "IMPORT_ERROR" };
187
+ }
188
+ }
189
+ if (!sqlite3Api || typeof sqlite3Api.capi?.sqlite3_deserialize === "undefined") {
190
+ return {
191
+ id,
192
+ type: "error",
193
+ message: "Import not supported in this SQLite WASM runtime",
194
+ code: "IMPORT_NOT_SUPPORTED"
195
+ };
196
+ }
197
+ return {
146
198
  id,
147
199
  type: "error",
148
- message: "Import not supported in this SQLite WASM runtime",
200
+ message: "Import requires runtime-specific deserialize wiring and is unavailable in this worker build",
149
201
  code: "IMPORT_NOT_SUPPORTED"
150
- });
151
- return;
152
- }
153
- sendResponse({
154
- id,
155
- type: "error",
156
- message: "Import requires runtime-specific deserialize wiring and is unavailable in this worker build",
157
- code: "IMPORT_NOT_SUPPORTED"
158
- });
159
- }
160
- function handleMessage(request) {
161
- try {
162
- switch (request.type) {
163
- case "open":
164
- handleOpen(request.id, request.ddlStatements, request.dbName);
165
- return;
166
- case "close":
167
- handleClose(request.id);
168
- return;
169
- case "execute":
170
- handleExecute(request.id, request.sql, request.params);
171
- return;
172
- case "query":
173
- handleQuery(request.id, request.sql, request.params);
174
- return;
175
- case "begin":
176
- handleExecute(request.id, "BEGIN");
177
- return;
178
- case "commit":
179
- handleExecute(request.id, "COMMIT");
180
- return;
181
- case "rollback":
182
- handleExecute(request.id, "ROLLBACK");
183
- return;
184
- case "migrate":
185
- if (!db) {
186
- sendResponse({
202
+ };
203
+ }
204
+ async function handle(request) {
205
+ try {
206
+ switch (request.type) {
207
+ case "open":
208
+ return await open(request.id, request.ddlStatements, request.dbName);
209
+ case "close":
210
+ return close(request.id);
211
+ case "execute":
212
+ return execute(request.id, request.sql, request.params);
213
+ case "query":
214
+ return query(request.id, request.sql, request.params);
215
+ case "begin":
216
+ return execute(request.id, "BEGIN");
217
+ case "commit":
218
+ return execute(request.id, "COMMIT");
219
+ case "rollback":
220
+ return execute(request.id, "ROLLBACK");
221
+ case "migrate":
222
+ return migrate(request.id, request.statements);
223
+ case "import":
224
+ return importData(request.id, request.data);
225
+ case "export":
226
+ return {
187
227
  id: request.id,
188
228
  type: "error",
189
- message: "Database is not open",
190
- code: "DB_NOT_OPEN"
191
- });
192
- return;
193
- }
194
- try {
195
- for (const sql of request.statements) {
196
- db.exec({ sql });
197
- }
198
- sendResponse({ id: request.id, type: "success" });
199
- } catch (error) {
200
- sendResponse({
229
+ message: "Export not yet supported in browser worker",
230
+ code: "EXPORT_NOT_SUPPORTED"
231
+ };
232
+ default:
233
+ return {
201
234
  id: request.id,
202
235
  type: "error",
203
- message: error.message,
204
- code: "MIGRATE_ERROR"
205
- });
206
- }
207
- return;
208
- case "export":
209
- sendResponse({
210
- id: request.id,
211
- type: "error",
212
- message: "Export not yet supported in browser worker",
213
- code: "EXPORT_NOT_SUPPORTED"
214
- });
215
- return;
216
- case "import":
217
- handleImport(request.id, request.data);
218
- return;
219
- default:
220
- sendResponse({
221
- id: request.id,
222
- type: "error",
223
- message: "Unknown request type",
224
- code: "UNKNOWN_REQUEST"
225
- });
236
+ message: "Unknown request type",
237
+ code: "UNKNOWN_REQUEST"
238
+ };
239
+ }
240
+ } catch (error) {
241
+ return {
242
+ id: request.id,
243
+ type: "error",
244
+ message: error.message,
245
+ code: "WORKER_ERROR"
246
+ };
226
247
  }
227
- } catch (error) {
228
- sendResponse({
229
- id: request.id,
230
- type: "error",
231
- message: error.message,
232
- code: "WORKER_ERROR"
233
- });
234
248
  }
249
+ return { handle };
235
250
  }
251
+
252
+ // src/adapters/sqlite-wasm-worker.ts
253
+ var core = createSqliteWasmCore();
236
254
  self.onmessage = (event) => {
237
- handleMessage(event.data);
255
+ void core.handle(event.data).then((response) => {
256
+ self.postMessage(response);
257
+ });
238
258
  };
239
259
  //# sourceMappingURL=sqlite-wasm-worker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/adapters/sqlite-wasm-worker.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n/**\n * Web Worker script for running SQLite WASM.\n *\n * This file is intended to run inside a Web Worker in browsers.\n * It loads @sqlite.org/sqlite-wasm, initializes SQLite with OPFS persistence\n * (falling back to in-memory if unavailable), and processes messages from\n * the main thread via the WorkerRequest/WorkerResponse protocol.\n *\n * This script cannot be tested in Node.js — it is validated in E2E browser tests.\n */\n\nimport type { WorkerRequest, WorkerResponse } from './sqlite-wasm-channel'\n\ninterface SqliteDb {\n\texec(opts: {\n\t\tsql: string\n\t\tbind?: unknown[]\n\t\treturnValue?: string\n\t\trowMode?: string\n\t\tcallback?: (row: Record<string, unknown>) => void\n\t}): void\n\tclose(): void\n\tdeserialize?: (data: Uint8Array) => void\n}\n\ndeclare const self: DedicatedWorkerGlobalScope\n\nlet db: SqliteDb | null = null\nlet sqlite3Api: unknown = null\n\nfunction sendResponse(response: WorkerResponse): void {\n\tself.postMessage(response)\n}\n\nfunction handleExecute(id: number, sql: string, params?: unknown[]): void {\n\tif (!db) {\n\t\tsendResponse({ id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' })\n\t\treturn\n\t}\n\ttry {\n\t\tdb.exec({ sql, bind: params })\n\t\tsendResponse({ id, type: 'success' })\n\t} catch (error) {\n\t\tsendResponse({ id, type: 'error', message: (error as Error).message, code: 'EXEC_ERROR' })\n\t}\n}\n\nfunction handleQuery(id: number, sql: string, params?: unknown[]): void {\n\tif (!db) {\n\t\tsendResponse({ id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' })\n\t\treturn\n\t}\n\ttry {\n\t\tconst rows: Record<string, unknown>[] = []\n\t\tdb.exec({\n\t\t\tsql,\n\t\t\tbind: params,\n\t\t\trowMode: 'object',\n\t\t\tcallback: (row: Record<string, unknown>) => {\n\t\t\t\trows.push({ ...row })\n\t\t\t},\n\t\t})\n\t\tsendResponse({ id, type: 'success', data: rows })\n\t} catch (error) {\n\t\tsendResponse({ id, type: 'error', message: (error as Error).message, code: 'QUERY_ERROR' })\n\t}\n}\n\nfunction opfsDatabaseFilename(dbName: string): string {\n\tconst base = dbName.replace(/[^a-zA-Z0-9._-]/g, '_')\n\treturn base.endsWith('.db') ? base : `${base}.db`\n}\n\n/** Headless browsers and some profiles hang on OPFS VFS install; fall back to memory. */\nconst OPFS_INIT_TIMEOUT_MS = 10_000\n\nasync function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {\n\tlet timer: ReturnType<typeof setTimeout> | undefined\n\ttry {\n\t\treturn await Promise.race([\n\t\t\tpromise,\n\t\t\tnew Promise<T>((_, reject) => {\n\t\t\t\ttimer = setTimeout(\n\t\t\t\t\t() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),\n\t\t\t\t\ttimeoutMs,\n\t\t\t\t)\n\t\t\t}),\n\t\t])\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer)\n\t}\n}\n\nasync function handleOpen(id: number, ddlStatements: string[], dbName?: string): Promise<void> {\n\ttry {\n\t\tconst sqlite3InitModule = (await import('@sqlite.org/sqlite-wasm')).default\n\n\t\t// In production builds, Vite hashes asset filenames (e.g. sqlite3-[hash].wasm).\n\t\t// The sqlite3 module's default locateFile resolves the unhashed name, causing a 404.\n\t\t// Templates set __KORA_SQLITE_WASM_URL via `import wasmUrl from '...sqlite3.wasm?url'`\n\t\t// so we can override locateFile with the correct hashed URL.\n\t\tconst wasmUrl = (globalThis as Record<string, unknown>).__KORA_SQLITE_WASM_URL as\n\t\t\t| string\n\t\t\t| undefined\n\t\tconst initOptions = wasmUrl\n\t\t\t? {\n\t\t\t\t\tlocateFile: (file: string) => {\n\t\t\t\t\t\tif (file.endsWith('.wasm')) return wasmUrl\n\t\t\t\t\t\treturn file\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: undefined\n\n\t\t// sqlite3InitModule accepts Emscripten Module overrides but the types don't reflect this\n\t\tconst initFn = sqlite3InitModule as unknown as (\n\t\t\topts?: Record<string, unknown>,\n\t\t) => Promise<unknown>\n\t\tconst sqlite3 = (await withTimeout(\n\t\t\tinitFn(initOptions),\n\t\t\t60_000,\n\t\t\t'SQLite3 module init',\n\t\t)) as Awaited<ReturnType<typeof sqlite3InitModule>>\n\t\tsqlite3Api = sqlite3\n\n\t\t// Try OPFS persistence first\n\t\tlet useOpfs = false\n\t\tif (sqlite3.installOpfsSAHPoolVfs) {\n\t\t\ttry {\n\t\t\t\tconst pool = await withTimeout(\n\t\t\t\t\tsqlite3.installOpfsSAHPoolVfs({ name: 'kora-opfs' }),\n\t\t\t\t\tOPFS_INIT_TIMEOUT_MS,\n\t\t\t\t\t'OPFS VFS install',\n\t\t\t\t)\n\t\t\t\tdb = new pool.OpfsSAHPoolDb(opfsDatabaseFilename(dbName ?? 'kora-db'))\n\t\t\t\tuseOpfs = true\n\t\t\t} catch {\n\t\t\t\t// OPFS unavailable or too slow (common in headless CI), fall back to in-memory\n\t\t\t\tconsole.warn('[kora] OPFS unavailable, falling back to in-memory SQLite')\n\t\t\t}\n\t\t}\n\n\t\tif (!useOpfs) {\n\t\t\tdb = new sqlite3.oo1.DB({ filename: ':memory:' })\n\t\t}\n\n\t\t// Set pragmas\n\t\tdb?.exec({ sql: 'PRAGMA journal_mode = WAL' })\n\t\tdb?.exec({ sql: 'PRAGMA foreign_keys = ON' })\n\n\t\t// Execute DDL statements\n\t\tfor (const sql of ddlStatements) {\n\t\t\tif (sql.startsWith('--kora:safe-alter')) {\n\t\t\t\t// Safe ALTER TABLE — ignore \"duplicate column name\" errors for existing columns\n\t\t\t\ttry {\n\t\t\t\t\tdb?.exec({ sql: sql.replace('--kora:safe-alter\\n', '') })\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconst msg = (e as Error).message || ''\n\t\t\t\t\tif (!msg.includes('duplicate column name')) {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdb?.exec({ sql })\n\t\t\t}\n\t\t}\n\n\t\tsendResponse({ id, type: 'success' })\n\t} catch (error) {\n\t\tsendResponse({\n\t\t\tid,\n\t\t\ttype: 'error',\n\t\t\tmessage: (error as Error).message,\n\t\t\tcode: 'INIT_ERROR',\n\t\t})\n\t}\n}\n\nfunction handleClose(id: number): void {\n\tif (db) {\n\t\tdb.close()\n\t\tdb = null\n\t}\n\tsendResponse({ id, type: 'success' })\n}\n\nfunction handleImport(id: number, data: Uint8Array): void {\n\tif (!db) {\n\t\tsendResponse({ id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' })\n\t\treturn\n\t}\n\n\tconst dbWithDeserialize = db as SqliteDb & { deserialize?: (bytes: Uint8Array) => void }\n\tif (typeof dbWithDeserialize.deserialize === 'function') {\n\t\ttry {\n\t\t\tdbWithDeserialize.deserialize(data)\n\t\t\tsendResponse({ id, type: 'success' })\n\t\t\treturn\n\t\t} catch (error) {\n\t\t\tsendResponse({ id, type: 'error', message: (error as Error).message, code: 'IMPORT_ERROR' })\n\t\t\treturn\n\t\t}\n\t}\n\n\tconst sqlite3 = sqlite3Api as {\n\t\too1?: { DB?: new (...args: unknown[]) => SqliteDb }\n\t\tcapi?: { sqlite3_deserialize?: unknown }\n\t} | null\n\n\tif (!sqlite3 || typeof sqlite3.capi?.sqlite3_deserialize === 'undefined') {\n\t\tsendResponse({\n\t\t\tid,\n\t\t\ttype: 'error',\n\t\t\tmessage: 'Import not supported in this SQLite WASM runtime',\n\t\t\tcode: 'IMPORT_NOT_SUPPORTED',\n\t\t})\n\t\treturn\n\t}\n\n\tsendResponse({\n\t\tid,\n\t\ttype: 'error',\n\t\tmessage:\n\t\t\t'Import requires runtime-specific deserialize wiring and is unavailable in this worker build',\n\t\tcode: 'IMPORT_NOT_SUPPORTED',\n\t})\n}\n\nfunction handleMessage(request: WorkerRequest): void {\n\ttry {\n\t\tswitch (request.type) {\n\t\t\tcase 'open':\n\t\t\t\t// open is async due to WASM loading\n\t\t\t\thandleOpen(request.id, request.ddlStatements, request.dbName)\n\t\t\t\treturn\n\t\t\tcase 'close':\n\t\t\t\thandleClose(request.id)\n\t\t\t\treturn\n\t\t\tcase 'execute':\n\t\t\t\thandleExecute(request.id, request.sql, request.params)\n\t\t\t\treturn\n\t\t\tcase 'query':\n\t\t\t\thandleQuery(request.id, request.sql, request.params)\n\t\t\t\treturn\n\t\t\tcase 'begin':\n\t\t\t\thandleExecute(request.id, 'BEGIN')\n\t\t\t\treturn\n\t\t\tcase 'commit':\n\t\t\t\thandleExecute(request.id, 'COMMIT')\n\t\t\t\treturn\n\t\t\tcase 'rollback':\n\t\t\t\thandleExecute(request.id, 'ROLLBACK')\n\t\t\t\treturn\n\t\t\tcase 'migrate':\n\t\t\t\tif (!db) {\n\t\t\t\t\tsendResponse({\n\t\t\t\t\t\tid: request.id,\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\tmessage: 'Database is not open',\n\t\t\t\t\t\tcode: 'DB_NOT_OPEN',\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tfor (const sql of request.statements) {\n\t\t\t\t\t\tdb.exec({ sql })\n\t\t\t\t\t}\n\t\t\t\t\tsendResponse({ id: request.id, type: 'success' })\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsendResponse({\n\t\t\t\t\t\tid: request.id,\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\tmessage: (error as Error).message,\n\t\t\t\t\t\tcode: 'MIGRATE_ERROR',\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\tcase 'export':\n\t\t\t\t// Export is not trivially supported via the oo1 API in the browser.\n\t\t\t\t// In a real implementation, we'd use the C API's sqlite3_serialize.\n\t\t\t\tsendResponse({\n\t\t\t\t\tid: request.id,\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\tmessage: 'Export not yet supported in browser worker',\n\t\t\t\t\tcode: 'EXPORT_NOT_SUPPORTED',\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\tcase 'import':\n\t\t\t\thandleImport(request.id, request.data)\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t\tsendResponse({\n\t\t\t\t\tid: (request as WorkerRequest).id,\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\tmessage: 'Unknown request type',\n\t\t\t\t\tcode: 'UNKNOWN_REQUEST',\n\t\t\t\t})\n\t\t}\n\t} catch (error) {\n\t\tsendResponse({\n\t\t\tid: request.id,\n\t\t\ttype: 'error',\n\t\t\tmessage: (error as Error).message,\n\t\t\tcode: 'WORKER_ERROR',\n\t\t})\n\t}\n}\n\n// Listen for messages from the main thread\nself.onmessage = (event: MessageEvent<WorkerRequest>) => {\n\thandleMessage(event.data)\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/adapters/sqlite-wasm-worker-core.ts","../../src/adapters/sqlite-wasm-worker.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n/**\n * Reusable SQLite WASM core, decoupled from any specific worker global.\n *\n * The dedicated worker ({@link file://./sqlite-wasm-worker.ts}) wires one core to\n * `self.onmessage`/`self.postMessage`.\n *\n * The WASM module and the OPFS SyncAccessHandle pool are cached at module scope\n * and shared across every core in the same worker: the pool holds\n * multiple database files keyed by filename, so installing it once and opening\n * each database within it avoids the single-writer conflict that installing the\n * pool twice in one scope would cause.\n *\n * This file cannot be unit-tested in Node (no WASM/OPFS); it is exercised through\n * the browser E2E suite.\n */\n\nimport type { WorkerRequest, WorkerResponse } from './sqlite-wasm-channel'\n\ninterface SqliteDb {\n\texec(opts: {\n\t\tsql: string\n\t\tbind?: unknown[]\n\t\treturnValue?: string\n\t\trowMode?: string\n\t\tcallback?: (row: Record<string, unknown>) => void\n\t}): void\n\tclose(): void\n\tdeserialize?: (data: Uint8Array) => void\n}\n\ninterface OpfsPool {\n\tOpfsSAHPoolDb: new (filename: string) => SqliteDb\n}\n\ninterface Sqlite3Api {\n\too1: { DB: new (opts: { filename: string }) => SqliteDb }\n\tinstallOpfsSAHPoolVfs?: (opts: { name: string }) => Promise<OpfsPool>\n\tcapi?: { sqlite3_deserialize?: unknown }\n}\n\n/** OPFS SAH pool name. Shared across all databases on the origin (the pool holds\n * multiple db files keyed by filename), so it must NOT be namespaced per database\n * or existing persisted data would be orphaned. */\nconst OPFS_POOL_NAME = 'kora-opfs'\n\n/** Headless browsers and some profiles hang on OPFS VFS install; fall back to memory. */\nconst OPFS_INIT_TIMEOUT_MS = 10_000\n\nasync function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {\n\tlet timer: ReturnType<typeof setTimeout> | undefined\n\ttry {\n\t\treturn await Promise.race([\n\t\t\tpromise,\n\t\t\tnew Promise<T>((_, reject) => {\n\t\t\t\ttimer = setTimeout(\n\t\t\t\t\t() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),\n\t\t\t\t\ttimeoutMs,\n\t\t\t\t)\n\t\t\t}),\n\t\t])\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer)\n\t}\n}\n\nfunction opfsDatabaseFilename(dbName: string): string {\n\tconst base = dbName.replace(/[^a-zA-Z0-9._-]/g, '_')\n\treturn base.endsWith('.db') ? base : `${base}.db`\n}\n\n/**\n * Classify why the OPFS SyncAccessHandle pool could not be installed, so the\n * fallback to in-memory is explainable rather than silent.\n */\nfunction classifyOpfsFailure(error: unknown): 'lock-conflict' | 'timeout' | 'unsupported' {\n\tconst message = error instanceof Error ? error.message : String(error)\n\tif (/timed out|timeout/i.test(message)) {\n\t\treturn 'timeout'\n\t}\n\tif (\n\t\t/lock|already|in use|in-use|NoModificationAllowed|acquire|SyncAccessHandle|being created/i.test(\n\t\t\tmessage,\n\t\t)\n\t) {\n\t\treturn 'lock-conflict'\n\t}\n\treturn 'unsupported'\n}\n\n// Scope-global caches shared by every core in this worker.\nlet sqlite3Promise: Promise<Sqlite3Api> | null = null\nlet opfsPoolPromise: Promise<OpfsPool | null> | null = null\nlet opfsFallbackReason: 'lock-conflict' | 'timeout' | 'unsupported' | undefined\n\nasync function loadSqlite3(): Promise<Sqlite3Api> {\n\tconst sqlite3InitModule = (await import('@sqlite.org/sqlite-wasm')).default\n\t// In production builds, Vite hashes asset filenames (e.g. sqlite3-[hash].wasm).\n\t// The sqlite3 module's default locateFile resolves the unhashed name, causing a\n\t// 404. The worker/host entry sets __KORA_SQLITE_WASM_URL via a `?url` import so\n\t// we can override locateFile with the correct hashed URL.\n\tconst wasmUrl = (globalThis as Record<string, unknown>).__KORA_SQLITE_WASM_URL as\n\t\t| string\n\t\t| undefined\n\tconst initOptions = wasmUrl\n\t\t? {\n\t\t\t\tlocateFile: (file: string): string => (file.endsWith('.wasm') ? wasmUrl : file),\n\t\t\t}\n\t\t: undefined\n\tconst initFn = sqlite3InitModule as unknown as (\n\t\topts?: Record<string, unknown>,\n\t) => Promise<unknown>\n\treturn (await withTimeout(initFn(initOptions), 60_000, 'SQLite3 module init')) as Sqlite3Api\n}\n\nfunction getSqlite3(): Promise<Sqlite3Api> {\n\tif (!sqlite3Promise) {\n\t\tsqlite3Promise = loadSqlite3()\n\t}\n\treturn sqlite3Promise\n}\n\nasync function installOpfsPool(sqlite3: Sqlite3Api): Promise<OpfsPool | null> {\n\tif (!sqlite3.installOpfsSAHPoolVfs) {\n\t\topfsFallbackReason = 'unsupported'\n\t\treturn null\n\t}\n\ttry {\n\t\treturn await withTimeout(\n\t\t\tsqlite3.installOpfsSAHPoolVfs({ name: OPFS_POOL_NAME }),\n\t\t\tOPFS_INIT_TIMEOUT_MS,\n\t\t\t'OPFS VFS install',\n\t\t)\n\t} catch (error) {\n\t\topfsFallbackReason = classifyOpfsFailure(error)\n\t\treturn null\n\t}\n}\n\nfunction getOpfsPool(sqlite3: Sqlite3Api): Promise<OpfsPool | null> {\n\tif (!opfsPoolPromise) {\n\t\topfsPoolPromise = installOpfsPool(sqlite3)\n\t}\n\treturn opfsPoolPromise\n}\n\n/** Handle to a single database, dispatching the worker protocol for it. */\nexport interface SqliteWasmCore {\n\thandle(request: WorkerRequest): Promise<WorkerResponse>\n}\n\n/**\n * Creates a core bound to one database. `handle` resolves with the response for\n * each request; the caller routes it back through the dedicated worker's\n * `postMessage`.\n */\nexport function createSqliteWasmCore(): SqliteWasmCore {\n\tlet db: SqliteDb | null = null\n\tlet sqlite3Api: Sqlite3Api | null = null\n\tlet persistent = false\n\n\tasync function open(\n\t\tid: number,\n\t\tddlStatements: string[],\n\t\tdbName?: string,\n\t): Promise<WorkerResponse> {\n\t\ttry {\n\t\t\t// Re-run idempotent DDL on the existing handle rather than opening the\n\t\t\t// database a second time.\n\t\t\tif (db) {\n\t\t\t\tapplyDdl(db, ddlStatements)\n\t\t\t\treturn { id, type: 'success', data: buildOpenData() }\n\t\t\t}\n\n\t\t\tconst sqlite3 = await getSqlite3()\n\t\t\tsqlite3Api = sqlite3\n\t\t\tconst pool = await getOpfsPool(sqlite3)\n\n\t\t\tif (pool) {\n\t\t\t\tdb = new pool.OpfsSAHPoolDb(opfsDatabaseFilename(dbName ?? 'kora-db'))\n\t\t\t\tpersistent = true\n\t\t\t} else {\n\t\t\t\tdb = new sqlite3.oo1.DB({ filename: ':memory:' })\n\t\t\t\tpersistent = false\n\t\t\t}\n\n\t\t\tdb.exec({ sql: 'PRAGMA journal_mode = WAL' })\n\t\t\tdb.exec({ sql: 'PRAGMA foreign_keys = ON' })\n\n\t\t\tapplyDdl(db, ddlStatements)\n\t\t\treturn { id, type: 'success', data: buildOpenData() }\n\t\t} catch (error) {\n\t\t\treturn { id, type: 'error', message: (error as Error).message, code: 'INIT_ERROR' }\n\t\t}\n\t}\n\n\tfunction buildOpenData(): { persistent: boolean; fallbackReason?: string } {\n\t\treturn {\n\t\t\tpersistent,\n\t\t\t...(persistent ? {} : { fallbackReason: opfsFallbackReason ?? 'unsupported' }),\n\t\t}\n\t}\n\n\tfunction applyDdl(target: SqliteDb, ddlStatements: string[]): void {\n\t\tfor (const sql of ddlStatements) {\n\t\t\tif (sql.startsWith('--kora:safe-alter')) {\n\t\t\t\ttry {\n\t\t\t\t\ttarget.exec({ sql: sql.replace('--kora:safe-alter\\n', '') })\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst msg = (error as Error).message || ''\n\t\t\t\t\tif (!msg.includes('duplicate column name')) {\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget.exec({ sql })\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction execute(id: number, sql: string, params?: unknown[]): WorkerResponse {\n\t\tif (!db) {\n\t\t\treturn { id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' }\n\t\t}\n\t\ttry {\n\t\t\tdb.exec({ sql, bind: params })\n\t\t\treturn { id, type: 'success' }\n\t\t} catch (error) {\n\t\t\treturn { id, type: 'error', message: (error as Error).message, code: 'EXEC_ERROR' }\n\t\t}\n\t}\n\n\tfunction query(id: number, sql: string, params?: unknown[]): WorkerResponse {\n\t\tif (!db) {\n\t\t\treturn { id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' }\n\t\t}\n\t\ttry {\n\t\t\tconst rows: Record<string, unknown>[] = []\n\t\t\tdb.exec({\n\t\t\t\tsql,\n\t\t\t\tbind: params,\n\t\t\t\trowMode: 'object',\n\t\t\t\tcallback: (row: Record<string, unknown>) => {\n\t\t\t\t\trows.push({ ...row })\n\t\t\t\t},\n\t\t\t})\n\t\t\treturn { id, type: 'success', data: rows }\n\t\t} catch (error) {\n\t\t\treturn { id, type: 'error', message: (error as Error).message, code: 'QUERY_ERROR' }\n\t\t}\n\t}\n\n\tfunction close(id: number): WorkerResponse {\n\t\tif (db) {\n\t\t\tdb.close()\n\t\t\tdb = null\n\t\t}\n\t\treturn { id, type: 'success' }\n\t}\n\n\tfunction migrate(id: number, statements: string[]): WorkerResponse {\n\t\tif (!db) {\n\t\t\treturn { id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' }\n\t\t}\n\t\ttry {\n\t\t\tfor (const sql of statements) {\n\t\t\t\tdb.exec({ sql })\n\t\t\t}\n\t\t\treturn { id, type: 'success' }\n\t\t} catch (error) {\n\t\t\treturn { id, type: 'error', message: (error as Error).message, code: 'MIGRATE_ERROR' }\n\t\t}\n\t}\n\n\tfunction importData(id: number, data: Uint8Array): WorkerResponse {\n\t\tif (!db) {\n\t\t\treturn { id, type: 'error', message: 'Database is not open', code: 'DB_NOT_OPEN' }\n\t\t}\n\t\tconst dbWithDeserialize = db as SqliteDb & { deserialize?: (bytes: Uint8Array) => void }\n\t\tif (typeof dbWithDeserialize.deserialize === 'function') {\n\t\t\ttry {\n\t\t\t\tdbWithDeserialize.deserialize(data)\n\t\t\t\treturn { id, type: 'success' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { id, type: 'error', message: (error as Error).message, code: 'IMPORT_ERROR' }\n\t\t\t}\n\t\t}\n\t\tif (!sqlite3Api || typeof sqlite3Api.capi?.sqlite3_deserialize === 'undefined') {\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\ttype: 'error',\n\t\t\t\tmessage: 'Import not supported in this SQLite WASM runtime',\n\t\t\t\tcode: 'IMPORT_NOT_SUPPORTED',\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tid,\n\t\t\ttype: 'error',\n\t\t\tmessage:\n\t\t\t\t'Import requires runtime-specific deserialize wiring and is unavailable in this worker build',\n\t\t\tcode: 'IMPORT_NOT_SUPPORTED',\n\t\t}\n\t}\n\n\tasync function handle(request: WorkerRequest): Promise<WorkerResponse> {\n\t\ttry {\n\t\t\tswitch (request.type) {\n\t\t\t\tcase 'open':\n\t\t\t\t\treturn await open(request.id, request.ddlStatements, request.dbName)\n\t\t\t\tcase 'close':\n\t\t\t\t\treturn close(request.id)\n\t\t\t\tcase 'execute':\n\t\t\t\t\treturn execute(request.id, request.sql, request.params)\n\t\t\t\tcase 'query':\n\t\t\t\t\treturn query(request.id, request.sql, request.params)\n\t\t\t\tcase 'begin':\n\t\t\t\t\treturn execute(request.id, 'BEGIN')\n\t\t\t\tcase 'commit':\n\t\t\t\t\treturn execute(request.id, 'COMMIT')\n\t\t\t\tcase 'rollback':\n\t\t\t\t\treturn execute(request.id, 'ROLLBACK')\n\t\t\t\tcase 'migrate':\n\t\t\t\t\treturn migrate(request.id, request.statements)\n\t\t\t\tcase 'import':\n\t\t\t\t\treturn importData(request.id, request.data)\n\t\t\t\tcase 'export':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: request.id,\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\tmessage: 'Export not yet supported in browser worker',\n\t\t\t\t\t\tcode: 'EXPORT_NOT_SUPPORTED',\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: (request as WorkerRequest).id,\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\tmessage: 'Unknown request type',\n\t\t\t\t\t\tcode: 'UNKNOWN_REQUEST',\n\t\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tid: request.id,\n\t\t\t\ttype: 'error',\n\t\t\t\tmessage: (error as Error).message,\n\t\t\t\tcode: 'WORKER_ERROR',\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { handle }\n}\n","/// <reference lib=\"webworker\" />\n/**\n * Web Worker script for running SQLite WASM in a dedicated worker.\n *\n * This file is intended to run inside a Web Worker in browsers. It wires one\n * {@link createSqliteWasmCore} to the worker's message channel.\n *\n * This script cannot be tested in Node.js; it is validated in E2E browser tests.\n */\n\nimport type { WorkerRequest } from './sqlite-wasm-channel'\nimport { createSqliteWasmCore } from './sqlite-wasm-worker-core'\n\ndeclare const self: DedicatedWorkerGlobalScope\n\nconst core = createSqliteWasmCore()\n\nself.onmessage = (event: MessageEvent<WorkerRequest>): void => {\n\tvoid core.handle(event.data).then((response) => {\n\t\tself.postMessage(response)\n\t})\n}\n"],"mappings":"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","names":[]}