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.
Files changed (47) hide show
  1. package/NOTICE +56 -0
  2. package/README.md +112 -104
  3. package/dist/LICENSE +21 -0
  4. package/dist/NOTICE +56 -0
  5. package/dist/abandon.d.ts +77 -0
  6. package/dist/api.d.ts +426 -0
  7. package/dist/bulk.d.ts +57 -0
  8. package/dist/capabilities.d.ts +23 -0
  9. package/dist/client.d.ts +221 -0
  10. package/dist/credits.d.ts +31 -0
  11. package/dist/{esm/src/debug.d.ts → debug.d.ts} +21 -10
  12. package/dist/delete.d.ts +48 -0
  13. package/dist/epochs.d.ts +85 -0
  14. package/dist/errors.d.ts +76 -0
  15. package/dist/index.d.ts +8 -0
  16. package/dist/index.js +5 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/inspect.d.ts +96 -0
  19. package/dist/locks.d.ts +172 -0
  20. package/dist/logger.d.ts +24 -0
  21. package/dist/pool.d.ts +191 -0
  22. package/dist/queries.d.ts +65 -0
  23. package/dist/scheduler.d.ts +145 -0
  24. package/dist/sqlite-codes.d.ts +154 -0
  25. package/dist/supervisor.d.ts +17 -0
  26. package/dist/transaction.d.ts +61 -0
  27. package/dist/types.d.ts +642 -0
  28. package/dist/utils.d.ts +156 -0
  29. package/dist/worker/cloneable.d.ts +25 -0
  30. package/dist/worker/probes.d.ts +26 -0
  31. package/dist/worker/sqlite-code.d.ts +9 -0
  32. package/dist/worker/statement-cache.d.ts +36 -0
  33. package/dist/worker/wa-sqlite-async.wasm +0 -0
  34. package/dist/worker/wa-sqlite-jspi.wasm +0 -0
  35. package/dist/worker/wa-sqlite.wasm +0 -0
  36. package/dist/worker/worker.js +11 -0
  37. package/dist/worker/worker.js.map +1 -0
  38. package/package.json +46 -22
  39. package/dist/esm/index.js +0 -424
  40. package/dist/esm/rslib.config.d.ts +0 -2
  41. package/dist/esm/rstest.config.d.ts +0 -2
  42. package/dist/esm/src/client.d.ts +0 -332
  43. package/dist/esm/src/index.d.ts +0 -1
  44. package/dist/esm/src/orchestrator.d.ts +0 -87
  45. package/dist/esm/src/types.d.ts +0 -83
  46. package/dist/esm/src/utils.d.ts +0 -6
  47. /package/dist/{esm/src → worker}/worker.d.ts +0 -0
package/dist/api.d.ts ADDED
@@ -0,0 +1,426 @@
1
+ /**
2
+ * The public type layer. Everything here is part of the package's API, which is
3
+ * why `index.ts` re-exports this module wholesale: a name list is what let
4
+ * `SQLiteQueryOptions` and `TransactionDB` end up in the shipped `.d.ts`
5
+ * without a consumer being able to name either.
6
+ *
7
+ * `types.ts` keeps the wire protocol and the VFS capability table.
8
+ * `CreateSQLiteClientOptions` stays in `client.ts`, beside the constructor that
9
+ * validates it: this module is the querying surface and its satellites — what a
10
+ * caller passes to a query, and what comes back.
11
+ */
12
+ import type { ClientDebugState } from './debug';
13
+ import type { ClientInspection } from './inspect';
14
+ import type { SQLiteBuild, SQLiteVFS } from './types';
15
+ /**
16
+ * Marks an options type as carrying an abort signal.
17
+ *
18
+ * The name is the point. `options?: Interruptible<…>` says at the signature
19
+ * that the method can be abandoned, where a bare alias would make a reader open
20
+ * the type to find out. Every abortable option type in this file is built from
21
+ * it, so `signal` is documented once and cannot drift between them.
22
+ *
23
+ * Not the bare `Abortable` that `@types/node` uses: this reads as an options
24
+ * bag augmented with one member — `PropsWithChildren`, not an adjective — which
25
+ * is what it is both wrapped, `Interruptible<{ chunkSize?: number }>`, and
26
+ * alone, `options?: Interruptible`.
27
+ *
28
+ * `T = unknown` rather than `Record<string, never>`: intersecting with the
29
+ * latter collapses `signal` to `never` and makes it unassignable.
30
+ */
31
+ export type Interruptible<T = unknown> = T & {
32
+ /**
33
+ * Aborts the work. Rejects with `signal.reason` — your reason, not an error
34
+ * of this library's making.
35
+ *
36
+ * On `bulkWrite()` and `output()` the abort lands **between** batches, never
37
+ * inside one: a multi-row INSERT is statement-atomic, so stopping inside a
38
+ * batch would either waste it whole or let it commit whole. An aborted
39
+ * `bulkWrite()` leaves the batches already written in place; an aborted
40
+ * `output()` is observationally a no-op, dropping its staging table and
41
+ * touching nothing else.
42
+ *
43
+ * Whether it also stops the statement SQLite is already executing depends on
44
+ * your build and your page: see the Interrupting a call section of API.md.
45
+ */
46
+ signal?: AbortSignal | undefined;
47
+ /**
48
+ * Milliseconds from the call within which it must finish, after which it is
49
+ * aborted and rejected with `OPERATION_TIMEOUT`. It is wall clock: time your
50
+ * own code spends — between two chunks of a `stream()`, inside a
51
+ * `transaction()` callback, between two `enqueue()` calls — counts against
52
+ * it, as does time spent waiting for a pool worker or for another tab's
53
+ * write lock.
54
+ *
55
+ * It aborts through the same path a `signal` does, so the same limit applies:
56
+ * see the Interrupting a call section of API.md.
57
+ */
58
+ timeout?: number | undefined;
59
+ };
60
+ /** Options every query method accepts. */
61
+ export type SQLiteQueryOptions = Interruptible;
62
+ /**
63
+ * Options for the methods that cross the worker boundary in chunks.
64
+ *
65
+ * `chunkSize` is not only a transport detail: back-pressure grants credits per
66
+ * chunk with a window of 2, so the worker may run up to `2 × chunkSize` rows
67
+ * ahead of the consumer. On `stream()` that is the only lever on how many rows
68
+ * are in flight.
69
+ */
70
+ export type SQLiteChunkOptions = Interruptible<{
71
+ /** Rows per chunk. Defaults to 500. */
72
+ chunkSize?: number;
73
+ }>;
74
+ export type SQLiteWriteResult<T extends Record<string, unknown>> = {
75
+ result: T[];
76
+ affected: number;
77
+ };
78
+ /**
79
+ * Options for `transaction()`.
80
+ *
81
+ * `signal` abandons the transaction at every stage: while it waits for a
82
+ * worker, once it holds one, and from inside the callback — every statement
83
+ * issued through `tx` inherits it, and a statement that carries a signal of its
84
+ * own can be aborted by either. An abandoned transaction rolls back and rejects
85
+ * with `signal.reason`; it never commits, not even when the callback catches
86
+ * its statement's rejection and returns normally.
87
+ *
88
+ * The callback itself cannot be interrupted — it is your code — but it can no
89
+ * longer reach the database: every statement it issues after the abort rejects
90
+ * without a worker round trip.
91
+ *
92
+ * One window is not abortable: `BEGIN`, `COMMIT` and `ROLLBACK` never carry the
93
+ * signal. Their completion is what decides whether a rollback is owed, so a
94
+ * client-side abort of one of them would risk leaving the transaction open on
95
+ * the connection. The abort lands as soon as such a statement settles.
96
+ *
97
+ * That window is short on a VFS holding one access handle per connection, and
98
+ * it is not on a VFS rotating a single exclusive one: there such a statement
99
+ * waits for whichever client holds the file, and your signal cannot shorten
100
+ * that wait. See the reduced mode described in VFS.md.
101
+ */
102
+ export type SQLiteTransactionOptions = Interruptible<{
103
+ /** Rejects write statements with `READ_ONLY_TRANSACTION`. Defaults to false. */
104
+ readOnly?: boolean;
105
+ /** Commits when the callback resolves. Defaults to true. */
106
+ autoCommit?: boolean;
107
+ }>;
108
+ /** Column definitions for `output()`. */
109
+ export type Schema = Record<string, string | {
110
+ type: string;
111
+ generated?: string;
112
+ required?: boolean;
113
+ unique?: boolean;
114
+ }>;
115
+ export type Index<SCHEMA extends Schema> = keyof SCHEMA | (keyof SCHEMA)[] | ({
116
+ unique?: boolean;
117
+ } & ({
118
+ column: keyof SCHEMA;
119
+ } | {
120
+ columns: (keyof SCHEMA)[];
121
+ }));
122
+ export type SQLiteOutputOptions<SCHEMA extends Schema> = Interruptible<{
123
+ indexes?: Index<SCHEMA>[];
124
+ /** Rows queued for writing above which `enqueue()` defers. See `SQLiteBulkWriteOptions`. */
125
+ queueSize?: number | undefined;
126
+ }>;
127
+ /**
128
+ * Options `bulkWrite()` accepts.
129
+ *
130
+ * `queueSize` bounds how far the producer may run ahead of the database. Rows
131
+ * are handed over in batches of at most 32 766 bound values; a batch that has
132
+ * been handed over but not yet written is held in memory until it is, and
133
+ * nothing caps how many of those accumulate unless you await `enqueue()`.
134
+ *
135
+ * It is a number of rows, and nothing else: it says nothing about what those
136
+ * rows weigh. A table whose columns carry blobs holds far more per row than a
137
+ * table of integers, and only you know which one you are loading — set the
138
+ * value yourself when the rows are heavy.
139
+ *
140
+ * The default is two batches' worth, derived from the column count: about
141
+ * 13 100 rows for 5 columns, 2 180 for 30. A value smaller than one batch is legal
142
+ * and means one INSERT in flight, the least the batching allows. Anything below
143
+ * 1 is raised to 1: a batch always holds at least one row, so a lower cap could
144
+ * never be satisfied.
145
+ */
146
+ export type SQLiteBulkWriteOptions = Interruptible<{
147
+ /** Rows queued for writing above which `enqueue()` defers. */
148
+ queueSize?: number | undefined;
149
+ }>;
150
+ /** A row for `output()`: generated columns are computed, never supplied. */
151
+ export type SQLiteOutputRow<SCHEMA extends Schema> = {
152
+ [K in keyof SCHEMA as SCHEMA[K] extends {
153
+ generated: string;
154
+ } ? never : K]: any;
155
+ };
156
+ /**
157
+ * Buffers a row, flushing automatically when the buffer fills.
158
+ *
159
+ * Awaiting the returned promise applies back-pressure: it is already resolved
160
+ * while fewer than `queueSize` rows are queued for writing, and resolves once
161
+ * a batch settles when they are not. Ignoring it is legal, and leaves the load
162
+ * unbounded exactly as it was before the option existed — the bound is an
163
+ * offer, not a guarantee.
164
+ *
165
+ * It never rejects. A failed batch surfaces at the next `enqueue()`, which
166
+ * throws, and at `close()`, which rejects.
167
+ */
168
+ type EnqueueRow<ROW> = (data: ROW) => Promise<void>;
169
+ export type SQLiteBulkWriter<KEYS extends string> = {
170
+ enqueue: EnqueueRow<Record<KEYS, any>>;
171
+ /** Flushes what remains and resolves with the total affected row count. */
172
+ close: () => Promise<number>;
173
+ };
174
+ export type SQLiteOutputWriter<SCHEMA extends Schema> = {
175
+ enqueue: EnqueueRow<SQLiteOutputRow<SCHEMA>>;
176
+ close: () => Promise<number>;
177
+ };
178
+ /**
179
+ * The querying surface, shared by the client and by a transaction.
180
+ *
181
+ * It exists so the two cannot drift: they had already done so, one taking
182
+ * `any[]` where the other took `unknown[]`, and two different option types on
183
+ * `chunk`. A method added to one is now added to both by construction.
184
+ *
185
+ * @remarks
186
+ * **The row type parameter is a claim, not a check.** `read<T>`, `first<T>`,
187
+ * `chunk<T>` and `stream<T>` cast SQLite's output to `T` and validate nothing:
188
+ * a column that is missing, renamed or of another type reaches you typed as if
189
+ * it were not. SQLite is dynamically typed and a query's shape is only known at
190
+ * runtime, so the alternative would be a schema the caller declares twice.
191
+ * Validate at the boundary if you need the guarantee — this is `as`, not a
192
+ * parser.
193
+ */
194
+ export type SQLiteQueryAPI = {
195
+ /**
196
+ * Executes a SELECT query and returns all matching rows as an array.
197
+ *
198
+ * Read queries are dispatched to any available worker in the pool,
199
+ * enabling concurrent execution across multiple readers.
200
+ *
201
+ * @param sql - SQL query string. Must be a SELECT (or equivalent read) statement.
202
+ * @param params - Positional parameters bound to `?` placeholders.
203
+ * @param options - Optional query options (`chunkSize`, `signal`).
204
+ * @returns Promise resolving to an array of typed rows (`T[]`). Returns `[]` for empty results.
205
+ */
206
+ read: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteChunkOptions) => Promise<T[]>;
207
+ /**
208
+ * Executes a DML or DDL statement (INSERT, UPDATE, DELETE, CREATE, DROP, etc.)
209
+ * and returns both any result rows and the number of affected rows.
210
+ *
211
+ * Write queries are serialized through a single dedicated writer worker.
212
+ * Concurrent writes queue behind each other — only one write executes at a time.
213
+ *
214
+ * @param sql - SQL statement. Any statement not classified as a read by `isReadQuery`.
215
+ * @param params - Positional parameters bound to `?` placeholders.
216
+ * @param options - Optional query options (`signal`).
217
+ * @returns Promise resolving to `{ result: T[], affected: number }` where
218
+ * `affected` is the SQLite `changes()` count for the statement.
219
+ */
220
+ write: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteQueryOptions) => Promise<SQLiteWriteResult<T>>;
221
+ /**
222
+ * Executes a query and yields result rows in chunks via an async generator.
223
+ * Memory-efficient for large result sets — rows are not buffered in full.
224
+ *
225
+ * @remarks
226
+ * **Worker held for full generator lifetime.** A pool worker is acquired when
227
+ * the generator is created and released only when the generator is fully
228
+ * exhausted or the caller uses `break`. Failing to exhaust the generator
229
+ * starves the pool. Always use `for await...of` to completion or `break` to exit.
230
+ *
231
+ * **`NOT_A_READ_QUERY` timing.** Because `chunk()` is an async generator, its
232
+ * body does not run until the first `next()` call. Passing a write statement
233
+ * does not throw at the call site — the `SQLiteError` arrives on the first
234
+ * `await gen.next()` (or the first iteration of `for await...of`).
235
+ *
236
+ * @param sql - SQL query string. Must be a SELECT (or equivalent read) statement.
237
+ * @param params - Positional parameters bound to `?` placeholders.
238
+ * @param options - Optional options including `chunkSize` (default `500`),
239
+ * `signal` (AbortSignal to cancel).
240
+ * @returns AsyncGenerator yielding `T[]` chunks of at most `chunkSize` rows.
241
+ */
242
+ chunk: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteChunkOptions) => AsyncGenerator<T[]>;
243
+ /**
244
+ * Executes a query and yields individual result rows via an async generator.
245
+ * Flattens chunk boundaries — each iteration yields one `T` row, not a chunk.
246
+ * Use `chunk()` when you need the rows grouped by chunk.
247
+ *
248
+ * @remarks
249
+ * **`NOT_A_READ_QUERY` timing.** Because `stream()` is an async generator, its
250
+ * body does not run until the first `next()` call. Passing a write statement
251
+ * does not throw at the call site — the `SQLiteError` arrives on the first
252
+ * `await gen.next()` (or the first iteration of `for await...of`).
253
+ *
254
+ * @param sql - SQL query string. Must be a SELECT (or equivalent read) statement.
255
+ * @param params - Positional parameters bound to `?` placeholders.
256
+ * @param options - Optional query options (`chunkSize`, `signal`).
257
+ * @returns AsyncGenerator yielding individual rows of type `T`.
258
+ */
259
+ stream: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteChunkOptions) => AsyncGenerator<T>;
260
+ /**
261
+ * Executes a query and returns the first row, or `undefined` if no rows match.
262
+ *
263
+ * Internally uses `chunkSize: 1` and asks the worker to stop after the first
264
+ * row. Because the worker runs in a separate thread it may race ahead between
265
+ * the break and the stop signal, so early termination is best-effort on small
266
+ * result sets. A hard bound will arrive with back-pressure in a future wave.
267
+ *
268
+ * @param sql - SQL query string.
269
+ * @param params - Positional parameters bound to `?` placeholders.
270
+ * @param options - Optional query options (`signal`).
271
+ * @returns Promise resolving to the first row as `T`, or `undefined` if no rows.
272
+ */
273
+ first: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteQueryOptions) => Promise<T | undefined>;
274
+ /**
275
+ * Creates a buffered bulk-insert utility that batches rows to stay within
276
+ * SQLite's variable limit (`SQLITE_MAX_VARS = 32766`).
277
+ *
278
+ * Call `enqueue()` for each row to insert, then `close()` to flush the
279
+ * remaining buffer and await completion.
280
+ *
281
+ * @remarks
282
+ * **`bulkWrite()` is not atomic:** batches are committed as they flush, so a
283
+ * failure leaves the rows already written in place. Call it on a `tx` if you
284
+ * need all-or-nothing.
285
+ *
286
+ * That commit per batch is also what it costs: measured at ~3.4 ms
287
+ * (synchronous build) and ~5.3 ms (Asyncify build) per commit on Chromium.
288
+ * A load wrapped in `transaction()` commits once and buys the rest back.
289
+ *
290
+ * @param table - Target table name.
291
+ * @param keys - Column names for the INSERT statement.
292
+ * @param options - `signal` aborts the load between batches. `close()` then
293
+ * rejects with `signal.reason`. **The batches already flushed stay
294
+ * written** — `bulkWrite()` is not atomic outside a transaction, so an
295
+ * abort stops the load, it does not undo it. Run it inside `transaction()`
296
+ * when abandoning must mean rolling back.
297
+ * @returns Object with:
298
+ * - `enqueue(data)` — buffers a row, flushing automatically when the buffer fills.
299
+ * - `close()` — flushes remaining rows and resolves with total affected row count.
300
+ */
301
+ bulkWrite: <KEYS extends string>(table: string, keys: KEYS[], options?: SQLiteBulkWriteOptions) => SQLiteBulkWriter<KEYS>;
302
+ /**
303
+ * Schema-driven table replacement: drops the existing table, creates a new one
304
+ * from the provided schema, bulk-inserts all enqueued rows, then creates indexes.
305
+ *
306
+ * Useful for full-refresh ETL patterns where a table is rebuilt from scratch.
307
+ *
308
+ * @remarks
309
+ * **Inside a transaction, `output()` costs more than it looks.** On its own it
310
+ * loads rows outside any transaction and holds the write lock only for the
311
+ * final swap. Called on a `tx`, the entire load runs inside your transaction —
312
+ * every other write, in this tab and in others, waits for it to finish.
313
+ *
314
+ * @param table - Table name to drop and recreate.
315
+ * @param schema - Column definition map. Values are SQL type strings or
316
+ * objects with `{ type, required?, unique?, generated? }`.
317
+ * @param options - `indexes` array for index creation after the swap, and
318
+ * `signal` to abort the load. An aborted `output()` leaves the previous
319
+ * target intact and untouched.
320
+ * @returns Object with `enqueue(data)` and `close()` following the same
321
+ * contract as {@link SQLiteQueryAPI.bulkWrite}.
322
+ */
323
+ output: <SCHEMA extends Schema>(table: string, schema: SCHEMA, options?: SQLiteOutputOptions<SCHEMA>) => SQLiteOutputWriter<SCHEMA>;
324
+ };
325
+ export type SQLiteDB = SQLiteQueryAPI & {
326
+ /**
327
+ * Executes a callback within a SQLite transaction, providing a scoped
328
+ * `SQLiteTransactionDB` with `read`, `write`, `chunk`, `stream`, `first`,
329
+ * `bulkWrite`, `output`, `commit`, and `rollback` methods.
330
+ *
331
+ * The worker is held exclusively for the transaction's duration.
332
+ * On callback success: auto-commits if `autoCommit` is `true` (default).
333
+ * On callback error: rolls back automatically.
334
+ * The callback may call `db.commit()` or `db.rollback()` manually.
335
+ *
336
+ * @remarks
337
+ * **Worker crash mid-transaction.** If the worker dies while the callback is
338
+ * running, the transaction rejects with a `WORKER_CRASHED` error. The
339
+ * database engine inside the terminated worker handles its own rollback, but
340
+ * any OPFS file lock the worker held is not released until the browser
341
+ * reclaims the terminated worker's file handles — the timing of that
342
+ * reclamation is outside this library's control.
343
+ *
344
+ * @param callback - Async function receiving a `SQLiteTransactionDB` instance.
345
+ * @param options - `readOnly` (default `false`) prevents write statements;
346
+ * `autoCommit` (default `true`) commits on callback success.
347
+ * @returns Promise resolving to the value returned by `callback`.
348
+ */
349
+ transaction: <T = void>(callback: (db: SQLiteTransactionDB) => Promise<T>, options?: SQLiteTransactionOptions) => Promise<T>;
350
+ /**
351
+ * Drains in-flight work, rejects queued work, closes each database connection,
352
+ * then terminates all workers in the pool.
353
+ *
354
+ * The returned promise settles once every worker has posted `closed` and been
355
+ * terminated, or once `drainTimeout` milliseconds have elapsed (whichever
356
+ * comes first). Calling `close()` a second time returns the **same** promise
357
+ * object — the operation runs exactly once.
358
+ *
359
+ * @remarks
360
+ * **Stored data is NOT deleted.** `close()` releases workers and connections;
361
+ * it removes nothing. What a database leaves behind, and how to remove it,
362
+ * depends on the VFS — and this library does not yet expose a deletion that
363
+ * routes through the VFS itself.
364
+ *
365
+ * Deleting files under `navigator.storage.getDirectory()` is only correct for
366
+ * the plain OPFS VFS, on a database that is already closed, and even there it
367
+ * leaves SQLite's `-journal` and `-wal` siblings unless you remove them too.
368
+ * It is wrong elsewhere:
369
+ *
370
+ * - `AccessHandlePoolVFS` keeps every database inside one directory named
371
+ * after the VFS, in a fixed set of pre-allocated files with opaque names.
372
+ * Removing a file does not free its slot — it takes capacity away from the
373
+ * pool, and once capacity runs out no further database opens.
374
+ * - `IDBBatchAtomicVFS` and `IDBMirrorVFS` store nothing in OPFS at all;
375
+ * their data lives in an IndexedDB database named after the VFS class, so
376
+ * an OPFS deletion is a no-op.
377
+ *
378
+ * Until a `deleteDatabase` exists here, treat removal as VFS-specific and
379
+ * check what your chosen VFS actually writes.
380
+ */
381
+ close: () => Promise<void>;
382
+ /** This client's UUID, unique across the origin. */
383
+ readonly id: string;
384
+ /** This client's label, index included — what its log lines are prefixed with. */
385
+ readonly name: string;
386
+ /** The database file, normalized: the identity every lock name is built on. */
387
+ readonly file: string;
388
+ readonly vfs: SQLiteVFS;
389
+ /** The build actually loaded, resolved by `defaultBuildFor` when not passed. */
390
+ readonly build: SQLiteBuild;
391
+ /**
392
+ * The number of workers the pool runs: `poolSize` as requested, capped by
393
+ * the VFS and by the environment. Exact once every worker has opened or
394
+ * declined; every query waits for that, so it is settled by the time any
395
+ * query returns.
396
+ */
397
+ readonly poolSize: number;
398
+ /**
399
+ * Who else is live on this database, right now, in every tab of this origin.
400
+ *
401
+ * A snapshot, stale the instant it resolves: it informs a UI and never
402
+ * authorizes an action. Poll it if you want it to move — each call is a fresh
403
+ * census costing well under a tenth of a millisecond, and it takes no lock,
404
+ * so it cannot slow a query down.
405
+ */
406
+ inspect: () => Promise<ClientInspection>;
407
+ /**
408
+ * Internal diagnostic handle. Not part of the stable public API.
409
+ * Shape is subject to change without notice.
410
+ * @internal
411
+ */
412
+ debug?: ClientDebugState;
413
+ };
414
+ export type SQLiteTransactionDB = SQLiteQueryAPI & {
415
+ commit: () => Promise<void>;
416
+ rollback: () => Promise<void>;
417
+ /**
418
+ * Aborted when this transaction fails or is abandoned — its own signal or
419
+ * timeout, close(), an abandoned write, or an error the callback lets
420
+ * escape — with the value `transaction()` rejects with. Never aborted when
421
+ * it succeeds. Hand it to work of your own the callback awaits, such as a
422
+ * `fetch`, so that work stops with the transaction.
423
+ */
424
+ readonly signal: AbortSignal;
425
+ };
426
+ export {};
package/dist/bulk.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ import type { Schema, SQLiteBulkWriteOptions, SQLiteOutputOptions, SQLiteOutputRow, SQLiteTransactionOptions } from './api';
2
+ import { type Locks } from './locks';
3
+ import type { Logger } from './logger';
4
+ /**
5
+ * The options these three actually pass is a signal and nothing else, so that
6
+ * is what they ask for. `any` here accepted a misspelt option in silence, which
7
+ * is the one thing a narrow type was never meant to buy.
8
+ */
9
+ type BulkCallOptions = {
10
+ signal?: AbortSignal | undefined;
11
+ };
12
+ export type WriteFn = (sql: string, params?: unknown[], options?: BulkCallOptions) => Promise<{
13
+ result: unknown[];
14
+ affected: number;
15
+ }>;
16
+ export type ReadFn = (sql: string, params?: unknown[], options?: BulkCallOptions) => Promise<unknown[]>;
17
+ export type TransactionFn = <T>(callback: (db: {
18
+ write: (sql: string, params?: unknown[], options?: BulkCallOptions) => Promise<{
19
+ result: unknown[];
20
+ affected: number;
21
+ }>;
22
+ }) => Promise<T>, options?: SQLiteTransactionOptions) => Promise<T>;
23
+ export declare const createBulk: (shared: {
24
+ file: string;
25
+ locks: Locks;
26
+ logger: Logger;
27
+ maxVariables?: number;
28
+ }) => (target: {
29
+ read: ReadFn;
30
+ write: WriteFn;
31
+ transaction: TransactionFn;
32
+ /**
33
+ * Takes this batch's place in the caller's statement queue, SYNCHRONOUSLY,
34
+ * at the moment `flush()` commits to it — from `close()` or from the
35
+ * `enqueue()` that filled the buffer. `started` is what was issued before
36
+ * it; `done()` gives the place back.
37
+ *
38
+ * Supplied by a transaction, where every statement shares one connection.
39
+ * The client path supplies none: there each statement takes its own lease.
40
+ * Without it the batch posts a microtask after `flush()` returns, so a
41
+ * statement issued AFTER it runs first — a stale read rather than an error.
42
+ */
43
+ reserve?: () => {
44
+ started: Promise<void>;
45
+ done: () => void;
46
+ };
47
+ }) => {
48
+ bulkWrite: <KEYS extends string>(table: string, keys: KEYS[], options?: SQLiteBulkWriteOptions, before?: Promise<unknown>) => {
49
+ enqueue: (data: { [K in KEYS]: any; }) => Promise<void>;
50
+ close: () => Promise<number>;
51
+ };
52
+ output: <SCHEMA extends Schema>(table: string, schema: SCHEMA, options?: SQLiteOutputOptions<SCHEMA>) => {
53
+ enqueue: (data: SQLiteOutputRow<SCHEMA>) => Promise<void>;
54
+ close: () => Promise<number>;
55
+ };
56
+ };
57
+ export {};
@@ -0,0 +1,23 @@
1
+ import { type PlatformFeature, type SQLiteBuild, type SQLiteVFS } from './types';
2
+ /**
3
+ * Every feature this module can decide: probed, or explicitly exempt. A
4
+ * feature declared in a capability table and absent here is a mistake, and
5
+ * tests/unit/capabilities.test.ts is what says so.
6
+ */
7
+ export declare const KNOWN_FEATURES: ReadonlySet<PlatformFeature>;
8
+ /** What this engine can do, probed once by the caller. */
9
+ export declare const detectFeatures: () => ReadonlySet<PlatformFeature>;
10
+ /**
11
+ * The first feature this pair needs and this engine lacks, or null.
12
+ *
13
+ * Pure, and takes `available` rather than probing, because the branches worth
14
+ * testing are the negative ones and they are unreachable in a real browser:
15
+ * JSPI cannot be taken away from Chromium.
16
+ */
17
+ export declare const missingFeature: (vfs: SQLiteVFS, build: SQLiteBuild, available: ReadonlySet<PlatformFeature>) => PlatformFeature | null;
18
+ /**
19
+ * The message for a missing feature, derived from the capability tables so it
20
+ * cannot drift from them. Names an alternative build when the build is at
21
+ * fault, and VFS that do not need the feature when the VFS is.
22
+ */
23
+ export declare const describeMissing: (vfs: SQLiteVFS, build: SQLiteBuild, feature: PlatformFeature) => string;