firebird-wasm 0.2.0 → 0.4.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 (68) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +4 -1
  3. package/dist/.tsbuildinfo.build +1 -1
  4. package/dist/browser/engine-transport.d.ts +63 -5
  5. package/dist/browser/engine-transport.d.ts.map +1 -1
  6. package/dist/browser/engine-transport.js +290 -8
  7. package/dist/browser/engine-transport.js.map +1 -1
  8. package/dist/browser/firebird-browser.d.ts +252 -7
  9. package/dist/browser/firebird-browser.d.ts.map +1 -1
  10. package/dist/browser/firebird-browser.js +373 -20
  11. package/dist/browser/firebird-browser.js.map +1 -1
  12. package/dist/browser/index.d.ts +8 -2
  13. package/dist/browser/index.d.ts.map +1 -1
  14. package/dist/browser/index.js +19 -3
  15. package/dist/browser/index.js.map +1 -1
  16. package/dist/browser/opfs-fs.d.ts +72 -0
  17. package/dist/browser/opfs-fs.d.ts.map +1 -0
  18. package/dist/browser/opfs-fs.js +249 -0
  19. package/dist/browser/opfs-fs.js.map +1 -0
  20. package/dist/browser/params.d.ts +30 -3
  21. package/dist/browser/params.d.ts.map +1 -1
  22. package/dist/browser/params.js +97 -22
  23. package/dist/browser/params.js.map +1 -1
  24. package/dist/browser/shared-transport.d.ts +9 -2
  25. package/dist/browser/shared-transport.d.ts.map +1 -1
  26. package/dist/browser/shared-transport.js +33 -2
  27. package/dist/browser/shared-transport.js.map +1 -1
  28. package/dist/browser/statement-types.d.ts +18 -0
  29. package/dist/browser/statement-types.d.ts.map +1 -0
  30. package/dist/browser/statement-types.js +39 -0
  31. package/dist/browser/statement-types.js.map +1 -0
  32. package/dist/browser/value-types.d.ts +173 -0
  33. package/dist/browser/value-types.d.ts.map +1 -0
  34. package/dist/browser/value-types.js +222 -0
  35. package/dist/browser/value-types.js.map +1 -0
  36. package/dist/browser/worker-entry.d.ts.map +1 -1
  37. package/dist/browser/worker-entry.js +38 -1
  38. package/dist/browser/worker-entry.js.map +1 -1
  39. package/dist/browser/worker-protocol.d.ts +1 -1
  40. package/dist/browser/worker-protocol.d.ts.map +1 -1
  41. package/dist/browser/worker-transport.d.ts +9 -2
  42. package/dist/browser/worker-transport.d.ts.map +1 -1
  43. package/dist/browser/worker-transport.js +29 -2
  44. package/dist/browser/worker-transport.js.map +1 -1
  45. package/dist/firebird.d.ts +69 -5
  46. package/dist/firebird.d.ts.map +1 -1
  47. package/dist/firebird.js +187 -49
  48. package/dist/firebird.js.map +1 -1
  49. package/dist/index.d.ts +4 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +9 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/sql-tag.d.ts +184 -0
  54. package/dist/sql-tag.d.ts.map +1 -0
  55. package/dist/sql-tag.js +287 -0
  56. package/dist/sql-tag.js.map +1 -0
  57. package/dist/statement-types.d.ts +23 -0
  58. package/dist/statement-types.d.ts.map +1 -0
  59. package/dist/statement-types.js +44 -0
  60. package/dist/statement-types.js.map +1 -0
  61. package/dist/types.d.ts +62 -0
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/wasm/firebird-embedded.js +1 -1
  64. package/dist/wasm/firebird-embedded.wasm +0 -0
  65. package/dist/wasm-loader.d.ts +44 -2
  66. package/dist/wasm-loader.d.ts.map +1 -1
  67. package/dist/wasm-loader.js.map +1 -1
  68. package/package.json +3 -2
@@ -10,26 +10,42 @@
10
10
  * ```
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.allocString = exports.loadFirebirdWasm = exports.IndexedDBVFS = exports.serveEngine = exports.WorkerTransport = exports.electLeader = exports.SharedEngineTransport = exports.DirectTransport = exports.splitStatements = exports.DatabaseLockedError = exports.databaseLockName = exports.acquireDatabaseLock = exports.hasTransactionOptions = exports.isolationCode = exports.firebirdTypeName = exports.encodeParamValue = exports.encodeParams = exports.FirebirdBrowserTransaction = exports.FirebirdBrowser = void 0;
13
+ exports.allocString = exports.loadFirebirdWasm = exports.IndexedDBVFS = exports.serveEngine = exports.WorkerTransport = exports.electLeader = exports.SharedEngineTransport = exports.DirectTransport = exports.splitStatements = exports.DatabaseLockedError = exports.databaseLockName = exports.acquireDatabaseLock = exports.hasTypeOptions = exports.applySerializers = exports.applyTypes = exports.hasTransactionOptions = exports.isolationCode = exports.BLOB_SIDE_CHANNEL = exports.attachBlobs = exports.decodeDescription = exports.statementKind = exports.firebirdTypeName = exports.encodeParamValue = exports.encodeParams = exports.toStatement = exports.isSqlFragment = exports.RawSql = exports.SqlFragment = exports.sql = exports.FirebirdBrowserTransaction = exports.FirebirdBrowser = void 0;
14
14
  var firebird_browser_1 = require("./firebird-browser");
15
15
  Object.defineProperty(exports, "FirebirdBrowser", { enumerable: true, get: function () { return firebird_browser_1.FirebirdBrowser; } });
16
16
  Object.defineProperty(exports, "FirebirdBrowserTransaction", { enumerable: true, get: function () { return firebird_browser_1.FirebirdBrowserTransaction; } });
17
+ var sql_tag_1 = require("../sql-tag");
18
+ Object.defineProperty(exports, "sql", { enumerable: true, get: function () { return sql_tag_1.sql; } });
19
+ Object.defineProperty(exports, "SqlFragment", { enumerable: true, get: function () { return sql_tag_1.SqlFragment; } });
20
+ Object.defineProperty(exports, "RawSql", { enumerable: true, get: function () { return sql_tag_1.RawSql; } });
21
+ Object.defineProperty(exports, "isSqlFragment", { enumerable: true, get: function () { return sql_tag_1.isSqlFragment; } });
22
+ Object.defineProperty(exports, "toStatement", { enumerable: true, get: function () { return sql_tag_1.toStatement; } });
17
23
  var params_1 = require("./params");
18
24
  Object.defineProperty(exports, "encodeParams", { enumerable: true, get: function () { return params_1.encodeParams; } });
19
25
  Object.defineProperty(exports, "encodeParamValue", { enumerable: true, get: function () { return params_1.encodeParamValue; } });
20
26
  var field_types_1 = require("./field-types");
21
27
  Object.defineProperty(exports, "firebirdTypeName", { enumerable: true, get: function () { return field_types_1.firebirdTypeName; } });
28
+ var statement_types_1 = require("../statement-types");
29
+ Object.defineProperty(exports, "statementKind", { enumerable: true, get: function () { return statement_types_1.statementKind; } });
30
+ var engine_transport_1 = require("./engine-transport");
31
+ Object.defineProperty(exports, "decodeDescription", { enumerable: true, get: function () { return engine_transport_1.decodeDescription; } });
32
+ Object.defineProperty(exports, "attachBlobs", { enumerable: true, get: function () { return engine_transport_1.attachBlobs; } });
33
+ Object.defineProperty(exports, "BLOB_SIDE_CHANNEL", { enumerable: true, get: function () { return engine_transport_1.BLOB_SIDE_CHANNEL; } });
22
34
  var isolation_1 = require("./isolation");
23
35
  Object.defineProperty(exports, "isolationCode", { enumerable: true, get: function () { return isolation_1.isolationCode; } });
24
36
  Object.defineProperty(exports, "hasTransactionOptions", { enumerable: true, get: function () { return isolation_1.hasTransactionOptions; } });
37
+ var value_types_1 = require("./value-types");
38
+ Object.defineProperty(exports, "applyTypes", { enumerable: true, get: function () { return value_types_1.applyTypes; } });
39
+ Object.defineProperty(exports, "applySerializers", { enumerable: true, get: function () { return value_types_1.applySerializers; } });
40
+ Object.defineProperty(exports, "hasTypeOptions", { enumerable: true, get: function () { return value_types_1.hasTypeOptions; } });
25
41
  var db_lock_1 = require("./db-lock");
26
42
  Object.defineProperty(exports, "acquireDatabaseLock", { enumerable: true, get: function () { return db_lock_1.acquireDatabaseLock; } });
27
43
  Object.defineProperty(exports, "databaseLockName", { enumerable: true, get: function () { return db_lock_1.databaseLockName; } });
28
44
  Object.defineProperty(exports, "DatabaseLockedError", { enumerable: true, get: function () { return db_lock_1.DatabaseLockedError; } });
29
45
  var sql_script_1 = require("./sql-script");
30
46
  Object.defineProperty(exports, "splitStatements", { enumerable: true, get: function () { return sql_script_1.splitStatements; } });
31
- var engine_transport_1 = require("./engine-transport");
32
- Object.defineProperty(exports, "DirectTransport", { enumerable: true, get: function () { return engine_transport_1.DirectTransport; } });
47
+ var engine_transport_2 = require("./engine-transport");
48
+ Object.defineProperty(exports, "DirectTransport", { enumerable: true, get: function () { return engine_transport_2.DirectTransport; } });
33
49
  var shared_transport_1 = require("./shared-transport");
34
50
  Object.defineProperty(exports, "SharedEngineTransport", { enumerable: true, get: function () { return shared_transport_1.SharedEngineTransport; } });
35
51
  var leader_election_1 = require("./leader-election");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,uDAAiF;AAAxE,mHAAA,eAAe,OAAA;AAAE,8HAAA,0BAA0B,OAAA;AAGpD,mCAA0D;AAAjD,sGAAA,YAAY,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AAEvC,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA;AAEzB,yCAAmE;AAA1D,0GAAA,aAAa,OAAA;AAAE,kHAAA,qBAAqB,OAAA;AAE7C,qCAImB;AAHjB,8GAAA,mBAAmB,OAAA;AACnB,2GAAA,gBAAgB,OAAA;AAChB,8GAAA,mBAAmB,OAAA;AAIrB,2CAA+C;AAAtC,6GAAA,eAAe,OAAA;AAGxB,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AAOxB,uDAA2D;AAAlD,yHAAA,qBAAqB,OAAA;AAG9B,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AAGpB,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AAGxB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AAQpB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AAGrB,8CAA+D;AAAtD,+GAAA,gBAAgB,OAAA;AAAE,0GAAA,WAAW,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,uDAAiF;AAAxE,mHAAA,eAAe,OAAA;AAAE,8HAAA,0BAA0B,OAAA;AAUpD,sCAAkF;AAAzE,8FAAA,GAAG,OAAA;AAAE,sGAAA,WAAW,OAAA;AAAE,iGAAA,MAAM,OAAA;AAAE,wGAAA,aAAa,OAAA;AAAE,sGAAA,WAAW,OAAA;AAG7D,mCAA0D;AAAjD,sGAAA,YAAY,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AAEvC,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA;AACzB,sDAAmD;AAA1C,gHAAA,aAAa,OAAA;AACtB,uDAAuF;AAA9E,qHAAA,iBAAiB,OAAA;AAAE,+GAAA,WAAW,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAE1D,yCAAmE;AAA1D,0GAAA,aAAa,OAAA;AAAE,kHAAA,qBAAqB,OAAA;AAE7C,6CAA6E;AAApE,yGAAA,UAAU,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AAAE,6GAAA,cAAc,OAAA;AAGrD,qCAImB;AAHjB,8GAAA,mBAAmB,OAAA;AACnB,2GAAA,gBAAgB,OAAA;AAChB,8GAAA,mBAAmB,OAAA;AAIrB,2CAA+C;AAAtC,6GAAA,eAAe,OAAA;AAGxB,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AAOxB,uDAA2D;AAAlD,yHAAA,qBAAqB,OAAA;AAG9B,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AAGpB,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AAGxB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AAQpB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AAGrB,8CAA+D;AAAtD,+GAAA,gBAAgB,OAAA;AAAE,0GAAA,WAAW,OAAA"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * opfs-fs.ts – an Emscripten filesystem backed by OPFS sync access handles.
3
+ *
4
+ * The IndexedDB path keeps the whole database in memory and copies the image
5
+ * out on every persist. That is a durability strategy bolted beside the engine.
6
+ * This is the other shape: Firebird's own reads and writes land in a file, and
7
+ * there is no persist step because there is nothing to copy.
8
+ *
9
+ * Three facts make it possible, and each was checked rather than assumed:
10
+ *
11
+ * 1. **Firebird's I/O reaches JavaScript.** A custom filesystem mounted in
12
+ * Emscripten's FS sees the engine's reads and writes — measured at 1,678
13
+ * writes and 14.1 MB for a create-plus-insert, all through `stream_ops`.
14
+ * 2. **`FileSystemSyncAccessHandle` is synchronous**, which is what a
15
+ * filesystem callback needs: `read`, `write`, `truncate` and `getSize`
16
+ * return values rather than promises. It exists only in a Worker, and the
17
+ * engine already runs in one — a browser cannot run it anywhere else.
18
+ * 3. **Handles are opened before the mount.** Opening one is async and a
19
+ * stream op cannot await, so the database's handle is acquired up front
20
+ * and the mount owns it from then on.
21
+ *
22
+ * What this deliberately does not do is host a general filesystem. One mount
23
+ * holds one database, because that is what Firebird opens: the probe recorded
24
+ * exactly one `open` for a create-and-query cycle. Temporary files, if the
25
+ * engine ever wants them, stay on MEMFS where they belong — they are scratch,
26
+ * and paying an OPFS round trip for them would be a cost with no durability to
27
+ * show for it.
28
+ */
29
+ import type { FirebirdWasmModule } from '../wasm-loader';
30
+ /**
31
+ * `FileSystemSyncAccessHandle`, as much of it as is used here.
32
+ *
33
+ * Declared rather than imported: the DOM lib in this project's TypeScript
34
+ * target does not carry it, and a hand-written interface says exactly which
35
+ * four methods this depends on.
36
+ */
37
+ interface SyncAccessHandle {
38
+ read(buffer: ArrayBufferView, options?: {
39
+ at?: number;
40
+ }): number;
41
+ write(buffer: ArrayBufferView, options?: {
42
+ at?: number;
43
+ }): number;
44
+ truncate(size: number): void;
45
+ getSize(): number;
46
+ flush(): void;
47
+ close(): void;
48
+ }
49
+ /** True where OPFS sync access handles can actually be used. */
50
+ export declare function opfsAvailable(): boolean;
51
+ /**
52
+ * Open — creating if needed — the sync access handle for one database.
53
+ *
54
+ * @throws if another handle on the same file is already open. OPFS enforces
55
+ * that exclusively, which is a stronger and more honest guarantee than the
56
+ * Web Lock the IndexedDB path uses: two tabs cannot both hold the file, and
57
+ * the second one is told so by the platform rather than by a convention.
58
+ */
59
+ export declare function openDatabaseHandle(name: string): Promise<SyncAccessHandle>;
60
+ /** Delete a database's file. Fails silently when there is nothing to delete. */
61
+ export declare function removeDatabaseFile(name: string): Promise<void>;
62
+ /**
63
+ * Mount a filesystem at `mountpoint` whose files are OPFS sync access handles.
64
+ *
65
+ * `files` maps a name inside the mount to its already-open handle. Nothing
66
+ * else can be created there: a filesystem that silently accepted a second file
67
+ * would be one that silently lost it, since only the listed handles are backed
68
+ * by anything.
69
+ */
70
+ export declare function mountOpfs(mod: FirebirdWasmModule, mountpoint: string, files: Map<string, SyncAccessHandle>): void;
71
+ export {};
72
+ //# sourceMappingURL=opfs-fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opfs-fs.d.ts","sourceRoot":"","sources":["../../src/browser/opfs-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAMzD;;;;;;GAMG;AACH,UAAU,gBAAgB;IACxB,IAAI,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IACjE,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,IAAI,MAAM,CAAC;IAClB,KAAK,IAAI,IAAI,CAAC;IACd,KAAK,IAAI,IAAI,CAAC;CACf;AAeD,gEAAgE;AAChE,wBAAgB,aAAa,IAAI,OAAO,CAgBvC;AASD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAKhF;AAED,iFAAiF;AACjF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpE;AAuCD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,kBAAkB,EACvB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACnC,IAAI,CA8KN"}
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ /**
3
+ * opfs-fs.ts – an Emscripten filesystem backed by OPFS sync access handles.
4
+ *
5
+ * The IndexedDB path keeps the whole database in memory and copies the image
6
+ * out on every persist. That is a durability strategy bolted beside the engine.
7
+ * This is the other shape: Firebird's own reads and writes land in a file, and
8
+ * there is no persist step because there is nothing to copy.
9
+ *
10
+ * Three facts make it possible, and each was checked rather than assumed:
11
+ *
12
+ * 1. **Firebird's I/O reaches JavaScript.** A custom filesystem mounted in
13
+ * Emscripten's FS sees the engine's reads and writes — measured at 1,678
14
+ * writes and 14.1 MB for a create-plus-insert, all through `stream_ops`.
15
+ * 2. **`FileSystemSyncAccessHandle` is synchronous**, which is what a
16
+ * filesystem callback needs: `read`, `write`, `truncate` and `getSize`
17
+ * return values rather than promises. It exists only in a Worker, and the
18
+ * engine already runs in one — a browser cannot run it anywhere else.
19
+ * 3. **Handles are opened before the mount.** Opening one is async and a
20
+ * stream op cannot await, so the database's handle is acquired up front
21
+ * and the mount owns it from then on.
22
+ *
23
+ * What this deliberately does not do is host a general filesystem. One mount
24
+ * holds one database, because that is what Firebird opens: the probe recorded
25
+ * exactly one `open` for a create-and-query cycle. Temporary files, if the
26
+ * engine ever wants them, stay on MEMFS where they belong — they are scratch,
27
+ * and paying an OPFS round trip for them would be a cost with no durability to
28
+ * show for it.
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.opfsAvailable = opfsAvailable;
32
+ exports.openDatabaseHandle = openDatabaseHandle;
33
+ exports.removeDatabaseFile = removeDatabaseFile;
34
+ exports.mountOpfs = mountOpfs;
35
+ /** True where OPFS sync access handles can actually be used. */
36
+ function opfsAvailable() {
37
+ const scope = globalThis;
38
+ if (typeof scope.navigator?.storage?.getDirectory !== 'function')
39
+ return false;
40
+ // Sync access handles are Worker-only. On a main thread the API is present
41
+ // and `createSyncAccessHandle` rejects, which would surface as a failure deep
42
+ // inside a mount rather than as a refusal to start. `importScripts` is the
43
+ // cheapest reliable marker of a worker scope and needs no DOM lib types.
44
+ return (scope.WorkerGlobalScope !== undefined || typeof scope.importScripts === 'function');
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // Opening the file
48
+ // ---------------------------------------------------------------------------
49
+ /** Directory under the OPFS root holding this library's databases. */
50
+ const OPFS_DIRECTORY = 'firebird';
51
+ /**
52
+ * Open — creating if needed — the sync access handle for one database.
53
+ *
54
+ * @throws if another handle on the same file is already open. OPFS enforces
55
+ * that exclusively, which is a stronger and more honest guarantee than the
56
+ * Web Lock the IndexedDB path uses: two tabs cannot both hold the file, and
57
+ * the second one is told so by the platform rather than by a convention.
58
+ */
59
+ async function openDatabaseHandle(name) {
60
+ const root = (await navigator.storage.getDirectory());
61
+ const dir = await root.getDirectoryHandle(OPFS_DIRECTORY, { create: true });
62
+ const file = await dir.getFileHandle(`${name}.fdb`, { create: true });
63
+ return file.createSyncAccessHandle();
64
+ }
65
+ /** Delete a database's file. Fails silently when there is nothing to delete. */
66
+ async function removeDatabaseFile(name) {
67
+ const root = (await navigator.storage.getDirectory());
68
+ const dir = await root.getDirectoryHandle(OPFS_DIRECTORY, { create: true });
69
+ await dir.removeEntry(`${name}.fdb`).catch(() => undefined);
70
+ }
71
+ const S_IFDIR = 0o040000;
72
+ const S_IFREG = 0o100000;
73
+ const ENOENT = 44;
74
+ const EPERM = 63;
75
+ /**
76
+ * Mount a filesystem at `mountpoint` whose files are OPFS sync access handles.
77
+ *
78
+ * `files` maps a name inside the mount to its already-open handle. Nothing
79
+ * else can be created there: a filesystem that silently accepted a second file
80
+ * would be one that silently lost it, since only the listed handles are backed
81
+ * by anything.
82
+ */
83
+ function mountOpfs(mod, mountpoint, files) {
84
+ const FS = mod.FS;
85
+ // A scratch buffer, because the WASM heap is a SharedArrayBuffer under
86
+ // pthreads and OPFS rejects views onto one. Grown as needed and reused, so
87
+ // the cost is one copy per operation rather than one allocation.
88
+ let scratch = new Uint8Array(65536);
89
+ const scratchFor = (length) => {
90
+ if (scratch.byteLength < length) {
91
+ scratch = new Uint8Array(Math.max(length, scratch.byteLength * 2));
92
+ }
93
+ return scratch.subarray(0, length);
94
+ };
95
+ const attrs = (node, size) => ({
96
+ dev: 1,
97
+ ino: node.id,
98
+ mode: node.mode,
99
+ nlink: 1,
100
+ uid: 0,
101
+ gid: 0,
102
+ rdev: node.rdev,
103
+ size,
104
+ atime: new Date(node.timestamp),
105
+ mtime: new Date(node.timestamp),
106
+ ctime: new Date(node.timestamp),
107
+ blksize: 4096,
108
+ blocks: Math.ceil(size / 4096),
109
+ });
110
+ const streamOps = {
111
+ open() {
112
+ /* The handle is already open; there is nothing per-stream to do. */
113
+ },
114
+ close() {
115
+ // Deliberately not closed here. The handle outlives any single open —
116
+ // Firebird opens and closes the database repeatedly within one session,
117
+ // and reopening a sync access handle is both async and exclusive, so a
118
+ // close here would make the next open fail.
119
+ },
120
+ llseek(stream, offset, whence) {
121
+ let position = offset;
122
+ if (whence === 1)
123
+ position += stream.position;
124
+ else if (whence === 2)
125
+ position += stream.node.handle.getSize();
126
+ if (position < 0)
127
+ throw new FS.ErrnoError(28); // EINVAL
128
+ return position;
129
+ },
130
+ read(stream, buffer, offset, length, position) {
131
+ const handle = stream.node.handle;
132
+ const target = scratchFor(length);
133
+ const read = handle.read(target, { at: position });
134
+ if (read > 0)
135
+ buffer.set(target.subarray(0, read), offset);
136
+ return read;
137
+ },
138
+ write(stream, buffer, offset, length, position) {
139
+ const handle = stream.node.handle;
140
+ const source = scratchFor(length);
141
+ source.set(buffer.subarray(offset, offset + length));
142
+ return handle.write(source, { at: position });
143
+ },
144
+ };
145
+ const fileOps = {
146
+ getattr(node) {
147
+ return attrs(node, node.handle.getSize());
148
+ },
149
+ setattr(node, attr) {
150
+ if (attr.mode !== undefined)
151
+ node.mode = attr.mode;
152
+ if (attr.timestamp !== undefined)
153
+ node.timestamp = attr.timestamp;
154
+ if (attr.size !== undefined)
155
+ node.handle.truncate(attr.size);
156
+ },
157
+ };
158
+ /**
159
+ * Bind a name to its pre-opened handle as a file node, once.
160
+ *
161
+ * Cached on the directory so `lookup` keeps returning the same node: the FS
162
+ * treats node identity as file identity, and a fresh object each time would
163
+ * make the same file look like a different one.
164
+ */
165
+ const materialise = (parent, name) => {
166
+ const existing = parent.contents?.[name];
167
+ if (existing)
168
+ return existing;
169
+ const handle = files.get(name);
170
+ if (!handle)
171
+ throw new FS.ErrnoError(ENOENT);
172
+ const node = FS.createNode(parent, name, S_IFREG | 0o666, 0);
173
+ node.node_ops = fileOps;
174
+ node.stream_ops = streamOps;
175
+ node.handle = handle;
176
+ node.timestamp = Date.now();
177
+ parent.contents[name] = node;
178
+ return node;
179
+ };
180
+ const dirOps = {
181
+ getattr(node) {
182
+ return attrs(node, 4096);
183
+ },
184
+ setattr(node, attr) {
185
+ if (attr.mode !== undefined)
186
+ node.mode = attr.mode;
187
+ if (attr.timestamp !== undefined)
188
+ node.timestamp = attr.timestamp;
189
+ },
190
+ /**
191
+ * A file exists here when its handle has bytes in it.
192
+ *
193
+ * Opening a sync access handle creates the underlying file, so the file is
194
+ * always *there* — which would make every database look pre-existing and
195
+ * Firebird's `O_CREAT | O_EXCL` fail with EEXIST on a database that has
196
+ * never been written. Size is what actually distinguishes "not yet a
197
+ * database" from "a database", so size is what existence means.
198
+ */
199
+ lookup(parent, name) {
200
+ const cached = parent.contents?.[name];
201
+ if (cached)
202
+ return cached;
203
+ const handle = files.get(name);
204
+ if (!handle || handle.getSize() === 0)
205
+ throw new FS.ErrnoError(ENOENT);
206
+ return materialise(parent, name);
207
+ },
208
+ mknod(parent, name) {
209
+ // Creating the database is the engine binding itself to the handle that
210
+ // was opened for it. Any other name has no backing store, and a file
211
+ // with none would read back empty later rather than failing now.
212
+ if (!files.has(name))
213
+ throw new FS.ErrnoError(EPERM);
214
+ return materialise(parent, name);
215
+ },
216
+ rename() {
217
+ throw new FS.ErrnoError(EPERM);
218
+ },
219
+ unlink() {
220
+ throw new FS.ErrnoError(EPERM);
221
+ },
222
+ rmdir() {
223
+ throw new FS.ErrnoError(EPERM);
224
+ },
225
+ readdir(node) {
226
+ return ['.', '..', ...Object.keys(node.contents ?? {})];
227
+ },
228
+ symlink() {
229
+ throw new FS.ErrnoError(EPERM);
230
+ },
231
+ };
232
+ const filesystem = {
233
+ mount() {
234
+ // Only the directory. Its files appear through `lookup`, which is what
235
+ // lets an unwritten database be absent rather than empty.
236
+ const root = FS.createNode(null, '/', S_IFDIR | 0o777, 0);
237
+ root.node_ops = dirOps;
238
+ root.stream_ops = {};
239
+ root.contents = {};
240
+ root.timestamp = Date.now();
241
+ return root;
242
+ },
243
+ };
244
+ if (!FS.analyzePath(mountpoint).exists) {
245
+ FS.mkdir(mountpoint);
246
+ }
247
+ FS.mount(filesystem, {}, mountpoint);
248
+ }
249
+ //# sourceMappingURL=opfs-fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opfs-fs.js","sourceRoot":"","sources":["../../src/browser/opfs-fs.ts"],"names":[],"mappings":"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"}
@@ -6,15 +6,25 @@
6
6
  *
7
7
  * u32 count
8
8
  * per parameter:
9
- * u8 isNull
10
- * u32 byteLength (absent when isNull)
11
- * ... UTF-8 bytes (absent when isNull)
9
+ * u8 flags bit 0: SQL NULL; bit 1: a binary form follows the text
10
+ * u32 byteLength (absent when NULL)
11
+ * ... UTF-8 bytes (absent when NULL)
12
+ * u8 kind (only with bit 1) 1: INT64, 2: DOUBLE
13
+ * 8 the value (only with bit 1) little-endian
12
14
  *
13
15
  * Every value is sent as text. The engine describes the input message as
14
16
  * VARCHAR UTF-8 and converts to each column's actual type, which is why one
15
17
  * path handles integers, dates and strings alike — the alternative is
16
18
  * reimplementing Firebird's conversion rules here and getting them subtly
17
19
  * wrong.
20
+ *
21
+ * A number or bigint also travels as the 64-bit value it is, beside its text.
22
+ * The engine uses that form where the column is floating-point or a whole
23
+ * number: no text is parsed, and a double arrives bit for bit (Firebird's
24
+ * text-to-double conversion is off by an ulp for about one value in six).
25
+ * Every other column — NUMERIC and DECIMAL with their exact decimal
26
+ * conversion, VARCHAR, dates — gets the text, so `1.1` into a NUMERIC(18,2)
27
+ * is still 1.10 and into a VARCHAR still '1.1'.
18
28
  */
19
29
  import type { QueryParams } from '../types';
20
30
  /**
@@ -23,6 +33,18 @@ import type { QueryParams } from '../types';
23
33
  * @throws if the value has no unambiguous SQL text form.
24
34
  */
25
35
  export declare function encodeParamValue(value: unknown, index: number): string;
36
+ /** The binary form of a parameter, when it has one. */
37
+ export declare const BINARY_INT64 = 1;
38
+ export declare const BINARY_DOUBLE = 2;
39
+ /**
40
+ * A number's or bigint's binary form: a safe integer and a bigint within
41
+ * INT64 go as INT64, any other finite number as DOUBLE. Anything else — a
42
+ * bigint beyond 64 bits included, which only the text can carry — has none.
43
+ */
44
+ export declare function binaryParamForm(value: unknown): {
45
+ kind: number;
46
+ value: bigint | number;
47
+ } | null;
26
48
  /**
27
49
  * Pack parameters into the buffer the C API expects.
28
50
  *
@@ -30,4 +52,9 @@ export declare function encodeParamValue(value: unknown, index: number): string;
30
52
  * interchangeably for "absent", and rejecting one would be a trap.
31
53
  */
32
54
  export declare function encodeParams(params: QueryParams): Uint8Array;
55
+ /**
56
+ * Pack the parameter sets of a batch: a u32 row count, then each row's
57
+ * parameters exactly as encodeParams lays one set out, back to back.
58
+ */
59
+ export declare function encodeParamRows(rows: QueryParams[]): Uint8Array;
33
60
  //# sourceMappingURL=params.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../../src/browser/params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA6CtE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,CAkC5D"}
1
+ {"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../../src/browser/params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA6CtE;AAED,uDAAuD;AACvD,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,aAAa,IAAI,CAAC;AAK/B;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,IAAI,CAW/F;AAuCD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,CAU5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,UAAU,CAqB/D"}
@@ -7,19 +7,32 @@
7
7
  *
8
8
  * u32 count
9
9
  * per parameter:
10
- * u8 isNull
11
- * u32 byteLength (absent when isNull)
12
- * ... UTF-8 bytes (absent when isNull)
10
+ * u8 flags bit 0: SQL NULL; bit 1: a binary form follows the text
11
+ * u32 byteLength (absent when NULL)
12
+ * ... UTF-8 bytes (absent when NULL)
13
+ * u8 kind (only with bit 1) 1: INT64, 2: DOUBLE
14
+ * 8 the value (only with bit 1) little-endian
13
15
  *
14
16
  * Every value is sent as text. The engine describes the input message as
15
17
  * VARCHAR UTF-8 and converts to each column's actual type, which is why one
16
18
  * path handles integers, dates and strings alike — the alternative is
17
19
  * reimplementing Firebird's conversion rules here and getting them subtly
18
20
  * wrong.
21
+ *
22
+ * A number or bigint also travels as the 64-bit value it is, beside its text.
23
+ * The engine uses that form where the column is floating-point or a whole
24
+ * number: no text is parsed, and a double arrives bit for bit (Firebird's
25
+ * text-to-double conversion is off by an ulp for about one value in six).
26
+ * Every other column — NUMERIC and DECIMAL with their exact decimal
27
+ * conversion, VARCHAR, dates — gets the text, so `1.1` into a NUMERIC(18,2)
28
+ * is still 1.10 and into a VARCHAR still '1.1'.
19
29
  */
20
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.BINARY_DOUBLE = exports.BINARY_INT64 = void 0;
21
32
  exports.encodeParamValue = encodeParamValue;
33
+ exports.binaryParamForm = binaryParamForm;
22
34
  exports.encodeParams = encodeParams;
35
+ exports.encodeParamRows = encodeParamRows;
23
36
  /**
24
37
  * Render one parameter the way Firebird's string-to-type conversion expects.
25
38
  *
@@ -56,6 +69,59 @@ function encodeParamValue(value, index) {
56
69
  }
57
70
  throw new TypeError(`Parameter ${index} has unsupported type ${value === null ? 'null' : typeof value}; pass a string, number, bigint, boolean, Date, null or undefined`);
58
71
  }
72
+ /** The binary form of a parameter, when it has one. */
73
+ exports.BINARY_INT64 = 1;
74
+ exports.BINARY_DOUBLE = 2;
75
+ const INT64_MIN = -(2n ** 63n);
76
+ const INT64_MAX = 2n ** 63n - 1n;
77
+ /**
78
+ * A number's or bigint's binary form: a safe integer and a bigint within
79
+ * INT64 go as INT64, any other finite number as DOUBLE. Anything else — a
80
+ * bigint beyond 64 bits included, which only the text can carry — has none.
81
+ */
82
+ function binaryParamForm(value) {
83
+ if (typeof value === 'number') {
84
+ if (!Number.isFinite(value))
85
+ return null;
86
+ return Number.isSafeInteger(value)
87
+ ? { kind: exports.BINARY_INT64, value: BigInt(value) }
88
+ : { kind: exports.BINARY_DOUBLE, value };
89
+ }
90
+ if (typeof value === 'bigint' && value >= INT64_MIN && value <= INT64_MAX) {
91
+ return { kind: exports.BINARY_INT64, value };
92
+ }
93
+ return null;
94
+ }
95
+ function encodeOne(value, index, encoder) {
96
+ if (value === null || value === undefined)
97
+ return { text: null, binary: null };
98
+ return { text: encoder.encode(encodeParamValue(value, index)), binary: binaryParamForm(value) };
99
+ }
100
+ function sizeOf(p) {
101
+ return 1 + (p.text ? 4 + p.text.length : 0) + (p.binary ? 9 : 0);
102
+ }
103
+ function writeParams(out, view, pos, encoded) {
104
+ view.setUint32(pos, encoded.length, true);
105
+ pos += 4;
106
+ for (const p of encoded) {
107
+ out[pos++] = (p.text ? 0 : 1) | (p.binary ? 2 : 0);
108
+ if (p.text) {
109
+ view.setUint32(pos, p.text.length, true);
110
+ pos += 4;
111
+ out.set(p.text, pos);
112
+ pos += p.text.length;
113
+ }
114
+ if (p.binary) {
115
+ out[pos++] = p.binary.kind;
116
+ if (p.binary.kind === exports.BINARY_INT64)
117
+ view.setBigInt64(pos, p.binary.value, true);
118
+ else
119
+ view.setFloat64(pos, p.binary.value, true);
120
+ pos += 8;
121
+ }
122
+ }
123
+ return pos;
124
+ }
59
125
  /**
60
126
  * Pack parameters into the buffer the C API expects.
61
127
  *
@@ -64,29 +130,38 @@ function encodeParamValue(value, index) {
64
130
  */
65
131
  function encodeParams(params) {
66
132
  const encoder = new TextEncoder();
67
- const encoded = params.map((value, index) => value === null || value === undefined
68
- ? null
69
- : encoder.encode(encodeParamValue(value, index)));
133
+ const encoded = params.map((value, index) => encodeOne(value, index, encoder));
70
134
  let size = 4;
71
- for (const bytes of encoded) {
72
- size += 1 + (bytes ? 4 + bytes.length : 0);
73
- }
135
+ for (const p of encoded)
136
+ size += sizeOf(p);
74
137
  const out = new Uint8Array(size);
75
- const view = new DataView(out.buffer);
76
- let pos = 0;
77
- view.setUint32(pos, encoded.length, true);
78
- pos += 4;
79
- for (const bytes of encoded) {
80
- if (!bytes) {
81
- out[pos++] = 1; // isNull
82
- continue;
138
+ writeParams(out, new DataView(out.buffer), 0, encoded);
139
+ return out;
140
+ }
141
+ /**
142
+ * Pack the parameter sets of a batch: a u32 row count, then each row's
143
+ * parameters exactly as encodeParams lays one set out, back to back.
144
+ */
145
+ function encodeParamRows(rows) {
146
+ const encoder = new TextEncoder();
147
+ const encodedRows = rows.map((row, r) => {
148
+ if (!Array.isArray(row)) {
149
+ throw new TypeError(`Row ${r} of the batch is not an array of parameters`);
83
150
  }
84
- out[pos++] = 0;
85
- view.setUint32(pos, bytes.length, true);
86
- pos += 4;
87
- out.set(bytes, pos);
88
- pos += bytes.length;
151
+ return row.map((value, index) => encodeOne(value, index, encoder));
152
+ });
153
+ let size = 4;
154
+ for (const row of encodedRows) {
155
+ size += 4;
156
+ for (const p of row)
157
+ size += sizeOf(p);
89
158
  }
159
+ const out = new Uint8Array(size);
160
+ const view = new DataView(out.buffer);
161
+ view.setUint32(0, encodedRows.length, true);
162
+ let pos = 4;
163
+ for (const row of encodedRows)
164
+ pos = writeParams(out, view, pos, row);
90
165
  return out;
91
166
  }
92
167
  //# sourceMappingURL=params.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"params.js","sourceRoot":"","sources":["../../src/browser/params.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;AASH,4CA6CC;AAQD,oCAkCC;AA5FD;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,KAAc,EAAE,KAAa;IAC5D,QAAQ,OAAO,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC;QAEf,KAAK,QAAQ;YACX,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,UAAU,CAClB,aAAa,KAAK,OAAO,KAAK,uCAAuC,CACtE,CAAC;YACJ,CAAC;YACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QAEvB,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;QAE1B,KAAK,SAAS;YACZ,+BAA+B;YAC/B,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAElC;YACE,MAAM;IACV,CAAC;IAED,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,UAAU,CAAC,aAAa,KAAK,qBAAqB,CAAC,CAAC;QAChE,CAAC;QACD,wEAAwE;QACxE,+DAA+D;QAC/D,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CACjB,aAAa,KAAK,qDAAqD;YACrE,gEAAgE,CACnE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,SAAS,CACjB,aAAa,KAAK,yBAChB,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,KACnC,mEAAmE,CACpE,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,MAAmB;IAC9C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAElC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAC1C,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QACnC,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CACnD,CAAC;IAEF,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,GAAG,IAAI,CAAC,CAAC;IAET,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;YACzB,SAAS;QACX,CAAC;QACD,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACxC,GAAG,IAAI,CAAC,CAAC;QACT,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACpB,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"params.js","sourceRoot":"","sources":["../../src/browser/params.ts"],"names":[],"mappings":"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"}