@korajs/store 1.0.0-beta.2 → 1.0.0-beta.5
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.
- package/dist/adapters/better-sqlite3.cjs.map +1 -1
- package/dist/adapters/better-sqlite3.d.cts +1 -1
- package/dist/adapters/better-sqlite3.d.ts +1 -1
- package/dist/adapters/better-sqlite3.js +1 -1
- package/dist/adapters/indexeddb.cjs +161 -35
- package/dist/adapters/indexeddb.cjs.map +1 -1
- package/dist/adapters/indexeddb.d.cts +2 -2
- package/dist/adapters/indexeddb.d.ts +2 -2
- package/dist/adapters/indexeddb.js +3 -3
- package/dist/adapters/sqlite-wasm-shared-host.cjs +333 -56
- package/dist/adapters/sqlite-wasm-shared-host.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-shared-host.d.cts +81 -1
- package/dist/adapters/sqlite-wasm-shared-host.d.ts +81 -1
- package/dist/adapters/sqlite-wasm-shared-host.js +51 -56
- package/dist/adapters/sqlite-wasm-shared-host.js.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.cjs +206 -208
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +8 -257
- package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
- package/dist/adapters/sqlite-wasm.cjs +161 -35
- package/dist/adapters/sqlite-wasm.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm.d.cts +14 -3
- package/dist/adapters/sqlite-wasm.d.ts +14 -3
- package/dist/adapters/sqlite-wasm.js +3 -3
- package/dist/{backup-IQE4QC7Q.js → backup-5S7K2Z35.js} +3 -3
- package/dist/chunk-3Y2IERBF.js +255 -0
- package/dist/chunk-3Y2IERBF.js.map +1 -0
- package/dist/{chunk-IOEFNHHP.js → chunk-COJSQBXW.js} +2 -2
- package/dist/{chunk-RCTG3IJG.js → chunk-CYO3YKFL.js} +2 -2
- package/dist/{chunk-6NKLDBTY.js → chunk-GSJ7EEUC.js} +2 -1
- package/dist/chunk-GSJ7EEUC.js.map +1 -0
- package/dist/{chunk-OCOGQRHW.js → chunk-HS6DBMST.js} +2 -2
- package/dist/{chunk-QUJGXSZ6.js → chunk-Q57CHIIN.js} +154 -37
- package/dist/chunk-Q57CHIIN.js.map +1 -0
- package/dist/{chunk-2VRPF25R.js → chunk-RL43UYQZ.js} +3 -3
- package/dist/{chunk-QL2XVZRN.js → chunk-TUR7RGEP.js} +12 -1
- package/dist/{chunk-QL2XVZRN.js.map → chunk-TUR7RGEP.js.map} +1 -1
- package/dist/{export-audit-MT2LTMIN.js → export-audit-ODGQTQIK.js} +3 -3
- package/dist/index.cjs +132 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -5
- package/dist/index.d.ts +37 -5
- package/dist/index.js +131 -12
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +1 -0
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +3 -3
- package/dist/{sqlite-wasm-channel-DUDPclTE.d.cts → sqlite-wasm-channel-Bx57s8Cq.d.cts} +1 -1
- package/dist/{sqlite-wasm-channel-DUDPclTE.d.ts → sqlite-wasm-channel-Bx57s8Cq.d.ts} +1 -1
- package/dist/sqlite-wasm-channel-NGSBJR44.js +12 -0
- package/dist/{types-5h4Hqcwc.d.ts → types-C1kigrWz.d.ts} +1 -1
- package/dist/{types-k6AZgiH4.d.ts → types-D1MzKVmk.d.cts} +10 -0
- package/dist/{types-k6AZgiH4.d.cts → types-D1MzKVmk.d.ts} +10 -0
- package/dist/{types-DfPiPwKr.d.cts → types-DAo9oduO.d.cts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-6NKLDBTY.js.map +0 -1
- package/dist/chunk-QUJGXSZ6.js.map +0 -1
- package/dist/sqlite-wasm-channel-H43KEZLM.js +0 -12
- /package/dist/{backup-IQE4QC7Q.js.map → backup-5S7K2Z35.js.map} +0 -0
- /package/dist/{chunk-IOEFNHHP.js.map → chunk-COJSQBXW.js.map} +0 -0
- /package/dist/{chunk-RCTG3IJG.js.map → chunk-CYO3YKFL.js.map} +0 -0
- /package/dist/{chunk-OCOGQRHW.js.map → chunk-HS6DBMST.js.map} +0 -0
- /package/dist/{chunk-2VRPF25R.js.map → chunk-RL43UYQZ.js.map} +0 -0
- /package/dist/{export-audit-MT2LTMIN.js.map → export-audit-ODGQTQIK.js.map} +0 -0
- /package/dist/{sqlite-wasm-channel-H43KEZLM.js.map → sqlite-wasm-channel-NGSBJR44.js.map} +0 -0
|
@@ -1,66 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSqliteWasmCore
|
|
3
|
+
} from "../chunk-3Y2IERBF.js";
|
|
4
|
+
|
|
1
5
|
// src/adapters/sqlite-wasm-shared-host.ts
|
|
2
6
|
var SW_REQUEST = "kora-sw-request";
|
|
3
7
|
var SW_RESPONSE = "kora-sw-response";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const entry = { worker, pending: /* @__PURE__ */ new Map() };
|
|
12
|
-
worker.onmessage = (event) => {
|
|
13
|
-
const response = event.data;
|
|
14
|
-
const requestId = entry.pending.get(response.id);
|
|
15
|
-
if (!requestId) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
entry.pending.delete(response.id);
|
|
19
|
-
const port = findPortForRequest(requestId);
|
|
20
|
-
if (port) {
|
|
21
|
-
const msg = {
|
|
22
|
-
type: SW_RESPONSE,
|
|
23
|
-
requestId,
|
|
24
|
-
response
|
|
25
|
-
};
|
|
26
|
-
port.postMessage(msg);
|
|
8
|
+
function createSharedWorkerHost(options) {
|
|
9
|
+
const cores = /* @__PURE__ */ new Map();
|
|
10
|
+
function coreFor(dbName) {
|
|
11
|
+
let core = cores.get(dbName);
|
|
12
|
+
if (!core) {
|
|
13
|
+
core = options.createCore();
|
|
14
|
+
cores.set(dbName, core);
|
|
27
15
|
}
|
|
28
|
-
|
|
29
|
-
pools.set(dbName, entry);
|
|
30
|
-
return entry;
|
|
31
|
-
}
|
|
32
|
-
var portRequestIds = /* @__PURE__ */ new Map();
|
|
33
|
-
var requestPort = /* @__PURE__ */ new Map();
|
|
34
|
-
function findPortForRequest(requestId) {
|
|
35
|
-
return requestPort.get(requestId);
|
|
36
|
-
}
|
|
37
|
-
self.onconnect = (event) => {
|
|
38
|
-
const port = event.ports[0];
|
|
39
|
-
if (!port) {
|
|
40
|
-
return;
|
|
16
|
+
return core;
|
|
41
17
|
}
|
|
42
|
-
port
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
18
|
+
function connect(port) {
|
|
19
|
+
port.start();
|
|
20
|
+
port.addEventListener("message", (event) => {
|
|
21
|
+
const data = event.data;
|
|
22
|
+
if (data?.type !== SW_REQUEST) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const core = coreFor(data.dbName);
|
|
26
|
+
void core.handle(data.request).then(
|
|
27
|
+
(response) => {
|
|
28
|
+
port.postMessage({ type: SW_RESPONSE, requestId: data.requestId, response });
|
|
29
|
+
},
|
|
30
|
+
(error) => {
|
|
31
|
+
const message = error instanceof Error ? error.message : "SharedWorker core failed";
|
|
32
|
+
port.postMessage({
|
|
33
|
+
type: SW_RESPONSE,
|
|
34
|
+
requestId: data.requestId,
|
|
35
|
+
response: {
|
|
36
|
+
id: data.request.id,
|
|
37
|
+
type: "error",
|
|
38
|
+
message,
|
|
39
|
+
code: "SHARED_WORKER_CORE_ERROR"
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return { connect };
|
|
47
|
+
}
|
|
48
|
+
if (typeof SharedWorkerGlobalScope !== "undefined" && typeof self !== "undefined" && self instanceof SharedWorkerGlobalScope) {
|
|
49
|
+
const host = createSharedWorkerHost({ createCore: createSqliteWasmCore });
|
|
50
|
+
self.addEventListener("connect", (event) => {
|
|
51
|
+
const port = event.ports[0];
|
|
52
|
+
if (!port) {
|
|
58
53
|
return;
|
|
59
54
|
}
|
|
60
|
-
|
|
61
|
-
requestPort.delete(requestId);
|
|
62
|
-
}
|
|
63
|
-
portRequestIds.delete(port);
|
|
55
|
+
host.connect(port);
|
|
64
56
|
});
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
createSharedWorkerHost
|
|
65
60
|
};
|
|
66
61
|
//# sourceMappingURL=sqlite-wasm-shared-host.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/sqlite-wasm-shared-host.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n/**\n * SharedWorker host:
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/sqlite-wasm-shared-host.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n/**\n * SharedWorker host: runs SQLite WASM directly inside the SharedWorker, one\n * database core per `dbName`, shared by every tab on the origin.\n *\n * A SharedWorker CANNOT spawn a nested `Worker` (the `Worker` constructor is not\n * defined in `SharedWorkerGlobalScope` in Chromium), so the host does not delegate\n * to a dedicated worker. It runs {@link createSqliteWasmCore} in its own scope.\n * Because each request is answered by a Promise from the core, responses are\n * correlated to their caller directly, with no inner-id bookkeeping.\n *\n * Bundle this file separately and pass its URL as `store.sharedWorkerUrl` alongside\n * `workerUrl`. The entry that bundles it must set `__KORA_SQLITE_WASM_URL` (via a\n * `?url` import of the sqlite wasm binary) the same way the dedicated worker entry\n * does, so the core can locate the hashed WASM asset in production builds.\n *\n * @example\n * ```typescript\n * createApp({\n * store: {\n * workerUrl: '/sqlite-wasm-worker.js',\n * sharedWorkerUrl: '/sqlite-wasm-shared-host.js',\n * },\n * })\n * ```\n */\n\nimport type { WorkerRequest, WorkerResponse } from './sqlite-wasm-channel'\nimport { type SqliteWasmCore, createSqliteWasmCore } from './sqlite-wasm-worker-core'\n\nconst SW_REQUEST = 'kora-sw-request'\nconst SW_RESPONSE = 'kora-sw-response'\n\ninterface SharedWorkerRpcRequest {\n\ttype: typeof SW_REQUEST\n\trequestId: string\n\tdbName: string\n\tworkerUrl: string\n\trequest: WorkerRequest\n}\n\ninterface SharedWorkerRpcResponse {\n\ttype: typeof SW_RESPONSE\n\trequestId: string\n\tresponse: WorkerResponse\n}\n\n/** Minimal structural view of a connected client `MessagePort`. */\nexport interface HostPort {\n\tstart(): void\n\tpostMessage(message: SharedWorkerRpcResponse): void\n\taddEventListener(\n\t\ttype: 'message' | 'messageerror',\n\t\thandler: (event: { data: unknown }) => void,\n\t): void\n}\n\nexport interface SharedWorkerHostOptions {\n\t/** Creates a database core. Injectable so the host routing can be unit-tested. */\n\tcreateCore: () => SqliteWasmCore\n}\n\nexport interface SharedWorkerHost {\n\t/** Wire a newly connected client port into the host. */\n\tconnect(port: HostPort): void\n}\n\n/**\n * Creates the SharedWorker host routing core: one SQLite core per `dbName`, shared\n * by every connected tab, with each request answered directly by the core.\n */\nexport function createSharedWorkerHost(options: SharedWorkerHostOptions): SharedWorkerHost {\n\tconst cores = new Map<string, SqliteWasmCore>()\n\n\tfunction coreFor(dbName: string): SqliteWasmCore {\n\t\tlet core = cores.get(dbName)\n\t\tif (!core) {\n\t\t\tcore = options.createCore()\n\t\t\tcores.set(dbName, core)\n\t\t}\n\t\treturn core\n\t}\n\n\tfunction connect(port: HostPort): void {\n\t\tport.start()\n\n\t\tport.addEventListener('message', (event: { data: unknown }): void => {\n\t\t\tconst data = event.data as SharedWorkerRpcRequest | undefined\n\t\t\tif (data?.type !== SW_REQUEST) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst core = coreFor(data.dbName)\n\t\t\tvoid core.handle(data.request).then(\n\t\t\t\t(response) => {\n\t\t\t\t\tport.postMessage({ type: SW_RESPONSE, requestId: data.requestId, response })\n\t\t\t\t},\n\t\t\t\t(error: unknown) => {\n\t\t\t\t\t// The core catches its own errors, so this only fires on an unexpected\n\t\t\t\t\t// throw. Relay it so the client never hangs waiting for a response.\n\t\t\t\t\tconst message = error instanceof Error ? error.message : 'SharedWorker core failed'\n\t\t\t\t\tport.postMessage({\n\t\t\t\t\t\ttype: SW_RESPONSE,\n\t\t\t\t\t\trequestId: data.requestId,\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tid: data.request.id,\n\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t\tcode: 'SHARED_WORKER_CORE_ERROR',\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t}\n\n\treturn { connect }\n}\n\n// Wire the host to the SharedWorker global only when running as an actual\n// SharedWorker. The guard uses `instanceof SharedWorkerGlobalScope` so it is true\n// in a real SharedWorker and false everywhere else (Node test runtimes, the main\n// thread, a dedicated worker), which keeps `createSharedWorkerHost` unit-testable\n// in isolation. A connection is delivered as a `connect` event whose `ports[0]` is\n// the client MessagePort.\ndeclare const self: SharedWorkerGlobalScope\nif (\n\ttypeof SharedWorkerGlobalScope !== 'undefined' &&\n\ttypeof self !== 'undefined' &&\n\tself instanceof SharedWorkerGlobalScope\n) {\n\tconst host = createSharedWorkerHost({ createCore: createSqliteWasmCore })\n\n\tself.addEventListener('connect', (event: MessageEvent): void => {\n\t\tconst port = event.ports[0]\n\t\tif (!port) {\n\t\t\treturn\n\t\t}\n\t\thost.connect(port as unknown as HostPort)\n\t})\n}\n"],"mappings":";;;;;AA8BA,IAAM,aAAa;AACnB,IAAM,cAAc;AAwCb,SAAS,uBAAuB,SAAoD;AAC1F,QAAM,QAAQ,oBAAI,IAA4B;AAE9C,WAAS,QAAQ,QAAgC;AAChD,QAAI,OAAO,MAAM,IAAI,MAAM;AAC3B,QAAI,CAAC,MAAM;AACV,aAAO,QAAQ,WAAW;AAC1B,YAAM,IAAI,QAAQ,IAAI;AAAA,IACvB;AACA,WAAO;AAAA,EACR;AAEA,WAAS,QAAQ,MAAsB;AACtC,SAAK,MAAM;AAEX,SAAK,iBAAiB,WAAW,CAAC,UAAmC;AACpE,YAAM,OAAO,MAAM;AACnB,UAAI,MAAM,SAAS,YAAY;AAC9B;AAAA,MACD;AAEA,YAAM,OAAO,QAAQ,KAAK,MAAM;AAChC,WAAK,KAAK,OAAO,KAAK,OAAO,EAAE;AAAA,QAC9B,CAAC,aAAa;AACb,eAAK,YAAY,EAAE,MAAM,aAAa,WAAW,KAAK,WAAW,SAAS,CAAC;AAAA,QAC5E;AAAA,QACA,CAAC,UAAmB;AAGnB,gBAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,eAAK,YAAY;AAAA,YAChB,MAAM;AAAA,YACN,WAAW,KAAK;AAAA,YAChB,UAAU;AAAA,cACT,IAAI,KAAK,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA,MAAM;AAAA,YACP;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ;AAClB;AASA,IACC,OAAO,4BAA4B,eACnC,OAAO,SAAS,eAChB,gBAAgB,yBACf;AACD,QAAM,OAAO,uBAAuB,EAAE,YAAY,qBAAqB,CAAC;AAExE,OAAK,iBAAiB,WAAW,CAAC,UAA8B;AAC/D,UAAM,OAAO,MAAM,MAAM,CAAC;AAC1B,QAAI,CAAC,MAAM;AACV;AAAA,IACD;AACA,SAAK,QAAQ,IAA2B;AAAA,EACzC,CAAC;AACF;","names":[]}
|
|
@@ -22,48 +22,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
|
|
25
|
-
// src/adapters/sqlite-wasm-worker.ts
|
|
26
|
-
var
|
|
27
|
-
var sqlite3Api = null;
|
|
28
|
-
function sendResponse(response) {
|
|
29
|
-
self.postMessage(response);
|
|
30
|
-
}
|
|
31
|
-
function handleExecute(id, sql, params) {
|
|
32
|
-
if (!db) {
|
|
33
|
-
sendResponse({ id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" });
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
db.exec({ sql, bind: params });
|
|
38
|
-
sendResponse({ id, type: "success" });
|
|
39
|
-
} catch (error) {
|
|
40
|
-
sendResponse({ id, type: "error", message: error.message, code: "EXEC_ERROR" });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function handleQuery(id, sql, params) {
|
|
44
|
-
if (!db) {
|
|
45
|
-
sendResponse({ id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" });
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
const rows = [];
|
|
50
|
-
db.exec({
|
|
51
|
-
sql,
|
|
52
|
-
bind: params,
|
|
53
|
-
rowMode: "object",
|
|
54
|
-
callback: (row) => {
|
|
55
|
-
rows.push({ ...row });
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
sendResponse({ id, type: "success", data: rows });
|
|
59
|
-
} catch (error) {
|
|
60
|
-
sendResponse({ id, type: "error", message: error.message, code: "QUERY_ERROR" });
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function opfsDatabaseFilename(dbName) {
|
|
64
|
-
const base = dbName.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
65
|
-
return base.endsWith(".db") ? base : `${base}.db`;
|
|
66
|
-
}
|
|
25
|
+
// src/adapters/sqlite-wasm-worker-core.ts
|
|
26
|
+
var OPFS_POOL_NAME = "kora-opfs";
|
|
67
27
|
var OPFS_INIT_TIMEOUT_MS = 1e4;
|
|
68
28
|
async function withTimeout(promise, timeoutMs, label) {
|
|
69
29
|
let timer;
|
|
@@ -81,205 +41,243 @@ async function withTimeout(promise, timeoutMs, label) {
|
|
|
81
41
|
if (timer !== void 0) clearTimeout(timer);
|
|
82
42
|
}
|
|
83
43
|
}
|
|
84
|
-
|
|
44
|
+
function opfsDatabaseFilename(dbName) {
|
|
45
|
+
const base = dbName.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
46
|
+
return base.endsWith(".db") ? base : `${base}.db`;
|
|
47
|
+
}
|
|
48
|
+
function classifyOpfsFailure(error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
if (/timed out|timeout/i.test(message)) {
|
|
51
|
+
return "timeout";
|
|
52
|
+
}
|
|
53
|
+
if (/lock|already|in use|in-use|NoModificationAllowed|acquire|SyncAccessHandle|being created/i.test(
|
|
54
|
+
message
|
|
55
|
+
)) {
|
|
56
|
+
return "lock-conflict";
|
|
57
|
+
}
|
|
58
|
+
return "unsupported";
|
|
59
|
+
}
|
|
60
|
+
var sqlite3Promise = null;
|
|
61
|
+
var opfsPoolPromise = null;
|
|
62
|
+
var opfsFallbackReason;
|
|
63
|
+
async function loadSqlite3() {
|
|
64
|
+
const sqlite3InitModule = (await import("@sqlite.org/sqlite-wasm")).default;
|
|
65
|
+
const wasmUrl = globalThis.__KORA_SQLITE_WASM_URL;
|
|
66
|
+
const initOptions = wasmUrl ? {
|
|
67
|
+
locateFile: (file) => file.endsWith(".wasm") ? wasmUrl : file
|
|
68
|
+
} : void 0;
|
|
69
|
+
const initFn = sqlite3InitModule;
|
|
70
|
+
return await withTimeout(initFn(initOptions), 6e4, "SQLite3 module init");
|
|
71
|
+
}
|
|
72
|
+
function getSqlite3() {
|
|
73
|
+
if (!sqlite3Promise) {
|
|
74
|
+
sqlite3Promise = loadSqlite3();
|
|
75
|
+
}
|
|
76
|
+
return sqlite3Promise;
|
|
77
|
+
}
|
|
78
|
+
async function installOpfsPool(sqlite3) {
|
|
79
|
+
if (!sqlite3.installOpfsSAHPoolVfs) {
|
|
80
|
+
opfsFallbackReason = "unsupported";
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
85
83
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (file.endsWith(".wasm")) return wasmUrl;
|
|
91
|
-
return file;
|
|
92
|
-
}
|
|
93
|
-
} : void 0;
|
|
94
|
-
const initFn = sqlite3InitModule;
|
|
95
|
-
const sqlite3 = await withTimeout(
|
|
96
|
-
initFn(initOptions),
|
|
97
|
-
6e4,
|
|
98
|
-
"SQLite3 module init"
|
|
84
|
+
return await withTimeout(
|
|
85
|
+
sqlite3.installOpfsSAHPoolVfs({ name: OPFS_POOL_NAME }),
|
|
86
|
+
OPFS_INIT_TIMEOUT_MS,
|
|
87
|
+
"OPFS VFS install"
|
|
99
88
|
);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
89
|
+
} catch (error) {
|
|
90
|
+
opfsFallbackReason = classifyOpfsFailure(error);
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function getOpfsPool(sqlite3) {
|
|
95
|
+
if (!opfsPoolPromise) {
|
|
96
|
+
opfsPoolPromise = installOpfsPool(sqlite3);
|
|
97
|
+
}
|
|
98
|
+
return opfsPoolPromise;
|
|
99
|
+
}
|
|
100
|
+
function createSqliteWasmCore() {
|
|
101
|
+
let db = null;
|
|
102
|
+
let sqlite3Api = null;
|
|
103
|
+
let persistent = false;
|
|
104
|
+
async function open(id, ddlStatements, dbName) {
|
|
105
|
+
try {
|
|
106
|
+
if (db) {
|
|
107
|
+
applyDdl(db, ddlStatements);
|
|
108
|
+
return { id, type: "success", data: buildOpenData() };
|
|
109
|
+
}
|
|
110
|
+
const sqlite3 = await getSqlite3();
|
|
111
|
+
sqlite3Api = sqlite3;
|
|
112
|
+
const pool = await getOpfsPool(sqlite3);
|
|
113
|
+
if (pool) {
|
|
110
114
|
db = new pool.OpfsSAHPoolDb(opfsDatabaseFilename(dbName ?? "kora-db"));
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
`[kora] OPFS unavailable (${fallbackReason}), falling back to in-memory SQLite`
|
|
116
|
-
);
|
|
115
|
+
persistent = true;
|
|
116
|
+
} else {
|
|
117
|
+
db = new sqlite3.oo1.DB({ filename: ":memory:" });
|
|
118
|
+
persistent = false;
|
|
117
119
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
db.exec({ sql: "PRAGMA journal_mode = WAL" });
|
|
121
|
+
db.exec({ sql: "PRAGMA foreign_keys = ON" });
|
|
122
|
+
applyDdl(db, ddlStatements);
|
|
123
|
+
return { id, type: "success", data: buildOpenData() };
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return { id, type: "error", message: error.message, code: "INIT_ERROR" };
|
|
123
126
|
}
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
}
|
|
128
|
+
function buildOpenData() {
|
|
129
|
+
return {
|
|
130
|
+
persistent,
|
|
131
|
+
...persistent ? {} : { fallbackReason: opfsFallbackReason ?? "unsupported" }
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function applyDdl(target, ddlStatements) {
|
|
126
135
|
for (const sql of ddlStatements) {
|
|
127
136
|
if (sql.startsWith("--kora:safe-alter")) {
|
|
128
137
|
try {
|
|
129
|
-
|
|
130
|
-
} catch (
|
|
131
|
-
const msg =
|
|
138
|
+
target.exec({ sql: sql.replace("--kora:safe-alter\n", "") });
|
|
139
|
+
} catch (error) {
|
|
140
|
+
const msg = error.message || "";
|
|
132
141
|
if (!msg.includes("duplicate column name")) {
|
|
133
|
-
throw
|
|
142
|
+
throw error;
|
|
134
143
|
}
|
|
135
144
|
}
|
|
136
145
|
} else {
|
|
137
|
-
|
|
146
|
+
target.exec({ sql });
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
|
-
sendResponse({
|
|
141
|
-
id,
|
|
142
|
-
type: "success",
|
|
143
|
-
data: { persistent: useOpfs, ...fallbackReason ? { fallbackReason } : {} }
|
|
144
|
-
});
|
|
145
|
-
} catch (error) {
|
|
146
|
-
sendResponse({
|
|
147
|
-
id,
|
|
148
|
-
type: "error",
|
|
149
|
-
message: error.message,
|
|
150
|
-
code: "INIT_ERROR"
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
function classifyOpfsFailure(error) {
|
|
155
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
156
|
-
if (/timed out|timeout/i.test(message)) {
|
|
157
|
-
return "timeout";
|
|
158
149
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
150
|
+
function execute(id, sql, params) {
|
|
151
|
+
if (!db) {
|
|
152
|
+
return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
db.exec({ sql, bind: params });
|
|
156
|
+
return { id, type: "success" };
|
|
157
|
+
} catch (error) {
|
|
158
|
+
return { id, type: "error", message: error.message, code: "EXEC_ERROR" };
|
|
159
|
+
}
|
|
163
160
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
function query(id, sql, params) {
|
|
162
|
+
if (!db) {
|
|
163
|
+
return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const rows = [];
|
|
167
|
+
db.exec({
|
|
168
|
+
sql,
|
|
169
|
+
bind: params,
|
|
170
|
+
rowMode: "object",
|
|
171
|
+
callback: (row) => {
|
|
172
|
+
rows.push({ ...row });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return { id, type: "success", data: rows };
|
|
176
|
+
} catch (error) {
|
|
177
|
+
return { id, type: "error", message: error.message, code: "QUERY_ERROR" };
|
|
178
|
+
}
|
|
170
179
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return;
|
|
180
|
+
function close(id) {
|
|
181
|
+
if (db) {
|
|
182
|
+
db.close();
|
|
183
|
+
db = null;
|
|
184
|
+
}
|
|
185
|
+
return { id, type: "success" };
|
|
177
186
|
}
|
|
178
|
-
|
|
179
|
-
|
|
187
|
+
function migrate(id, statements) {
|
|
188
|
+
if (!db) {
|
|
189
|
+
return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
|
|
190
|
+
}
|
|
180
191
|
try {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
192
|
+
for (const sql of statements) {
|
|
193
|
+
db.exec({ sql });
|
|
194
|
+
}
|
|
195
|
+
return { id, type: "success" };
|
|
184
196
|
} catch (error) {
|
|
185
|
-
|
|
186
|
-
return;
|
|
197
|
+
return { id, type: "error", message: error.message, code: "MIGRATE_ERROR" };
|
|
187
198
|
}
|
|
188
199
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
200
|
+
function importData(id, data) {
|
|
201
|
+
if (!db) {
|
|
202
|
+
return { id, type: "error", message: "Database is not open", code: "DB_NOT_OPEN" };
|
|
203
|
+
}
|
|
204
|
+
const dbWithDeserialize = db;
|
|
205
|
+
if (typeof dbWithDeserialize.deserialize === "function") {
|
|
206
|
+
try {
|
|
207
|
+
dbWithDeserialize.deserialize(data);
|
|
208
|
+
return { id, type: "success" };
|
|
209
|
+
} catch (error) {
|
|
210
|
+
return { id, type: "error", message: error.message, code: "IMPORT_ERROR" };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (!sqlite3Api || typeof sqlite3Api.capi?.sqlite3_deserialize === "undefined") {
|
|
214
|
+
return {
|
|
215
|
+
id,
|
|
216
|
+
type: "error",
|
|
217
|
+
message: "Import not supported in this SQLite WASM runtime",
|
|
218
|
+
code: "IMPORT_NOT_SUPPORTED"
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
192
222
|
id,
|
|
193
223
|
type: "error",
|
|
194
|
-
message: "Import
|
|
224
|
+
message: "Import requires runtime-specific deserialize wiring and is unavailable in this worker build",
|
|
195
225
|
code: "IMPORT_NOT_SUPPORTED"
|
|
196
|
-
}
|
|
197
|
-
return;
|
|
226
|
+
};
|
|
198
227
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
handleExecute(request.id, "BEGIN");
|
|
223
|
-
return;
|
|
224
|
-
case "commit":
|
|
225
|
-
handleExecute(request.id, "COMMIT");
|
|
226
|
-
return;
|
|
227
|
-
case "rollback":
|
|
228
|
-
handleExecute(request.id, "ROLLBACK");
|
|
229
|
-
return;
|
|
230
|
-
case "migrate":
|
|
231
|
-
if (!db) {
|
|
232
|
-
sendResponse({
|
|
228
|
+
async function handle(request) {
|
|
229
|
+
try {
|
|
230
|
+
switch (request.type) {
|
|
231
|
+
case "open":
|
|
232
|
+
return await open(request.id, request.ddlStatements, request.dbName);
|
|
233
|
+
case "close":
|
|
234
|
+
return close(request.id);
|
|
235
|
+
case "execute":
|
|
236
|
+
return execute(request.id, request.sql, request.params);
|
|
237
|
+
case "query":
|
|
238
|
+
return query(request.id, request.sql, request.params);
|
|
239
|
+
case "begin":
|
|
240
|
+
return execute(request.id, "BEGIN");
|
|
241
|
+
case "commit":
|
|
242
|
+
return execute(request.id, "COMMIT");
|
|
243
|
+
case "rollback":
|
|
244
|
+
return execute(request.id, "ROLLBACK");
|
|
245
|
+
case "migrate":
|
|
246
|
+
return migrate(request.id, request.statements);
|
|
247
|
+
case "import":
|
|
248
|
+
return importData(request.id, request.data);
|
|
249
|
+
case "export":
|
|
250
|
+
return {
|
|
233
251
|
id: request.id,
|
|
234
252
|
type: "error",
|
|
235
|
-
message: "
|
|
236
|
-
code: "
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
for (const sql of request.statements) {
|
|
242
|
-
db.exec({ sql });
|
|
243
|
-
}
|
|
244
|
-
sendResponse({ id: request.id, type: "success" });
|
|
245
|
-
} catch (error) {
|
|
246
|
-
sendResponse({
|
|
253
|
+
message: "Export not yet supported in browser worker",
|
|
254
|
+
code: "EXPORT_NOT_SUPPORTED"
|
|
255
|
+
};
|
|
256
|
+
default:
|
|
257
|
+
return {
|
|
247
258
|
id: request.id,
|
|
248
259
|
type: "error",
|
|
249
|
-
message:
|
|
250
|
-
code: "
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
});
|
|
261
|
-
return;
|
|
262
|
-
case "import":
|
|
263
|
-
handleImport(request.id, request.data);
|
|
264
|
-
return;
|
|
265
|
-
default:
|
|
266
|
-
sendResponse({
|
|
267
|
-
id: request.id,
|
|
268
|
-
type: "error",
|
|
269
|
-
message: "Unknown request type",
|
|
270
|
-
code: "UNKNOWN_REQUEST"
|
|
271
|
-
});
|
|
260
|
+
message: "Unknown request type",
|
|
261
|
+
code: "UNKNOWN_REQUEST"
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
} catch (error) {
|
|
265
|
+
return {
|
|
266
|
+
id: request.id,
|
|
267
|
+
type: "error",
|
|
268
|
+
message: error.message,
|
|
269
|
+
code: "WORKER_ERROR"
|
|
270
|
+
};
|
|
272
271
|
}
|
|
273
|
-
} catch (error) {
|
|
274
|
-
sendResponse({
|
|
275
|
-
id: request.id,
|
|
276
|
-
type: "error",
|
|
277
|
-
message: error.message,
|
|
278
|
-
code: "WORKER_ERROR"
|
|
279
|
-
});
|
|
280
272
|
}
|
|
273
|
+
return { handle };
|
|
281
274
|
}
|
|
275
|
+
|
|
276
|
+
// src/adapters/sqlite-wasm-worker.ts
|
|
277
|
+
var core = createSqliteWasmCore();
|
|
282
278
|
self.onmessage = (event) => {
|
|
283
|
-
|
|
279
|
+
void core.handle(event.data).then((response) => {
|
|
280
|
+
self.postMessage(response);
|
|
281
|
+
});
|
|
284
282
|
};
|
|
285
283
|
//# sourceMappingURL=sqlite-wasm-worker.cjs.map
|