browser-sqlite 1.0.0-rc.3 → 1.0.0-rc.5
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/NOTICE +56 -0
- package/README.md +112 -104
- package/dist/LICENSE +21 -0
- package/dist/NOTICE +56 -0
- package/dist/abandon.d.ts +77 -0
- package/dist/api.d.ts +426 -0
- package/dist/bulk.d.ts +57 -0
- package/dist/capabilities.d.ts +23 -0
- package/dist/client.d.ts +221 -0
- package/dist/credits.d.ts +31 -0
- package/dist/{esm/src/debug.d.ts → debug.d.ts} +21 -10
- package/dist/delete.d.ts +48 -0
- package/dist/epochs.d.ts +85 -0
- package/dist/errors.d.ts +76 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +96 -0
- package/dist/locks.d.ts +172 -0
- package/dist/logger.d.ts +24 -0
- package/dist/pool.d.ts +191 -0
- package/dist/queries.d.ts +65 -0
- package/dist/scheduler.d.ts +145 -0
- package/dist/sqlite-codes.d.ts +154 -0
- package/dist/supervisor.d.ts +17 -0
- package/dist/transaction.d.ts +61 -0
- package/dist/types.d.ts +642 -0
- package/dist/utils.d.ts +156 -0
- package/dist/worker/cloneable.d.ts +25 -0
- package/dist/worker/probes.d.ts +26 -0
- package/dist/worker/sqlite-code.d.ts +9 -0
- package/dist/worker/statement-cache.d.ts +36 -0
- package/dist/worker/wa-sqlite-async.wasm +0 -0
- package/dist/worker/wa-sqlite-jspi.wasm +0 -0
- package/dist/worker/wa-sqlite.wasm +0 -0
- package/dist/worker/worker.js +11 -0
- package/dist/worker/worker.js.map +1 -0
- package/package.json +46 -22
- package/dist/esm/index.js +0 -424
- package/dist/esm/rslib.config.d.ts +0 -2
- package/dist/esm/rstest.config.d.ts +0 -2
- package/dist/esm/src/client.d.ts +0 -332
- package/dist/esm/src/index.d.ts +0 -1
- package/dist/esm/src/orchestrator.d.ts +0 -87
- package/dist/esm/src/types.d.ts +0 -83
- package/dist/esm/src/utils.d.ts +0 -6
- /package/dist/{esm/src → worker}/worker.d.ts +0 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
import type { SQLiteErrorCode } from './errors';
|
|
2
|
+
import type { SQLiteResultCode } from './sqlite-codes';
|
|
3
|
+
export type SQLiteWorkerMessageData<_T = unknown> = {
|
|
4
|
+
callId: number;
|
|
5
|
+
terminate?: boolean;
|
|
6
|
+
} & (SQLWorkerResultData[keyof SQLWorkerResultData] | {
|
|
7
|
+
type: 'error';
|
|
8
|
+
message: string;
|
|
9
|
+
});
|
|
10
|
+
export type SQLWorkerResultData<T = unknown> = {
|
|
11
|
+
open: {
|
|
12
|
+
success: boolean;
|
|
13
|
+
};
|
|
14
|
+
sql: {
|
|
15
|
+
type: 'partial';
|
|
16
|
+
result: T[];
|
|
17
|
+
} | {
|
|
18
|
+
type: 'one';
|
|
19
|
+
sizes: number[];
|
|
20
|
+
};
|
|
21
|
+
abort: {
|
|
22
|
+
type: 'done';
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export declare const SharedArrayTypes: {
|
|
26
|
+
INT: number;
|
|
27
|
+
STRING: number;
|
|
28
|
+
OBJECT: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The savepoint a transaction asks the worker to handle around one query
|
|
32
|
+
* (spec 2026-09-11, D4/D5). `conclude` settles the savepoint the previous
|
|
33
|
+
* savepointed write left open — `release` keeps that write, `undo` rolls it
|
|
34
|
+
* back first — and `open` starts one for this query's own statement. Both run
|
|
35
|
+
* before the statement, conclusion first. Internal: no consumer sets it.
|
|
36
|
+
*/
|
|
37
|
+
export type SavepointOp = {
|
|
38
|
+
conclude?: 'release' | 'undo';
|
|
39
|
+
open?: true;
|
|
40
|
+
};
|
|
41
|
+
type SQLOptions = {
|
|
42
|
+
chunkSize?: number;
|
|
43
|
+
/** Chunks the worker may send before waiting for a credit. Spec §3.2. */
|
|
44
|
+
credits?: number;
|
|
45
|
+
/** When true, the worker installs an async progress handler so an AbortSignal can stop a running step(). */
|
|
46
|
+
abortable?: boolean;
|
|
47
|
+
/** See `SavepointOp`. */
|
|
48
|
+
savepoint?: SavepointOp;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Where a worker fetches its `.wasm` from, when the consumer overrode it.
|
|
52
|
+
*
|
|
53
|
+
* Discriminated rather than a single string because the two forms differ in
|
|
54
|
+
* what they leave to the Emscripten glue. `base` is a directory: the glue
|
|
55
|
+
* supplies the file name (`locateFile('wa-sqlite-async.wasm')`), so nothing
|
|
56
|
+
* here names the three builds' files — and nothing has to be renamed when
|
|
57
|
+
* wa-sqlite renames one. `file` is the whole URL, typically content-hashed by
|
|
58
|
+
* a bundler, so the glue's file name is discarded.
|
|
59
|
+
*
|
|
60
|
+
* Always absolute: `resolveWasmLocation` (`src/utils.ts`) resolves against the
|
|
61
|
+
* page before the `open` message is posted, so the worker applies it without
|
|
62
|
+
* knowing what it was relative to.
|
|
63
|
+
*/
|
|
64
|
+
export type WasmLocation = {
|
|
65
|
+
base: string;
|
|
66
|
+
} | {
|
|
67
|
+
file: string;
|
|
68
|
+
};
|
|
69
|
+
export type ClientMessageData = {
|
|
70
|
+
type: 'open';
|
|
71
|
+
file: string;
|
|
72
|
+
vfs: SQLiteVFS;
|
|
73
|
+
build?: SQLiteBuild;
|
|
74
|
+
pragmas?: Record<string, string>;
|
|
75
|
+
/** Statements retained per worker; see `src/client.ts`. Internal. */
|
|
76
|
+
statementCacheSize?: number;
|
|
77
|
+
/** Bytes retained per worker; see `src/client.ts`. Internal. */
|
|
78
|
+
statementCacheBytes?: number;
|
|
79
|
+
wasm?: WasmLocation;
|
|
80
|
+
/** Shared abort slots, one Int32 per worker. Isolated contexts only. */
|
|
81
|
+
abortSlots?: SharedArrayBuffer;
|
|
82
|
+
/** This worker's index into `abortSlots`. */
|
|
83
|
+
abortIndex?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Features this worker must find before opening; it declines instead of
|
|
86
|
+
* opening when one is missing (spec 2026-09-13). Sent to slots of index
|
|
87
|
+
* ≥ 1 only, and only by a VFS that declares `singleConnectionWithout`.
|
|
88
|
+
*/
|
|
89
|
+
declineWithout?: readonly PlatformFeature[];
|
|
90
|
+
/**
|
|
91
|
+
* Features worker 0 probes before opening, where the VFS is exclusive
|
|
92
|
+
* without one (spec 2026-09-15, §3.2): it reports them with `probed`,
|
|
93
|
+
* then loads nothing until `proceed`. Sent to slot 0 only, and only by a
|
|
94
|
+
* VFS that declares `exclusiveConnectionWithout`.
|
|
95
|
+
*/
|
|
96
|
+
probeFirst?: readonly PlatformFeature[];
|
|
97
|
+
} | {
|
|
98
|
+
type: 'query';
|
|
99
|
+
callId: number;
|
|
100
|
+
sql: string;
|
|
101
|
+
params: unknown[];
|
|
102
|
+
options?: SQLOptions;
|
|
103
|
+
} | {
|
|
104
|
+
type: 'close';
|
|
105
|
+
callId: number;
|
|
106
|
+
} | {
|
|
107
|
+
type: 'credit';
|
|
108
|
+
callId: number;
|
|
109
|
+
n: number;
|
|
110
|
+
} | {
|
|
111
|
+
type: 'stop';
|
|
112
|
+
callId: number;
|
|
113
|
+
}
|
|
114
|
+
/** The client decided the connection lock; worker 0 may open (spec 2026-09-15). */
|
|
115
|
+
| {
|
|
116
|
+
type: 'proceed';
|
|
117
|
+
callId: number;
|
|
118
|
+
} | {
|
|
119
|
+
type: 'delete';
|
|
120
|
+
callId: number;
|
|
121
|
+
file: string;
|
|
122
|
+
vfs: SQLiteVFS;
|
|
123
|
+
build?: SQLiteBuild;
|
|
124
|
+
wasm?: WasmLocation;
|
|
125
|
+
};
|
|
126
|
+
export type WorkerMessageData = {
|
|
127
|
+
type: 'ready';
|
|
128
|
+
callId: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The worker found a feature of `declineWithout` missing and opened nothing:
|
|
132
|
+
* the environment caps the pool (spec 2026-09-13).
|
|
133
|
+
*/
|
|
134
|
+
| {
|
|
135
|
+
type: 'declined';
|
|
136
|
+
callId: number;
|
|
137
|
+
missing: PlatformFeature;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Worker 0's answer to `probeFirst`: the first feature missing, or null. It
|
|
141
|
+
* opens nothing until the client sends `proceed` (spec 2026-09-15, §3.2).
|
|
142
|
+
*/
|
|
143
|
+
| {
|
|
144
|
+
type: 'probed';
|
|
145
|
+
callId: number;
|
|
146
|
+
missing: PlatformFeature | null;
|
|
147
|
+
} | {
|
|
148
|
+
type: 'chunk';
|
|
149
|
+
callId: number;
|
|
150
|
+
data: unknown[];
|
|
151
|
+
} | {
|
|
152
|
+
type: 'done';
|
|
153
|
+
callId: number;
|
|
154
|
+
affected: number;
|
|
155
|
+
/**
|
|
156
|
+
* Statements compiled while serving this query — zero on a cache hit.
|
|
157
|
+
* Rides the same message as `affected` rather than opening a channel:
|
|
158
|
+
* the effect this instruments is a count, not a duration (`mem:lessons`,
|
|
159
|
+
* "for a sub-millisecond effect, count the round trips").
|
|
160
|
+
*/
|
|
161
|
+
prepared: number;
|
|
162
|
+
/**
|
|
163
|
+
* Whether the connection is inside a transaction once this query has
|
|
164
|
+
* ended — `sqlite3_get_autocommit() === 0`. SQLite can leave a
|
|
165
|
+
* transaction by itself: an interrupted INSERT/UPDATE/DELETE rolls the
|
|
166
|
+
* whole transaction back. Absent when the worker could not read it.
|
|
167
|
+
*/
|
|
168
|
+
inTransaction?: boolean | undefined;
|
|
169
|
+
} | {
|
|
170
|
+
type: 'error';
|
|
171
|
+
callId: number;
|
|
172
|
+
message: string;
|
|
173
|
+
cause?: unknown;
|
|
174
|
+
/** SQLite's numeric result code, when the failure came from SQLite. */
|
|
175
|
+
sqliteCode?: SQLiteResultCode;
|
|
176
|
+
/**
|
|
177
|
+
* SQLite's extended result code, read in the worker where the statement
|
|
178
|
+
* failed (spec 2026-09-14, §5.1). Sent by the query path only, and
|
|
179
|
+
* unfiltered: this is exactly what SQLite reported, including a value
|
|
180
|
+
* equal to `sqliteCode` (no subtype). The client is what drops it in
|
|
181
|
+
* that case (D9); when SQLite does report a subtype,
|
|
182
|
+
* `(sqliteExtendedCode & 0xff) === sqliteCode`.
|
|
183
|
+
*/
|
|
184
|
+
sqliteExtendedCode?: number;
|
|
185
|
+
/**
|
|
186
|
+
* A code this library minted, when the worker knows the cause. The
|
|
187
|
+
* generic path by which a worker-side error keeps its code across the
|
|
188
|
+
* boundary — `worker.ts` copies it off any thrown error carrying one, so
|
|
189
|
+
* this is a structural contract and not a hook for one class.
|
|
190
|
+
*
|
|
191
|
+
* **Nothing sets it today.** `WorkerQueryTimeout` was its only producer
|
|
192
|
+
* and it went with the execution budget when `timeout` became a
|
|
193
|
+
* client-side wall-clock deadline. Kept rather than deleted: it is the
|
|
194
|
+
* twin of `sqliteCode` above, which is load-bearing, and rebuilding it
|
|
195
|
+
* would cost the same three sites it occupies.
|
|
196
|
+
*/
|
|
197
|
+
errorCode?: SQLiteErrorCode;
|
|
198
|
+
/**
|
|
199
|
+
* Whether the connection is inside a transaction once this query has
|
|
200
|
+
* ended — `sqlite3_get_autocommit() === 0`. SQLite can leave a
|
|
201
|
+
* transaction by itself: an interrupted INSERT/UPDATE/DELETE rolls the
|
|
202
|
+
* whole transaction back. Absent when the worker could not read it.
|
|
203
|
+
*/
|
|
204
|
+
inTransaction?: boolean | undefined;
|
|
205
|
+
} | {
|
|
206
|
+
type: 'closed';
|
|
207
|
+
callId: number;
|
|
208
|
+
} | {
|
|
209
|
+
type: 'deleted';
|
|
210
|
+
callId: number;
|
|
211
|
+
}
|
|
212
|
+
/** The delete worker found nothing at that name; deleteDatabase turns it into DATABASE_NOT_FOUND. */
|
|
213
|
+
| {
|
|
214
|
+
type: 'not-found';
|
|
215
|
+
} | {
|
|
216
|
+
type: 'open-error';
|
|
217
|
+
callId: number;
|
|
218
|
+
message: string;
|
|
219
|
+
cause?: unknown;
|
|
220
|
+
/** SQLite's numeric result code, when the failure came from SQLite. */
|
|
221
|
+
sqliteCode?: SQLiteResultCode;
|
|
222
|
+
};
|
|
223
|
+
/** Which wa-sqlite WebAssembly build a worker loads. */
|
|
224
|
+
export type SQLiteBuild = 'sync' | 'async' | 'jspi';
|
|
225
|
+
/**
|
|
226
|
+
* What each build needs from the engine beyond plain WebAssembly.
|
|
227
|
+
*
|
|
228
|
+
* `satisfies Record<SQLiteBuild, …>` and not `SQLiteBuild = keyof typeof …`:
|
|
229
|
+
* the check must run in this direction. Adding a build to the union then fails
|
|
230
|
+
* to compile until its requirements are declared, where `keyof` would let a
|
|
231
|
+
* forgotten entry mean silently that the build does not exist. `VFS_CAPABILITIES`
|
|
232
|
+
* derives `SQLiteVFS` from its keys because it *is* the VFS registry; the build
|
|
233
|
+
* registry is `WA_SQLITE_BUILDS` in the worker, and this table describes one
|
|
234
|
+
* attribute of builds rather than the builds themselves.
|
|
235
|
+
*/
|
|
236
|
+
export declare const BUILD_REQUIREMENTS: {
|
|
237
|
+
readonly sync: readonly [];
|
|
238
|
+
readonly async: readonly [];
|
|
239
|
+
readonly jspi: readonly ["jspi"];
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* Platform features a build USES when present and works without, at a cost —
|
|
243
|
+
* the symmetric of `degradesWithout` on a VFS, at the level where this one
|
|
244
|
+
* actually lives. The `sync` build cannot carry an abort into a running
|
|
245
|
+
* `step()` without a `SharedArrayBuffer`, and there is no SharedArrayBuffer
|
|
246
|
+
* outside a cross-origin isolated context: measured 2026-09-04, it is not
|
|
247
|
+
* restricted there, it is absent. Nothing here names COOP/COEP or
|
|
248
|
+
* Document-Isolation-Policy: any of them satisfies the probe, and one of them
|
|
249
|
+
* is Chrome-only.
|
|
250
|
+
*/
|
|
251
|
+
export declare const BUILD_DEGRADES_WITHOUT: {
|
|
252
|
+
readonly sync: readonly ["cross-origin-isolated"];
|
|
253
|
+
readonly async: readonly [];
|
|
254
|
+
readonly jspi: readonly [];
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* A platform feature a VFS may need. Which browser versions ship each one is
|
|
258
|
+
* documentation data, not runtime data, so it lives in the VFS.md generator
|
|
259
|
+
* (`scripts/render-vfs-matrix.ts`) with its sources — not here, where it would
|
|
260
|
+
* ship to every consumer for nothing.
|
|
261
|
+
*/
|
|
262
|
+
export type PlatformFeature = 'opfs' | 'readwrite-unsafe' | 'jspi' | 'writable-stream' | 'cross-origin-isolated';
|
|
263
|
+
/** Where a VFS keeps the database. */
|
|
264
|
+
export type VFSStorage = 'opfs' | 'indexeddb' | 'memory';
|
|
265
|
+
/**
|
|
266
|
+
* How a VFS arranges a database in its storage — which is not the same
|
|
267
|
+
* question as `storage`, and cannot be derived from it: `AccessHandlePoolVFS`
|
|
268
|
+
* is `storage: 'opfs'` yet keeps opaque, randomly named slot files whose
|
|
269
|
+
* association with a SQLite path lives in a header inside each file.
|
|
270
|
+
*
|
|
271
|
+
* `deleteDatabase` reads this to decide whether the database is also an OPFS
|
|
272
|
+
* entry it can remove by name after `jDelete` — the pass that covers the two
|
|
273
|
+
* VFS whose `jDelete` does not delete. A wrong value here is a deletion that
|
|
274
|
+
* reports success over an intact file.
|
|
275
|
+
*/
|
|
276
|
+
export type VFSLayout = 'opfs-path' | 'opfs-pool' | 'idb-store' | 'memory';
|
|
277
|
+
/** How much of the database a VFS keeps resident in RAM. */
|
|
278
|
+
export type VFSMemoryModel = 'page-cache' | 'whole-database';
|
|
279
|
+
/** What a VFS can and cannot do. One entry per VFS, and no second table. */
|
|
280
|
+
export type VFSCapability = {
|
|
281
|
+
/** Builds this VFS can run on, most preferred first. */
|
|
282
|
+
readonly builds: readonly [SQLiteBuild, ...SQLiteBuild[]];
|
|
283
|
+
/** Largest pool this VFS supports; `null` when unbounded. */
|
|
284
|
+
readonly maxPoolSize: number | null;
|
|
285
|
+
/** Why the cap exists. Required whenever `maxPoolSize` is not null. */
|
|
286
|
+
readonly poolLimitReason: string | null;
|
|
287
|
+
/** Whether several connections may share one database. */
|
|
288
|
+
readonly multiConnection: boolean;
|
|
289
|
+
/** Whether data outlives `close()`. */
|
|
290
|
+
readonly persistent: boolean;
|
|
291
|
+
/**
|
|
292
|
+
* `page-cache`: only SQLite's page cache is resident, bounded by
|
|
293
|
+
* `PRAGMA cache_size`. `whole-database`: the entire database is resident,
|
|
294
|
+
* and `poolSize` multiplies it.
|
|
295
|
+
*/
|
|
296
|
+
readonly memoryModel: VFSMemoryModel;
|
|
297
|
+
/** Where the database actually lives. */
|
|
298
|
+
readonly storage: VFSStorage;
|
|
299
|
+
/** How the database is arranged within that storage. */
|
|
300
|
+
readonly layout: VFSLayout;
|
|
301
|
+
/**
|
|
302
|
+
* Whether this VFS takes its OPFS access handle in the EXCLUSIVE mode —
|
|
303
|
+
* `createSyncAccessHandle()` with no `mode`, rather than
|
|
304
|
+
* `mode: 'readwrite-unsafe'`.
|
|
305
|
+
*
|
|
306
|
+
* It decides whether an acquisition has to be retried. A terminated context
|
|
307
|
+
* releases its Web Locks at once but keeps its OPFS access handles for up to
|
|
308
|
+
* ~2 s on Chromium (HANDLE-CORPSE, `mem:measurements`), so a VFS taking an
|
|
309
|
+
* exclusive handle can meet a file held by something that answers nothing:
|
|
310
|
+
* no lock to wait on, no owner to ask, only time to wait out. Where
|
|
311
|
+
* `readwrite-unsafe` is used a second handle is granted regardless, and a
|
|
312
|
+
* dead holder blocks nobody.
|
|
313
|
+
*
|
|
314
|
+
* Declared rather than detected, because the error is not available where the
|
|
315
|
+
* decision has to be made: wa-sqlite's `jOpen` swallows it (measured
|
|
316
|
+
* 2026-09-18) and SQLite reports a bare `SQLITE_CANTOPEN`. Where the error IS
|
|
317
|
+
* available — VFS instantiation — `createVfsInstance` tests it directly and
|
|
318
|
+
* needs no declaration.
|
|
319
|
+
*
|
|
320
|
+
* NOT declared for `OPFSAdaptiveVFS` and `OPFSWriteAheadVFS`, which ask for
|
|
321
|
+
* `readwrite-unsafe` and fall back to an exclusive handle only on an engine
|
|
322
|
+
* that lacks it. That combination is real but out of reach: Firefox releases
|
|
323
|
+
* a dead worker's handle in 1-6 ms (HANDLE-ORPHAN), a window nothing loses.
|
|
324
|
+
*/
|
|
325
|
+
readonly exclusiveFileHandle: boolean;
|
|
326
|
+
/**
|
|
327
|
+
* Platform features without which this VFS cannot work at all.
|
|
328
|
+
*
|
|
329
|
+
* `readwrite-unsafe` is the one that bites: WebIDL ignores the unknown
|
|
330
|
+
* dictionary member on engines that do not implement it, so the handle
|
|
331
|
+
* silently opens exclusive, and a second connection then waits or fails
|
|
332
|
+
* depending on the VFS — see `degradesWithout` and `singleConnectionWithout`.
|
|
333
|
+
* Declaring it is what lets the conformance suite probe for it and skip,
|
|
334
|
+
* instead of leaving it to surface as a 60-second timeout.
|
|
335
|
+
*/
|
|
336
|
+
readonly requires: readonly PlatformFeature[];
|
|
337
|
+
/**
|
|
338
|
+
* Platform features this VFS uses when present and works without, at a cost.
|
|
339
|
+
*
|
|
340
|
+
* `OPFSAdaptiveVFS` is the case this field exists for. Without
|
|
341
|
+
* `readwrite-unsafe` it rotates a single exclusive access handle between
|
|
342
|
+
* connections instead of holding one each. That works — Firefox is the engine
|
|
343
|
+
* the browser suite exercises it on — but a connection in a long
|
|
344
|
+
* uninterruptible statement holds the handle, and every other connection to
|
|
345
|
+
* the database, in another client or tab, waits for it. Within one client it
|
|
346
|
+
* runs a single worker there: see `singleConnectionWithout`.
|
|
347
|
+
*
|
|
348
|
+
* Without this distinction, a support table derived from browser specs would
|
|
349
|
+
* mark that VFS broken everywhere outside Chromium, when it merely degrades.
|
|
350
|
+
*/
|
|
351
|
+
readonly degradesWithout: readonly PlatformFeature[];
|
|
352
|
+
/**
|
|
353
|
+
* Platform features without which a pool of more than one worker buys this
|
|
354
|
+
* VFS nothing, so it runs on one (spec 2026-09-13, §3 and §10). Either the
|
|
355
|
+
* VFS holds its database file exclusively for a connection's whole life and
|
|
356
|
+
* a second worker cannot open at all (`OPFSWriteAheadVFS`), or it rotates one
|
|
357
|
+
* exclusive access handle between connections and a second worker only waits
|
|
358
|
+
* its turn (`OPFSAdaptiveVFS` — measured 2026-09-14 on Firefox: a pool of one
|
|
359
|
+
* was faster at startup and on bursts of reads, and equal everywhere else).
|
|
360
|
+
* The pool's surplus workers probe the feature before loading anything and
|
|
361
|
+
* decline (`src/worker/probes.ts`); every feature listed needs a probe there.
|
|
362
|
+
*/
|
|
363
|
+
readonly singleConnectionWithout: readonly PlatformFeature[];
|
|
364
|
+
/**
|
|
365
|
+
* Files this VFS keeps beside the database, by suffix, beyond the three every
|
|
366
|
+
* layout may have (`''`, `-journal`, `-wal`). `deleteDatabase` removes them
|
|
367
|
+
* with the rest; a file missing from this list outlives its database.
|
|
368
|
+
*
|
|
369
|
+
* `OPFSWriteAheadVFS` keeps its write-ahead log in two files of its own,
|
|
370
|
+
* `-wa0` and `-wa1` (wa-sqlite's `#getWriteAheadNameFromDbName`) — measured
|
|
371
|
+
* left behind by every deletion until 2026-09-14.
|
|
372
|
+
*/
|
|
373
|
+
readonly extraFileSuffixes: readonly string[];
|
|
374
|
+
/**
|
|
375
|
+
* Whether every statement on this VFS must hand its worker back to the event
|
|
376
|
+
* loop while it runs, abortable or not.
|
|
377
|
+
*
|
|
378
|
+
* `IDBBatchAtomicVFS` is why it exists. Its `jLock` opens a readwrite
|
|
379
|
+
* IndexedDB transaction on reaching SHARED, and IndexedDB commits a
|
|
380
|
+
* transaction only once its thread returns to the event loop. A worker inside
|
|
381
|
+
* one long statement never did, so every other connection's read queued
|
|
382
|
+
* behind it until the statement ended — measured 2026-09-14 on both engines
|
|
383
|
+
* (`mem:measurements`, IDB-SIGNAL). The worker then runs its progress handler
|
|
384
|
+
* on every statement, a task turn every `PROGRESS_OPS` VM ops, which measured
|
|
385
|
+
* no cost. The `sync` build cannot yield and ignores it.
|
|
386
|
+
*/
|
|
387
|
+
readonly yieldsDuringStatements: boolean;
|
|
388
|
+
/**
|
|
389
|
+
* PRAGMAs this library applies on open for this VFS.
|
|
390
|
+
*
|
|
391
|
+
* Merged UNDER the consumer's `pragmas`, so any key they set wins and they
|
|
392
|
+
* never lose a default by setting an unrelated one — `foreign_keys` is the
|
|
393
|
+
* common case, and replacing rather than merging would silently disable
|
|
394
|
+
* everything below it.
|
|
395
|
+
*
|
|
396
|
+
* The bar is deliberately high, and almost nothing clears it: **more
|
|
397
|
+
* performance without less reliability, sourced rather than guessed.** Three
|
|
398
|
+
* things were weighed and rejected. `journal_mode=wal` universally, because
|
|
399
|
+
* no VFS here implements `xShmMap` and upstream gives write-ahead logging to
|
|
400
|
+
* `OPFSWriteAheadVFS` alone, inside the VFS and unreachable by pragma.
|
|
401
|
+
* `synchronous=normal`, because relaxing durability spends the consumer's
|
|
402
|
+
* data, not their milliseconds. And `cache_size`, because raising it changes
|
|
403
|
+
* a mode without a measurable gain — Firefox showed none at all, and the
|
|
404
|
+
* heap it can then reach is never given back (measured 2026-09-02).
|
|
405
|
+
*/
|
|
406
|
+
readonly defaultPragmas: Readonly<Record<string, string>>;
|
|
407
|
+
/**
|
|
408
|
+
* Whether this VFS enforces an origin-wide exclusive connection lock for the
|
|
409
|
+
* client's lifetime.
|
|
410
|
+
*
|
|
411
|
+
* When `true`, `createSQLiteClient` acquires a `bsq:conn:…` Web Lock on first
|
|
412
|
+
* use. A second client that attempts to open the same database receives `DATABASE_IN_USE`
|
|
413
|
+
* immediately on its first query instead of silently reading a frozen, broken
|
|
414
|
+
* view. This field is the only thing standing between a consumer and an
|
|
415
|
+
* unfalsifiable silent failure — `SELECT 1` and even
|
|
416
|
+
* `SELECT count(*) FROM sqlite_master` pass on a broken second client.
|
|
417
|
+
*
|
|
418
|
+
* `true` only for `AccessHandlePoolVFS`, whose OPFS access-handle pool is not
|
|
419
|
+
* sharable across connections (measured AHP-2TAB, 2026-09-01).
|
|
420
|
+
* `false` for `IDBMirrorVFS` — despite `multiConnection: false` — because two
|
|
421
|
+
* clients on that VFS DO share data over its origin-wide `BroadcastChannel`
|
|
422
|
+
* (measured 2026-09-01, 3/3 both engines). `multiConnection: false` there marks
|
|
423
|
+
* concurrent-writer unsafety, not isolation.
|
|
424
|
+
* `false` for the memory VFS, which are isolated by construction and have
|
|
425
|
+
* nothing to exclude.
|
|
426
|
+
*
|
|
427
|
+
* `VFS_CAPABILITIES` is the single source of truth the client guard, the
|
|
428
|
+
* conformance suite, the VFS.md generator and the benchmark page all read.
|
|
429
|
+
* The gate is by this declaration, not by VFS name.
|
|
430
|
+
*/
|
|
431
|
+
readonly exclusiveConnection: boolean;
|
|
432
|
+
/**
|
|
433
|
+
* Platform features without which this VFS holds its database file
|
|
434
|
+
* exclusively for a connection's whole life, across the origin — so the
|
|
435
|
+
* client takes `bsq:conn` exclusively, as for `exclusiveConnection`, and a
|
|
436
|
+
* second client gets `DATABASE_IN_USE` (spec 2026-09-15).
|
|
437
|
+
*
|
|
438
|
+
* `OPFSWriteAheadVFS` without `readwrite-unsafe`: upstream's VFS requires the
|
|
439
|
+
* mode and keeps its three access handles for the connection's life, so
|
|
440
|
+
* nothing else can open the file — every query of a second client failed
|
|
441
|
+
* with WORKER_CRASHED on Firefox, 20/20 per shape (2026-09-15).
|
|
442
|
+
*
|
|
443
|
+
* The page cannot probe these features, so worker 0 probes them before
|
|
444
|
+
* opening (`src/worker/probes.ts`): every feature listed needs a probe there,
|
|
445
|
+
* and must also be in `singleConnectionWithout`, whose surplus workers
|
|
446
|
+
* decline before they touch the file.
|
|
447
|
+
*/
|
|
448
|
+
readonly exclusiveConnectionWithout: readonly PlatformFeature[];
|
|
449
|
+
};
|
|
450
|
+
/**
|
|
451
|
+
* The single source of truth for VFS selection. `SQLiteVFS` is derived from its
|
|
452
|
+
* keys, `worker/worker.ts` must supply a loader for every key, the guards in
|
|
453
|
+
* `client.ts` read it, the conformance suite gates its scenarios on it, and the
|
|
454
|
+
* VFS.md table is generated from it. Nothing may hold a second copy.
|
|
455
|
+
*
|
|
456
|
+
* Build order is a decision per VFS, not a rule: `sync` is both the fastest and
|
|
457
|
+
* the most portable build, so it leads wherever supported; `OPFSAdaptiveVFS`
|
|
458
|
+
* cannot use it and leads with `async` because `jspi` is Chromium-only.
|
|
459
|
+
*
|
|
460
|
+
* Every declared build combination is verified by running it against the pinned
|
|
461
|
+
* wa-sqlite v1.1.2, never copied from upstream's table.
|
|
462
|
+
*/
|
|
463
|
+
export declare const VFS_CAPABILITIES: {
|
|
464
|
+
readonly OPFSWriteAheadVFS: {
|
|
465
|
+
readonly builds: readonly ["sync", "async", "jspi"];
|
|
466
|
+
readonly maxPoolSize: null;
|
|
467
|
+
readonly poolLimitReason: null;
|
|
468
|
+
readonly multiConnection: true;
|
|
469
|
+
readonly persistent: true;
|
|
470
|
+
readonly memoryModel: 'page-cache';
|
|
471
|
+
readonly storage: 'opfs';
|
|
472
|
+
readonly layout: 'opfs-path';
|
|
473
|
+
readonly exclusiveFileHandle: false;
|
|
474
|
+
readonly requires: readonly ["opfs"];
|
|
475
|
+
readonly degradesWithout: readonly ["readwrite-unsafe"];
|
|
476
|
+
readonly singleConnectionWithout: readonly ["readwrite-unsafe"];
|
|
477
|
+
readonly extraFileSuffixes: readonly ["-wa0", "-wa1"];
|
|
478
|
+
readonly yieldsDuringStatements: false;
|
|
479
|
+
readonly exclusiveConnection: false;
|
|
480
|
+
readonly exclusiveConnectionWithout: readonly ["readwrite-unsafe"];
|
|
481
|
+
readonly defaultPragmas: {};
|
|
482
|
+
};
|
|
483
|
+
readonly OPFSAdaptiveVFS: {
|
|
484
|
+
readonly builds: readonly ["async", "jspi"];
|
|
485
|
+
readonly maxPoolSize: null;
|
|
486
|
+
readonly poolLimitReason: null;
|
|
487
|
+
readonly multiConnection: true;
|
|
488
|
+
readonly persistent: true;
|
|
489
|
+
readonly memoryModel: 'page-cache';
|
|
490
|
+
readonly storage: 'opfs';
|
|
491
|
+
readonly layout: 'opfs-path';
|
|
492
|
+
readonly exclusiveFileHandle: false;
|
|
493
|
+
readonly requires: readonly ["opfs"];
|
|
494
|
+
readonly degradesWithout: readonly ["readwrite-unsafe"];
|
|
495
|
+
readonly singleConnectionWithout: readonly ["readwrite-unsafe"];
|
|
496
|
+
readonly extraFileSuffixes: readonly [];
|
|
497
|
+
readonly yieldsDuringStatements: false;
|
|
498
|
+
readonly exclusiveConnection: false;
|
|
499
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
500
|
+
readonly defaultPragmas: {};
|
|
501
|
+
};
|
|
502
|
+
readonly OPFSCoopSyncVFS: {
|
|
503
|
+
readonly builds: readonly ["sync", "async", "jspi"];
|
|
504
|
+
readonly maxPoolSize: 1;
|
|
505
|
+
readonly poolLimitReason: 'it rotates one exclusive access handle between connections, so another worker only waits its turn';
|
|
506
|
+
readonly multiConnection: true;
|
|
507
|
+
readonly persistent: true;
|
|
508
|
+
readonly memoryModel: 'page-cache';
|
|
509
|
+
readonly storage: 'opfs';
|
|
510
|
+
readonly layout: 'opfs-path';
|
|
511
|
+
readonly exclusiveFileHandle: true;
|
|
512
|
+
readonly requires: readonly ["opfs"];
|
|
513
|
+
readonly degradesWithout: readonly [];
|
|
514
|
+
readonly singleConnectionWithout: readonly [];
|
|
515
|
+
readonly extraFileSuffixes: readonly [];
|
|
516
|
+
readonly yieldsDuringStatements: false;
|
|
517
|
+
readonly exclusiveConnection: false;
|
|
518
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
519
|
+
readonly defaultPragmas: {};
|
|
520
|
+
};
|
|
521
|
+
readonly AccessHandlePoolVFS: {
|
|
522
|
+
readonly builds: readonly ["sync", "async", "jspi"];
|
|
523
|
+
readonly maxPoolSize: 1;
|
|
524
|
+
readonly poolLimitReason: 'it cannot share access handles between connections';
|
|
525
|
+
readonly multiConnection: false;
|
|
526
|
+
readonly persistent: true;
|
|
527
|
+
readonly memoryModel: 'page-cache';
|
|
528
|
+
readonly storage: 'opfs';
|
|
529
|
+
readonly layout: 'opfs-pool';
|
|
530
|
+
readonly exclusiveFileHandle: true;
|
|
531
|
+
readonly requires: readonly ["opfs"];
|
|
532
|
+
readonly degradesWithout: readonly [];
|
|
533
|
+
readonly singleConnectionWithout: readonly [];
|
|
534
|
+
readonly extraFileSuffixes: readonly [];
|
|
535
|
+
readonly yieldsDuringStatements: false;
|
|
536
|
+
readonly exclusiveConnection: true;
|
|
537
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
538
|
+
readonly defaultPragmas: {
|
|
539
|
+
readonly locking_mode: 'exclusive';
|
|
540
|
+
readonly journal_mode: 'wal';
|
|
541
|
+
};
|
|
542
|
+
};
|
|
543
|
+
readonly IDBBatchAtomicVFS: {
|
|
544
|
+
readonly builds: readonly ["async", "jspi"];
|
|
545
|
+
readonly maxPoolSize: null;
|
|
546
|
+
readonly poolLimitReason: null;
|
|
547
|
+
readonly multiConnection: true;
|
|
548
|
+
readonly persistent: true;
|
|
549
|
+
readonly memoryModel: 'page-cache';
|
|
550
|
+
readonly storage: 'indexeddb';
|
|
551
|
+
readonly layout: 'idb-store';
|
|
552
|
+
readonly exclusiveFileHandle: false;
|
|
553
|
+
readonly requires: readonly [];
|
|
554
|
+
readonly degradesWithout: readonly [];
|
|
555
|
+
readonly singleConnectionWithout: readonly [];
|
|
556
|
+
readonly extraFileSuffixes: readonly [];
|
|
557
|
+
readonly yieldsDuringStatements: true;
|
|
558
|
+
readonly exclusiveConnection: false;
|
|
559
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
560
|
+
readonly defaultPragmas: {};
|
|
561
|
+
};
|
|
562
|
+
readonly IDBMirrorVFS: {
|
|
563
|
+
readonly builds: readonly ["async", "jspi"];
|
|
564
|
+
readonly maxPoolSize: 1;
|
|
565
|
+
readonly poolLimitReason: 'its pages are mirrored per worker and commits propagate asynchronously, so a larger pool reads stale data or fails outright';
|
|
566
|
+
readonly multiConnection: false;
|
|
567
|
+
readonly persistent: true;
|
|
568
|
+
readonly memoryModel: 'whole-database';
|
|
569
|
+
readonly storage: 'indexeddb';
|
|
570
|
+
readonly layout: 'idb-store';
|
|
571
|
+
readonly exclusiveFileHandle: false;
|
|
572
|
+
readonly requires: readonly [];
|
|
573
|
+
readonly degradesWithout: readonly [];
|
|
574
|
+
readonly singleConnectionWithout: readonly [];
|
|
575
|
+
readonly extraFileSuffixes: readonly [];
|
|
576
|
+
readonly yieldsDuringStatements: false;
|
|
577
|
+
readonly exclusiveConnection: false;
|
|
578
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
579
|
+
readonly defaultPragmas: {};
|
|
580
|
+
};
|
|
581
|
+
readonly OPFSAnyContextVFS: {
|
|
582
|
+
readonly builds: readonly ["async", "jspi"];
|
|
583
|
+
readonly maxPoolSize: null;
|
|
584
|
+
readonly poolLimitReason: null;
|
|
585
|
+
readonly multiConnection: true;
|
|
586
|
+
readonly persistent: true;
|
|
587
|
+
readonly memoryModel: 'page-cache';
|
|
588
|
+
readonly storage: 'opfs';
|
|
589
|
+
readonly layout: 'opfs-path';
|
|
590
|
+
readonly exclusiveFileHandle: false;
|
|
591
|
+
readonly requires: readonly ["opfs", "writable-stream"];
|
|
592
|
+
readonly degradesWithout: readonly [];
|
|
593
|
+
readonly singleConnectionWithout: readonly [];
|
|
594
|
+
readonly extraFileSuffixes: readonly [];
|
|
595
|
+
readonly yieldsDuringStatements: false;
|
|
596
|
+
readonly exclusiveConnection: false;
|
|
597
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
598
|
+
readonly defaultPragmas: {};
|
|
599
|
+
};
|
|
600
|
+
readonly MemoryVFS: {
|
|
601
|
+
readonly builds: readonly ["sync", "async", "jspi"];
|
|
602
|
+
readonly maxPoolSize: 1;
|
|
603
|
+
readonly poolLimitReason: 'its pages live in the worker that opened them, so a larger pool would open independent databases that diverge silently';
|
|
604
|
+
readonly multiConnection: false;
|
|
605
|
+
readonly persistent: false;
|
|
606
|
+
readonly memoryModel: 'whole-database';
|
|
607
|
+
readonly storage: 'memory';
|
|
608
|
+
readonly layout: 'memory';
|
|
609
|
+
readonly exclusiveFileHandle: false;
|
|
610
|
+
readonly requires: readonly [];
|
|
611
|
+
readonly degradesWithout: readonly [];
|
|
612
|
+
readonly singleConnectionWithout: readonly [];
|
|
613
|
+
readonly extraFileSuffixes: readonly [];
|
|
614
|
+
readonly yieldsDuringStatements: false;
|
|
615
|
+
readonly exclusiveConnection: false;
|
|
616
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
617
|
+
readonly defaultPragmas: {};
|
|
618
|
+
};
|
|
619
|
+
readonly MemoryAsyncVFS: {
|
|
620
|
+
readonly builds: readonly ["async", "jspi"];
|
|
621
|
+
readonly maxPoolSize: 1;
|
|
622
|
+
readonly poolLimitReason: 'its pages live in the worker that opened them, so a larger pool would open independent databases that diverge silently';
|
|
623
|
+
readonly multiConnection: false;
|
|
624
|
+
readonly persistent: false;
|
|
625
|
+
readonly memoryModel: 'whole-database';
|
|
626
|
+
readonly storage: 'memory';
|
|
627
|
+
readonly layout: 'memory';
|
|
628
|
+
readonly exclusiveFileHandle: false;
|
|
629
|
+
readonly requires: readonly [];
|
|
630
|
+
readonly degradesWithout: readonly [];
|
|
631
|
+
readonly singleConnectionWithout: readonly [];
|
|
632
|
+
readonly extraFileSuffixes: readonly [];
|
|
633
|
+
readonly yieldsDuringStatements: false;
|
|
634
|
+
readonly exclusiveConnection: false;
|
|
635
|
+
readonly exclusiveConnectionWithout: readonly [];
|
|
636
|
+
readonly defaultPragmas: {};
|
|
637
|
+
};
|
|
638
|
+
};
|
|
639
|
+
export type SQLiteVFS = keyof typeof VFS_CAPABILITIES;
|
|
640
|
+
/** The build used when the caller does not name one. */
|
|
641
|
+
export declare const defaultBuildFor: (vfs: SQLiteVFS) => SQLiteBuild;
|
|
642
|
+
export {};
|