browser-sqlite 1.0.0-rc.3 → 1.0.0-rc.4
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 +435 -63
- package/dist/LICENSE +21 -0
- package/dist/NOTICE +56 -0
- package/dist/api.d.ts +376 -0
- package/dist/bulk.d.ts +42 -0
- package/dist/capabilities.d.ts +23 -0
- package/dist/client.d.ts +198 -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 +42 -0
- package/dist/epochs.d.ts +55 -0
- package/dist/errors.d.ts +37 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/locks.d.ts +54 -0
- package/dist/logger.d.ts +24 -0
- package/dist/pool.d.ts +98 -0
- package/dist/queries.d.ts +36 -0
- package/dist/scheduler.d.ts +131 -0
- package/dist/supervisor.d.ts +17 -0
- package/dist/transaction.d.ts +38 -0
- package/dist/types.d.ts +348 -0
- package/dist/utils.d.ts +116 -0
- package/dist/worker/cloneable.d.ts +25 -0
- package/dist/worker/statement-cache.d.ts +22 -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 +36 -20
- 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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lalexdotcom
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/NOTICE
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
THIRD-PARTY NOTICES
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
browser-sqlite is distributed under the MIT License; see LICENSE.
|
|
5
|
+
|
|
6
|
+
Its published worker artifact (dist/worker/worker.js) has third-party code
|
|
7
|
+
bundled into it, and ships compiled WebAssembly built from third-party
|
|
8
|
+
sources (dist/worker/wa-sqlite.wasm, wa-sqlite-async.wasm, wa-sqlite-jspi.wasm).
|
|
9
|
+
The notices below travel with those files and must be preserved in any
|
|
10
|
+
redistribution.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
-------------------------------------------------------------------------------
|
|
14
|
+
wa-sqlite — https://github.com/rhashimoto/wa-sqlite
|
|
15
|
+
-------------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
The JavaScript glue and the VFS implementations bundled into
|
|
18
|
+
dist/worker/worker.js, and the .wasm binaries beside it, are produced by
|
|
19
|
+
wa-sqlite.
|
|
20
|
+
|
|
21
|
+
MIT License
|
|
22
|
+
|
|
23
|
+
Copyright (c) 2023 Roy T. Hashimoto
|
|
24
|
+
|
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
26
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
27
|
+
in the Software without restriction, including without limitation the rights
|
|
28
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
29
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
30
|
+
furnished to do so, subject to the following conditions:
|
|
31
|
+
|
|
32
|
+
The above copyright notice and this permission notice shall be included in all
|
|
33
|
+
copies or substantial portions of the Software.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
39
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41
|
+
SOFTWARE.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
-------------------------------------------------------------------------------
|
|
45
|
+
SQLite — https://sqlite.org
|
|
46
|
+
-------------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
The .wasm binaries are builds of SQLite. SQLite is in the public domain and
|
|
49
|
+
requires no attribution; the customary blessing is reproduced here.
|
|
50
|
+
|
|
51
|
+
The author disclaims copyright to this source code. In place of
|
|
52
|
+
a legal notice, here is a blessing:
|
|
53
|
+
|
|
54
|
+
May you do good and not evil.
|
|
55
|
+
May you find forgiveness for yourself and forgive others.
|
|
56
|
+
May you share freely, never taking more than you give.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
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
|
+
/**
|
|
14
|
+
* Marks an options type as carrying an abort signal.
|
|
15
|
+
*
|
|
16
|
+
* The name is the point. `options?: OptionsWithSignal<…>` says at the signature
|
|
17
|
+
* that the method can be abandoned, where a bare alias would make a reader open
|
|
18
|
+
* the type to find out. Every abortable option type in this file is built from
|
|
19
|
+
* it, so `signal` is documented once and cannot drift between them.
|
|
20
|
+
*
|
|
21
|
+
* Not the bare `Abortable` that `@types/node` uses: this reads as an options
|
|
22
|
+
* bag augmented with one member — `PropsWithChildren`, not an adjective — which
|
|
23
|
+
* is what it is both wrapped, `OptionsWithSignal<{ chunkSize?: number }>`, and
|
|
24
|
+
* alone, `options?: OptionsWithSignal`.
|
|
25
|
+
*
|
|
26
|
+
* `T = unknown` rather than `Record<string, never>`: intersecting with the
|
|
27
|
+
* latter collapses `signal` to `never` and makes it unassignable.
|
|
28
|
+
*/
|
|
29
|
+
export type OptionsWithSignal<T = unknown> = T & {
|
|
30
|
+
/**
|
|
31
|
+
* Aborts the work. Rejects with `signal.reason` — your reason, not an error
|
|
32
|
+
* of this library's making.
|
|
33
|
+
*
|
|
34
|
+
* On `bulkWrite()` and `output()` the abort lands **between** batches, never
|
|
35
|
+
* inside one: a multi-row INSERT is statement-atomic, so stopping inside a
|
|
36
|
+
* batch would either waste it whole or let it commit whole. An aborted
|
|
37
|
+
* `bulkWrite()` leaves the batches already written in place; an aborted
|
|
38
|
+
* `output()` is observationally a no-op, dropping its staging table and
|
|
39
|
+
* touching nothing else.
|
|
40
|
+
*/
|
|
41
|
+
signal?: AbortSignal | undefined;
|
|
42
|
+
};
|
|
43
|
+
/** Options every query method accepts. */
|
|
44
|
+
export type SQLiteQueryOptions = OptionsWithSignal;
|
|
45
|
+
/**
|
|
46
|
+
* Options for the methods that cross the worker boundary in chunks.
|
|
47
|
+
*
|
|
48
|
+
* `chunkSize` is not only a transport detail: back-pressure grants credits per
|
|
49
|
+
* chunk with a window of 2, so the worker may run up to `2 × chunkSize` rows
|
|
50
|
+
* ahead of the consumer. On `stream()` that is the only lever on how many rows
|
|
51
|
+
* are in flight.
|
|
52
|
+
*/
|
|
53
|
+
export type SQLiteChunkOptions = OptionsWithSignal<{
|
|
54
|
+
/** Rows per chunk. Defaults to 500. */
|
|
55
|
+
chunkSize?: number;
|
|
56
|
+
}>;
|
|
57
|
+
export type SQLiteWriteResult<T extends Record<string, unknown>> = {
|
|
58
|
+
result: T[];
|
|
59
|
+
affected: number;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Options for `transaction()`.
|
|
63
|
+
*
|
|
64
|
+
* `signal` abandons the transaction at every stage: while it waits for a
|
|
65
|
+
* worker, once it holds one, and from inside the callback — every statement
|
|
66
|
+
* issued through `tx` inherits it, and a statement that carries a signal of its
|
|
67
|
+
* own can be aborted by either. An abandoned transaction rolls back and rejects
|
|
68
|
+
* with `signal.reason`; it never commits, not even when the callback catches
|
|
69
|
+
* its statement's rejection and returns normally.
|
|
70
|
+
*
|
|
71
|
+
* The callback itself cannot be interrupted — it is your code — but it can no
|
|
72
|
+
* longer reach the database: every statement it issues after the abort rejects
|
|
73
|
+
* without a worker round trip.
|
|
74
|
+
*
|
|
75
|
+
* One window is not abortable: `BEGIN`, `COMMIT` and `ROLLBACK` never carry the
|
|
76
|
+
* signal. Their completion is what decides whether a rollback is owed, so a
|
|
77
|
+
* client-side abort of one of them would risk leaving the transaction open on
|
|
78
|
+
* the connection. The abort lands as soon as such a statement settles.
|
|
79
|
+
*
|
|
80
|
+
* That window is short on a VFS holding one access handle per connection, and
|
|
81
|
+
* it is not on a VFS rotating a single exclusive one: there such a statement
|
|
82
|
+
* waits for whichever client holds the file, and your signal cannot shorten
|
|
83
|
+
* that wait. See the reduced mode described under VFS Selection.
|
|
84
|
+
*/
|
|
85
|
+
export type SQLiteTransactionOptions = OptionsWithSignal<{
|
|
86
|
+
/** Rejects write statements with `READ_ONLY_TRANSACTION`. Defaults to false. */
|
|
87
|
+
readOnly?: boolean;
|
|
88
|
+
/** Commits when the callback resolves. Defaults to true. */
|
|
89
|
+
autoCommit?: boolean;
|
|
90
|
+
}>;
|
|
91
|
+
/** Column definitions for `output()`. */
|
|
92
|
+
export type Schema = Record<string, string | {
|
|
93
|
+
type: string;
|
|
94
|
+
generated?: string;
|
|
95
|
+
required?: boolean;
|
|
96
|
+
unique?: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
export type Index<SCHEMA extends Schema> = keyof SCHEMA | (keyof SCHEMA)[] | ({
|
|
99
|
+
unique?: boolean;
|
|
100
|
+
} & ({
|
|
101
|
+
column: keyof SCHEMA;
|
|
102
|
+
} | {
|
|
103
|
+
columns: (keyof SCHEMA)[];
|
|
104
|
+
}));
|
|
105
|
+
export type SQLiteOutputOptions<SCHEMA extends Schema> = OptionsWithSignal<{
|
|
106
|
+
indexes?: Index<SCHEMA>[];
|
|
107
|
+
/** Rows queued for writing above which `enqueue()` defers. See `SQLiteBulkWriteOptions`. */
|
|
108
|
+
queueSize?: number | undefined;
|
|
109
|
+
}>;
|
|
110
|
+
/**
|
|
111
|
+
* Options `bulkWrite()` accepts.
|
|
112
|
+
*
|
|
113
|
+
* `queueSize` bounds how far the producer may run ahead of the database. Rows
|
|
114
|
+
* are handed over in batches of at most 32 766 bound values; a batch that has
|
|
115
|
+
* been handed over but not yet written is held in memory until it is, and
|
|
116
|
+
* nothing caps how many of those accumulate unless you await `enqueue()`.
|
|
117
|
+
*
|
|
118
|
+
* It is a number of rows, and nothing else: it says nothing about what those
|
|
119
|
+
* rows weigh. A table whose columns carry blobs holds far more per row than a
|
|
120
|
+
* table of integers, and only you know which one you are loading — set the
|
|
121
|
+
* value yourself when the rows are heavy.
|
|
122
|
+
*
|
|
123
|
+
* The default is two batches' worth, derived from the column count: about
|
|
124
|
+
* 13 100 rows for 5 columns, 2 180 for 30. A value smaller than one batch is legal
|
|
125
|
+
* and means one INSERT in flight, the least the batching allows. Anything below
|
|
126
|
+
* 1 is raised to 1: a batch always holds at least one row, so a lower cap could
|
|
127
|
+
* never be satisfied.
|
|
128
|
+
*/
|
|
129
|
+
export type SQLiteBulkWriteOptions = OptionsWithSignal<{
|
|
130
|
+
/** Rows queued for writing above which `enqueue()` defers. */
|
|
131
|
+
queueSize?: number | undefined;
|
|
132
|
+
}>;
|
|
133
|
+
/** A row for `output()`: generated columns are computed, never supplied. */
|
|
134
|
+
export type SQLiteOutputRow<SCHEMA extends Schema> = {
|
|
135
|
+
[K in keyof SCHEMA as SCHEMA[K] extends {
|
|
136
|
+
generated: string;
|
|
137
|
+
} ? never : K]: any;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Buffers a row, flushing automatically when the buffer fills.
|
|
141
|
+
*
|
|
142
|
+
* Awaiting the returned promise applies back-pressure: it is already resolved
|
|
143
|
+
* while fewer than `queueSize` rows are queued for writing, and resolves once
|
|
144
|
+
* a batch settles when they are not. Ignoring it is legal, and leaves the load
|
|
145
|
+
* unbounded exactly as it was before the option existed — the bound is an
|
|
146
|
+
* offer, not a guarantee.
|
|
147
|
+
*
|
|
148
|
+
* It never rejects. A failed batch surfaces at the next `enqueue()`, which
|
|
149
|
+
* throws, and at `close()`, which rejects.
|
|
150
|
+
*/
|
|
151
|
+
type EnqueueRow<ROW> = (data: ROW) => Promise<void>;
|
|
152
|
+
export type SQLiteBulkWriter<KEYS extends string> = {
|
|
153
|
+
enqueue: EnqueueRow<Record<KEYS, any>>;
|
|
154
|
+
/** Flushes what remains and resolves with the total affected row count. */
|
|
155
|
+
close: () => Promise<number>;
|
|
156
|
+
};
|
|
157
|
+
export type SQLiteOutputWriter<SCHEMA extends Schema> = {
|
|
158
|
+
enqueue: EnqueueRow<SQLiteOutputRow<SCHEMA>>;
|
|
159
|
+
close: () => Promise<number>;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* The querying surface, shared by the client and by a transaction.
|
|
163
|
+
*
|
|
164
|
+
* It exists so the two cannot drift: they had already done so, one taking
|
|
165
|
+
* `any[]` where the other took `unknown[]`, and two different option types on
|
|
166
|
+
* `chunk`. A method added to one is now added to both by construction.
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* **The row type parameter is a claim, not a check.** `read<T>`, `first<T>`,
|
|
170
|
+
* `chunk<T>` and `stream<T>` cast SQLite's output to `T` and validate nothing:
|
|
171
|
+
* a column that is missing, renamed or of another type reaches you typed as if
|
|
172
|
+
* it were not. SQLite is dynamically typed and a query's shape is only known at
|
|
173
|
+
* runtime, so the alternative would be a schema the caller declares twice.
|
|
174
|
+
* Validate at the boundary if you need the guarantee — this is `as`, not a
|
|
175
|
+
* parser.
|
|
176
|
+
*/
|
|
177
|
+
export type SQLiteQueryAPI = {
|
|
178
|
+
/**
|
|
179
|
+
* Executes a SELECT query and returns all matching rows as an array.
|
|
180
|
+
*
|
|
181
|
+
* Read queries are dispatched to any available worker in the pool,
|
|
182
|
+
* enabling concurrent execution across multiple readers.
|
|
183
|
+
*
|
|
184
|
+
* @param sql - SQL query string. Must be a SELECT (or equivalent read) statement.
|
|
185
|
+
* @param params - Positional parameters bound to `?` placeholders.
|
|
186
|
+
* @param options - Optional query options (`chunkSize`, `signal`).
|
|
187
|
+
* @returns Promise resolving to an array of typed rows (`T[]`). Returns `[]` for empty results.
|
|
188
|
+
*/
|
|
189
|
+
read: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteChunkOptions) => Promise<T[]>;
|
|
190
|
+
/**
|
|
191
|
+
* Executes a DML or DDL statement (INSERT, UPDATE, DELETE, CREATE, DROP, etc.)
|
|
192
|
+
* and returns both any result rows and the number of affected rows.
|
|
193
|
+
*
|
|
194
|
+
* Write queries are serialized through a single dedicated writer worker.
|
|
195
|
+
* Concurrent writes queue behind each other — only one write executes at a time.
|
|
196
|
+
*
|
|
197
|
+
* @param sql - SQL statement. Any statement not classified as a read by `isReadQuery`.
|
|
198
|
+
* @param params - Positional parameters bound to `?` placeholders.
|
|
199
|
+
* @param options - Optional query options (`signal`).
|
|
200
|
+
* @returns Promise resolving to `{ result: T[], affected: number }` where
|
|
201
|
+
* `affected` is the SQLite `changes()` count for the statement.
|
|
202
|
+
*/
|
|
203
|
+
write: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: OptionsWithSignal) => Promise<SQLiteWriteResult<T>>;
|
|
204
|
+
/**
|
|
205
|
+
* Executes a query and yields result rows in chunks via an async generator.
|
|
206
|
+
* Memory-efficient for large result sets — rows are not buffered in full.
|
|
207
|
+
*
|
|
208
|
+
* @remarks
|
|
209
|
+
* **Worker held for full generator lifetime.** A pool worker is acquired when
|
|
210
|
+
* the generator is created and released only when the generator is fully
|
|
211
|
+
* exhausted or the caller uses `break`. Failing to exhaust the generator
|
|
212
|
+
* starves the pool. Always use `for await...of` to completion or `break` to exit.
|
|
213
|
+
*
|
|
214
|
+
* **`NOT_A_READ_QUERY` timing.** Because `chunk()` is an async generator, its
|
|
215
|
+
* body does not run until the first `next()` call. Passing a write statement
|
|
216
|
+
* does not throw at the call site — the `SQLiteError` arrives on the first
|
|
217
|
+
* `await gen.next()` (or the first iteration of `for await...of`).
|
|
218
|
+
*
|
|
219
|
+
* @param sql - SQL query string. Must be a SELECT (or equivalent read) statement.
|
|
220
|
+
* @param params - Positional parameters bound to `?` placeholders.
|
|
221
|
+
* @param options - Optional options including `chunkSize` (default `500`),
|
|
222
|
+
* `signal` (AbortSignal to cancel).
|
|
223
|
+
* @returns AsyncGenerator yielding `T[]` chunks of at most `chunkSize` rows.
|
|
224
|
+
*/
|
|
225
|
+
chunk: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteChunkOptions) => AsyncGenerator<T[]>;
|
|
226
|
+
/**
|
|
227
|
+
* Executes a query and yields individual result rows via an async generator.
|
|
228
|
+
* Flattens chunk boundaries — each iteration yields one `T` row, not a chunk.
|
|
229
|
+
* Use `chunk()` when you need the rows grouped by chunk.
|
|
230
|
+
*
|
|
231
|
+
* @remarks
|
|
232
|
+
* **`NOT_A_READ_QUERY` timing.** Because `stream()` is an async generator, its
|
|
233
|
+
* body does not run until the first `next()` call. Passing a write statement
|
|
234
|
+
* does not throw at the call site — the `SQLiteError` arrives on the first
|
|
235
|
+
* `await gen.next()` (or the first iteration of `for await...of`).
|
|
236
|
+
*
|
|
237
|
+
* @param sql - SQL query string. Must be a SELECT (or equivalent read) statement.
|
|
238
|
+
* @param params - Positional parameters bound to `?` placeholders.
|
|
239
|
+
* @param options - Optional query options (`chunkSize`, `signal`).
|
|
240
|
+
* @returns AsyncGenerator yielding individual rows of type `T`.
|
|
241
|
+
*/
|
|
242
|
+
stream: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: SQLiteChunkOptions) => AsyncGenerator<T>;
|
|
243
|
+
/**
|
|
244
|
+
* Executes a query and returns the first row, or `undefined` if no rows match.
|
|
245
|
+
*
|
|
246
|
+
* Internally uses `chunkSize: 1` and asks the worker to stop after the first
|
|
247
|
+
* row. Because the worker runs in a separate thread it may race ahead between
|
|
248
|
+
* the break and the stop signal, so early termination is best-effort on small
|
|
249
|
+
* result sets. A hard bound will arrive with back-pressure in a future wave.
|
|
250
|
+
*
|
|
251
|
+
* @param sql - SQL query string.
|
|
252
|
+
* @param params - Positional parameters bound to `?` placeholders.
|
|
253
|
+
* @param options - Optional query options (`signal`).
|
|
254
|
+
* @returns Promise resolving to the first row as `T`, or `undefined` if no rows.
|
|
255
|
+
*/
|
|
256
|
+
first: <T extends Record<string, unknown>>(sql: string, params?: unknown[], options?: OptionsWithSignal) => Promise<T | undefined>;
|
|
257
|
+
/**
|
|
258
|
+
* Creates a buffered bulk-insert utility that batches rows to stay within
|
|
259
|
+
* SQLite's variable limit (`SQLITE_MAX_VARS = 32766`).
|
|
260
|
+
*
|
|
261
|
+
* Call `enqueue()` for each row to insert, then `close()` to flush the
|
|
262
|
+
* remaining buffer and await completion.
|
|
263
|
+
*
|
|
264
|
+
* @remarks
|
|
265
|
+
* **`bulkWrite()` is not atomic:** batches are committed as they flush, so a
|
|
266
|
+
* failure leaves the rows already written in place. Call it on a `tx` if you
|
|
267
|
+
* need all-or-nothing.
|
|
268
|
+
*
|
|
269
|
+
* That commit per batch is also what it costs: measured at ~3.4 ms
|
|
270
|
+
* (synchronous build) and ~5.3 ms (Asyncify build) per commit on Chromium.
|
|
271
|
+
* A load wrapped in `transaction()` commits once and buys the rest back.
|
|
272
|
+
*
|
|
273
|
+
* @param table - Target table name.
|
|
274
|
+
* @param keys - Column names for the INSERT statement.
|
|
275
|
+
* @param options - `signal` aborts the load between batches. `close()` then
|
|
276
|
+
* rejects with `signal.reason`. **The batches already flushed stay
|
|
277
|
+
* written** — `bulkWrite()` is not atomic outside a transaction, so an
|
|
278
|
+
* abort stops the load, it does not undo it. Run it inside `transaction()`
|
|
279
|
+
* when abandoning must mean rolling back.
|
|
280
|
+
* @returns Object with:
|
|
281
|
+
* - `enqueue(data)` — buffers a row, flushing automatically when the buffer fills.
|
|
282
|
+
* - `close()` — flushes remaining rows and resolves with total affected row count.
|
|
283
|
+
*/
|
|
284
|
+
bulkWrite: <KEYS extends string>(table: string, keys: KEYS[], options?: SQLiteBulkWriteOptions) => SQLiteBulkWriter<KEYS>;
|
|
285
|
+
/**
|
|
286
|
+
* Schema-driven table replacement: drops the existing table, creates a new one
|
|
287
|
+
* from the provided schema, bulk-inserts all enqueued rows, then creates indexes.
|
|
288
|
+
*
|
|
289
|
+
* Useful for full-refresh ETL patterns where a table is rebuilt from scratch.
|
|
290
|
+
*
|
|
291
|
+
* @remarks
|
|
292
|
+
* **Inside a transaction, `output()` costs more than it looks.** On its own it
|
|
293
|
+
* loads rows outside any transaction and holds the write lock only for the
|
|
294
|
+
* final swap. Called on a `tx`, the entire load runs inside your transaction —
|
|
295
|
+
* every other write, in this tab and in others, waits for it to finish.
|
|
296
|
+
*
|
|
297
|
+
* @param table - Table name to drop and recreate.
|
|
298
|
+
* @param schema - Column definition map. Values are SQL type strings or
|
|
299
|
+
* objects with `{ type, required?, unique?, generated? }`.
|
|
300
|
+
* @param options - `indexes` array for index creation after the swap, and
|
|
301
|
+
* `signal` to abort the load. An aborted `output()` leaves the previous
|
|
302
|
+
* target intact and untouched.
|
|
303
|
+
* @returns Object with `enqueue(data)` and `close()` following the same
|
|
304
|
+
* contract as {@link SQLiteQueryAPI.bulkWrite}.
|
|
305
|
+
*/
|
|
306
|
+
output: <SCHEMA extends Schema>(table: string, schema: SCHEMA, options?: SQLiteOutputOptions<SCHEMA>) => SQLiteOutputWriter<SCHEMA>;
|
|
307
|
+
};
|
|
308
|
+
export type SQLiteDB = SQLiteQueryAPI & {
|
|
309
|
+
/**
|
|
310
|
+
* Executes a callback within a SQLite transaction, providing a scoped
|
|
311
|
+
* `SQLiteTransactionDB` with `read`, `write`, `chunk`, `stream`, `first`,
|
|
312
|
+
* `bulkWrite`, `output`, `commit`, and `rollback` methods.
|
|
313
|
+
*
|
|
314
|
+
* The worker is held exclusively for the transaction's duration.
|
|
315
|
+
* On callback success: auto-commits if `autoCommit` is `true` (default).
|
|
316
|
+
* On callback error: rolls back automatically.
|
|
317
|
+
* The callback may call `db.commit()` or `db.rollback()` manually.
|
|
318
|
+
*
|
|
319
|
+
* @remarks
|
|
320
|
+
* **Worker crash mid-transaction.** If the worker dies while the callback is
|
|
321
|
+
* running, the transaction rejects with a `WORKER_CRASHED` error. The
|
|
322
|
+
* database engine inside the terminated worker handles its own rollback, but
|
|
323
|
+
* any OPFS file lock the worker held is not released until the browser
|
|
324
|
+
* reclaims the terminated worker's file handles — the timing of that
|
|
325
|
+
* reclamation is outside this library's control.
|
|
326
|
+
*
|
|
327
|
+
* @param callback - Async function receiving a `SQLiteTransactionDB` instance.
|
|
328
|
+
* @param options - `readOnly` (default `false`) prevents write statements;
|
|
329
|
+
* `autoCommit` (default `true`) commits on callback success.
|
|
330
|
+
* @returns Promise resolving to the value returned by `callback`.
|
|
331
|
+
*/
|
|
332
|
+
transaction: <T = void>(callback: (db: SQLiteTransactionDB) => Promise<T>, options?: SQLiteTransactionOptions) => Promise<T>;
|
|
333
|
+
/**
|
|
334
|
+
* Drains in-flight work, rejects queued work, closes each database connection,
|
|
335
|
+
* then terminates all workers in the pool.
|
|
336
|
+
*
|
|
337
|
+
* The returned promise settles once every worker has posted `closed` and been
|
|
338
|
+
* terminated, or once `drainTimeout` milliseconds have elapsed (whichever
|
|
339
|
+
* comes first). Calling `close()` a second time returns the **same** promise
|
|
340
|
+
* object — the operation runs exactly once.
|
|
341
|
+
*
|
|
342
|
+
* @remarks
|
|
343
|
+
* **Stored data is NOT deleted.** `close()` releases workers and connections;
|
|
344
|
+
* it removes nothing. What a database leaves behind, and how to remove it,
|
|
345
|
+
* depends on the VFS — and this library does not yet expose a deletion that
|
|
346
|
+
* routes through the VFS itself.
|
|
347
|
+
*
|
|
348
|
+
* Deleting files under `navigator.storage.getDirectory()` is only correct for
|
|
349
|
+
* the plain OPFS VFS, on a database that is already closed, and even there it
|
|
350
|
+
* leaves SQLite's `-journal` and `-wal` siblings unless you remove them too.
|
|
351
|
+
* It is wrong elsewhere:
|
|
352
|
+
*
|
|
353
|
+
* - `AccessHandlePoolVFS` keeps every database inside one directory named
|
|
354
|
+
* after the VFS, in a fixed set of pre-allocated files with opaque names.
|
|
355
|
+
* Removing a file does not free its slot — it takes capacity away from the
|
|
356
|
+
* pool, and once capacity runs out no further database opens.
|
|
357
|
+
* - `IDBBatchAtomicVFS` and `IDBMirrorVFS` store nothing in OPFS at all;
|
|
358
|
+
* their data lives in an IndexedDB database named after the VFS class, so
|
|
359
|
+
* an OPFS deletion is a no-op.
|
|
360
|
+
*
|
|
361
|
+
* Until a `deleteDatabase` exists here, treat removal as VFS-specific and
|
|
362
|
+
* check what your chosen VFS actually writes.
|
|
363
|
+
*/
|
|
364
|
+
close: () => Promise<void>;
|
|
365
|
+
/**
|
|
366
|
+
* Internal diagnostic handle. Not part of the stable public API.
|
|
367
|
+
* Shape is subject to change without notice.
|
|
368
|
+
* @internal
|
|
369
|
+
*/
|
|
370
|
+
debug?: ClientDebugState;
|
|
371
|
+
};
|
|
372
|
+
export type SQLiteTransactionDB = SQLiteQueryAPI & {
|
|
373
|
+
commit: () => Promise<void>;
|
|
374
|
+
rollback: () => Promise<void>;
|
|
375
|
+
};
|
|
376
|
+
export {};
|
package/dist/bulk.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
bulkWrite: <KEYS extends string>(table: string, keys: KEYS[], options?: SQLiteBulkWriteOptions, before?: Promise<unknown>) => {
|
|
34
|
+
enqueue: (data: { [K in KEYS]: any; }) => Promise<void>;
|
|
35
|
+
close: () => Promise<number>;
|
|
36
|
+
};
|
|
37
|
+
output: <SCHEMA extends Schema>(table: string, schema: SCHEMA, options?: SQLiteOutputOptions<SCHEMA>) => {
|
|
38
|
+
enqueue: (data: SQLiteOutputRow<SCHEMA>) => Promise<void>;
|
|
39
|
+
close: () => Promise<number>;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
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;
|