firebird-wasm 0.7.0 → 0.9.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/CHANGELOG.md +266 -0
- package/README.md +31 -15
- package/dist/.tsbuildinfo.build +1 -1
- package/dist/browser/engine-transport.d.ts +2 -0
- package/dist/browser/engine-transport.d.ts.map +1 -1
- package/dist/browser/engine-transport.js +43 -11
- package/dist/browser/engine-transport.js.map +1 -1
- package/dist/browser/firebird-browser.d.ts.map +1 -1
- package/dist/browser/firebird-browser.js +59 -20
- package/dist/browser/firebird-browser.js.map +1 -1
- package/dist/browser/index.d.ts +3 -3
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +6 -3
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/params.d.ts +8 -2
- package/dist/browser/params.d.ts.map +1 -1
- package/dist/browser/params.js +14 -5
- package/dist/browser/params.js.map +1 -1
- package/dist/browser/serve-engine.d.ts +30 -0
- package/dist/browser/serve-engine.d.ts.map +1 -0
- package/dist/browser/serve-engine.js +93 -0
- package/dist/browser/serve-engine.js.map +1 -0
- package/dist/browser/worker-entry.d.ts +8 -22
- package/dist/browser/worker-entry.d.ts.map +1 -1
- package/dist/browser/worker-entry.js +18 -79
- package/dist/browser/worker-entry.js.map +1 -1
- package/dist/electric/apply.d.ts +53 -0
- package/dist/electric/apply.d.ts.map +1 -0
- package/dist/electric/apply.js +88 -0
- package/dist/electric/apply.js.map +1 -0
- package/dist/electric/index.d.ts +133 -0
- package/dist/electric/index.d.ts.map +1 -0
- package/dist/electric/index.js +378 -0
- package/dist/electric/index.js.map +1 -0
- package/dist/electric/serial.d.ts +20 -0
- package/dist/electric/serial.d.ts.map +1 -0
- package/dist/electric/serial.js +29 -0
- package/dist/electric/serial.js.map +1 -0
- package/dist/electric/values.d.ts +65 -0
- package/dist/electric/values.d.ts.map +1 -0
- package/dist/electric/values.js +257 -0
- package/dist/electric/values.js.map +1 -0
- package/dist/electric/writes.d.ts +99 -0
- package/dist/electric/writes.d.ts.map +1 -0
- package/dist/electric/writes.js +282 -0
- package/dist/electric/writes.js.map +1 -0
- package/dist/electric-server/capture.d.ts +51 -0
- package/dist/electric-server/capture.d.ts.map +1 -0
- package/dist/electric-server/capture.js +224 -0
- package/dist/electric-server/capture.js.map +1 -0
- package/dist/electric-server/catalog.d.ts +61 -0
- package/dist/electric-server/catalog.d.ts.map +1 -0
- package/dist/electric-server/catalog.js +137 -0
- package/dist/electric-server/catalog.js.map +1 -0
- package/dist/electric-server/index.d.ts +85 -0
- package/dist/electric-server/index.d.ts.map +1 -0
- package/dist/electric-server/index.js +528 -0
- package/dist/electric-server/index.js.map +1 -0
- package/dist/electric-server/where.d.ts +30 -0
- package/dist/electric-server/where.d.ts.map +1 -0
- package/dist/electric-server/where.js +243 -0
- package/dist/electric-server/where.js.map +1 -0
- package/dist/firebird.d.ts +3 -1
- package/dist/firebird.d.ts.map +1 -1
- package/dist/firebird.js +259 -22
- package/dist/firebird.js.map +1 -1
- package/dist/frameworks/query-store.d.ts +99 -0
- package/dist/frameworks/query-store.d.ts.map +1 -0
- package/dist/frameworks/query-store.js +166 -0
- package/dist/frameworks/query-store.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +68 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +92 -0
- package/dist/react/index.js.map +1 -0
- package/dist/repl/index.d.ts +76 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +328 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/vue/index.d.ts +68 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +107 -0
- package/dist/vue/index.js.map +1 -0
- package/dist/wasm/firebird-embedded-st.js +1 -1
- package/dist/wasm/firebird-embedded-st.wasm +0 -0
- package/dist/wasm/firebird-embedded.js +1 -1
- package/dist/wasm/firebird-embedded.wasm +0 -0
- package/dist/wasm-loader.d.ts +57 -7
- package/dist/wasm-loader.d.ts.map +1 -1
- package/dist/wasm-loader.js +106 -21
- package/dist/wasm-loader.js.map +1 -1
- package/package.json +50 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,272 @@ All notable changes to `firebird-wasm`. This project follows
|
|
|
4
4
|
[semantic versioning](https://semver.org/); while the major version is 0 the
|
|
5
5
|
API may still move between minor releases.
|
|
6
6
|
|
|
7
|
+
## 0.9.0 — 2026-10-19
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Closing the last database frees the engine.** A module used to stay for
|
|
12
|
+
the life of the page or process; now the transports count the databases
|
|
13
|
+
that use one, and the last `close()` disposes it, unless whoever called
|
|
14
|
+
`loadFirebirdWasm()` still owns it. The next database loads a new module
|
|
15
|
+
(0.33–0.43 s without threads, about 1 s threaded); to keep one loaded
|
|
16
|
+
across closes, call `loadFirebirdWasm()` once, which owns it. A `memory://` database
|
|
17
|
+
went with its `close()` already; nothing else kept state in the module. An
|
|
18
|
+
`opfs://` database's access handle is now closed on `close()` too, so the
|
|
19
|
+
same Worker can open it again.
|
|
20
|
+
- **The build without threads is the default.** `wasmGlueFile()`,
|
|
21
|
+
`loadFirebirdWasm()`, `DirectTransport` and `cdnArtifacts()` now pick
|
|
22
|
+
`firebird-embedded-st` unless asked for threads, in Node and in a cross-origin
|
|
23
|
+
isolated page too; until now `'auto'` picked the threaded build wherever it
|
|
24
|
+
could run. The build without threads needs no `SharedArrayBuffer` and no
|
|
25
|
+
Worker, starts in about a third of the time (0.33–0.43 s against
|
|
26
|
+
0.87–1.06 s), and was not slower in anything measured; `firebird-quake2`
|
|
27
|
+
plays the same on it (a 5 ms tic on demo1 either way). What it gives up is
|
|
28
|
+
statement and idle timeouts. To keep the threaded build, ask for it:
|
|
29
|
+
`wasmGlueFile(true)` (or `wasmGlueFile(self.crossOriginIsolated)` for
|
|
30
|
+
threads where the page allows them), `loadFirebirdWasm({ threads: true })`,
|
|
31
|
+
`new DirectTransport({ threads: true })`, `cdnArtifacts({ threads: true })`.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **`disposeFirebirdWasm(mod)`** ends a module and lets it go: every database
|
|
36
|
+
detached, the engine shut down (`_fb_dispose`, which calls `fb_shutdown`),
|
|
37
|
+
the threaded build's workers terminated, and the module out of the cache.
|
|
38
|
+
Two things held a dropped threaded module: its 32 workers (about 400 MB in
|
|
39
|
+
Node) and the main thread's `Atomics.waitAsync` on its mailbox. Over ten
|
|
40
|
+
load/dispose cycles in Node, RSS levels off at about 200 MB without threads
|
|
41
|
+
and 300 MB threaded. Needs a rebuilt artifact.
|
|
42
|
+
- **Bytes as parameters.** A `Uint8Array` or `ArrayBuffer` binds as its own
|
|
43
|
+
bytes into a `BLOB` or a `BINARY` / `VARBINARY` (`OCTETS`) column, on both
|
|
44
|
+
backends and by every route (`exec`, `query`, transactions, `execBatch`).
|
|
45
|
+
The browser engine marks the bytes as bytes, so any other column refuses
|
|
46
|
+
them instead of reading them as text; `FirebirdLite` hands them to the
|
|
47
|
+
driver as a `Buffer`. They used to throw.
|
|
48
|
+
- **`bytea` syncs.** `firebird-wasm/electric` decodes Electric's `\x…` hex
|
|
49
|
+
into bytes, and `tableFromSchema` maps `bytea` to `BLOB SUB_TYPE BINARY`
|
|
50
|
+
(`VARCHAR(255) CHARACTER SET OCTETS` in a key). The shape server serves a
|
|
51
|
+
binary `BLOB`, `BINARY` and `VARBINARY` as `bytea`, byte for byte.
|
|
52
|
+
- **`syncShapesToTables`: several tables, one transaction per batch.** The
|
|
53
|
+
shapes are followed together and each batch is applied to every table in
|
|
54
|
+
one Firebird transaction with every shape's position, so a Postgres
|
|
55
|
+
transaction that wrote to two tables never shows in one of them alone. A
|
|
56
|
+
batch waits until every shape has reached up-to-date after its last change,
|
|
57
|
+
and until all are at the same `global_last_seen_lsn` where the server sends
|
|
58
|
+
it; a shape behind is refreshed. The shape server now sends
|
|
59
|
+
`global_last_seen_lsn` (its log position) as Electric does.
|
|
60
|
+
`syncShapeToTable` is the one-shape case of the same code.
|
|
61
|
+
- **A write path: `createWriteQueue`.** `insert`, `update` and `delete`
|
|
62
|
+
apply to the synced table at once and are recorded in `ELECTRIC_WRITES`
|
|
63
|
+
in the same transaction (so they survive a reload and an offline spell),
|
|
64
|
+
then go to the app's API through `send`, in order, retried on failure. A
|
|
65
|
+
sync given `writes` applies the pending writes again after every batch, so
|
|
66
|
+
the source's older state never shows over them, and drops each write once
|
|
67
|
+
its change comes back: by the transaction id `send` returned (Electric's
|
|
68
|
+
`txids`, which the shape server now sends too), by the row changing, or
|
|
69
|
+
after `confirmTimeoutMs`. A `WriteRejected` rolls the write back by
|
|
70
|
+
fetching the table's shape again. Syncs and the queue now run their
|
|
71
|
+
transactions on a database one at a time.
|
|
72
|
+
- **The shape server takes `where`, pages its snapshots, prunes its log,
|
|
73
|
+
wakes on events, and runs beside others.**
|
|
74
|
+
- `where` (and Electric's `params[n]`) is parsed and written as Firebird
|
|
75
|
+
SQL with every value bound; functions, casts and subqueries are refused
|
|
76
|
+
with a 400. Each `where` and `columns` is a shape with its own handle,
|
|
77
|
+
and a row that stops matching leaves as a delete.
|
|
78
|
+
- Snapshots are served `snapshotPageRows` (10 000) rows a response, by
|
|
79
|
+
key.
|
|
80
|
+
- The log is pruned of changes older than `retainLogMs` (7 days), or by
|
|
81
|
+
`prune(before)`; a client further behind is sent back to a snapshot.
|
|
82
|
+
- Commits wake live requests through the `ELECTRIC_CHANGES` event, with
|
|
83
|
+
polling (now every 1 s) as the fallback.
|
|
84
|
+
- Numbering takes a lock, so several servers can serve one database.
|
|
85
|
+
- **An example app that syncs from two servers:
|
|
86
|
+
[`examples/electric`](./examples/electric).** Two lists of notes, each a
|
|
87
|
+
table in the page's Firebird: one follows Postgres through Electric, the
|
|
88
|
+
other a Firebird server through `firebird-wasm/electric-server`. Writes go
|
|
89
|
+
to the source and come back down the shape; `db.live()` draws the lists;
|
|
90
|
+
`<firebird-repl>` queries the local copy. A Node server and a
|
|
91
|
+
`docker-compose.yml` run the sources. CI runs it in Chromium against real
|
|
92
|
+
containers, with both engine builds.
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- **The statement cache sees DDL it did not run.** It emptied itself before
|
|
97
|
+
DDL the bridge ran, but not for DDL inside `EXECUTE STATEMENT`, a
|
|
98
|
+
procedure, or another attachment: a kept `SELECT` of a table dropped that
|
|
99
|
+
way went on returning the dropped table's rows, and a kept call of a
|
|
100
|
+
procedure altered that way ran its old body. The engine now counts each
|
|
101
|
+
committed metadata change (patch 0007), and a database's kept statements go
|
|
102
|
+
when the count has moved. Reads and writes never move it, so the cache
|
|
103
|
+
works as before for them; `_fb_metadata_commits()` reads the count.
|
|
104
|
+
Calling `_fb_statement_cache()` after such DDL is no longer needed. Needs a
|
|
105
|
+
rebuilt artifact.
|
|
106
|
+
- **`EXECUTE STATEMENT` runs in the browser engine.** It did nothing, without
|
|
107
|
+
an error: an `INSERT` through it inserted no row, `INTO` gave `NULL`, and
|
|
108
|
+
`FOR EXECUTE STATEMENT … DO` gave no rows. It runs through Firebird's
|
|
109
|
+
External Data Sources (`jrd/extds`) even without `ON EXTERNAL`, and the
|
|
110
|
+
build replaced that directory with no-op stubs. It is compiled now, so
|
|
111
|
+
parameters, `WITH AUTONOMOUS TRANSACTION` and the caller's transaction work
|
|
112
|
+
as in Firebird, and its errors are reported.
|
|
113
|
+
Needs a rebuilt artifact: 170–200 KB larger, 54–55 KB gzipped (+2 %).
|
|
114
|
+
- **The browser engine reads `BINARY` and `VARBINARY` (`OCTETS`) values as
|
|
115
|
+
bytes**, as it reads a binary `BLOB`: base64 by default, a `Uint8Array`
|
|
116
|
+
with `types: { binary: true }`. They were read as text, which turned bytes
|
|
117
|
+
that are not UTF-8 into replacement characters (`GEN_UUID()` among them).
|
|
118
|
+
- **Two `syncShapeToTable` calls started together on a new database no
|
|
119
|
+
longer stop one of them.** Both found no `ELECTRIC_SHAPES` table and both
|
|
120
|
+
created it; the second creation failed ("unsuccessful metadata update")
|
|
121
|
+
and that sync stopped before it began. The loser now looks again and goes
|
|
122
|
+
on with the table the other made. Found by the example, which starts its
|
|
123
|
+
two syncs at once.
|
|
124
|
+
- **Closing a shape server while a live request waits no longer crashes the
|
|
125
|
+
process.** `close()` disconnected at once, and a waiting live request's next
|
|
126
|
+
poll started a transaction on the closed connection, where the native
|
|
127
|
+
client segfaults rather than throwing. `close()` now waits for whatever is
|
|
128
|
+
running on the connection, and the requests still waiting end with a 503.
|
|
129
|
+
Found as an intermittent crash of `browser-firebird-shapes.spec.ts`, which
|
|
130
|
+
closes its server while the browser is still following it.
|
|
131
|
+
|
|
132
|
+
## 0.8.0 — 2026-10-18
|
|
133
|
+
|
|
134
|
+
### Security
|
|
135
|
+
|
|
136
|
+
- **Importing the library no longer starts an engine server, and a page's
|
|
137
|
+
window is never served.** `firebird-wasm/browser` re-exported
|
|
138
|
+
`serveEngine` from the Worker entry, which started serving as soon as it
|
|
139
|
+
was loaded wherever `self.postMessage` existed, and a page's `window` has
|
|
140
|
+
one. So every page that imported the library listened for engine requests
|
|
141
|
+
on its window. With the engine on the page thread (the build without
|
|
142
|
+
threads, new in 0.7.0) that listener shared the page's engine, and any
|
|
143
|
+
window able to `postMessage` to the page, a frame or an opener of another
|
|
144
|
+
origin, could run SQL against its databases. With the engine in a Worker it
|
|
145
|
+
had no engine to reach. Now `serveEngine` lives in a module without side
|
|
146
|
+
effects, the Worker entry starts only in a dedicated Worker, and
|
|
147
|
+
`serveEngine` refuses a scope that has a `document`. Upgrade from 0.7.0 if
|
|
148
|
+
you run the engine on the page thread.
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- **`firebird-wasm/electric-server`: a Firebird server's tables over
|
|
153
|
+
Electric's protocol.** `createShapeServer({ database, tables })` returns a
|
|
154
|
+
Node HTTP handler that `syncShapeToTable` syncs from as it would from
|
|
155
|
+
Electric, so a table on a Firebird server reaches Firebird in the browser
|
|
156
|
+
with no Postgres. Triggers log each changed row's key; the server numbers
|
|
157
|
+
the log in commit order before every read, so a transaction that wrote
|
|
158
|
+
first and committed last is never skipped, and a connection opened before
|
|
159
|
+
the capture was installed is captured too. Tested on Firebird 3, 4 and 5,
|
|
160
|
+
and end to end into the engine in Chromium.
|
|
161
|
+
- **`firebird-wasm/electric`: sync a Postgres table through Electric.**
|
|
162
|
+
`syncShapeToTable(db, { shape, table, shapeKey })` keeps a Firebird table in
|
|
163
|
+
step with an Electric shape: each batch Electric marks up-to-date applied in
|
|
164
|
+
one transaction with the sync position, a resume from that position after a
|
|
165
|
+
reload, a full reload in one transaction on must-refetch, Postgres text
|
|
166
|
+
converted exactly per column type (and unmapped types refused by name), and
|
|
167
|
+
an event per batch for `live()` and the hooks. `tableFromSchema()` writes a
|
|
168
|
+
`CREATE TABLE` from a shape's schema to review. Read-only, as Electric is.
|
|
169
|
+
`@electric-sql/client` is an optional peer dependency. Tested against a real
|
|
170
|
+
Postgres and Electric in CI. A Postgres `int8` is bound as its text, which
|
|
171
|
+
converts into `BIGINT` exactly and which the Node driver can bind.
|
|
172
|
+
- **`firebird-wasm/repl`: a SQL console as a custom element.**
|
|
173
|
+
`defineFirebirdRepl()` registers `<firebird-repl>`; give it a database
|
|
174
|
+
through its `db` property. Ctrl+Enter runs a script statement by statement
|
|
175
|
+
(`SET TERM` included) and stops at the first error; rows show as a table,
|
|
176
|
+
other statements with the rows they changed; ArrowUp and ArrowDown walk the
|
|
177
|
+
history. Values are drawn as text, never as HTML. A `db` set before the
|
|
178
|
+
element was defined, as frameworks do, is kept.
|
|
179
|
+
- **`firebird-wasm/react` and `firebird-wasm/vue`.** `useQuery` runs a
|
|
180
|
+
statement and re-runs it when its SQL or parameters change by value;
|
|
181
|
+
`useLiveQuery` re-runs it each time one of its events fires (`live()`
|
|
182
|
+
under a hook). Both give `rows`, `error`, `loading` and `refresh()`, keep
|
|
183
|
+
the previous rows while the next ones load, drop results that arrive after
|
|
184
|
+
the component moved on, and unsubscribe on unmount, StrictMode's double
|
|
185
|
+
mount included. React through `FirebirdProvider`, Vue through
|
|
186
|
+
`provideFirebird(db)` or `app.provide(FIREBIRD, db)`; the statement and
|
|
187
|
+
parameters may be refs or getters in Vue. React 18+ and Vue 3.3+ are
|
|
188
|
+
optional peer dependencies.
|
|
189
|
+
- **`examples/vite` and `examples/webpack`.** Minimal apps built by their own
|
|
190
|
+
bundlers from the package, run by CI in Chromium with and without
|
|
191
|
+
cross-origin isolation.
|
|
192
|
+
|
|
193
|
+
### Fixed
|
|
194
|
+
|
|
195
|
+
- **`FirebirdLite` binds a string into a DATE, TIME or TIMESTAMP parameter,
|
|
196
|
+
exactly.** The native driver takes a JS `Date` there and failed on a string
|
|
197
|
+
(`date.getFullYear is not a function`), so `firebird-wasm/electric`'s
|
|
198
|
+
`syncShapeToTable`, which sends dates and times as text, could not write to
|
|
199
|
+
a `FirebirdLite` database. Such a string is now sent as text and Firebird
|
|
200
|
+
converts it, as the browser engine does: to 1/10000 s, with no detour
|
|
201
|
+
through milliseconds or the process's time zone, and `WITH TIME ZONE` too
|
|
202
|
+
(with a Firebird 4 or later client library). A `Date` binds as before.
|
|
203
|
+
- **`FirebirdLite` binds a string into an integer or NUMERIC parameter digit
|
|
204
|
+
for digit.** The driver binds those as doubles: `'9007199254740993'` into
|
|
205
|
+
a BIGINT arrived as 9007199254740992, and `syncShapeToTable` sends `int8`
|
|
206
|
+
and `numeric` as text. Such a string is now sent as text too; a JS number
|
|
207
|
+
is unchanged, and `execBatch` declares a block's parameter as the column's
|
|
208
|
+
own type rather than DOUBLE PRECISION.
|
|
209
|
+
- **A bad parameter beside a BLOB no longer kills the process.** The driver
|
|
210
|
+
wrote a BLOB parameter while encoding the others, under a `Promise.all`
|
|
211
|
+
that rejected as soon as one failed, and the transaction was rolled back
|
|
212
|
+
under the blob's native calls: a date as a string, or a string too long for
|
|
213
|
+
its VARCHAR, beside a BLOB ended Node with a segmentation fault (seen in
|
|
214
|
+
Jest syncing a shape into a `FirebirdLite` database). `FirebirdLite` now
|
|
215
|
+
writes the blob before the driver encodes anything, so the failure is the
|
|
216
|
+
error it should be.
|
|
217
|
+
- **An event posted right after subscribing is no longer lost.** A
|
|
218
|
+
subscription's first delivery from the engine is a baseline, not news, and
|
|
219
|
+
the bridge absorbed whatever it said. With threads that delivery comes from
|
|
220
|
+
the engine's watcher thread some time after the subscription returns, so a
|
|
221
|
+
`POST_EVENT` that committed first was folded into it and never reported: a
|
|
222
|
+
`live()` query missed its first change in about one browser run in three.
|
|
223
|
+
Subscribing now waits for the baseline before returning (the build without
|
|
224
|
+
threads delivered it in time already).
|
|
225
|
+
- **`live()` no longer drops an event heard during a refresh.** It ran one
|
|
226
|
+
refresh at a time by ignoring events while one ran, but that refresh may
|
|
227
|
+
have read before the change committed, so the rows stayed stale until some
|
|
228
|
+
later event. An event during a refresh now earns exactly one more. `live()`
|
|
229
|
+
also subscribes before its first query rather than after, so a change
|
|
230
|
+
committed between the two is no longer in neither, and releases the
|
|
231
|
+
subscription if that query fails.
|
|
232
|
+
- **`FirebirdLite` binds a string into a BLOB parameter.** The native driver
|
|
233
|
+
takes a `Buffer` there and refused a string ("Unrecognized type used as
|
|
234
|
+
BLOB"); a string bound to a BLOB parameter is now passed as its UTF-8
|
|
235
|
+
bytes, in `exec`, `query`, transactions and `execBatch`. The browser engine
|
|
236
|
+
had the same gap, fixed above.
|
|
237
|
+
- **A string binds into a BLOB parameter.** `INSERT INTO notes (body) VALUES
|
|
238
|
+
(?)` with a `BLOB SUB_TYPE TEXT` column failed in the browser engine ("BLOB
|
|
239
|
+
and array data types are not supported for move operation"): a BLOB
|
|
240
|
+
parameter takes a blob's id, and the bridge only converted values. It now
|
|
241
|
+
writes the text as a blob in the statement's transaction and binds its id,
|
|
242
|
+
through `exec`, `query`, transactions and `execBatch` alike, with no size
|
|
243
|
+
limit of its own (text parameters were capped at 64 KB). A batch with a
|
|
244
|
+
BLOB parameter runs as one execute per row, since Firebird's batch takes no
|
|
245
|
+
blob written outside it.
|
|
246
|
+
- **`firebird-wasm/browser/worker-entry` can be imported.** The package's
|
|
247
|
+
`exports` did not list it, so the import the integration guide showed failed
|
|
248
|
+
in any bundler that honours `exports` (Vite and webpack both). It is now
|
|
249
|
+
exported, and so is `./package.json`.
|
|
250
|
+
- **`firebird-wasm/browser/worker-entry` imported with a bundler.** In a
|
|
251
|
+
Worker that imported the library before setting
|
|
252
|
+
`FIREBIRD_WORKER_OPTIONS`, the side effect above started the engine without
|
|
253
|
+
them, so its `.wasm` was looked for next to the Worker script.
|
|
254
|
+
- **A `CHAR(n)` in UTF-8 reads back as n characters.** Firebird pads a
|
|
255
|
+
`CHAR` to its length in bytes, four a character in UTF-8, and the browser
|
|
256
|
+
engine returned all of them: a `CHAR(36)` holding a uuid came back as the
|
|
257
|
+
uuid and 108 spaces. It is now cut to n characters, its own padding kept
|
|
258
|
+
(`'ab'` in a `CHAR(5)` is `'ab '`, `'žš'` is `'žš '`), as other
|
|
259
|
+
Firebird drivers return it. `OCTETS` and `NONE` columns, one byte a
|
|
260
|
+
character, are unchanged.
|
|
261
|
+
|
|
262
|
+
### Changed
|
|
263
|
+
|
|
264
|
+
- **A quoted column name keeps its case in results.** `query` upper-cased
|
|
265
|
+
every column name, so `SELECT title AS "title"` gave `TITLE`, unlike what
|
|
266
|
+
the integration guide said, and `SELECT "camelCase" FROM t` gave
|
|
267
|
+
`CAMELCASE`. Names are now as Firebird reports them, in the browser engine
|
|
268
|
+
and in `FirebirdLite` alike: unquoted names are still upper case (Firebird
|
|
269
|
+
folds them), so only quoted names change. Code that read a quoted name by
|
|
270
|
+
its upper-cased key (`row.CAMELCASE`) must use the name as written
|
|
271
|
+
(`row.camelCase`), or drop the quotes from the alias.
|
|
272
|
+
|
|
7
273
|
## 0.7.0 — 2026-10-18
|
|
8
274
|
|
|
9
275
|
### Fixed
|
package/README.md
CHANGED
|
@@ -51,11 +51,13 @@ const { rows } = await db.query('SELECT * FROM notes');
|
|
|
51
51
|
// [{ ID: 1, TITLE: 'Hello' }]
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
The default build, `firebird-embedded-st.js`, has no threads: it needs no
|
|
55
|
+
`SharedArrayBuffer`, so no cross-origin isolation, and can run without a
|
|
56
|
+
Worker. The threaded build (`wasmGlueFile(true)`, `threads: true`) adds
|
|
57
|
+
statement and idle timeouts, and has two structural constraints: the page must
|
|
55
58
|
be [cross-origin isolated](../../docs/integration.md#2-the-two-hard-requirements-and-the-build-without-them),
|
|
56
59
|
and the engine must run in a Worker — it blocks on mutexes, and a browser main
|
|
57
|
-
thread may not block.
|
|
58
|
-
has neither constraint and gives up statement and idle timeouts.
|
|
60
|
+
thread may not block. Until 0.9.0 the threaded build was the default.
|
|
59
61
|
|
|
60
62
|
## Quick start
|
|
61
63
|
|
|
@@ -114,7 +116,7 @@ Execute a query and return a `QueryResult<T>`:
|
|
|
114
116
|
|
|
115
117
|
```ts
|
|
116
118
|
interface QueryResult<T> {
|
|
117
|
-
rows: T[]; // result rows keyed by
|
|
119
|
+
rows: T[]; // result rows keyed by column name (upper case unless quoted)
|
|
118
120
|
fields: FieldInfo[]; // column metadata
|
|
119
121
|
}
|
|
120
122
|
```
|
|
@@ -155,8 +157,7 @@ FIREBIRD_PASSWORD=masterkey npm test
|
|
|
155
157
|
|
|
156
158
|
## Roadmap
|
|
157
159
|
|
|
158
|
-
Shipped in 0.1.0
|
|
159
|
-
the last:
|
|
160
|
+
Shipped in 0.1.0:
|
|
160
161
|
|
|
161
162
|
- [x] True WASM build — Firebird 6.0 compiled with Emscripten
|
|
162
163
|
- [x] Browser support via the WASM bundle, with the engine in a Web Worker
|
|
@@ -167,19 +168,34 @@ the last:
|
|
|
167
168
|
letting it overwrite the first
|
|
168
169
|
- [x] The prebuilt engine on npm, so using it needs no Emscripten
|
|
169
170
|
|
|
171
|
+
Shipped since:
|
|
172
|
+
|
|
173
|
+
- [x] Live queries built on Firebird's `POST_EVENT` (`live()`, `listen()`,
|
|
174
|
+
`notify()`)
|
|
175
|
+
- [x] Multi-tab *sharing* (`multiTab: 'shared'`): one tab runs the engine,
|
|
176
|
+
the others are served by it
|
|
177
|
+
- [x] OPFS backend (`opfs://name`), with no image copy and no persist step
|
|
178
|
+
- [x] A build without `SharedArrayBuffer` (`firebird-embedded-st`), for pages
|
|
179
|
+
served without COOP/COEP headers
|
|
180
|
+
- [x] React and Vue hooks (`firebird-wasm/react`, `firebird-wasm/vue`) and a
|
|
181
|
+
REPL element (`firebird-wasm/repl`)
|
|
182
|
+
- [x] ElectricSQL sync, read path: a shape from Postgres through Electric
|
|
183
|
+
(`firebird-wasm/electric`), or from a Firebird server
|
|
184
|
+
(`firebird-wasm/electric-server`), with an example app syncing from
|
|
185
|
+
both ([`examples/electric`](../../examples/electric)), `bytea`
|
|
186
|
+
included, and several tables in one transaction
|
|
187
|
+
(`syncShapesToTables`)
|
|
188
|
+
- [x] ElectricSQL writes: `createWriteQueue` applies a write at once, sends
|
|
189
|
+
it to the app's API, and keeps it over the sync until it comes back
|
|
190
|
+
- [x] Module disposal: `disposeFirebirdWasm()`, and closing the last
|
|
191
|
+
database frees the engine's memory
|
|
192
|
+
|
|
170
193
|
Next:
|
|
171
194
|
|
|
172
|
-
- [ ] Live queries built on Firebird's `POST_EVENT`
|
|
173
|
-
- [ ] Multi-tab *sharing* — a `SharedWorker` leader, so a second tab is served
|
|
174
|
-
rather than refused
|
|
175
|
-
- [ ] OPFS backend — a better match for page-oriented I/O than IndexedDB
|
|
176
195
|
- [ ] A typed binary result ABI, so exact numerics need not travel as strings
|
|
177
|
-
- [ ]
|
|
178
|
-
|
|
179
|
-
+245 KB gzipped, measured; what is missing is a way for `IntlManager`
|
|
180
|
-
to reach it without `dlopen`. See
|
|
196
|
+
- [ ] UNICODE collations (case- and accent-insensitive comparison), which
|
|
197
|
+
need ICU collation data in the build. See
|
|
181
198
|
[docs/roadmap.md](../../docs/roadmap.md)
|
|
182
|
-
- [ ] ElectricSQL sync
|
|
183
199
|
|
|
184
200
|
**"Firebird 4 & 5 support" is gone from this list because it was never the
|
|
185
201
|
gap.** The build tracks Firebird `master` and the shipped engine reports
|