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
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Pure worker scheduling: availability, wait queues, writer designation.
3
+ *
4
+ * This module is deliberately free of `Worker` and DOM imports so
5
+ * it can be exercised by fast Node tests. B1 survived for months because the
6
+ * scheduler was only reachable through slow browser tests.
7
+ */
8
+ import type { CreateSQLiteClientOptions } from './client';
9
+ /**
10
+ * A borrowed worker. `release()` is the only way back into the pool and is
11
+ * idempotent — a second call is a no-op, not an error.
12
+ */
13
+ export type Lease<W> = {
14
+ readonly worker: W;
15
+ release: () => void;
16
+ };
17
+ /**
18
+ * Decides whether a worker index may hold the write designation. The default
19
+ * accepts every index, so production behaviour is exactly what it was.
20
+ */
21
+ export type WriterPolicy = (index: number) => boolean;
22
+ /**
23
+ * TEST-ONLY, UNSUPPORTED, removable without notice.
24
+ *
25
+ * The barrier's browser test needs the failing configuration — writer not on
26
+ * the worker that serves the read — to be deterministic; at startup chance it
27
+ * occurs ~3 runs in 10. This type is declared here, and NOT in `client.ts`,
28
+ * because `src/index.ts` re-exports only `./client` and `./errors`: keeping it
29
+ * out of that path keeps it out of the published `.d.ts` and out of every
30
+ * consumer's autocompletion. `CreateSQLiteClientOptions` is pulled in with
31
+ * `import type`, which is erased at build time and creates no runtime cycle.
32
+ *
33
+ * A predicate that refuses every index leaves writes queued forever — use it
34
+ * with `poolSize >= 2`.
35
+ */
36
+ export type InternalSQLiteClientOptions = CreateSQLiteClientOptions & {
37
+ __unsafeTestWriterPolicy?: WriterPolicy;
38
+ /**
39
+ * TEST-ONLY, UNSUPPORTED. The byte bound has no falsifier without it: at a
40
+ * fixed default nothing in the suite can tell a working bound from one that
41
+ * never fires. Absent from the public options type on purpose.
42
+ */
43
+ __unsafeTestStatementCacheBytes?: number;
44
+ };
45
+ export type Scheduler<W> = {
46
+ add: (worker: W) => void;
47
+ /**
48
+ * Leases a worker, queueing when none is free.
49
+ *
50
+ * `signal` aborts the WAIT, and only the wait: it rejects with
51
+ * `signal.reason` while the request is still queued, and is ignored once a
52
+ * lease has been granted — from that point the caller owns the worker and
53
+ * owes a `release()`. Without it an abort could not land at all while the
54
+ * pool had nothing to lend, which is the state a VFS rotating one exclusive
55
+ * OPFS handle can stay in indefinitely.
56
+ */
57
+ acquire: (kind: 'read' | 'write', signal?: AbortSignal) => Promise<Lease<W>>;
58
+ /**
59
+ * Takes a worker out of the pool for good. A lease already outstanding on
60
+ * that index becomes inert: its `release()` neither hands the worker back nor
61
+ * counts towards `shutdown()`'s wait.
62
+ */
63
+ remove: (index: number) => void;
64
+ /**
65
+ * Takes a slot out of the pool for good because its worker DECLINED to open:
66
+ * the environment caps the pool below its requested size (spec 2026-09-13).
67
+ * Unlike `remove()`, the slot settles the readiness gate as neither opened
68
+ * nor failed, so it never appears in `onFirstSettle`'s `failedIndices` and
69
+ * never enters the startup retry round.
70
+ */
71
+ retire: (index: number) => void;
72
+ /**
73
+ * Closes the front door. Queued waiters reject with `reason`, later
74
+ * acquisitions reject the same way, and the returned promise settles when the
75
+ * last outstanding lease has come back.
76
+ */
77
+ shutdown: (reason: Error) => Promise<void>;
78
+ /**
79
+ * Read-only counters for the debug subsystem. The scheduler stays pure: it
80
+ * exposes numbers and knows nothing about debug (spec §3.2).
81
+ */
82
+ stats: () => {
83
+ read: number;
84
+ write: number;
85
+ available: number;
86
+ leased: number;
87
+ /**
88
+ * Callers suspended on the readiness gate. They are in NEITHER wait queue —
89
+ * the gate is awaited before `takeAvailable` is ever reached — so `read`
90
+ * and `write` cannot see them, and without this the debug surface reports
91
+ * an idle pool for the whole startup window.
92
+ *
93
+ * Waiting for the pool to *exist* is a different wait from waiting for a
94
+ * free worker, which is why this is its own counter and not folded in.
95
+ */
96
+ gated: number;
97
+ };
98
+ /**
99
+ * Removes a slot from the settled-set so that its next `add()` or `remove()`
100
+ * call counts again toward opening the readiness gate. Only effective while
101
+ * the gate is still closed; a no-op once the gate has opened.
102
+ *
103
+ * Used by the startup retry round: the client re-arms the failed slots so
104
+ * the gate stays closed until the retry slots have settled.
105
+ */
106
+ rearmSlot: (index: number) => void;
107
+ };
108
+ /**
109
+ * Creates a scheduler over workers identified by a numeric `index`.
110
+ *
111
+ * @param opts.onIdle - Called when a released worker returns to the available
112
+ * set with nothing queued behind it. The scheduler itself knows nothing about
113
+ * worker state.
114
+ */
115
+ export declare const createScheduler: <W extends {
116
+ index: number;
117
+ }>(opts?: {
118
+ onIdle?: (worker: W) => void;
119
+ canDesignateWriter?: WriterPolicy;
120
+ /**
121
+ * Total number of worker slots the pool will spawn. Once every slot has
122
+ * settled (via `add` when it becomes ready, or via `remove` when it dies or
123
+ * fails to open), a one-shot gate is lifted and `acquire()` may proceed.
124
+ * Omit or pass 0 for an immediately-open gate (tests and single-shot use).
125
+ */
126
+ poolSize?: number;
127
+ /**
128
+ * Called exactly once when every slot in [0, poolSize) has settled for the
129
+ * first time. Fires before the gate opens so the callback can call
130
+ * `rearmSlot()` to extend the wait for a retry round.
131
+ *
132
+ * `openedCount` — slots that settled via `add()` (became ready).
133
+ * `failedIndices` — slots that settled via `remove()` (died / timed out).
134
+ */
135
+ onFirstSettle?: (result: {
136
+ openedCount: number;
137
+ failedIndices: number[];
138
+ }) => void;
139
+ /**
140
+ * Called when the readiness gate resolves (opens). Not called when the gate
141
+ * is rejected via `shutdown()`. Use this to clear any startup-pending flag
142
+ * after the retry round (if any) has fully settled.
143
+ */
144
+ onGateOpen?: () => void;
145
+ }) => Scheduler<W>;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * The result codes of SQLite 3.53.0, keyed without the `SQLITE_` prefix, in two
3
+ * tables that match `SQLiteError`'s two fields: test the family on `sqliteCode`
4
+ * against `SQLITE_CODES` (`CONSTRAINT`, `FULL`), the subtype on
5
+ * `sqliteExtendedCode` against `SQLITE_EXTENDED_CODES` (`CONSTRAINT_UNIQUE`).
6
+ * An extended code's low byte is its family (`(2067 & 0xff) === 19`), and its key
7
+ * begins with the family's key. What each one means:
8
+ * https://sqlite.org/rescode.html.
9
+ *
10
+ * Transcribed from `src/sqlite.h.in` — the source of `sqlite3.h` — at SQLite's
11
+ * tag `version-3.53.0`, checked 2026-09-14. That is the SQLite of the vendored
12
+ * wa-sqlite, v1.1.2 (its `package.json` still reads 1.1.1: upstream did not
13
+ * bump it): its source-id, read from the wasm, is `2026-04-09 11:41:38
14
+ * 4525003a53a7fc63ca75`, and the tag's `manifest.uuid` begins with the same
15
+ * hash. Not read from wa-sqlite's `sqlite-constants.js`, which has no
16
+ * `BUSY_*`, `LOCKED_*`, `CANTOPEN_*`, `CORRUPT_*` or `READONLY_*` codes;
17
+ * `tests/unit/sqlite-codes.test.ts` checks every name the two share.
18
+ * Re-transcribe when wa-sqlite moves to another SQLite.
19
+ *
20
+ * `SQLiteError.sqliteCode` is typed `SQLiteResultCode` (strict): since
21
+ * `sqliteCodeOf`, it is always a primary code of the bundled SQLite (D10).
22
+ * `sqliteExtendedCode` stays open (`SQLiteExtendedResultCode | (number & {})`):
23
+ * a wrong read must stay representable (D9).
24
+ */
25
+ /** The 31 primary result codes — what `SQLiteError.sqliteCode` holds. */
26
+ export declare const SQLITE_CODES: Readonly<{
27
+ readonly OK: 0;
28
+ readonly ERROR: 1;
29
+ readonly INTERNAL: 2;
30
+ readonly PERM: 3;
31
+ readonly ABORT: 4;
32
+ readonly BUSY: 5;
33
+ readonly LOCKED: 6;
34
+ readonly NOMEM: 7;
35
+ readonly READONLY: 8;
36
+ readonly INTERRUPT: 9;
37
+ readonly IOERR: 10;
38
+ readonly CORRUPT: 11;
39
+ readonly NOTFOUND: 12;
40
+ readonly FULL: 13;
41
+ readonly CANTOPEN: 14;
42
+ readonly PROTOCOL: 15;
43
+ readonly EMPTY: 16;
44
+ readonly SCHEMA: 17;
45
+ readonly TOOBIG: 18;
46
+ readonly CONSTRAINT: 19;
47
+ readonly MISMATCH: 20;
48
+ readonly MISUSE: 21;
49
+ readonly NOLFS: 22;
50
+ readonly AUTH: 23;
51
+ readonly FORMAT: 24;
52
+ readonly RANGE: 25;
53
+ readonly NOTADB: 26;
54
+ readonly NOTICE: 27;
55
+ readonly WARNING: 28;
56
+ readonly ROW: 100;
57
+ readonly DONE: 101;
58
+ }>;
59
+ /**
60
+ * The 82 extended result codes — what `SQLiteError.sqliteExtendedCode` holds
61
+ * when SQLite reports a subtype. No primary code is repeated here.
62
+ */
63
+ export declare const SQLITE_EXTENDED_CODES: Readonly<{
64
+ readonly ERROR_MISSING_COLLSEQ: 257;
65
+ readonly ERROR_RETRY: 513;
66
+ readonly ERROR_SNAPSHOT: 769;
67
+ readonly ERROR_RESERVESIZE: 1025;
68
+ readonly ERROR_KEY: 1281;
69
+ readonly ERROR_UNABLE: 1537;
70
+ readonly IOERR_READ: 266;
71
+ readonly IOERR_SHORT_READ: 522;
72
+ readonly IOERR_WRITE: 778;
73
+ readonly IOERR_FSYNC: 1034;
74
+ readonly IOERR_DIR_FSYNC: 1290;
75
+ readonly IOERR_TRUNCATE: 1546;
76
+ readonly IOERR_FSTAT: 1802;
77
+ readonly IOERR_UNLOCK: 2058;
78
+ readonly IOERR_RDLOCK: 2314;
79
+ readonly IOERR_DELETE: 2570;
80
+ readonly IOERR_BLOCKED: 2826;
81
+ readonly IOERR_NOMEM: 3082;
82
+ readonly IOERR_ACCESS: 3338;
83
+ readonly IOERR_CHECKRESERVEDLOCK: 3594;
84
+ readonly IOERR_LOCK: 3850;
85
+ readonly IOERR_CLOSE: 4106;
86
+ readonly IOERR_DIR_CLOSE: 4362;
87
+ readonly IOERR_SHMOPEN: 4618;
88
+ readonly IOERR_SHMSIZE: 4874;
89
+ readonly IOERR_SHMLOCK: 5130;
90
+ readonly IOERR_SHMMAP: 5386;
91
+ readonly IOERR_SEEK: 5642;
92
+ readonly IOERR_DELETE_NOENT: 5898;
93
+ readonly IOERR_MMAP: 6154;
94
+ readonly IOERR_GETTEMPPATH: 6410;
95
+ readonly IOERR_CONVPATH: 6666;
96
+ readonly IOERR_VNODE: 6922;
97
+ readonly IOERR_AUTH: 7178;
98
+ readonly IOERR_BEGIN_ATOMIC: 7434;
99
+ readonly IOERR_COMMIT_ATOMIC: 7690;
100
+ readonly IOERR_ROLLBACK_ATOMIC: 7946;
101
+ readonly IOERR_DATA: 8202;
102
+ readonly IOERR_CORRUPTFS: 8458;
103
+ readonly IOERR_IN_PAGE: 8714;
104
+ readonly IOERR_BADKEY: 8970;
105
+ readonly IOERR_CODEC: 9226;
106
+ readonly LOCKED_SHAREDCACHE: 262;
107
+ readonly LOCKED_VTAB: 518;
108
+ readonly BUSY_RECOVERY: 261;
109
+ readonly BUSY_SNAPSHOT: 517;
110
+ readonly BUSY_TIMEOUT: 773;
111
+ readonly CANTOPEN_NOTEMPDIR: 270;
112
+ readonly CANTOPEN_ISDIR: 526;
113
+ readonly CANTOPEN_FULLPATH: 782;
114
+ readonly CANTOPEN_CONVPATH: 1038;
115
+ readonly CANTOPEN_DIRTYWAL: 1294;
116
+ readonly CANTOPEN_SYMLINK: 1550;
117
+ readonly CORRUPT_VTAB: 267;
118
+ readonly CORRUPT_SEQUENCE: 523;
119
+ readonly CORRUPT_INDEX: 779;
120
+ readonly READONLY_RECOVERY: 264;
121
+ readonly READONLY_CANTLOCK: 520;
122
+ readonly READONLY_ROLLBACK: 776;
123
+ readonly READONLY_DBMOVED: 1032;
124
+ readonly READONLY_CANTINIT: 1288;
125
+ readonly READONLY_DIRECTORY: 1544;
126
+ readonly ABORT_ROLLBACK: 516;
127
+ readonly CONSTRAINT_CHECK: 275;
128
+ readonly CONSTRAINT_COMMITHOOK: 531;
129
+ readonly CONSTRAINT_FOREIGNKEY: 787;
130
+ readonly CONSTRAINT_FUNCTION: 1043;
131
+ readonly CONSTRAINT_NOTNULL: 1299;
132
+ readonly CONSTRAINT_PRIMARYKEY: 1555;
133
+ readonly CONSTRAINT_TRIGGER: 1811;
134
+ readonly CONSTRAINT_UNIQUE: 2067;
135
+ readonly CONSTRAINT_VTAB: 2323;
136
+ readonly CONSTRAINT_ROWID: 2579;
137
+ readonly CONSTRAINT_PINNED: 2835;
138
+ readonly CONSTRAINT_DATATYPE: 3091;
139
+ readonly NOTICE_RECOVER_WAL: 283;
140
+ readonly NOTICE_RECOVER_ROLLBACK: 539;
141
+ readonly NOTICE_RBU: 795;
142
+ readonly WARNING_AUTOINDEX: 284;
143
+ readonly AUTH_USER: 279;
144
+ readonly OK_LOAD_PERMANENTLY: 256;
145
+ readonly OK_SYMLINK: 512;
146
+ }>;
147
+ /** A primary result code of SQLite 3.53.0 — the type of `SQLiteError.sqliteCode`. */
148
+ export type SQLiteResultCode = (typeof SQLITE_CODES)[keyof typeof SQLITE_CODES];
149
+ /**
150
+ * An extended result code of SQLite 3.53.0. `SQLiteError.sqliteExtendedCode`
151
+ * is typed `SQLiteExtendedResultCode | (number & {})`: open, because a wrong
152
+ * read must stay representable (spec D9), yet still completing these values.
153
+ */
154
+ export type SQLiteExtendedResultCode = (typeof SQLITE_EXTENDED_CODES)[keyof typeof SQLITE_EXTENDED_CODES];
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Pure restart policy for worker slots.
3
+ *
4
+ * Deliberately free of `Worker` and DOM imports so Node tests can
5
+ * drive it in milliseconds — the same reason `scheduler.ts` is pure. B1 lived
6
+ * for months because the only way to reach the pool's decisions was a browser.
7
+ *
8
+ * The caller reports facts; this module returns a decision and never acts.
9
+ */
10
+ export type SupervisorDecision = 'restart' | 'lost' | 'fail-client';
11
+ export type Supervisor = {
12
+ report: (index: number, event: 'spawned' | 'ready' | 'served' | 'died' | 'lost' | 'retired') => SupervisorDecision | undefined;
13
+ };
14
+ export declare const createSupervisor: (options: {
15
+ size: number;
16
+ maxWorkerRestarts?: number | undefined;
17
+ }) => Supervisor;
@@ -0,0 +1,61 @@
1
+ import type { SQLiteQueryAPI, SQLiteTransactionDB, SQLiteTransactionOptions } from './api';
2
+ import type { ReadFn, TransactionFn, WriteFn } from './bulk';
3
+ import { SQLiteError } from './errors';
4
+ import type { Logger } from './logger';
5
+ import type { PoolWorker } from './pool';
6
+ import type { Scheduler } from './scheduler';
7
+ /**
8
+ * Returns the `transaction()` method for a SQLiteDB instance.
9
+ *
10
+ * The returned function acquires exactly one lease for the full lifetime of
11
+ * the transaction. All SQLiteTransactionDB methods call worker-bound derivations
12
+ * directly — never the public API — so no secondary lease acquisition can
13
+ * occur during the callback.
14
+ */
15
+ export declare const createTransaction: (deps: {
16
+ scheduler: Scheduler<PoolWorker>;
17
+ afterWrite: (worker: PoolWorker) => Promise<unknown>;
18
+ /**
19
+ * Called when a connection may still hold an open transaction. The worker
20
+ * is lost rather than repaired: a "dirty worker" state is one more
21
+ * state the barrier would have to reason about, while a respawned
22
+ * connection is transaction-free by construction.
23
+ */
24
+ onPoisoned: (index: number, error: SQLiteError) => void;
25
+ /**
26
+ * Aborted when the client closes, with `CLIENT_CLOSED`.
27
+ *
28
+ * Merged into the transaction's own signal so that closing ABANDONS a
29
+ * running transaction the way a caller's `signal` does — the callback is
30
+ * not interrupted, it simply can no longer reach the database. Without it
31
+ * the caller of a transaction whose callback sits on an `await` that is not
32
+ * a statement waited for ever: nothing else in the transaction observes the
33
+ * client going away.
34
+ */
35
+ closeSignal: AbortSignal;
36
+ /**
37
+ * The client's bulk factory. Called per transaction with the transaction's
38
+ * own read/write and a pass-through `transaction`, so output()'s swap runs
39
+ * on the caller's transaction instead of opening a BEGIN SQLite does not
40
+ * allow.
41
+ */
42
+ bulkFor: (target: {
43
+ read: ReadFn;
44
+ write: WriteFn;
45
+ transaction: TransactionFn;
46
+ /** See `src/bulk.ts`: the batch's place in this transaction's queue. */
47
+ reserve?: () => {
48
+ started: Promise<void>;
49
+ done: () => void;
50
+ };
51
+ }) => {
52
+ bulkWrite: SQLiteQueryAPI['bulkWrite'];
53
+ output: SQLiteQueryAPI['output'];
54
+ };
55
+ /**
56
+ * Reached only through `always`: `rollback()` on a transaction that has
57
+ * already committed warns whatever the `debug` option says (spec R4) — a
58
+ * warning visible only under debug would be the same as silence.
59
+ */
60
+ logger: Pick<Logger, 'always'>;
61
+ }) => <T = void>(callback: (db: SQLiteTransactionDB) => Promise<T>, options?: SQLiteTransactionOptions) => Promise<T>;