firebird-wasm 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 (66) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +120 -0
  3. package/dist/.tsbuildinfo.build +1 -0
  4. package/dist/browser/db-lock.d.ts +92 -0
  5. package/dist/browser/db-lock.d.ts.map +1 -0
  6. package/dist/browser/db-lock.js +163 -0
  7. package/dist/browser/db-lock.js.map +1 -0
  8. package/dist/browser/engine-transport.d.ts +94 -0
  9. package/dist/browser/engine-transport.d.ts.map +1 -0
  10. package/dist/browser/engine-transport.js +217 -0
  11. package/dist/browser/engine-transport.js.map +1 -0
  12. package/dist/browser/field-types.d.ts +19 -0
  13. package/dist/browser/field-types.d.ts.map +1 -0
  14. package/dist/browser/field-types.js +79 -0
  15. package/dist/browser/field-types.js.map +1 -0
  16. package/dist/browser/firebird-browser.d.ts +249 -0
  17. package/dist/browser/firebird-browser.d.ts.map +1 -0
  18. package/dist/browser/firebird-browser.js +401 -0
  19. package/dist/browser/firebird-browser.js.map +1 -0
  20. package/dist/browser/index.d.ts +31 -0
  21. package/dist/browser/index.d.ts.map +1 -0
  22. package/dist/browser/index.js +39 -0
  23. package/dist/browser/index.js.map +1 -0
  24. package/dist/browser/indexeddb-vfs.d.ts +132 -0
  25. package/dist/browser/indexeddb-vfs.d.ts.map +1 -0
  26. package/dist/browser/indexeddb-vfs.js +285 -0
  27. package/dist/browser/indexeddb-vfs.js.map +1 -0
  28. package/dist/browser/params.d.ts +33 -0
  29. package/dist/browser/params.d.ts.map +1 -0
  30. package/dist/browser/params.js +92 -0
  31. package/dist/browser/params.js.map +1 -0
  32. package/dist/browser/sql-script.d.ts +27 -0
  33. package/dist/browser/sql-script.d.ts.map +1 -0
  34. package/dist/browser/sql-script.js +132 -0
  35. package/dist/browser/sql-script.js.map +1 -0
  36. package/dist/browser/worker-entry.d.ts +45 -0
  37. package/dist/browser/worker-entry.d.ts.map +1 -0
  38. package/dist/browser/worker-entry.js +79 -0
  39. package/dist/browser/worker-entry.js.map +1 -0
  40. package/dist/browser/worker-protocol.d.ts +37 -0
  41. package/dist/browser/worker-protocol.d.ts.map +1 -0
  42. package/dist/browser/worker-protocol.js +10 -0
  43. package/dist/browser/worker-protocol.js.map +1 -0
  44. package/dist/browser/worker-transport.d.ts +63 -0
  45. package/dist/browser/worker-transport.d.ts.map +1 -0
  46. package/dist/browser/worker-transport.js +133 -0
  47. package/dist/browser/worker-transport.js.map +1 -0
  48. package/dist/firebird.d.ts +73 -0
  49. package/dist/firebird.d.ts.map +1 -0
  50. package/dist/firebird.js +208 -0
  51. package/dist/firebird.js.map +1 -0
  52. package/dist/index.d.ts +22 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +28 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/types.d.ts +88 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +6 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/wasm/firebird-embedded.js +2 -0
  61. package/dist/wasm/firebird-embedded.wasm +0 -0
  62. package/dist/wasm-loader.d.ts +162 -0
  63. package/dist/wasm-loader.d.ts.map +1 -0
  64. package/dist/wasm-loader.js +103 -0
  65. package/dist/wasm-loader.js.map +1 -0
  66. package/package.json +86 -0
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ /**
3
+ * db-lock.ts – cross-tab exclusion for a single logical database.
4
+ *
5
+ * ## The hazard
6
+ *
7
+ * Every tab runs its own engine with its own complete copy of the database in
8
+ * Emscripten's in-memory filesystem, and `persist()` writes that **whole
9
+ * image** to IndexedDB. So two tabs on one database is not a
10
+ * write-interleaving problem that finer-grained locking would fix — it is
11
+ * last-writer-wins over the entire file:
12
+ *
13
+ * tab A: open (image v1) ─── write x ─────────────── persist (v1+x)
14
+ * tab B: open (image v1) ─── write y ─── persist (v1+y)
15
+ *
16
+ * B's `y` is gone. Not corrupted, not conflicted — silently absent, with both
17
+ * tabs showing a successful commit. `importDatabase()` being atomic does not
18
+ * help: each write is individually perfect and still wrong.
19
+ *
20
+ * ## Why the Web Locks API
21
+ *
22
+ * The property that matters is release-on-death. A lock built out of a flag
23
+ * in IndexedDB has to answer "the holder set this 40 seconds ago and stopped —
24
+ * crashed, or just busy?", and every answer is either a deadlock or a
25
+ * corruption window. Web Locks are held by the *agent*, so a closed tab, a
26
+ * crashed renderer or a killed background process releases immediately and
27
+ * exactly. There is no stale state to recover and no heartbeat to tune.
28
+ *
29
+ * Queueing is also free: a second tab waits for the first rather than
30
+ * spinning, and is granted the moment the first closes.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.DatabaseLockedError = void 0;
34
+ exports.databaseLockName = databaseLockName;
35
+ exports.acquireDatabaseLock = acquireDatabaseLock;
36
+ /** Thrown when another tab holds the database and did not release in time. */
37
+ class DatabaseLockedError extends Error {
38
+ constructor(
39
+ /** The logical database name that is held elsewhere. */
40
+ dbName,
41
+ /** How long we waited, in milliseconds. */
42
+ waitedMs) {
43
+ super(`Database "${dbName}" is already open in another tab or worker ` +
44
+ `(waited ${waitedMs}ms). Each tab keeps its own full copy of the ` +
45
+ `database, so allowing both would silently discard one tab's writes. ` +
46
+ `Close the other tab, or pass multiTab: 'allow-unsafe' if you are ` +
47
+ `certain only one of them writes.`);
48
+ this.dbName = dbName;
49
+ this.waitedMs = waitedMs;
50
+ this.name = 'DatabaseLockedError';
51
+ }
52
+ }
53
+ exports.DatabaseLockedError = DatabaseLockedError;
54
+ // ---------------------------------------------------------------------------
55
+ // Implementation
56
+ // ---------------------------------------------------------------------------
57
+ const DEFAULT_TIMEOUT_MS = 5000;
58
+ /** Lock names are namespaced so they cannot collide with an app's own locks. */
59
+ function databaseLockName(dbName) {
60
+ return `firebird-wasm:db:${dbName}`;
61
+ }
62
+ /** Whether this environment can enforce cross-tab exclusion at all. */
63
+ function locksAvailable() {
64
+ return (typeof navigator !== 'undefined' &&
65
+ typeof navigator.locks?.request === 'function');
66
+ }
67
+ /**
68
+ * Take the exclusive lock for `dbName`, waiting up to `timeoutMs`.
69
+ *
70
+ * Call this *before* reading the stored image. A tab that loads the database
71
+ * and then waits for the lock resumes with a snapshot that the departing tab
72
+ * has since replaced, which is the very overwrite the lock exists to prevent.
73
+ *
74
+ * Where the Web Locks API is missing — Node, jsdom, a non-secure context —
75
+ * there is nothing to enforce exclusion with. Rather than refuse to run, this
76
+ * warns and returns a lock with `enforced: false`: the single-tab case that
77
+ * covers Node and tests is safe on its own, and failing there would break
78
+ * environments that never had the hazard.
79
+ *
80
+ * @throws {DatabaseLockedError} if another tab holds it past the timeout.
81
+ */
82
+ async function acquireDatabaseLock(dbName, options = {}) {
83
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
84
+ if (!locksAvailable()) {
85
+ const warn = options.onUnavailable ?? ((m) => console.warn(m));
86
+ warn('[firebird-wasm] the Web Locks API is unavailable, so concurrent tabs ' +
87
+ 'cannot be detected. Opening the same database in two places will ' +
88
+ 'silently lose writes.');
89
+ return { enforced: false, release: async () => { } };
90
+ }
91
+ const name = databaseLockName(dbName);
92
+ const startedAt = nowMs();
93
+ // Two promises, because "granted" and "released" are different moments and
94
+ // the caller needs both. The lock is held for exactly as long as the
95
+ // callback's returned promise is pending, so `release` is what settles it.
96
+ let release;
97
+ const held = new Promise((resolve) => {
98
+ release = resolve;
99
+ });
100
+ let onGranted;
101
+ let onFailed;
102
+ const granted = new Promise((resolve, reject) => {
103
+ onGranted = resolve;
104
+ onFailed = reject;
105
+ });
106
+ // Aborting the signal cancels a *pending* request. Once granted it has no
107
+ // further effect, which is what makes it usable as an acquisition timeout.
108
+ const controller = new AbortController();
109
+ const timer = timeoutMs === Infinity
110
+ ? null
111
+ : setTimeout(() => controller.abort(), timeoutMs);
112
+ const done = navigator.locks.request(name, { mode: 'exclusive', signal: controller.signal }, () => {
113
+ onGranted();
114
+ return held;
115
+ });
116
+ // Rejects only if the request was abandoned before the callback ran; after a
117
+ // grant `granted` has already settled and this is a no-op.
118
+ done.catch(onFailed);
119
+ try {
120
+ await granted;
121
+ }
122
+ catch (err) {
123
+ if (timer !== null)
124
+ clearTimeout(timer);
125
+ // AbortError is our own timeout firing; anything else is a real fault and
126
+ // should not be dressed up as contention.
127
+ if (isAbortError(err)) {
128
+ throw new DatabaseLockedError(dbName, Math.round(nowMs() - startedAt));
129
+ }
130
+ throw err;
131
+ }
132
+ if (timer !== null)
133
+ clearTimeout(timer);
134
+ let released = false;
135
+ return {
136
+ enforced: true,
137
+ release: async () => {
138
+ if (released)
139
+ return;
140
+ released = true;
141
+ release();
142
+ // Await the request promise, so the lock is provably gone once this
143
+ // resolves: a caller that reopens immediately must not race itself.
144
+ await done.catch(() => { });
145
+ },
146
+ };
147
+ }
148
+ /**
149
+ * Checked by `name`, not `instanceof`. The abort arrives as a `DOMException`,
150
+ * which inherits from `Error` in a browser but not in Node, and not across
151
+ * realms even in a browser — a Worker's exception reaching the main thread
152
+ * fails an `instanceof Error` test that has nothing wrong with it.
153
+ */
154
+ function isAbortError(err) {
155
+ return (typeof err === 'object' &&
156
+ err !== null &&
157
+ err.name === 'AbortError');
158
+ }
159
+ /** Monotonic where available; only ever used for a human-facing duration. */
160
+ function nowMs() {
161
+ return typeof performance !== 'undefined' ? performance.now() : Date.now();
162
+ }
163
+ //# sourceMappingURL=db-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-lock.js","sourceRoot":"","sources":["../../src/browser/db-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * engine-transport.ts – the boundary between `FirebirdBrowser` and the engine.
3
+ *
4
+ * There are two ways to reach the compiled engine, and they differ enough to
5
+ * be worth naming:
6
+ *
7
+ * • {@link DirectTransport} calls the WASM exports in this thread. Simple,
8
+ * and what Node uses.
9
+ * • {@link WorkerTransport} (see `worker-transport.ts`) forwards to a Web
10
+ * Worker. Browsers *must* use it: the build uses pthreads, Firebird
11
+ * blocks on mutexes while opening a database, and a browser main thread is
12
+ * not allowed to block — calling the engine directly from a page deadlocks.
13
+ *
14
+ * Both sides of that split need the same operations, including filesystem
15
+ * access: persistence copies the database between Emscripten's in-memory FS
16
+ * and IndexedDB, and in the Worker case that filesystem lives in the Worker.
17
+ *
18
+ * Every method is async so the two are interchangeable, even though the direct
19
+ * one never actually suspends.
20
+ */
21
+ import type { Row, QueryResult, QueryParams } from '../types';
22
+ /** Opaque engine handle (database or transaction). 0 means "none". */
23
+ export type EngineHandle = number;
24
+ /**
25
+ * The operations `FirebirdBrowser` needs from the engine, wherever it runs.
26
+ *
27
+ * `txHandle` of 0 means "run this statement in its own transaction", matching
28
+ * the C API.
29
+ */
30
+ export interface EngineTransport {
31
+ /** Initialise the engine. Safe to call more than once. */
32
+ init(): Promise<void>;
33
+ createDatabase(path: string): Promise<EngineHandle>;
34
+ attachDatabase(path: string): Promise<EngineHandle>;
35
+ detachDatabase(dbHandle: EngineHandle): Promise<void>;
36
+ /** Returns the number of rows the statement affected. */
37
+ execute(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<number>;
38
+ query<T extends Row = Row>(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<QueryResult<T>>;
39
+ startTransaction(dbHandle: EngineHandle): Promise<EngineHandle>;
40
+ commit(txHandle: EngineHandle): Promise<void>;
41
+ rollback(txHandle: EngineHandle): Promise<void>;
42
+ mkdir(path: string): Promise<void>;
43
+ exists(path: string): Promise<boolean>;
44
+ readFile(path: string): Promise<Uint8Array>;
45
+ writeFile(path: string, data: Uint8Array): Promise<void>;
46
+ /** Release anything the transport owns. Does not detach databases. */
47
+ dispose(): Promise<void>;
48
+ }
49
+ /** Options accepted by {@link DirectTransport}. */
50
+ export interface DirectTransportOptions {
51
+ wasmBinary?: ArrayBuffer | string;
52
+ locateFile?: (filename: string) => string;
53
+ }
54
+ /** Decode the engine's JSON result set into rows keyed by column name. */
55
+ export declare function decodeResultSet<T extends Row>(json: string): QueryResult<T>;
56
+ /**
57
+ * Calls the engine in the current thread.
58
+ *
59
+ * Used by Node, by the Worker (which is where a browser's engine actually
60
+ * runs), and by tests that install a stub `createFirebirdModule`.
61
+ */
62
+ export declare class DirectTransport implements EngineTransport {
63
+ private readonly options;
64
+ private mod;
65
+ private initPromise;
66
+ constructor(options?: DirectTransportOptions);
67
+ init(): Promise<void>;
68
+ private doInit;
69
+ private get module();
70
+ /** Run `fn` with `str` allocated on the WASM heap, freeing it afterwards. */
71
+ private withString;
72
+ createDatabase(path: string): Promise<EngineHandle>;
73
+ attachDatabase(path: string): Promise<EngineHandle>;
74
+ detachDatabase(dbHandle: EngineHandle): Promise<void>;
75
+ /**
76
+ * Run `fn` with the packed parameters on the WASM heap.
77
+ *
78
+ * An empty list is passed as a null pointer rather than an empty buffer, so
79
+ * the C side takes its "no parameters" path and skips preparing an input
80
+ * message it would not use.
81
+ */
82
+ private withParams;
83
+ execute(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<number>;
84
+ query<T extends Row = Row>(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<QueryResult<T>>;
85
+ startTransaction(dbHandle: EngineHandle): Promise<EngineHandle>;
86
+ commit(txHandle: EngineHandle): Promise<void>;
87
+ rollback(txHandle: EngineHandle): Promise<void>;
88
+ mkdir(path: string): Promise<void>;
89
+ exists(path: string): Promise<boolean>;
90
+ readFile(path: string): Promise<Uint8Array>;
91
+ writeFile(path: string, data: Uint8Array): Promise<void>;
92
+ dispose(): Promise<void>;
93
+ }
94
+ //# sourceMappingURL=engine-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-transport.d.ts","sourceRoot":"","sources":["../../src/browser/engine-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAa,WAAW,EAAE,MAAM,UAAU,CAAC;AAQzE,sEAAsE;AACtE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACpD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACpD,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtD,yDAAyD;IACzD,OAAO,CACL,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EACvB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3B,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAChE,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGhD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD,uEAAuE;IACvE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAiCD,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAqB3E;AAMD;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,eAAe;IAIzC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,GAAG,CAAmC;IAC9C,OAAO,CAAC,WAAW,CAA8B;gBAEpB,OAAO,GAAE,sBAA2B;IAE3D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAQb,MAAM;IAYpB,OAAO,KAAK,MAAM,GAKjB;IAED,6EAA6E;IAC7E,OAAO,CAAC,UAAU;IAUZ,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IASnD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IASnD,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAmBZ,OAAO,CACX,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,MAAM,CAAC;IAeZ,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAC7B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAqBpB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAS/D,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAU7C,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM/B"}
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ /**
3
+ * engine-transport.ts – the boundary between `FirebirdBrowser` and the engine.
4
+ *
5
+ * There are two ways to reach the compiled engine, and they differ enough to
6
+ * be worth naming:
7
+ *
8
+ * • {@link DirectTransport} calls the WASM exports in this thread. Simple,
9
+ * and what Node uses.
10
+ * • {@link WorkerTransport} (see `worker-transport.ts`) forwards to a Web
11
+ * Worker. Browsers *must* use it: the build uses pthreads, Firebird
12
+ * blocks on mutexes while opening a database, and a browser main thread is
13
+ * not allowed to block — calling the engine directly from a page deadlocks.
14
+ *
15
+ * Both sides of that split need the same operations, including filesystem
16
+ * access: persistence copies the database between Emscripten's in-memory FS
17
+ * and IndexedDB, and in the Worker case that filesystem lives in the Worker.
18
+ *
19
+ * Every method is async so the two are interchangeable, even though the direct
20
+ * one never actually suspends.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.DirectTransport = void 0;
24
+ exports.decodeResultSet = decodeResultSet;
25
+ const wasm_loader_1 = require("../wasm-loader");
26
+ const params_1 = require("./params");
27
+ const field_types_1 = require("./field-types");
28
+ // ---------------------------------------------------------------------------
29
+ // Shared helpers
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Build an Error carrying whatever the engine reported.
33
+ *
34
+ * The C API returns only a numeric code; the readable Firebird message lives
35
+ * behind `_fb_last_error()` and is lost unless it is read immediately, before
36
+ * another call overwrites it.
37
+ */
38
+ function engineError(mod, context, code) {
39
+ const detail = (0, wasm_loader_1.lastError)(mod);
40
+ const suffix = code === undefined ? '' : ` (code ${code})`;
41
+ return new Error(detail ? `${context}${suffix}: ${detail}` : `${context}${suffix}`);
42
+ }
43
+ /** Decode the engine's JSON result set into rows keyed by column name. */
44
+ function decodeResultSet(json) {
45
+ const parsed = JSON.parse(json);
46
+ const fields = parsed.columns.map((c) => ({
47
+ name: c.name.toUpperCase(),
48
+ type: c.type,
49
+ typeName: (0, field_types_1.firebirdTypeName)(c.type, c.scale),
50
+ subType: c.subType,
51
+ scale: c.scale,
52
+ length: c.length,
53
+ nullable: c.nullable,
54
+ }));
55
+ const rows = parsed.rows.map((cols) => Object.fromEntries(fields.map((f, i) => [f.name, cols[i]])));
56
+ return { rows, fields };
57
+ }
58
+ // ---------------------------------------------------------------------------
59
+ // DirectTransport
60
+ // ---------------------------------------------------------------------------
61
+ /**
62
+ * Calls the engine in the current thread.
63
+ *
64
+ * Used by Node, by the Worker (which is where a browser's engine actually
65
+ * runs), and by tests that install a stub `createFirebirdModule`.
66
+ */
67
+ class DirectTransport {
68
+ constructor(options = {}) {
69
+ this.options = options;
70
+ this.mod = null;
71
+ this.initPromise = null;
72
+ }
73
+ async init() {
74
+ // Concurrent first calls must not each load the module.
75
+ if (!this.initPromise) {
76
+ this.initPromise = this.doInit();
77
+ }
78
+ await this.initPromise;
79
+ }
80
+ async doInit() {
81
+ this.mod = await (0, wasm_loader_1.loadFirebirdWasm)({
82
+ wasmBinary: this.options.wasmBinary,
83
+ locateFile: this.options.locateFile,
84
+ });
85
+ const rc = this.mod._fb_init();
86
+ if (rc !== 0) {
87
+ throw engineError(this.mod, 'Failed to initialise the Firebird engine', rc);
88
+ }
89
+ }
90
+ get module() {
91
+ if (!this.mod) {
92
+ throw new Error('EngineTransport used before init()');
93
+ }
94
+ return this.mod;
95
+ }
96
+ /** Run `fn` with `str` allocated on the WASM heap, freeing it afterwards. */
97
+ withString(str, fn) {
98
+ const mod = this.module;
99
+ const ptr = (0, wasm_loader_1.allocString)(mod, str);
100
+ try {
101
+ return fn(ptr);
102
+ }
103
+ finally {
104
+ mod._free(ptr);
105
+ }
106
+ }
107
+ async createDatabase(path) {
108
+ const mod = this.module;
109
+ const handle = this.withString(path, (p) => mod._fb_create_database(p));
110
+ if (handle === 0) {
111
+ throw engineError(mod, `Failed to create database "${path}"`);
112
+ }
113
+ return handle;
114
+ }
115
+ async attachDatabase(path) {
116
+ const mod = this.module;
117
+ const handle = this.withString(path, (p) => mod._fb_attach_database(p));
118
+ if (handle === 0) {
119
+ throw engineError(mod, `Failed to open database "${path}"`);
120
+ }
121
+ return handle;
122
+ }
123
+ async detachDatabase(dbHandle) {
124
+ this.module._fb_detach_database(dbHandle);
125
+ }
126
+ /**
127
+ * Run `fn` with the packed parameters on the WASM heap.
128
+ *
129
+ * An empty list is passed as a null pointer rather than an empty buffer, so
130
+ * the C side takes its "no parameters" path and skips preparing an input
131
+ * message it would not use.
132
+ */
133
+ withParams(params, fn) {
134
+ if (!params || params.length === 0) {
135
+ return fn(0, 0);
136
+ }
137
+ const mod = this.module;
138
+ const packed = (0, params_1.encodeParams)(params);
139
+ const ptr = mod._malloc(packed.length);
140
+ try {
141
+ mod.HEAPU8.set(packed, ptr);
142
+ return fn(ptr, packed.length);
143
+ }
144
+ finally {
145
+ mod._free(ptr);
146
+ }
147
+ }
148
+ async execute(dbHandle, txHandle, sql, params = []) {
149
+ const mod = this.module;
150
+ const rc = this.withString(sql, (sqlPtr) => this.withParams(params, (paramPtr, paramLen) => params.length === 0
151
+ ? mod._fb_execute(dbHandle, txHandle, sqlPtr)
152
+ : mod._fb_execute_params(dbHandle, txHandle, sqlPtr, paramPtr, paramLen)));
153
+ if (rc !== 0) {
154
+ throw engineError(mod, `Firebird exec failed for: ${sql}`, rc);
155
+ }
156
+ return mod._fb_last_affected_rows();
157
+ }
158
+ async query(dbHandle, txHandle, sql, params = []) {
159
+ const mod = this.module;
160
+ return this.withString(sql, (sqlPtr) => this.withParams(params, (paramPtr, paramLen) => {
161
+ const resultPtr = params.length === 0
162
+ ? mod._fb_query(dbHandle, txHandle, sqlPtr)
163
+ : mod._fb_query_params(dbHandle, txHandle, sqlPtr, paramPtr, paramLen);
164
+ if (resultPtr === 0) {
165
+ throw engineError(mod, `Firebird query failed for: ${sql}`);
166
+ }
167
+ // The engine owns the buffer until fb_free_result.
168
+ const json = mod.UTF8ToString(resultPtr);
169
+ mod._fb_free_result(resultPtr);
170
+ return decodeResultSet(json);
171
+ }));
172
+ }
173
+ async startTransaction(dbHandle) {
174
+ const mod = this.module;
175
+ const txHandle = mod._fb_start_transaction(dbHandle);
176
+ if (txHandle === 0) {
177
+ throw engineError(mod, 'Failed to start transaction');
178
+ }
179
+ return txHandle;
180
+ }
181
+ async commit(txHandle) {
182
+ const mod = this.module;
183
+ const rc = mod._fb_commit(txHandle);
184
+ if (rc !== 0) {
185
+ // fb_commit finishes the transaction whatever the outcome, so there is
186
+ // nothing left to roll back here.
187
+ throw engineError(mod, 'Transaction commit failed', rc);
188
+ }
189
+ }
190
+ async rollback(txHandle) {
191
+ this.module._fb_rollback(txHandle);
192
+ }
193
+ // ── Filesystem ─────────────────────────────────────────────────────────
194
+ async mkdir(path) {
195
+ const mod = this.module;
196
+ if (!mod.FS.analyzePath(path).exists) {
197
+ mod.FS.mkdir(path);
198
+ }
199
+ }
200
+ async exists(path) {
201
+ return this.module.FS.analyzePath(path).exists;
202
+ }
203
+ async readFile(path) {
204
+ return this.module.FS.readFile(path);
205
+ }
206
+ async writeFile(path, data) {
207
+ this.module.FS.writeFile(path, data);
208
+ }
209
+ async dispose() {
210
+ // The module is cached process-wide by loadFirebirdWasm and shared with
211
+ // any other instance, so it is deliberately not torn down here.
212
+ this.mod = null;
213
+ this.initPromise = null;
214
+ }
215
+ }
216
+ exports.DirectTransport = DirectTransport;
217
+ //# sourceMappingURL=engine-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-transport.js","sourceRoot":"","sources":["../../src/browser/engine-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * field-types.ts – readable names for Firebird's SQL type codes.
3
+ *
4
+ * The engine reports numeric type codes. Turning them into names is not
5
+ * decoration: `NUMERIC` and `DECIMAL` are stored as scaled integers and arrive
6
+ * as exact decimal strings, so a caller has to be able to tell them from a
7
+ * `VARCHAR` to know whether `"20.25"` is a number or text.
8
+ */
9
+ import type { FirebirdTypeName } from '../types';
10
+ /**
11
+ * Name a Firebird SQL type code.
12
+ *
13
+ * A non-zero `scale` reports `NUMERIC`: Firebird stores `NUMERIC` and
14
+ * `DECIMAL` as scaled `SMALLINT`, `INTEGER`, `BIGINT` or `INT128`, so the type
15
+ * code alone would call them integers and hide that the value is exact and
16
+ * arrives as a string.
17
+ */
18
+ export declare function firebirdTypeName(type: number, scale?: number): FirebirdTypeName;
19
+ //# sourceMappingURL=field-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../src/browser/field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAgDjD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,gBAAgB,CAgB1E"}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * field-types.ts – readable names for Firebird's SQL type codes.
4
+ *
5
+ * The engine reports numeric type codes. Turning them into names is not
6
+ * decoration: `NUMERIC` and `DECIMAL` are stored as scaled integers and arrive
7
+ * as exact decimal strings, so a caller has to be able to tell them from a
8
+ * `VARCHAR` to know whether `"20.25"` is a number or text.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.firebirdTypeName = firebirdTypeName;
12
+ // From firebird/impl/sqlda_pub.h. The nullable flag is the low bit, and is
13
+ // masked off before lookup.
14
+ const SQL_TEXT = 452;
15
+ const SQL_VARYING = 448;
16
+ const SQL_SHORT = 500;
17
+ const SQL_LONG = 496;
18
+ const SQL_FLOAT = 482;
19
+ const SQL_DOUBLE = 480;
20
+ const SQL_D_FLOAT = 530;
21
+ const SQL_TIMESTAMP = 510;
22
+ const SQL_BLOB = 520;
23
+ const SQL_ARRAY = 540;
24
+ const SQL_TYPE_TIME = 560;
25
+ const SQL_TYPE_DATE = 570;
26
+ const SQL_INT64 = 580;
27
+ const SQL_TIMESTAMP_TZ = 32754;
28
+ const SQL_TIME_TZ = 32756;
29
+ const SQL_INT128 = 32752;
30
+ const SQL_DEC16 = 32760;
31
+ const SQL_DEC34 = 32762;
32
+ const SQL_BOOLEAN = 32764;
33
+ const SQL_NULL = 32766;
34
+ const NAMES = {
35
+ [SQL_TEXT]: 'TEXT',
36
+ [SQL_VARYING]: 'VARYING',
37
+ [SQL_SHORT]: 'SMALLINT',
38
+ [SQL_LONG]: 'INTEGER',
39
+ [SQL_FLOAT]: 'FLOAT',
40
+ [SQL_DOUBLE]: 'DOUBLE',
41
+ [SQL_D_FLOAT]: 'DOUBLE',
42
+ [SQL_TIMESTAMP]: 'TIMESTAMP',
43
+ [SQL_BLOB]: 'BLOB',
44
+ [SQL_ARRAY]: 'ARRAY',
45
+ [SQL_TYPE_TIME]: 'TIME',
46
+ [SQL_TYPE_DATE]: 'DATE',
47
+ [SQL_INT64]: 'BIGINT',
48
+ [SQL_TIMESTAMP_TZ]: 'TIMESTAMP_TZ',
49
+ [SQL_TIME_TZ]: 'TIME_TZ',
50
+ [SQL_INT128]: 'INT128',
51
+ [SQL_DEC16]: 'DECFLOAT16',
52
+ [SQL_DEC34]: 'DECFLOAT34',
53
+ [SQL_BOOLEAN]: 'BOOLEAN',
54
+ [SQL_NULL]: 'NULL',
55
+ };
56
+ /**
57
+ * Name a Firebird SQL type code.
58
+ *
59
+ * A non-zero `scale` reports `NUMERIC`: Firebird stores `NUMERIC` and
60
+ * `DECIMAL` as scaled `SMALLINT`, `INTEGER`, `BIGINT` or `INT128`, so the type
61
+ * code alone would call them integers and hide that the value is exact and
62
+ * arrives as a string.
63
+ */
64
+ function firebirdTypeName(type, scale = 0) {
65
+ const base = type & ~1; // strip the nullable flag
66
+ if (scale !== 0) {
67
+ switch (base) {
68
+ case SQL_SHORT:
69
+ case SQL_LONG:
70
+ case SQL_INT64:
71
+ case SQL_INT128:
72
+ return 'NUMERIC';
73
+ default:
74
+ break;
75
+ }
76
+ }
77
+ return NAMES[base] ?? 'UNKNOWN';
78
+ }
79
+ //# sourceMappingURL=field-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-types.js","sourceRoot":"","sources":["../../src/browser/field-types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AA0DH,4CAgBC;AAtED,2EAA2E;AAC3E,4BAA4B;AAC5B,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,UAAU,GAAG,KAAK,CAAC;AACzB,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC;AAEvB,MAAM,KAAK,GAAqC;IAC9C,CAAC,QAAQ,CAAC,EAAE,MAAM;IAClB,CAAC,WAAW,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,EAAE,UAAU;IACvB,CAAC,QAAQ,CAAC,EAAE,SAAS;IACrB,CAAC,SAAS,CAAC,EAAE,OAAO;IACpB,CAAC,UAAU,CAAC,EAAE,QAAQ;IACtB,CAAC,WAAW,CAAC,EAAE,QAAQ;IACvB,CAAC,aAAa,CAAC,EAAE,WAAW;IAC5B,CAAC,QAAQ,CAAC,EAAE,MAAM;IAClB,CAAC,SAAS,CAAC,EAAE,OAAO;IACpB,CAAC,aAAa,CAAC,EAAE,MAAM;IACvB,CAAC,aAAa,CAAC,EAAE,MAAM;IACvB,CAAC,SAAS,CAAC,EAAE,QAAQ;IACrB,CAAC,gBAAgB,CAAC,EAAE,cAAc;IAClC,CAAC,WAAW,CAAC,EAAE,SAAS;IACxB,CAAC,UAAU,CAAC,EAAE,QAAQ;IACtB,CAAC,SAAS,CAAC,EAAE,YAAY;IACzB,CAAC,SAAS,CAAC,EAAE,YAAY;IACzB,CAAC,WAAW,CAAC,EAAE,SAAS;IACxB,CAAC,QAAQ,CAAC,EAAE,MAAM;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,gBAAgB,CAAC,IAAY,EAAE,KAAK,GAAG,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,0BAA0B;IAElD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,SAAS,CAAC;YACf,KAAK,QAAQ,CAAC;YACd,KAAK,SAAS,CAAC;YACf,KAAK,UAAU;gBACb,OAAO,SAAS,CAAC;YACnB;gBACE,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;AAClC,CAAC"}