@korajs/store 0.1.0

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 (43) hide show
  1. package/dist/adapters/better-sqlite3.cjs +166 -0
  2. package/dist/adapters/better-sqlite3.cjs.map +1 -0
  3. package/dist/adapters/better-sqlite3.d.cts +31 -0
  4. package/dist/adapters/better-sqlite3.d.ts +31 -0
  5. package/dist/adapters/better-sqlite3.js +117 -0
  6. package/dist/adapters/better-sqlite3.js.map +1 -0
  7. package/dist/adapters/indexeddb.cjs +550 -0
  8. package/dist/adapters/indexeddb.cjs.map +1 -0
  9. package/dist/adapters/indexeddb.d.cts +52 -0
  10. package/dist/adapters/indexeddb.d.ts +52 -0
  11. package/dist/adapters/indexeddb.js +205 -0
  12. package/dist/adapters/indexeddb.js.map +1 -0
  13. package/dist/adapters/sqlite-wasm-worker.cjs +215 -0
  14. package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -0
  15. package/dist/adapters/sqlite-wasm-worker.d.cts +2 -0
  16. package/dist/adapters/sqlite-wasm-worker.d.ts +2 -0
  17. package/dist/adapters/sqlite-wasm-worker.js +191 -0
  18. package/dist/adapters/sqlite-wasm-worker.js.map +1 -0
  19. package/dist/adapters/sqlite-wasm.cjs +354 -0
  20. package/dist/adapters/sqlite-wasm.cjs.map +1 -0
  21. package/dist/adapters/sqlite-wasm.d.cts +68 -0
  22. package/dist/adapters/sqlite-wasm.d.ts +68 -0
  23. package/dist/adapters/sqlite-wasm.js +14 -0
  24. package/dist/adapters/sqlite-wasm.js.map +1 -0
  25. package/dist/chunk-DXKLAQ6P.js +111 -0
  26. package/dist/chunk-DXKLAQ6P.js.map +1 -0
  27. package/dist/chunk-LAWV6CFH.js +62 -0
  28. package/dist/chunk-LAWV6CFH.js.map +1 -0
  29. package/dist/chunk-ZP5AXQ3Z.js +179 -0
  30. package/dist/chunk-ZP5AXQ3Z.js.map +1 -0
  31. package/dist/index.cjs +1288 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +376 -0
  34. package/dist/index.d.ts +376 -0
  35. package/dist/index.js +1194 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/sqlite-wasm-channel-46AOWNPM.js +10 -0
  38. package/dist/sqlite-wasm-channel-46AOWNPM.js.map +1 -0
  39. package/dist/sqlite-wasm-channel-Lakjuk2E.d.cts +104 -0
  40. package/dist/sqlite-wasm-channel-Lakjuk2E.d.ts +104 -0
  41. package/dist/types-DF-KDSK1.d.cts +106 -0
  42. package/dist/types-DF-KDSK1.d.ts +106 -0
  43. package/package.json +95 -0
@@ -0,0 +1,68 @@
1
+ import { SchemaDefinition } from '@korajs/core';
2
+ import { S as StorageAdapter, T as Transaction, M as MigrationPlan } from '../types-DF-KDSK1.cjs';
3
+ import { W as WorkerBridge } from '../sqlite-wasm-channel-Lakjuk2E.cjs';
4
+ export { M as Mutex, a as WebWorkerBridge, b as WorkerRequest, c as WorkerResponse } from '../sqlite-wasm-channel-Lakjuk2E.cjs';
5
+
6
+ /**
7
+ * Options for creating a SqliteWasmAdapter.
8
+ */
9
+ interface SqliteWasmAdapterOptions {
10
+ /**
11
+ * Injected WorkerBridge for testing. If omitted, a WebWorkerBridge is created
12
+ * in browser environments.
13
+ */
14
+ bridge?: WorkerBridge;
15
+ /**
16
+ * Database name for persistence. Used as the OPFS file name or IDB key.
17
+ */
18
+ dbName?: string;
19
+ /**
20
+ * URL to the sqlite-wasm-worker script. Required in browsers if no bridge is provided.
21
+ */
22
+ workerUrl?: string | URL;
23
+ }
24
+ /**
25
+ * SQLite WASM adapter that communicates with a SQLite instance through a WorkerBridge.
26
+ *
27
+ * In browsers, the bridge is backed by a Web Worker running SQLite WASM with OPFS persistence.
28
+ * In Node.js tests, the bridge is backed by MockWorkerBridge wrapping better-sqlite3.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Browser usage
33
+ * const adapter = new SqliteWasmAdapter({ workerUrl: '/sqlite-wasm-worker.js' })
34
+ *
35
+ * // Test usage with MockWorkerBridge
36
+ * import { MockWorkerBridge } from './sqlite-wasm-mock-bridge'
37
+ * const adapter = new SqliteWasmAdapter({ bridge: new MockWorkerBridge() })
38
+ * ```
39
+ */
40
+ declare class SqliteWasmAdapter implements StorageAdapter {
41
+ private bridge;
42
+ private opened;
43
+ private readonly mutex;
44
+ private readonly injectedBridge;
45
+ private readonly workerUrl;
46
+ private readonly dbName;
47
+ constructor(options?: SqliteWasmAdapterOptions);
48
+ open(schema: SchemaDefinition): Promise<void>;
49
+ close(): Promise<void>;
50
+ execute(sql: string, params?: unknown[]): Promise<void>;
51
+ query<T>(sql: string, params?: unknown[]): Promise<T[]>;
52
+ transaction(fn: (tx: Transaction) => Promise<void>): Promise<void>;
53
+ migrate(from: number, to: number, migration: MigrationPlan): Promise<void>;
54
+ /**
55
+ * Export the database as a Uint8Array (for IndexedDB persistence).
56
+ * Only available when the database is open.
57
+ */
58
+ exportDatabase(): Promise<Uint8Array>;
59
+ /**
60
+ * Import a serialized database snapshot.
61
+ */
62
+ importDatabase(data: Uint8Array): Promise<void>;
63
+ private guardOpen;
64
+ private sendRequest;
65
+ private sendChecked;
66
+ }
67
+
68
+ export { SqliteWasmAdapter, type SqliteWasmAdapterOptions, WorkerBridge };
@@ -0,0 +1,68 @@
1
+ import { SchemaDefinition } from '@korajs/core';
2
+ import { S as StorageAdapter, T as Transaction, M as MigrationPlan } from '../types-DF-KDSK1.js';
3
+ import { W as WorkerBridge } from '../sqlite-wasm-channel-Lakjuk2E.js';
4
+ export { M as Mutex, a as WebWorkerBridge, b as WorkerRequest, c as WorkerResponse } from '../sqlite-wasm-channel-Lakjuk2E.js';
5
+
6
+ /**
7
+ * Options for creating a SqliteWasmAdapter.
8
+ */
9
+ interface SqliteWasmAdapterOptions {
10
+ /**
11
+ * Injected WorkerBridge for testing. If omitted, a WebWorkerBridge is created
12
+ * in browser environments.
13
+ */
14
+ bridge?: WorkerBridge;
15
+ /**
16
+ * Database name for persistence. Used as the OPFS file name or IDB key.
17
+ */
18
+ dbName?: string;
19
+ /**
20
+ * URL to the sqlite-wasm-worker script. Required in browsers if no bridge is provided.
21
+ */
22
+ workerUrl?: string | URL;
23
+ }
24
+ /**
25
+ * SQLite WASM adapter that communicates with a SQLite instance through a WorkerBridge.
26
+ *
27
+ * In browsers, the bridge is backed by a Web Worker running SQLite WASM with OPFS persistence.
28
+ * In Node.js tests, the bridge is backed by MockWorkerBridge wrapping better-sqlite3.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Browser usage
33
+ * const adapter = new SqliteWasmAdapter({ workerUrl: '/sqlite-wasm-worker.js' })
34
+ *
35
+ * // Test usage with MockWorkerBridge
36
+ * import { MockWorkerBridge } from './sqlite-wasm-mock-bridge'
37
+ * const adapter = new SqliteWasmAdapter({ bridge: new MockWorkerBridge() })
38
+ * ```
39
+ */
40
+ declare class SqliteWasmAdapter implements StorageAdapter {
41
+ private bridge;
42
+ private opened;
43
+ private readonly mutex;
44
+ private readonly injectedBridge;
45
+ private readonly workerUrl;
46
+ private readonly dbName;
47
+ constructor(options?: SqliteWasmAdapterOptions);
48
+ open(schema: SchemaDefinition): Promise<void>;
49
+ close(): Promise<void>;
50
+ execute(sql: string, params?: unknown[]): Promise<void>;
51
+ query<T>(sql: string, params?: unknown[]): Promise<T[]>;
52
+ transaction(fn: (tx: Transaction) => Promise<void>): Promise<void>;
53
+ migrate(from: number, to: number, migration: MigrationPlan): Promise<void>;
54
+ /**
55
+ * Export the database as a Uint8Array (for IndexedDB persistence).
56
+ * Only available when the database is open.
57
+ */
58
+ exportDatabase(): Promise<Uint8Array>;
59
+ /**
60
+ * Import a serialized database snapshot.
61
+ */
62
+ importDatabase(data: Uint8Array): Promise<void>;
63
+ private guardOpen;
64
+ private sendRequest;
65
+ private sendChecked;
66
+ }
67
+
68
+ export { SqliteWasmAdapter, type SqliteWasmAdapterOptions, WorkerBridge };
@@ -0,0 +1,14 @@
1
+ import {
2
+ SqliteWasmAdapter
3
+ } from "../chunk-ZP5AXQ3Z.js";
4
+ import {
5
+ Mutex,
6
+ WebWorkerBridge
7
+ } from "../chunk-DXKLAQ6P.js";
8
+ import "../chunk-LAWV6CFH.js";
9
+ export {
10
+ Mutex,
11
+ SqliteWasmAdapter,
12
+ WebWorkerBridge
13
+ };
14
+ //# sourceMappingURL=sqlite-wasm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,111 @@
1
+ import {
2
+ WorkerTimeoutError
3
+ } from "./chunk-LAWV6CFH.js";
4
+
5
+ // src/adapters/sqlite-wasm-channel.ts
6
+ var Mutex = class {
7
+ locked = false;
8
+ waiters = [];
9
+ /**
10
+ * Acquire the mutex. Returns a release function.
11
+ * If the mutex is already held, the caller waits until it's released.
12
+ */
13
+ async acquire() {
14
+ if (!this.locked) {
15
+ this.locked = true;
16
+ return this.createRelease();
17
+ }
18
+ return new Promise((resolve) => {
19
+ this.waiters.push(() => {
20
+ resolve(this.createRelease());
21
+ });
22
+ });
23
+ }
24
+ createRelease() {
25
+ let released = false;
26
+ return () => {
27
+ if (released) return;
28
+ released = true;
29
+ const next = this.waiters.shift();
30
+ if (next) {
31
+ next();
32
+ } else {
33
+ this.locked = false;
34
+ }
35
+ };
36
+ }
37
+ };
38
+ var WebWorkerBridge = class {
39
+ worker;
40
+ pending = /* @__PURE__ */ new Map();
41
+ nextId = 1;
42
+ terminated = false;
43
+ timeoutMs;
44
+ /**
45
+ * @param workerUrl - URL to the sqlite-wasm-worker script
46
+ * @param timeoutMs - Timeout for worker responses in milliseconds (default: 30000)
47
+ */
48
+ constructor(workerUrl, timeoutMs = 3e4) {
49
+ this.timeoutMs = timeoutMs;
50
+ this.worker = new Worker(workerUrl, { type: "module" });
51
+ this.worker.onmessage = (event) => {
52
+ const response = event.data;
53
+ const entry = this.pending.get(response.id);
54
+ if (entry) {
55
+ this.pending.delete(response.id);
56
+ entry.resolve(response);
57
+ }
58
+ };
59
+ this.worker.onerror = (event) => {
60
+ const error = new Error(`Worker error: ${event.message}`);
61
+ for (const [id, entry] of this.pending) {
62
+ this.pending.delete(id);
63
+ entry.reject(error);
64
+ }
65
+ };
66
+ }
67
+ async send(request) {
68
+ if (this.terminated) {
69
+ return {
70
+ id: request.id,
71
+ type: "error",
72
+ message: "Worker has been terminated",
73
+ code: "WORKER_TERMINATED"
74
+ };
75
+ }
76
+ const id = this.nextId++;
77
+ const req = { ...request, id };
78
+ return new Promise((resolve, reject) => {
79
+ const timer = setTimeout(() => {
80
+ this.pending.delete(id);
81
+ reject(new WorkerTimeoutError(req.type, this.timeoutMs));
82
+ }, this.timeoutMs);
83
+ this.pending.set(id, {
84
+ resolve: (response) => {
85
+ clearTimeout(timer);
86
+ resolve(response);
87
+ },
88
+ reject: (error) => {
89
+ clearTimeout(timer);
90
+ reject(error);
91
+ }
92
+ });
93
+ this.worker.postMessage(req);
94
+ });
95
+ }
96
+ terminate() {
97
+ if (this.terminated) return;
98
+ this.terminated = true;
99
+ this.worker.terminate();
100
+ for (const [id, entry] of this.pending) {
101
+ this.pending.delete(id);
102
+ entry.reject(new Error("Worker terminated"));
103
+ }
104
+ }
105
+ };
106
+
107
+ export {
108
+ Mutex,
109
+ WebWorkerBridge
110
+ };
111
+ //# sourceMappingURL=chunk-DXKLAQ6P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/sqlite-wasm-channel.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\nimport { WorkerTimeoutError } from '../errors'\n\n// === Message Protocol ===\n\n/**\n * Request message sent from the main thread to the SQLite WASM worker.\n * Each request carries a unique `id` for response correlation.\n */\nexport type WorkerRequest =\n\t| { id: number; type: 'open'; ddlStatements: string[] }\n\t| { id: number; type: 'close' }\n\t| { id: number; type: 'execute'; sql: string; params?: unknown[] }\n\t| { id: number; type: 'query'; sql: string; params?: unknown[] }\n\t| { id: number; type: 'begin' }\n\t| { id: number; type: 'commit' }\n\t| { id: number; type: 'rollback' }\n\t| { id: number; type: 'migrate'; from: number; to: number; statements: string[] }\n\t| { id: number; type: 'export' }\n\t| { id: number; type: 'import'; data: Uint8Array }\n\n/**\n * Response message sent from the worker back to the main thread.\n * Matches the request `id` for correlation.\n */\nexport type WorkerResponse =\n\t| { id: number; type: 'success'; data?: unknown }\n\t| { id: number; type: 'error'; message: string; code: string; context?: Record<string, unknown> }\n\n// === WorkerBridge Interface ===\n\n/**\n * Abstraction over the communication channel with the SQLite WASM worker.\n * In browsers, this is backed by a real Web Worker via MessagePort.\n * In Node.js tests, this is backed by better-sqlite3 via MockWorkerBridge.\n */\nexport interface WorkerBridge {\n\t/** Send a request to the worker and wait for a response. */\n\tsend(request: WorkerRequest): Promise<WorkerResponse>\n\n\t/** Terminate the worker. Safe to call multiple times. */\n\tterminate(): void\n}\n\n// === Mutex ===\n\n/**\n * Async mutex for serializing transaction access across the async worker boundary.\n * Only one transaction may be active at a time.\n */\nexport class Mutex {\n\tprivate locked = false\n\tprivate waiters: Array<() => void> = []\n\n\t/**\n\t * Acquire the mutex. Returns a release function.\n\t * If the mutex is already held, the caller waits until it's released.\n\t */\n\tasync acquire(): Promise<() => void> {\n\t\tif (!this.locked) {\n\t\t\tthis.locked = true\n\t\t\treturn this.createRelease()\n\t\t}\n\n\t\treturn new Promise<() => void>((resolve) => {\n\t\t\tthis.waiters.push(() => {\n\t\t\t\tresolve(this.createRelease())\n\t\t\t})\n\t\t})\n\t}\n\n\tprivate createRelease(): () => void {\n\t\tlet released = false\n\t\treturn () => {\n\t\t\tif (released) return\n\t\t\treleased = true\n\t\t\tconst next = this.waiters.shift()\n\t\t\tif (next) {\n\t\t\t\tnext()\n\t\t\t} else {\n\t\t\t\tthis.locked = false\n\t\t\t}\n\t\t}\n\t}\n}\n\n// === WebWorkerBridge ===\n\n/**\n * WorkerBridge implementation for browser environments.\n * Communicates with an actual Web Worker running SQLite WASM.\n */\nexport class WebWorkerBridge implements WorkerBridge {\n\tprivate worker: Worker\n\tprivate pending = new Map<\n\t\tnumber,\n\t\t{ resolve: (r: WorkerResponse) => void; reject: (e: Error) => void }\n\t>()\n\tprivate nextId = 1\n\tprivate terminated = false\n\tprivate timeoutMs: number\n\n\t/**\n\t * @param workerUrl - URL to the sqlite-wasm-worker script\n\t * @param timeoutMs - Timeout for worker responses in milliseconds (default: 30000)\n\t */\n\tconstructor(workerUrl: string | URL, timeoutMs = 30000) {\n\t\tthis.timeoutMs = timeoutMs\n\t\tthis.worker = new Worker(workerUrl, { type: 'module' })\n\t\tthis.worker.onmessage = (event: MessageEvent<WorkerResponse>) => {\n\t\t\tconst response = event.data\n\t\t\tconst entry = this.pending.get(response.id)\n\t\t\tif (entry) {\n\t\t\t\tthis.pending.delete(response.id)\n\t\t\t\tentry.resolve(response)\n\t\t\t}\n\t\t}\n\t\tthis.worker.onerror = (event) => {\n\t\t\t// Reject all pending requests on worker error\n\t\t\tconst error = new Error(`Worker error: ${event.message}`)\n\t\t\tfor (const [id, entry] of this.pending) {\n\t\t\t\tthis.pending.delete(id)\n\t\t\t\tentry.reject(error)\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: 'Worker has been terminated',\n\t\t\t\tcode: 'WORKER_TERMINATED',\n\t\t\t}\n\t\t}\n\n\t\tconst id = this.nextId++\n\t\tconst req = { ...request, id }\n\n\t\treturn new Promise<WorkerResponse>((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tthis.pending.delete(id)\n\t\t\t\treject(new WorkerTimeoutError(req.type, this.timeoutMs))\n\t\t\t}, this.timeoutMs)\n\n\t\t\tthis.pending.set(id, {\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.worker.postMessage(req)\n\t\t})\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) return\n\t\tthis.terminated = true\n\t\tthis.worker.terminate()\n\t\t// Reject any pending requests\n\t\tfor (const [id, entry] of this.pending) {\n\t\t\tthis.pending.delete(id)\n\t\t\tentry.reject(new Error('Worker terminated'))\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAkDO,IAAM,QAAN,MAAY;AAAA,EACV,SAAS;AAAA,EACT,UAA6B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMtC,MAAM,UAA+B;AACpC,QAAI,CAAC,KAAK,QAAQ;AACjB,WAAK,SAAS;AACd,aAAO,KAAK,cAAc;AAAA,IAC3B;AAEA,WAAO,IAAI,QAAoB,CAAC,YAAY;AAC3C,WAAK,QAAQ,KAAK,MAAM;AACvB,gBAAQ,KAAK,cAAc,CAAC;AAAA,MAC7B,CAAC;AAAA,IACF,CAAC;AAAA,EACF;AAAA,EAEQ,gBAA4B;AACnC,QAAI,WAAW;AACf,WAAO,MAAM;AACZ,UAAI,SAAU;AACd,iBAAW;AACX,YAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,UAAI,MAAM;AACT,aAAK;AAAA,MACN,OAAO;AACN,aAAK,SAAS;AAAA,MACf;AAAA,IACD;AAAA,EACD;AACD;AAQO,IAAM,kBAAN,MAA8C;AAAA,EAC5C;AAAA,EACA,UAAU,oBAAI,IAGpB;AAAA,EACM,SAAS;AAAA,EACT,aAAa;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,YAAY,WAAyB,YAAY,KAAO;AACvD,SAAK,YAAY;AACjB,SAAK,SAAS,IAAI,OAAO,WAAW,EAAE,MAAM,SAAS,CAAC;AACtD,SAAK,OAAO,YAAY,CAAC,UAAwC;AAChE,YAAM,WAAW,MAAM;AACvB,YAAM,QAAQ,KAAK,QAAQ,IAAI,SAAS,EAAE;AAC1C,UAAI,OAAO;AACV,aAAK,QAAQ,OAAO,SAAS,EAAE;AAC/B,cAAM,QAAQ,QAAQ;AAAA,MACvB;AAAA,IACD;AACA,SAAK,OAAO,UAAU,CAAC,UAAU;AAEhC,YAAM,QAAQ,IAAI,MAAM,iBAAiB,MAAM,OAAO,EAAE;AACxD,iBAAW,CAAC,IAAI,KAAK,KAAK,KAAK,SAAS;AACvC,aAAK,QAAQ,OAAO,EAAE;AACtB,cAAM,OAAO,KAAK;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,KAAK,SAAiD;AAC3D,QAAI,KAAK,YAAY;AACpB,aAAO;AAAA,QACN,IAAI,QAAQ;AAAA,QACZ,MAAM;AAAA,QACN,SAAS;AAAA,QACT,MAAM;AAAA,MACP;AAAA,IACD;AAEA,UAAM,KAAK,KAAK;AAChB,UAAM,MAAM,EAAE,GAAG,SAAS,GAAG;AAE7B,WAAO,IAAI,QAAwB,CAAC,SAAS,WAAW;AACvD,YAAM,QAAQ,WAAW,MAAM;AAC9B,aAAK,QAAQ,OAAO,EAAE;AACtB,eAAO,IAAI,mBAAmB,IAAI,MAAM,KAAK,SAAS,CAAC;AAAA,MACxD,GAAG,KAAK,SAAS;AAEjB,WAAK,QAAQ,IAAI,IAAI;AAAA,QACpB,SAAS,CAAC,aAAa;AACtB,uBAAa,KAAK;AAClB,kBAAQ,QAAQ;AAAA,QACjB;AAAA,QACA,QAAQ,CAAC,UAAU;AAClB,uBAAa,KAAK;AAClB,iBAAO,KAAK;AAAA,QACb;AAAA,MACD,CAAC;AAED,WAAK,OAAO,YAAY,GAAG;AAAA,IAC5B,CAAC;AAAA,EACF;AAAA,EAEA,YAAkB;AACjB,QAAI,KAAK,WAAY;AACrB,SAAK,aAAa;AAClB,SAAK,OAAO,UAAU;AAEtB,eAAW,CAAC,IAAI,KAAK,KAAK,KAAK,SAAS;AACvC,WAAK,QAAQ,OAAO,EAAE;AACtB,YAAM,OAAO,IAAI,MAAM,mBAAmB,CAAC;AAAA,IAC5C;AAAA,EACD;AACD;","names":[]}
@@ -0,0 +1,62 @@
1
+ // src/errors.ts
2
+ import { KoraError } from "@korajs/core";
3
+ var QueryError = class extends KoraError {
4
+ constructor(message, context) {
5
+ super(message, "QUERY_ERROR", context);
6
+ this.name = "QueryError";
7
+ }
8
+ };
9
+ var RecordNotFoundError = class extends KoraError {
10
+ constructor(collection, recordId) {
11
+ super(`Record "${recordId}" not found in collection "${collection}"`, "RECORD_NOT_FOUND", {
12
+ collection,
13
+ recordId
14
+ });
15
+ this.name = "RecordNotFoundError";
16
+ }
17
+ };
18
+ var AdapterError = class extends KoraError {
19
+ constructor(message, context) {
20
+ super(message, "ADAPTER_ERROR", context);
21
+ this.name = "AdapterError";
22
+ }
23
+ };
24
+ var StoreNotOpenError = class extends KoraError {
25
+ constructor() {
26
+ super("Store is not open. Call store.open() before performing operations.", "STORE_NOT_OPEN");
27
+ this.name = "StoreNotOpenError";
28
+ }
29
+ };
30
+ var WorkerInitError = class extends KoraError {
31
+ constructor(message, context) {
32
+ super(`Worker initialization failed: ${message}`, "WORKER_INIT_ERROR", context);
33
+ this.name = "WorkerInitError";
34
+ }
35
+ };
36
+ var WorkerTimeoutError = class extends KoraError {
37
+ constructor(operation, timeoutMs) {
38
+ super(
39
+ `Worker did not respond within ${timeoutMs}ms for operation "${operation}"`,
40
+ "WORKER_TIMEOUT",
41
+ { operation, timeoutMs }
42
+ );
43
+ this.name = "WorkerTimeoutError";
44
+ }
45
+ };
46
+ var PersistenceError = class extends KoraError {
47
+ constructor(message, context) {
48
+ super(`Persistence error: ${message}`, "PERSISTENCE_ERROR", context);
49
+ this.name = "PersistenceError";
50
+ }
51
+ };
52
+
53
+ export {
54
+ QueryError,
55
+ RecordNotFoundError,
56
+ AdapterError,
57
+ StoreNotOpenError,
58
+ WorkerInitError,
59
+ WorkerTimeoutError,
60
+ PersistenceError
61
+ };
62
+ //# sourceMappingURL=chunk-LAWV6CFH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"sourcesContent":["import { KoraError } from '@korajs/core'\n\n/**\n * Thrown when a query is invalid (bad field names, invalid operators, etc.).\n */\nexport class QueryError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'QUERY_ERROR', context)\n\t\tthis.name = 'QueryError'\n\t}\n}\n\n/**\n * Thrown when a record is not found by ID (findById, update, delete on missing record).\n */\nexport class RecordNotFoundError extends KoraError {\n\tconstructor(collection: string, recordId: string) {\n\t\tsuper(`Record \"${recordId}\" not found in collection \"${collection}\"`, 'RECORD_NOT_FOUND', {\n\t\t\tcollection,\n\t\t\trecordId,\n\t\t})\n\t\tthis.name = 'RecordNotFoundError'\n\t}\n}\n\n/**\n * Thrown when a storage adapter operation fails.\n */\nexport class AdapterError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'ADAPTER_ERROR', context)\n\t\tthis.name = 'AdapterError'\n\t}\n}\n\n/**\n * Thrown when an operation is attempted on a store that has not been opened.\n */\nexport class StoreNotOpenError extends KoraError {\n\tconstructor() {\n\t\tsuper('Store is not open. Call store.open() before performing operations.', 'STORE_NOT_OPEN')\n\t\tthis.name = 'StoreNotOpenError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker fails to initialize (WASM load failure, OPFS unavailable, etc.).\n */\nexport class WorkerInitError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Worker initialization failed: ${message}`, 'WORKER_INIT_ERROR', context)\n\t\tthis.name = 'WorkerInitError'\n\t}\n}\n\n/**\n * Thrown when the Web Worker does not respond within the configured timeout.\n */\nexport class WorkerTimeoutError extends KoraError {\n\tconstructor(operation: string, timeoutMs: number) {\n\t\tsuper(\n\t\t\t`Worker did not respond within ${timeoutMs}ms for operation \"${operation}\"`,\n\t\t\t'WORKER_TIMEOUT',\n\t\t\t{ operation, timeoutMs },\n\t\t)\n\t\tthis.name = 'WorkerTimeoutError'\n\t}\n}\n\n/**\n * Thrown when IndexedDB persistence operations fail (serialize/deserialize).\n */\nexport class PersistenceError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(`Persistence error: ${message}`, 'PERSISTENCE_ERROR', context)\n\t\tthis.name = 'PersistenceError'\n\t}\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAKnB,IAAM,aAAN,cAAyB,UAAU;AAAA,EACzC,YAAY,SAAiB,SAAmC;AAC/D,UAAM,SAAS,eAAe,OAAO;AACrC,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,sBAAN,cAAkC,UAAU;AAAA,EAClD,YAAY,YAAoB,UAAkB;AACjD,UAAM,WAAW,QAAQ,8BAA8B,UAAU,KAAK,oBAAoB;AAAA,MACzF;AAAA,MACA;AAAA,IACD,CAAC;AACD,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,eAAN,cAA2B,UAAU;AAAA,EAC3C,YAAY,SAAiB,SAAmC;AAC/D,UAAM,SAAS,iBAAiB,OAAO;AACvC,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,oBAAN,cAAgC,UAAU;AAAA,EAChD,cAAc;AACb,UAAM,sEAAsE,gBAAgB;AAC5F,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,kBAAN,cAA8B,UAAU;AAAA,EAC9C,YAAY,SAAiB,SAAmC;AAC/D,UAAM,iCAAiC,OAAO,IAAI,qBAAqB,OAAO;AAC9E,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,qBAAN,cAAiC,UAAU;AAAA,EACjD,YAAY,WAAmB,WAAmB;AACjD;AAAA,MACC,iCAAiC,SAAS,qBAAqB,SAAS;AAAA,MACxE;AAAA,MACA,EAAE,WAAW,UAAU;AAAA,IACxB;AACA,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,mBAAN,cAA+B,UAAU;AAAA,EAC/C,YAAY,SAAiB,SAAmC;AAC/D,UAAM,sBAAsB,OAAO,IAAI,qBAAqB,OAAO;AACnE,SAAK,OAAO;AAAA,EACb;AACD;","names":[]}
@@ -0,0 +1,179 @@
1
+ import {
2
+ Mutex
3
+ } from "./chunk-DXKLAQ6P.js";
4
+ import {
5
+ AdapterError,
6
+ StoreNotOpenError
7
+ } from "./chunk-LAWV6CFH.js";
8
+
9
+ // src/adapters/sqlite-wasm-adapter.ts
10
+ import { generateFullDDL } from "@korajs/core";
11
+ var SqliteWasmAdapter = class {
12
+ bridge = null;
13
+ opened = false;
14
+ mutex = new Mutex();
15
+ injectedBridge;
16
+ workerUrl;
17
+ dbName;
18
+ constructor(options = {}) {
19
+ this.injectedBridge = options.bridge;
20
+ this.workerUrl = options.workerUrl;
21
+ this.dbName = options.dbName ?? "kora-db";
22
+ }
23
+ async open(schema) {
24
+ if (this.opened) return;
25
+ if (this.injectedBridge) {
26
+ this.bridge = this.injectedBridge;
27
+ } else if (this.workerUrl) {
28
+ const { WebWorkerBridge } = await import("./sqlite-wasm-channel-46AOWNPM.js");
29
+ this.bridge = new WebWorkerBridge(this.workerUrl);
30
+ } else {
31
+ throw new AdapterError(
32
+ 'SqliteWasmAdapter requires either a bridge (for testing) or a workerUrl (for browsers). Pass { bridge: new MockWorkerBridge() } for tests, or { workerUrl: "/worker.js" } for browsers.'
33
+ );
34
+ }
35
+ const ddlStatements = generateFullDDL(schema);
36
+ const response = await this.sendRequest({ id: 0, type: "open", ddlStatements });
37
+ if (response.type === "error") {
38
+ throw new AdapterError(`Failed to open database: ${response.message}`, {
39
+ code: response.code,
40
+ dbName: this.dbName
41
+ });
42
+ }
43
+ this.opened = true;
44
+ }
45
+ async close() {
46
+ if (!this.bridge) return;
47
+ try {
48
+ await this.sendRequest({ id: 0, type: "close" });
49
+ } finally {
50
+ this.bridge.terminate();
51
+ this.bridge = null;
52
+ this.opened = false;
53
+ }
54
+ }
55
+ async execute(sql, params) {
56
+ this.guardOpen();
57
+ const response = await this.sendRequest({ id: 0, type: "execute", sql, params });
58
+ if (response.type === "error") {
59
+ throw new AdapterError(`Execute failed: ${response.message}`, { sql, params });
60
+ }
61
+ }
62
+ async query(sql, params) {
63
+ this.guardOpen();
64
+ const response = await this.sendRequest({ id: 0, type: "query", sql, params });
65
+ if (response.type === "error") {
66
+ throw new AdapterError(`Query failed: ${response.message}`, { sql, params });
67
+ }
68
+ return response.data ?? [];
69
+ }
70
+ async transaction(fn) {
71
+ this.guardOpen();
72
+ const release = await this.mutex.acquire();
73
+ try {
74
+ await this.sendChecked({ id: 0, type: "begin" }, "BEGIN transaction");
75
+ const tx = {
76
+ execute: async (sql, params) => {
77
+ const response = await this.sendRequest({ id: 0, type: "execute", sql, params });
78
+ if (response.type === "error") {
79
+ throw new AdapterError(`Transaction execute failed: ${response.message}`, {
80
+ sql,
81
+ params
82
+ });
83
+ }
84
+ },
85
+ query: async (sql, params) => {
86
+ const response = await this.sendRequest({ id: 0, type: "query", sql, params });
87
+ if (response.type === "error") {
88
+ throw new AdapterError(`Transaction query failed: ${response.message}`, { sql, params });
89
+ }
90
+ return response.data ?? [];
91
+ }
92
+ };
93
+ await fn(tx);
94
+ await this.sendChecked({ id: 0, type: "commit" }, "COMMIT transaction");
95
+ } catch (error) {
96
+ try {
97
+ await this.sendRequest({ id: 0, type: "rollback" });
98
+ } catch {
99
+ }
100
+ throw error;
101
+ } finally {
102
+ release();
103
+ }
104
+ }
105
+ async migrate(from, to, migration) {
106
+ this.guardOpen();
107
+ const release = await this.mutex.acquire();
108
+ try {
109
+ await this.sendChecked({ id: 0, type: "begin" }, "BEGIN migration");
110
+ for (const sql of migration.statements) {
111
+ const response = await this.sendRequest({ id: 0, type: "execute", sql });
112
+ if (response.type === "error") {
113
+ throw new AdapterError(`Migration from v${from} to v${to} failed: ${response.message}`, {
114
+ from,
115
+ to
116
+ });
117
+ }
118
+ }
119
+ await this.sendChecked({ id: 0, type: "commit" }, "COMMIT migration");
120
+ } catch (error) {
121
+ try {
122
+ await this.sendRequest({ id: 0, type: "rollback" });
123
+ } catch {
124
+ }
125
+ if (error instanceof AdapterError) throw error;
126
+ throw new AdapterError(
127
+ `Migration from v${from} to v${to} failed: ${error.message}`,
128
+ { from, to }
129
+ );
130
+ } finally {
131
+ release();
132
+ }
133
+ }
134
+ /**
135
+ * Export the database as a Uint8Array (for IndexedDB persistence).
136
+ * Only available when the database is open.
137
+ */
138
+ async exportDatabase() {
139
+ this.guardOpen();
140
+ const response = await this.sendRequest({ id: 0, type: "export" });
141
+ if (response.type === "error") {
142
+ throw new AdapterError(`Export failed: ${response.message}`);
143
+ }
144
+ return response.data;
145
+ }
146
+ /**
147
+ * Import a serialized database snapshot.
148
+ */
149
+ async importDatabase(data) {
150
+ this.guardOpen();
151
+ const response = await this.sendRequest({ id: 0, type: "import", data });
152
+ if (response.type === "error") {
153
+ throw new AdapterError(`Import failed: ${response.message}`);
154
+ }
155
+ }
156
+ guardOpen() {
157
+ if (!this.opened || !this.bridge) {
158
+ throw new StoreNotOpenError();
159
+ }
160
+ }
161
+ async sendRequest(request) {
162
+ const bridge = this.bridge;
163
+ if (!bridge) {
164
+ throw new StoreNotOpenError();
165
+ }
166
+ return bridge.send(request);
167
+ }
168
+ async sendChecked(request, description) {
169
+ const response = await this.sendRequest(request);
170
+ if (response.type === "error") {
171
+ throw new AdapterError(`${description} failed: ${response.message}`);
172
+ }
173
+ }
174
+ };
175
+
176
+ export {
177
+ SqliteWasmAdapter
178
+ };
179
+ //# sourceMappingURL=chunk-ZP5AXQ3Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/sqlite-wasm-adapter.ts"],"sourcesContent":["import { generateFullDDL } from '@korajs/core'\nimport type { SchemaDefinition } from '@korajs/core'\nimport { AdapterError, StoreNotOpenError } from '../errors'\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\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 dbName: string\n\n\tconstructor(options: SqliteWasmAdapterOptions = {}) {\n\t\tthis.injectedBridge = options.bridge\n\t\tthis.workerUrl = options.workerUrl\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.workerUrl) {\n\t\t\t// Dynamic import to avoid loading WebWorkerBridge in Node.js\n\t\t\tconst { WebWorkerBridge } = await import('./sqlite-wasm-channel')\n\t\t\tthis.bridge = new WebWorkerBridge(this.workerUrl)\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({ id: 0, type: 'open', ddlStatements })\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.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"],"mappings":";;;;;;;;;AAAA,SAAS,uBAAuB;AA4CzB,IAAM,oBAAN,MAAkD;AAAA,EAChD,SAA8B;AAAA,EAC9B,SAAS;AAAA,EACA,QAAQ,IAAI,MAAM;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,UAAoC,CAAC,GAAG;AACnD,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,YAAY,QAAQ;AACzB,SAAK,SAAS,QAAQ,UAAU;AAAA,EACjC;AAAA,EAEA,MAAM,KAAK,QAAyC;AACnD,QAAI,KAAK,OAAQ;AAEjB,QAAI,KAAK,gBAAgB;AACxB,WAAK,SAAS,KAAK;AAAA,IACpB,WAAW,KAAK,WAAW;AAE1B,YAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,mCAAuB;AAChE,WAAK,SAAS,IAAI,gBAAgB,KAAK,SAAS;AAAA,IACjD,OAAO;AACN,YAAM,IAAI;AAAA,QACT;AAAA,MAED;AAAA,IACD;AAEA,UAAM,gBAAgB,gBAAgB,MAAM;AAC5C,UAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,QAAQ,cAAc,CAAC;AAC9E,QAAI,SAAS,SAAS,SAAS;AAC9B,YAAM,IAAI,aAAa,4BAA4B,SAAS,OAAO,IAAI;AAAA,QACtE,MAAM,SAAS;AAAA,QACf,QAAQ,KAAK;AAAA,MACd,CAAC;AAAA,IACF;AACA,SAAK,SAAS;AAAA,EACf;AAAA,EAEA,MAAM,QAAuB;AAC5B,QAAI,CAAC,KAAK,OAAQ;AAElB,QAAI;AACH,YAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,QAAQ,CAAC;AAAA,IAChD,UAAE;AACD,WAAK,OAAO,UAAU;AACtB,WAAK,SAAS;AACd,WAAK,SAAS;AAAA,IACf;AAAA,EACD;AAAA,EAEA,MAAM,QAAQ,KAAa,QAAmC;AAC7D,SAAK,UAAU;AACf,UAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,WAAW,KAAK,OAAO,CAAC;AAC/E,QAAI,SAAS,SAAS,SAAS;AAC9B,YAAM,IAAI,aAAa,mBAAmB,SAAS,OAAO,IAAI,EAAE,KAAK,OAAO,CAAC;AAAA,IAC9E;AAAA,EACD;AAAA,EAEA,MAAM,MAAS,KAAa,QAAkC;AAC7D,SAAK,UAAU;AACf,UAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,SAAS,KAAK,OAAO,CAAC;AAC7E,QAAI,SAAS,SAAS,SAAS;AAC9B,YAAM,IAAI,aAAa,iBAAiB,SAAS,OAAO,IAAI,EAAE,KAAK,OAAO,CAAC;AAAA,IAC5E;AACA,WAAQ,SAAS,QAAgB,CAAC;AAAA,EACnC;AAAA,EAEA,MAAM,YAAY,IAAuD;AACxE,SAAK,UAAU;AAEf,UAAM,UAAU,MAAM,KAAK,MAAM,QAAQ;AACzC,QAAI;AACH,YAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,QAAQ,GAAG,mBAAmB;AAEpE,YAAM,KAAkB;AAAA,QACvB,SAAS,OAAO,KAAa,WAAsC;AAClE,gBAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,WAAW,KAAK,OAAO,CAAC;AAC/E,cAAI,SAAS,SAAS,SAAS;AAC9B,kBAAM,IAAI,aAAa,+BAA+B,SAAS,OAAO,IAAI;AAAA,cACzE;AAAA,cACA;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD;AAAA,QACA,OAAO,OAAU,KAAa,WAAqC;AAClE,gBAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,SAAS,KAAK,OAAO,CAAC;AAC7E,cAAI,SAAS,SAAS,SAAS;AAC9B,kBAAM,IAAI,aAAa,6BAA6B,SAAS,OAAO,IAAI,EAAE,KAAK,OAAO,CAAC;AAAA,UACxF;AACA,iBAAQ,SAAS,QAAgB,CAAC;AAAA,QACnC;AAAA,MACD;AAEA,YAAM,GAAG,EAAE;AACX,YAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,SAAS,GAAG,oBAAoB;AAAA,IACvE,SAAS,OAAO;AAEf,UAAI;AACH,cAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,WAAW,CAAC;AAAA,MACnD,QAAQ;AAAA,MAER;AACA,YAAM;AAAA,IACP,UAAE;AACD,cAAQ;AAAA,IACT;AAAA,EACD;AAAA,EAEA,MAAM,QAAQ,MAAc,IAAY,WAAyC;AAChF,SAAK,UAAU;AAEf,UAAM,UAAU,MAAM,KAAK,MAAM,QAAQ;AACzC,QAAI;AACH,YAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,QAAQ,GAAG,iBAAiB;AAElE,iBAAW,OAAO,UAAU,YAAY;AACvC,cAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,WAAW,IAAI,CAAC;AACvE,YAAI,SAAS,SAAS,SAAS;AAC9B,gBAAM,IAAI,aAAa,mBAAmB,IAAI,QAAQ,EAAE,YAAY,SAAS,OAAO,IAAI;AAAA,YACvF;AAAA,YACA;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAEA,YAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,SAAS,GAAG,kBAAkB;AAAA,IACrE,SAAS,OAAO;AACf,UAAI;AACH,cAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,WAAW,CAAC;AAAA,MACnD,QAAQ;AAAA,MAER;AACA,UAAI,iBAAiB,aAAc,OAAM;AACzC,YAAM,IAAI;AAAA,QACT,mBAAmB,IAAI,QAAQ,EAAE,YAAa,MAAgB,OAAO;AAAA,QACrE,EAAE,MAAM,GAAG;AAAA,MACZ;AAAA,IACD,UAAE;AACD,cAAQ;AAAA,IACT;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAsC;AAC3C,SAAK,UAAU;AACf,UAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,SAAS,CAAC;AACjE,QAAI,SAAS,SAAS,SAAS;AAC9B,YAAM,IAAI,aAAa,kBAAkB,SAAS,OAAO,EAAE;AAAA,IAC5D;AACA,WAAO,SAAS;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,MAAiC;AACrD,SAAK,UAAU;AACf,UAAM,WAAW,MAAM,KAAK,YAAY,EAAE,IAAI,GAAG,MAAM,UAAU,KAAK,CAAC;AACvE,QAAI,SAAS,SAAS,SAAS;AAC9B,YAAM,IAAI,aAAa,kBAAkB,SAAS,OAAO,EAAE;AAAA,IAC5D;AAAA,EACD;AAAA,EAEQ,YAAkB;AACzB,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,QAAQ;AACjC,YAAM,IAAI,kBAAkB;AAAA,IAC7B;AAAA,EACD;AAAA,EAEA,MAAc,YAAY,SAAiD;AAE1E,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,QAAQ;AACZ,YAAM,IAAI,kBAAkB;AAAA,IAC7B;AACA,WAAO,OAAO,KAAK,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAc,YAAY,SAAwB,aAAoC;AACrF,UAAM,WAAW,MAAM,KAAK,YAAY,OAAO;AAC/C,QAAI,SAAS,SAAS,SAAS;AAC9B,YAAM,IAAI,aAAa,GAAG,WAAW,YAAY,SAAS,OAAO,EAAE;AAAA,IACpE;AAAA,EACD;AACD;","names":[]}