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.
- package/LICENSE +201 -0
- package/README.md +120 -0
- package/dist/.tsbuildinfo.build +1 -0
- package/dist/browser/db-lock.d.ts +92 -0
- package/dist/browser/db-lock.d.ts.map +1 -0
- package/dist/browser/db-lock.js +163 -0
- package/dist/browser/db-lock.js.map +1 -0
- package/dist/browser/engine-transport.d.ts +94 -0
- package/dist/browser/engine-transport.d.ts.map +1 -0
- package/dist/browser/engine-transport.js +217 -0
- package/dist/browser/engine-transport.js.map +1 -0
- package/dist/browser/field-types.d.ts +19 -0
- package/dist/browser/field-types.d.ts.map +1 -0
- package/dist/browser/field-types.js +79 -0
- package/dist/browser/field-types.js.map +1 -0
- package/dist/browser/firebird-browser.d.ts +249 -0
- package/dist/browser/firebird-browser.d.ts.map +1 -0
- package/dist/browser/firebird-browser.js +401 -0
- package/dist/browser/firebird-browser.js.map +1 -0
- package/dist/browser/index.d.ts +31 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +39 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/indexeddb-vfs.d.ts +132 -0
- package/dist/browser/indexeddb-vfs.d.ts.map +1 -0
- package/dist/browser/indexeddb-vfs.js +285 -0
- package/dist/browser/indexeddb-vfs.js.map +1 -0
- package/dist/browser/params.d.ts +33 -0
- package/dist/browser/params.d.ts.map +1 -0
- package/dist/browser/params.js +92 -0
- package/dist/browser/params.js.map +1 -0
- package/dist/browser/sql-script.d.ts +27 -0
- package/dist/browser/sql-script.d.ts.map +1 -0
- package/dist/browser/sql-script.js +132 -0
- package/dist/browser/sql-script.js.map +1 -0
- package/dist/browser/worker-entry.d.ts +45 -0
- package/dist/browser/worker-entry.d.ts.map +1 -0
- package/dist/browser/worker-entry.js +79 -0
- package/dist/browser/worker-entry.js.map +1 -0
- package/dist/browser/worker-protocol.d.ts +37 -0
- package/dist/browser/worker-protocol.d.ts.map +1 -0
- package/dist/browser/worker-protocol.js +10 -0
- package/dist/browser/worker-protocol.js.map +1 -0
- package/dist/browser/worker-transport.d.ts +63 -0
- package/dist/browser/worker-transport.d.ts.map +1 -0
- package/dist/browser/worker-transport.js +133 -0
- package/dist/browser/worker-transport.js.map +1 -0
- package/dist/firebird.d.ts +73 -0
- package/dist/firebird.d.ts.map +1 -0
- package/dist/firebird.js +208 -0
- package/dist/firebird.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/wasm/firebird-embedded.js +2 -0
- package/dist/wasm/firebird-embedded.wasm +0 -0
- package/dist/wasm-loader.d.ts +162 -0
- package/dist/wasm-loader.d.ts.map +1 -0
- package/dist/wasm-loader.js +103 -0
- package/dist/wasm-loader.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* firebird-browser.ts – Browser-compatible FirebirdLite backed by WASM + IndexedDB.
|
|
3
|
+
*
|
|
4
|
+
* Provides the same PGlite-style async API as the Node.js `FirebirdLite` class,
|
|
5
|
+
* but runs entirely in the browser using:
|
|
6
|
+
*
|
|
7
|
+
* 1. The Firebird Embedded engine compiled to WebAssembly (see `wasm/`).
|
|
8
|
+
* 2. An IndexedDB-backed virtual filesystem for durable page storage.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { FirebirdBrowser } from 'firebird-wasm/browser';
|
|
13
|
+
*
|
|
14
|
+
* // A browser must run the engine in a Worker — see the `worker` option.
|
|
15
|
+
* const db = new FirebirdBrowser('mydb', {
|
|
16
|
+
* worker: new Worker('/firebird-engine-worker.js'),
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* await db.exec('CREATE TABLE t (id INTEGER, name VARCHAR(100))');
|
|
20
|
+
* const result = await db.query('SELECT * FROM t');
|
|
21
|
+
* await db.close();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { IndexedDBVFSOptions } from './indexeddb-vfs';
|
|
25
|
+
import type { EngineHandle, EngineTransport } from './engine-transport';
|
|
26
|
+
import type { QueryResult, Row, QueryParams, TransactionOptions } from '../types';
|
|
27
|
+
/** What a statement did. Returned by `exec()`. */
|
|
28
|
+
export interface ExecResult {
|
|
29
|
+
/** Rows affected — for INSERT, UPDATE and DELETE. 0 for DDL. */
|
|
30
|
+
affectedRows: number;
|
|
31
|
+
}
|
|
32
|
+
/** Options for creating a {@link FirebirdBrowser} instance. */
|
|
33
|
+
export interface FirebirdBrowserOptions {
|
|
34
|
+
/** Options forwarded to the IndexedDB VFS layer. */
|
|
35
|
+
vfs?: IndexedDBVFSOptions;
|
|
36
|
+
/**
|
|
37
|
+
* URL or `ArrayBuffer` of the `firebird-embedded.wasm` binary.
|
|
38
|
+
* Passed through to the engine loader.
|
|
39
|
+
*/
|
|
40
|
+
wasmBinary?: ArrayBuffer | string;
|
|
41
|
+
/**
|
|
42
|
+
* Custom `locateFile` callback for Emscripten.
|
|
43
|
+
* @see {@link import('../wasm-loader').WasmLoadOptions.locateFile}
|
|
44
|
+
*/
|
|
45
|
+
locateFile?: (filename: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Worker running the engine.
|
|
48
|
+
*
|
|
49
|
+
* **Browsers need this.** The WASM build uses pthreads, so Firebird blocks
|
|
50
|
+
* on mutexes while opening a database, and a browser main thread is not
|
|
51
|
+
* allowed to block — without a Worker the page deadlocks. Build the Worker
|
|
52
|
+
* script from `firebird-wasm/browser/worker-entry`.
|
|
53
|
+
*
|
|
54
|
+
* Omit it only where blocking the calling thread is acceptable, such as
|
|
55
|
+
* Node or a test harness driving a stub engine.
|
|
56
|
+
*/
|
|
57
|
+
worker?: Worker;
|
|
58
|
+
/**
|
|
59
|
+
* Use a transport of your own. Takes precedence over `worker`; mainly a
|
|
60
|
+
* seam for tests.
|
|
61
|
+
*/
|
|
62
|
+
transport?: EngineTransport;
|
|
63
|
+
/**
|
|
64
|
+
* Persist to IndexedDB automatically after writes.
|
|
65
|
+
*
|
|
66
|
+
* Without this, a tab closed without `close()` loses everything written in
|
|
67
|
+
* that session — the common way to leave a page. Enabled by default:
|
|
68
|
+
* silently losing committed data is a worse default than the cost of
|
|
69
|
+
* writing it.
|
|
70
|
+
*
|
|
71
|
+
* Set `false` to persist only on `close()` and explicit `persist()` calls.
|
|
72
|
+
*
|
|
73
|
+
* @default true
|
|
74
|
+
*/
|
|
75
|
+
autoPersist?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* How long to wait after the last write before persisting, in
|
|
78
|
+
* milliseconds. Bursts of statements coalesce into one persist.
|
|
79
|
+
*
|
|
80
|
+
* @default 500
|
|
81
|
+
*/
|
|
82
|
+
autoPersistDebounceMs?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Called when a background persist fails.
|
|
85
|
+
*
|
|
86
|
+
* Background persists cannot reject into caller code, and swallowing the
|
|
87
|
+
* error would hide data loss, so it is reported here. Defaults to
|
|
88
|
+
* `console.error`.
|
|
89
|
+
*/
|
|
90
|
+
onPersistError?: (error: Error) => void;
|
|
91
|
+
/**
|
|
92
|
+
* What to do when the same database is already open in another tab.
|
|
93
|
+
*
|
|
94
|
+
* Every tab keeps its own complete copy of the database and persists the
|
|
95
|
+
* whole image, so two writers do not interleave — the later persist discards
|
|
96
|
+
* the earlier tab's work entirely, with both tabs reporting success.
|
|
97
|
+
*
|
|
98
|
+
* - `'exclusive'` (default) takes a cross-tab lock and fails with
|
|
99
|
+
* {@link DatabaseLockedError} if another tab will not release it in time.
|
|
100
|
+
* - `'allow-unsafe'` skips the lock. Only sound when at most one of the
|
|
101
|
+
* tabs writes.
|
|
102
|
+
*
|
|
103
|
+
* @default 'exclusive'
|
|
104
|
+
*/
|
|
105
|
+
multiTab?: 'exclusive' | 'allow-unsafe';
|
|
106
|
+
/**
|
|
107
|
+
* How long to wait for another tab to release the database, in
|
|
108
|
+
* milliseconds. `Infinity` waits indefinitely.
|
|
109
|
+
*
|
|
110
|
+
* @default 5000
|
|
111
|
+
*/
|
|
112
|
+
lockTimeoutMs?: number;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Browser-side Firebird database backed by WASM + IndexedDB.
|
|
116
|
+
*
|
|
117
|
+
* Mirrors the `FirebirdLite` API so application code can switch between the
|
|
118
|
+
* Node.js native driver and the in-browser WASM engine with minimal changes.
|
|
119
|
+
*/
|
|
120
|
+
export declare class FirebirdBrowser {
|
|
121
|
+
private readonly dbName;
|
|
122
|
+
private readonly options;
|
|
123
|
+
private readonly vfs;
|
|
124
|
+
private readonly engine;
|
|
125
|
+
private dbHandle;
|
|
126
|
+
private closed;
|
|
127
|
+
private initPromise;
|
|
128
|
+
private readonly autoPersist;
|
|
129
|
+
private readonly autoPersistDebounceMs;
|
|
130
|
+
private readonly onPersistError;
|
|
131
|
+
private persistTimer;
|
|
132
|
+
/** In-flight persist, so two never overlap. */
|
|
133
|
+
private persistInFlight;
|
|
134
|
+
/** A write arrived while a persist was running; persist again after it. */
|
|
135
|
+
private persistAgain;
|
|
136
|
+
private lifecycleAttached;
|
|
137
|
+
private readonly multiTab;
|
|
138
|
+
private readonly lockTimeoutMs;
|
|
139
|
+
/** Held for the connection's lifetime; released by close(). */
|
|
140
|
+
private lock;
|
|
141
|
+
/**
|
|
142
|
+
* @param dbName Logical database name. Used as the IndexedDB store name
|
|
143
|
+
* and the filename inside Emscripten's virtual FS.
|
|
144
|
+
* @param options Optional configuration.
|
|
145
|
+
*/
|
|
146
|
+
constructor(dbName: string, options?: FirebirdBrowserOptions);
|
|
147
|
+
/** Path of the database inside Emscripten's filesystem. */
|
|
148
|
+
private get dbPath();
|
|
149
|
+
/**
|
|
150
|
+
* Execute one or more statements that do not return rows.
|
|
151
|
+
*
|
|
152
|
+
* A script may contain several statements, which is what makes this usable
|
|
153
|
+
* for migrations. Statement boundaries respect string literals, quoted
|
|
154
|
+
* identifiers, comments and `SET TERM`, so a stored procedure body full of
|
|
155
|
+
* semicolons survives intact. Each statement runs in its own transaction,
|
|
156
|
+
* committed on success — a failure part-way leaves the statements before it
|
|
157
|
+
* committed, as it would in `isql`.
|
|
158
|
+
*
|
|
159
|
+
* Parameters may only be supplied for a single statement: there is no way to
|
|
160
|
+
* say which statement a value belongs to otherwise. Use `query()` for
|
|
161
|
+
* parameterised statements that return rows.
|
|
162
|
+
*
|
|
163
|
+
* @returns one result per statement, in order.
|
|
164
|
+
*/
|
|
165
|
+
exec(sql: string, params?: QueryParams): Promise<ExecResult[]>;
|
|
166
|
+
/**
|
|
167
|
+
* Execute a SQL query and return the result rows.
|
|
168
|
+
*
|
|
169
|
+
* Parameters are bound with `?` placeholders, as in the Node.js backend:
|
|
170
|
+
*
|
|
171
|
+
* ```ts
|
|
172
|
+
* await db.query('SELECT * FROM items WHERE id = ?', [1]);
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
query<T extends Row = Row>(sql: string, params?: QueryParams, _options?: TransactionOptions): Promise<QueryResult<T>>;
|
|
176
|
+
/**
|
|
177
|
+
* Run a function inside an explicit transaction.
|
|
178
|
+
*/
|
|
179
|
+
transaction<T>(fn: (tx: FirebirdBrowserTransaction) => Promise<T>, _options?: TransactionOptions): Promise<T>;
|
|
180
|
+
/**
|
|
181
|
+
* Persist the in-memory database pages to IndexedDB.
|
|
182
|
+
* Call this periodically or before the page unloads to avoid data loss.
|
|
183
|
+
*/
|
|
184
|
+
persist(): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Close the database and release all resources.
|
|
187
|
+
*/
|
|
188
|
+
close(): Promise<void>;
|
|
189
|
+
/** Release the cross-tab lock, if this instance holds one. */
|
|
190
|
+
private releaseLock;
|
|
191
|
+
/** Note that the database has changed and schedule a persist. */
|
|
192
|
+
private markDirty;
|
|
193
|
+
private cancelScheduledPersist;
|
|
194
|
+
/**
|
|
195
|
+
* Persist without a caller to reject into.
|
|
196
|
+
*
|
|
197
|
+
* Failures are reported through `onPersistError`; letting them become
|
|
198
|
+
* unhandled rejections would hide data loss.
|
|
199
|
+
*/
|
|
200
|
+
private persistInBackground;
|
|
201
|
+
/**
|
|
202
|
+
* Flush when the page is being hidden or unloaded.
|
|
203
|
+
*
|
|
204
|
+
* `visibilitychange` to hidden is the event to rely on: it fires on mobile
|
|
205
|
+
* when an app is backgrounded, where `beforeunload` and `unload` often do
|
|
206
|
+
* not fire at all. `pagehide` covers the bfcache case. Neither can await
|
|
207
|
+
* an async write, so this is best-effort — which is why writes are also
|
|
208
|
+
* persisted on a debounce rather than only here.
|
|
209
|
+
*/
|
|
210
|
+
private attachLifecycleListeners;
|
|
211
|
+
private detachLifecycleListeners;
|
|
212
|
+
private readonly onVisibilityChange;
|
|
213
|
+
private readonly onPageHide;
|
|
214
|
+
private ensureReady;
|
|
215
|
+
private init;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* A handle to an active transaction in the browser WASM engine.
|
|
219
|
+
*
|
|
220
|
+
* Statements issued here are bound to the transaction handle, so a rollback
|
|
221
|
+
* really does undo them.
|
|
222
|
+
*/
|
|
223
|
+
export declare class FirebirdBrowserTransaction {
|
|
224
|
+
private readonly engine;
|
|
225
|
+
private readonly dbHandle;
|
|
226
|
+
private readonly txHandle;
|
|
227
|
+
private finished;
|
|
228
|
+
constructor(engine: EngineTransport, dbHandle: EngineHandle, txHandle: EngineHandle);
|
|
229
|
+
/** Whether this transaction has already been rolled back. */
|
|
230
|
+
get isFinished(): boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Roll this transaction back and stop.
|
|
233
|
+
*
|
|
234
|
+
* The enclosing `transaction()` will not commit afterwards. Use this to
|
|
235
|
+
* abandon a transaction deliberately, rather than throwing an error you do
|
|
236
|
+
* not mean — throwing also rolls back, but it propagates to the caller.
|
|
237
|
+
*/
|
|
238
|
+
rollback(): Promise<void>;
|
|
239
|
+
private assertUsable;
|
|
240
|
+
/**
|
|
241
|
+
* Execute a DDL/DML statement inside this transaction.
|
|
242
|
+
*
|
|
243
|
+
* @returns the number of rows affected.
|
|
244
|
+
*/
|
|
245
|
+
exec(sql: string, params?: QueryParams): Promise<ExecResult>;
|
|
246
|
+
/** Execute a SELECT inside this transaction and return rows. */
|
|
247
|
+
query<T extends Row = Row>(sql: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=firebird-browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebird-browser.d.ts","sourceRoot":"","sources":["../../src/browser/firebird-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAKxE,OAAO,KAAK,EACV,WAAW,EACX,GAAG,EACH,WAAW,EACX,kBAAkB,EACnB,MAAM,UAAU,CAAC;AAMlB,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,oDAAoD;IACpD,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAClC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACxC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,EAAE,WAAW,GAAG,cAAc,CAAC;IACxC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAUD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAA8B;IAEjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,YAAY,CAA8C;IAClE,+CAA+C;IAC/C,OAAO,CAAC,eAAe,CAA8B;IACrD,2EAA2E;IAC3E,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,iBAAiB,CAAS;IAElC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,+DAA+D;IAC/D,OAAO,CAAC,IAAI,CAA6B;IAEzC;;;;OAIG;gBACS,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B;IAwBhE,2DAA2D;IAC3D,OAAO,KAAK,MAAM,GAEjB;IAID;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IA+BxE;;;;;;;;OAQG;IACG,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,EACxB,QAAQ,GAAE,kBAAuB,GAChC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAK1B;;OAEG;IACG,WAAW,CAAC,CAAC,EACjB,EAAE,EAAE,CAAC,EAAE,EAAE,0BAA0B,KAAK,OAAO,CAAC,CAAC,CAAC,EAClD,QAAQ,GAAE,kBAAuB,GAChC,OAAO,CAAC,CAAC,CAAC;IA8Bb;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC9B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC5B,8DAA8D;YAChD,WAAW;IAQzB,iEAAiE;IACjE,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,sBAAsB;IAO9B;;;;;OAKG;YACW,mBAAmB;IASjC;;;;;;;;OAQG;IACH,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAKjC;IAEF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAGzB;YAIY,WAAW;YAaX,IAAI;CA4BnB;AAMD;;;;;GAKG;AACH,qBAAa,0BAA0B;IAInC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL3B,OAAO,CAAC,QAAQ,CAAS;gBAGN,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY;IAGzC,6DAA6D;IAC7D,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B,OAAO,CAAC,YAAY;IAMpB;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAWtE,gEAAgE;IAC1D,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CAI3B"}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* firebird-browser.ts – Browser-compatible FirebirdLite backed by WASM + IndexedDB.
|
|
4
|
+
*
|
|
5
|
+
* Provides the same PGlite-style async API as the Node.js `FirebirdLite` class,
|
|
6
|
+
* but runs entirely in the browser using:
|
|
7
|
+
*
|
|
8
|
+
* 1. The Firebird Embedded engine compiled to WebAssembly (see `wasm/`).
|
|
9
|
+
* 2. An IndexedDB-backed virtual filesystem for durable page storage.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { FirebirdBrowser } from 'firebird-wasm/browser';
|
|
14
|
+
*
|
|
15
|
+
* // A browser must run the engine in a Worker — see the `worker` option.
|
|
16
|
+
* const db = new FirebirdBrowser('mydb', {
|
|
17
|
+
* worker: new Worker('/firebird-engine-worker.js'),
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* await db.exec('CREATE TABLE t (id INTEGER, name VARCHAR(100))');
|
|
21
|
+
* const result = await db.query('SELECT * FROM t');
|
|
22
|
+
* await db.close();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.FirebirdBrowserTransaction = exports.FirebirdBrowser = void 0;
|
|
27
|
+
const indexeddb_vfs_1 = require("./indexeddb-vfs");
|
|
28
|
+
const engine_transport_1 = require("./engine-transport");
|
|
29
|
+
const worker_transport_1 = require("./worker-transport");
|
|
30
|
+
const sql_script_1 = require("./sql-script");
|
|
31
|
+
const db_lock_1 = require("./db-lock");
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Shared helpers
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Implementation
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Browser-side Firebird database backed by WASM + IndexedDB.
|
|
40
|
+
*
|
|
41
|
+
* Mirrors the `FirebirdLite` API so application code can switch between the
|
|
42
|
+
* Node.js native driver and the in-browser WASM engine with minimal changes.
|
|
43
|
+
*/
|
|
44
|
+
class FirebirdBrowser {
|
|
45
|
+
/**
|
|
46
|
+
* @param dbName Logical database name. Used as the IndexedDB store name
|
|
47
|
+
* and the filename inside Emscripten's virtual FS.
|
|
48
|
+
* @param options Optional configuration.
|
|
49
|
+
*/
|
|
50
|
+
constructor(dbName, options = {}) {
|
|
51
|
+
this.dbHandle = 0;
|
|
52
|
+
this.closed = false;
|
|
53
|
+
this.initPromise = null;
|
|
54
|
+
this.persistTimer = null;
|
|
55
|
+
/** In-flight persist, so two never overlap. */
|
|
56
|
+
this.persistInFlight = null;
|
|
57
|
+
/** A write arrived while a persist was running; persist again after it. */
|
|
58
|
+
this.persistAgain = false;
|
|
59
|
+
this.lifecycleAttached = false;
|
|
60
|
+
/** Held for the connection's lifetime; released by close(). */
|
|
61
|
+
this.lock = null;
|
|
62
|
+
this.onVisibilityChange = () => {
|
|
63
|
+
if (document.visibilityState === 'hidden') {
|
|
64
|
+
this.cancelScheduledPersist();
|
|
65
|
+
void this.persistInBackground();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
this.onPageHide = () => {
|
|
69
|
+
this.cancelScheduledPersist();
|
|
70
|
+
void this.persistInBackground();
|
|
71
|
+
};
|
|
72
|
+
this.dbName = dbName;
|
|
73
|
+
this.options = options;
|
|
74
|
+
this.vfs = new indexeddb_vfs_1.IndexedDBVFS(options.vfs);
|
|
75
|
+
this.multiTab = options.multiTab ?? 'exclusive';
|
|
76
|
+
this.lockTimeoutMs = options.lockTimeoutMs ?? 5000;
|
|
77
|
+
this.autoPersist = options.autoPersist ?? true;
|
|
78
|
+
this.autoPersistDebounceMs = options.autoPersistDebounceMs ?? 500;
|
|
79
|
+
this.onPersistError =
|
|
80
|
+
options.onPersistError ??
|
|
81
|
+
((error) => console.error('[firebird-wasm] background persist failed', error));
|
|
82
|
+
this.engine =
|
|
83
|
+
options.transport ??
|
|
84
|
+
(options.worker
|
|
85
|
+
? new worker_transport_1.WorkerTransport(options.worker)
|
|
86
|
+
: new engine_transport_1.DirectTransport({
|
|
87
|
+
wasmBinary: options.wasmBinary,
|
|
88
|
+
locateFile: options.locateFile,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
/** Path of the database inside Emscripten's filesystem. */
|
|
92
|
+
get dbPath() {
|
|
93
|
+
return `/data/${this.dbName}.fdb`;
|
|
94
|
+
}
|
|
95
|
+
// ── Public API (mirrors FirebirdLite) ─────────────────────────────────
|
|
96
|
+
/**
|
|
97
|
+
* Execute one or more statements that do not return rows.
|
|
98
|
+
*
|
|
99
|
+
* A script may contain several statements, which is what makes this usable
|
|
100
|
+
* for migrations. Statement boundaries respect string literals, quoted
|
|
101
|
+
* identifiers, comments and `SET TERM`, so a stored procedure body full of
|
|
102
|
+
* semicolons survives intact. Each statement runs in its own transaction,
|
|
103
|
+
* committed on success — a failure part-way leaves the statements before it
|
|
104
|
+
* committed, as it would in `isql`.
|
|
105
|
+
*
|
|
106
|
+
* Parameters may only be supplied for a single statement: there is no way to
|
|
107
|
+
* say which statement a value belongs to otherwise. Use `query()` for
|
|
108
|
+
* parameterised statements that return rows.
|
|
109
|
+
*
|
|
110
|
+
* @returns one result per statement, in order.
|
|
111
|
+
*/
|
|
112
|
+
async exec(sql, params = []) {
|
|
113
|
+
await this.ensureReady();
|
|
114
|
+
const statements = (0, sql_script_1.splitStatements)(sql);
|
|
115
|
+
if (params.length > 0 && statements.length > 1) {
|
|
116
|
+
throw new Error(`Parameters cannot be used with a multi-statement script ` +
|
|
117
|
+
`(${statements.length} statements found); run the statements separately`);
|
|
118
|
+
}
|
|
119
|
+
const results = [];
|
|
120
|
+
for (const statement of statements) {
|
|
121
|
+
const affectedRows = await this.engine.execute(this.dbHandle, 0, statement.sql, params);
|
|
122
|
+
results.push({ affectedRows });
|
|
123
|
+
}
|
|
124
|
+
if (results.length > 0) {
|
|
125
|
+
this.markDirty();
|
|
126
|
+
}
|
|
127
|
+
return results;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Execute a SQL query and return the result rows.
|
|
131
|
+
*
|
|
132
|
+
* Parameters are bound with `?` placeholders, as in the Node.js backend:
|
|
133
|
+
*
|
|
134
|
+
* ```ts
|
|
135
|
+
* await db.query('SELECT * FROM items WHERE id = ?', [1]);
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
async query(sql, params = [], _options = {}) {
|
|
139
|
+
await this.ensureReady();
|
|
140
|
+
return this.engine.query(this.dbHandle, 0, sql, params);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Run a function inside an explicit transaction.
|
|
144
|
+
*/
|
|
145
|
+
async transaction(fn, _options = {}) {
|
|
146
|
+
await this.ensureReady();
|
|
147
|
+
const txHandle = await this.engine.startTransaction(this.dbHandle);
|
|
148
|
+
const tx = new FirebirdBrowserTransaction(this.engine, this.dbHandle, txHandle);
|
|
149
|
+
let result;
|
|
150
|
+
try {
|
|
151
|
+
result = await fn(tx);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
if (!tx.isFinished) {
|
|
155
|
+
await this.engine.rollback(txHandle);
|
|
156
|
+
}
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
// The callback may have rolled back explicitly; committing after that
|
|
160
|
+
// would target a handle the engine has already finished with.
|
|
161
|
+
if (tx.isFinished) {
|
|
162
|
+
this.markDirty();
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
// A failed commit finishes the transaction too, so there is nothing left
|
|
166
|
+
// to roll back here.
|
|
167
|
+
await this.engine.commit(txHandle);
|
|
168
|
+
this.markDirty();
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Persist the in-memory database pages to IndexedDB.
|
|
173
|
+
* Call this periodically or before the page unloads to avoid data loss.
|
|
174
|
+
*/
|
|
175
|
+
async persist() {
|
|
176
|
+
if (!this.dbHandle)
|
|
177
|
+
return;
|
|
178
|
+
// Two persists must not interleave: both read the image and write the
|
|
179
|
+
// same store, and the later one could finish first and roll the database
|
|
180
|
+
// back to an older state.
|
|
181
|
+
if (this.persistInFlight) {
|
|
182
|
+
this.persistAgain = true;
|
|
183
|
+
await this.persistInFlight;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
this.cancelScheduledPersist();
|
|
187
|
+
const run = (async () => {
|
|
188
|
+
const image = await this.engine.readFile(this.dbPath);
|
|
189
|
+
await this.vfs.importDatabase(image);
|
|
190
|
+
})();
|
|
191
|
+
this.persistInFlight = run;
|
|
192
|
+
try {
|
|
193
|
+
await run;
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
this.persistInFlight = null;
|
|
197
|
+
}
|
|
198
|
+
// Writes that arrived mid-persist are not covered by the image just
|
|
199
|
+
// written, so go again.
|
|
200
|
+
if (this.persistAgain) {
|
|
201
|
+
this.persistAgain = false;
|
|
202
|
+
await this.persist();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Close the database and release all resources.
|
|
207
|
+
*/
|
|
208
|
+
async close() {
|
|
209
|
+
if (this.closed)
|
|
210
|
+
return;
|
|
211
|
+
// Stop scheduling before marking closed, so nothing fires mid-teardown.
|
|
212
|
+
this.cancelScheduledPersist();
|
|
213
|
+
this.detachLifecycleListeners();
|
|
214
|
+
// A background persist may still be running; let it finish so it cannot
|
|
215
|
+
// write after the engine has gone.
|
|
216
|
+
if (this.persistInFlight) {
|
|
217
|
+
try {
|
|
218
|
+
await this.persistInFlight;
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// Already reported through onPersistError.
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
this.closed = true;
|
|
225
|
+
if (this.dbHandle) {
|
|
226
|
+
// Persist before closing.
|
|
227
|
+
await this.persist();
|
|
228
|
+
await this.engine.detachDatabase(this.dbHandle);
|
|
229
|
+
this.dbHandle = 0;
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
await this.vfs.close();
|
|
233
|
+
await this.engine.dispose();
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
// Last, and unconditionally: a lock still held after a failed teardown
|
|
237
|
+
// locks the database out of every future tab until the page is gone.
|
|
238
|
+
await this.releaseLock();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** Release the cross-tab lock, if this instance holds one. */
|
|
242
|
+
async releaseLock() {
|
|
243
|
+
const lock = this.lock;
|
|
244
|
+
this.lock = null;
|
|
245
|
+
await lock?.release();
|
|
246
|
+
}
|
|
247
|
+
// ── Automatic persistence ─────────────────────────────────────────────
|
|
248
|
+
/** Note that the database has changed and schedule a persist. */
|
|
249
|
+
markDirty() {
|
|
250
|
+
if (!this.autoPersist || this.closed)
|
|
251
|
+
return;
|
|
252
|
+
if (this.persistTimer !== null) {
|
|
253
|
+
clearTimeout(this.persistTimer);
|
|
254
|
+
}
|
|
255
|
+
this.persistTimer = setTimeout(() => {
|
|
256
|
+
this.persistTimer = null;
|
|
257
|
+
void this.persistInBackground();
|
|
258
|
+
}, this.autoPersistDebounceMs);
|
|
259
|
+
}
|
|
260
|
+
cancelScheduledPersist() {
|
|
261
|
+
if (this.persistTimer !== null) {
|
|
262
|
+
clearTimeout(this.persistTimer);
|
|
263
|
+
this.persistTimer = null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Persist without a caller to reject into.
|
|
268
|
+
*
|
|
269
|
+
* Failures are reported through `onPersistError`; letting them become
|
|
270
|
+
* unhandled rejections would hide data loss.
|
|
271
|
+
*/
|
|
272
|
+
async persistInBackground() {
|
|
273
|
+
if (this.closed)
|
|
274
|
+
return;
|
|
275
|
+
try {
|
|
276
|
+
await this.persist();
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
this.onPersistError(err instanceof Error ? err : new Error(String(err)));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Flush when the page is being hidden or unloaded.
|
|
284
|
+
*
|
|
285
|
+
* `visibilitychange` to hidden is the event to rely on: it fires on mobile
|
|
286
|
+
* when an app is backgrounded, where `beforeunload` and `unload` often do
|
|
287
|
+
* not fire at all. `pagehide` covers the bfcache case. Neither can await
|
|
288
|
+
* an async write, so this is best-effort — which is why writes are also
|
|
289
|
+
* persisted on a debounce rather than only here.
|
|
290
|
+
*/
|
|
291
|
+
attachLifecycleListeners() {
|
|
292
|
+
if (this.lifecycleAttached || !this.autoPersist)
|
|
293
|
+
return;
|
|
294
|
+
if (typeof document === 'undefined' || typeof addEventListener !== 'function') {
|
|
295
|
+
return; // not a browser
|
|
296
|
+
}
|
|
297
|
+
this.lifecycleAttached = true;
|
|
298
|
+
document.addEventListener('visibilitychange', this.onVisibilityChange);
|
|
299
|
+
addEventListener('pagehide', this.onPageHide);
|
|
300
|
+
}
|
|
301
|
+
detachLifecycleListeners() {
|
|
302
|
+
if (!this.lifecycleAttached)
|
|
303
|
+
return;
|
|
304
|
+
this.lifecycleAttached = false;
|
|
305
|
+
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
|
306
|
+
removeEventListener('pagehide', this.onPageHide);
|
|
307
|
+
}
|
|
308
|
+
// ── Initialisation ────────────────────────────────────────────────────
|
|
309
|
+
async ensureReady() {
|
|
310
|
+
if (this.dbHandle)
|
|
311
|
+
return;
|
|
312
|
+
if (this.closed) {
|
|
313
|
+
throw new Error('FirebirdBrowser instance has been closed');
|
|
314
|
+
}
|
|
315
|
+
// Prevent concurrent initialisation
|
|
316
|
+
if (!this.initPromise) {
|
|
317
|
+
this.initPromise = this.init();
|
|
318
|
+
}
|
|
319
|
+
await this.initPromise;
|
|
320
|
+
}
|
|
321
|
+
async init() {
|
|
322
|
+
// Before anything reads the stored image. A tab that loaded the database
|
|
323
|
+
// and then waited for the lock would resume with a snapshot the departing
|
|
324
|
+
// tab has since replaced — the very overwrite the lock prevents.
|
|
325
|
+
if (this.multiTab === 'exclusive') {
|
|
326
|
+
this.lock = await (0, db_lock_1.acquireDatabaseLock)(this.dbName, {
|
|
327
|
+
timeoutMs: this.lockTimeoutMs,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
await this.engine.init();
|
|
331
|
+
await this.engine.mkdir('/data');
|
|
332
|
+
// Restore any previously persisted image into the engine's filesystem
|
|
333
|
+
// before attaching, so a reload reopens the same database.
|
|
334
|
+
await this.vfs.open(this.dbName);
|
|
335
|
+
const stored = await this.vfs.exportDatabase();
|
|
336
|
+
if (stored.byteLength > 0) {
|
|
337
|
+
await this.engine.writeFile(this.dbPath, stored);
|
|
338
|
+
}
|
|
339
|
+
this.dbHandle = (await this.engine.exists(this.dbPath))
|
|
340
|
+
? await this.engine.attachDatabase(this.dbPath)
|
|
341
|
+
: await this.engine.createDatabase(this.dbPath);
|
|
342
|
+
this.attachLifecycleListeners();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
exports.FirebirdBrowser = FirebirdBrowser;
|
|
346
|
+
// ---------------------------------------------------------------------------
|
|
347
|
+
// Transaction handle
|
|
348
|
+
// ---------------------------------------------------------------------------
|
|
349
|
+
/**
|
|
350
|
+
* A handle to an active transaction in the browser WASM engine.
|
|
351
|
+
*
|
|
352
|
+
* Statements issued here are bound to the transaction handle, so a rollback
|
|
353
|
+
* really does undo them.
|
|
354
|
+
*/
|
|
355
|
+
class FirebirdBrowserTransaction {
|
|
356
|
+
constructor(engine, dbHandle, txHandle) {
|
|
357
|
+
this.engine = engine;
|
|
358
|
+
this.dbHandle = dbHandle;
|
|
359
|
+
this.txHandle = txHandle;
|
|
360
|
+
this.finished = false;
|
|
361
|
+
}
|
|
362
|
+
/** Whether this transaction has already been rolled back. */
|
|
363
|
+
get isFinished() {
|
|
364
|
+
return this.finished;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Roll this transaction back and stop.
|
|
368
|
+
*
|
|
369
|
+
* The enclosing `transaction()` will not commit afterwards. Use this to
|
|
370
|
+
* abandon a transaction deliberately, rather than throwing an error you do
|
|
371
|
+
* not mean — throwing also rolls back, but it propagates to the caller.
|
|
372
|
+
*/
|
|
373
|
+
async rollback() {
|
|
374
|
+
if (this.finished)
|
|
375
|
+
return;
|
|
376
|
+
this.finished = true;
|
|
377
|
+
await this.engine.rollback(this.txHandle);
|
|
378
|
+
}
|
|
379
|
+
assertUsable() {
|
|
380
|
+
if (this.finished) {
|
|
381
|
+
throw new Error('Transaction has already been rolled back');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Execute a DDL/DML statement inside this transaction.
|
|
386
|
+
*
|
|
387
|
+
* @returns the number of rows affected.
|
|
388
|
+
*/
|
|
389
|
+
async exec(sql, params = []) {
|
|
390
|
+
this.assertUsable();
|
|
391
|
+
const affectedRows = await this.engine.execute(this.dbHandle, this.txHandle, sql, params);
|
|
392
|
+
return { affectedRows };
|
|
393
|
+
}
|
|
394
|
+
/** Execute a SELECT inside this transaction and return rows. */
|
|
395
|
+
async query(sql, params = []) {
|
|
396
|
+
this.assertUsable();
|
|
397
|
+
return this.engine.query(this.dbHandle, this.txHandle, sql, params);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
exports.FirebirdBrowserTransaction = FirebirdBrowserTransaction;
|
|
401
|
+
//# sourceMappingURL=firebird-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebird-browser.js","sourceRoot":"","sources":["../../src/browser/firebird-browser.ts"],"names":[],"mappings":"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"}
|