@crvouga/sqlite-mem 1.8.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -154,4 +154,4 @@ bun run build
154
154
 
155
155
  ## PR and commits
156
156
 
157
- Use [Conventional Commits](https://www.conventionalcommits.org/) for commits and PR titles (enforced in CI). Prefer squash merges with a conventional title. Releasing is automated via semantic-release see [README.md](README.md#releasing).
157
+ Use [Conventional Commits](https://www.conventionalcommits.org/) for commits and PR titles (enforced on PRs). Prefer squash merges with a conventional title so the npm bump is `feat` minor / `fix` → patch. Direct pushes to `main` with any other subject still publish a patch. See [README.md](README.md#releasing).
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # sqlite-mem
2
2
 
3
+ [npm](https://www.npmjs.com/package/@crvouga/sqlite-mem) · [GitHub](https://github.com/crvouga/sqlite-mem)
4
+
3
5
  Pure TypeScript, completely in-memory SQLite implementation aiming for **full SQLite3 SQL dialect parity** (same statements → same results).
4
6
 
5
7
  - Runs in modern browsers and Node.js / Bun
@@ -41,7 +43,7 @@ Requires Node.js ≥ 20 or Bun ≥ 1.1. The published package is **ESM only** (`
41
43
  ## Usage
42
44
 
43
45
  ```ts
44
- import { Database } from "@crvouga/sqlite-mem";
46
+ import { Database, Snapshot } from "@crvouga/sqlite-mem";
45
47
 
46
48
  const db = new Database();
47
49
 
@@ -57,9 +59,10 @@ db.prepare(`INSERT INTO users (name) VALUES (?)`).run("Alice");
57
59
  const users = db.query<{ id: number; name: string }>(`SELECT * FROM users`);
58
60
  console.log(users);
59
61
 
60
- const snap = db.snapshot();
61
- const db2 = new Database();
62
- db2.restore(snap);
62
+ const seed = db.snapshot();
63
+ const db2 = seed.open();
64
+ const bytes = seed.encode();
65
+ const db3 = Snapshot.decode(bytes).open();
63
66
  ```
64
67
 
65
68
  All methods are **synchronous** — do not `await` them. Browser and Node/Bun share the same in-memory JS surface (no filesystem; `ATTACH` opens a new empty in-memory schema, not a file).
@@ -79,7 +82,7 @@ From the repo root after that install: `bun run example`.
79
82
  ## API
80
83
 
81
84
  ```ts
82
- import { Database, SqliteError } from "@crvouga/sqlite-mem";
85
+ import { Database, Snapshot, SqliteError } from "@crvouga/sqlite-mem";
83
86
 
84
87
  interface DatabaseOptions {
85
88
  seed?: number | bigint; // default 1 — ignored when random is "os"
@@ -93,8 +96,7 @@ interface Database {
93
96
  query<T = QueryRow>(sql: string, params?: BindValue[]): T[];
94
97
  prepare(sql: string): Statement;
95
98
  transaction<T>(fn: () => T): T;
96
- snapshot(): Uint8Array;
97
- restore(snapshot: Uint8Array): void;
99
+ snapshot(): Snapshot;
98
100
  close(): void;
99
101
  [Symbol.dispose]?(): void; // alias for close() when Symbol.dispose exists
100
102
  readonly changes: number;
@@ -121,6 +123,12 @@ interface ResultSet {
121
123
  lastInsertRowid: number | bigint;
122
124
  }
123
125
 
126
+ class Snapshot {
127
+ open(options?: DatabaseOptions): Database;
128
+ encode(): Uint8Array;
129
+ static decode(bytes: Uint8Array): Snapshot;
130
+ }
131
+
124
132
  class SqliteError extends Error {
125
133
  readonly category: ErrorCategory; // syntax, no_such_table, constraint_unique, misuse, …
126
134
  readonly sqliteCode: string; // always set; default "SQLITE_ERROR"
@@ -128,7 +136,7 @@ class SqliteError extends Error {
128
136
  }
129
137
  ```
130
138
 
131
- Stick to `Database`, `Statement`, and `SqliteError` for application code. Advanced internals (`parse`, `tokenize`, `evalExpr`, snapshot codec pieces, `SqlValue` utilities, `Prng`, …) are available only from `@crvouga/sqlite-mem/unstable` and are **exempt from semver**.
139
+ Stick to `Database`, `Snapshot`, `Statement`, and `SqliteError` for application code. Advanced internals (`parse`, `tokenize`, `evalExpr`, snapshot codec pieces, `SqlValue` utilities, `Prng`, …) are available only from `@crvouga/sqlite-mem/unstable` and are **exempt from semver**.
132
140
 
133
141
  ### Method semantics
134
142
 
@@ -138,7 +146,10 @@ Stick to `Database`, `Statement`, and `SqliteError` for application code. Advanc
138
146
  | `query(sql, params?)` | **Single statement only** (trailing `;` is fine). Returns all rows. Multi-statement scripts throw `misuse`. |
139
147
  | `prepare(sql)` | **Single statement only**. Parses immediately; AST is reused. Pass binds as rest args to `run` / `all` / `get` / `result` on each call. |
140
148
  | `transaction(fn)` | If idle: `BEGIN` → `fn()` → `COMMIT`, or `ROLLBACK` + rethrow. If already in a transaction: nested savepoint. Nested SQL `BEGIN` still errors. `close()` inside `fn` throws `misuse`. |
141
- | `snapshot` / `restore` | Custom binary format (see below). |
149
+ | `snapshot()` | Freeze a reusable {@link Snapshot} template (no encode). Illegal inside a transaction. |
150
+ | `Snapshot.open()` | Copy-on-write fork from a template. Parent stays open. |
151
+ | `Snapshot.encode()` | Lazy SQLM blob for persistence / worker boot (computed once, cached). |
152
+ | `Snapshot.decode(bytes)` | Decode a blob once per `Uint8Array` (WeakMap); later `open()` calls are CoW. |
142
153
  | `close()` | Idempotent; rolls back an open SQL transaction; further ops throw `misuse`. Also available as `[Symbol.dispose]` when supported. |
143
154
 
144
155
  SQL `BEGIN` / `COMMIT` / `ROLLBACK` / `SAVEPOINT` / `RELEASE` are first-class. Empty / comment-only SQL on `prepare` / `query` throws `misuse` (`empty statement`), matching SQLite prepare failure.
@@ -174,13 +185,17 @@ Duplicate column names collapse in row objects (last write wins). Use `stmt.resu
174
185
 
175
186
  ### Snapshots
176
187
 
188
+ - `db.snapshot()` returns a frozen in-memory {@link Snapshot}. Per-test isolation should `seed.open()` (copy-on-write, ~µs). Encoded bytes are **lazy** via `snapshot.encode()`.
177
189
  - Format magic `SQLM` followed by an explicit little-endian format-version `u32` — **not** a portable `.sqlite` file and not loadable by the SQLite CLI.
178
- - Round-trips ordinary tables, views, indexes, change counters, PRNG state, and clock.
190
+ - Round-trips ordinary tables, views, indexes (SQLM v4 compact index keys; v3 persisted full `IndexStore`; v1/v2 blobs rebuild indexes on hydrate), change counters, PRNG state, and clock.
179
191
  - **Not** encoded: triggers, ATTACH’d schemas, virtual tables (FTS / RTREE / …), `userVersion`.
180
- - Cannot `restore()` while a transaction is open.
181
- - `restore()` replaces `now` with a fixed clock from the snapshot (a live `() => Date` is overwritten). `{ now: "system" }` stays live after restore.
182
- - Equivalent databases produce byte-identical snapshots (schema/rows sorted) **within a single library version**.
183
- - **Compatibility policy:** newer library versions can always restore older snapshots; older libraries cannot restore newer format versions (`snapshot_version` / `SQLITE_FORMAT`). Corrupt magic yields a distinct error.
192
+ - Cannot `snapshot()` while a transaction is open.
193
+ - `Snapshot.decode(bytes)` does not mutate the input `Uint8Array`. The same buffer object is decoded once (WeakMap) and later opens are CoW.
194
+ - `open()` shares frozen tables until either side writes; idle `open().snapshot().encode()` is byte-identical to `snapshot().encode()`.
195
+ - `open()` uses a fixed clock from the snapshot unless you pass `{ now: "system" }`, which stays live.
196
+ - Equivalent databases produce byte-identical `encode()` output (schema/rows sorted) **within a single library version**.
197
+ - Per-test isolation (CI-tier, 200 users + 800 items): `Snapshot.open` ~µs; `encode()` / `decode().open()` is the persistence path. See [benchmarks/PERFORMANCE.md](benchmarks/PERFORMANCE.md).
198
+ - **Compatibility policy:** newer library versions can always decode older snapshots; older libraries cannot decode newer format versions (`snapshot_version` / `SQLITE_FORMAT`). Corrupt magic yields a distinct error.
184
199
 
185
200
  ## Determinism
186
201
 
@@ -189,9 +204,9 @@ The engine is deterministic by default. Invariants:
189
204
  | Source | Default | Override / notes |
190
205
  | --- | --- | --- |
191
206
  | `random()` / `randomblob()` | Seeded xorshift64* (`seed: 1`) | `new Database({ seed })` or `{ random: "os" }` for CSPRNG (not rolled back / not restored) |
192
- | `date('now')` / friends | Fixed `2000-01-01T00:00:00.000Z` | `new Database({ now: Date \| (() => Date) \| "system" })` — `"system"` is wall clock and is **not** frozen by `restore()` |
193
- | Table scans | Rowid order | Same order after `snapshot`/`restore` |
194
- | Snapshots | Sorted schema/rows + PRNG state + clock | Restored into PRNG and `now` |
207
+ | `date('now')` / friends | Fixed `2000-01-01T00:00:00.000Z` | `new Database({ now: Date \| (() => Date) \| "system" })` — `"system"` is wall clock and is **not** frozen by `open()` |
208
+ | Table scans | Rowid order | Same order after `snapshot`/`open` |
209
+ | Snapshots | Sorted schema/rows + PRNG state + clock | Applied by `open()` into PRNG and `now` |
195
210
  | Transactions | PRNG rolls back with `ROLLBACK`/`SAVEPOINT` | Matches data rollback |
196
211
  | Numbers | IEEE `-0` canonicalized to `+0` | Bind, affinity, and arithmetic |
197
212
 
@@ -238,7 +253,7 @@ This is **not** a drop-in replacement for `sql.js`, `@sqlite.org/sqlite-wasm`, o
238
253
  2. **No named-object binds and no sticky `bind()`** — pass positional rest args / arrays in declaration order to `query` / `run` / `all` / `get` / `result`.
239
254
  3. **`query` / `prepare` are single-statement only** — multi-statement scripts belong in `exec()` (which does not take bind parameters).
240
255
  4. **`exec` returns `void` and takes no params** — use `db.prepare(…).run(…)` or `db.query(…)` for binds; use `db.changes` / `stmt.run()` for counters.
241
- 5. **`'now'` is not wall-clock** unless you pass `{ now: "system" }` or `{ now: () => new Date() }`. Default is year 2000. `restore()` freezes a snapshot clock except when constructed with `"system"`.
256
+ 5. **`'now'` is not wall-clock** unless you pass `{ now: "system" }` or `{ now: () => new Date() }`. Default is year 2000. `open()` freezes a snapshot clock except when constructed with `"system"`.
242
257
  6. **`random()` is seeded**, not OS entropy, unless you pass `{ random: "os" }`. Snapshots restore the seeded PRNG; OS entropy is not rewound.
243
258
  7. **Snapshots are not `.sqlite` files** and do not round-trip FTS / triggers / ATTACH.
244
259
  8. **No better-sqlite3 extras** — no `iterate`, `pluck`/`raw`, `safeIntegers` option, `pragma()` helper, `loadExtension`, or SQLite-file `serialize()`.
@@ -274,16 +289,16 @@ Publishing is fully automated. You never bump `version` or run `npm publish` by
274
289
 
275
290
  ### How a release happens
276
291
 
277
- 1. Push or merge to `main` with [Conventional Commits](https://www.conventionalcommits.org/).
292
+ 1. Push or merge to `main`. Prefer [Conventional Commits](https://www.conventionalcommits.org/) so the bump is `feat` → minor / `fix` → patch / `BREAKING` → major; any other subject still publishes a patch.
278
293
  2. CI runs commitlint, format/lint/typecheck, build, package verification, tests, browser smoke, and benchmarks.
279
294
  3. If every gate is green, [semantic-release](https://semantic-release.gitbook.io/) analyzes commits since the last git tag, bumps semver, publishes to npm, and creates a GitHub Release.
280
295
 
281
296
  | Commit | Version bump |
282
297
  | --- | --- |
283
- | `fix: …` | patch (`0.1.0` → `0.1.1`) |
284
- | `feat: …` | minor (`0.1.0` → `0.2.0`) |
285
- | `feat!: …` or `BREAKING CHANGE:` footer | major (`0.2.0` → `1.0.0`) |
286
- | `docs:`, `chore:`, `refactor:`, `test:`, | no release |
298
+ | `fix: …` / `perf: …` | patch (`1.9.0` → `1.9.1`) |
299
+ | `feat: …` | minor (`1.9.0` → `1.10.0`) |
300
+ | `feat!: …` or `BREAKING CHANGE:` footer | major (`1.10.0` → `2.0.0`) |
301
+ | any other message on `main` (including Cursor-style subjects) | patch |
287
302
 
288
303
  Examples:
289
304
 
@@ -292,8 +307,7 @@ feat: add window function support
292
307
  fix: handle NULL in UNIQUE constraints
293
308
  feat!: rename snapshot() return type
294
309
 
295
- chore: tweak CI timeouts
296
- docs: clarify determinism table
310
+ Refactor AdoptedDatabase interface # still publishes a patch
297
311
  ```
298
312
 
299
313
  PR titles must also follow Conventional Commits (enforced in CI). Prefer squash merges with a conventional title.
@@ -327,7 +341,7 @@ Do this once so CI can publish. Full checklist: **[docs/SECRETS.md](./docs/SECRE
327
341
 
328
342
  Validate the checklist anytime with `bun run secrets:doctor`.
329
343
 
330
- After that, every green push to `main` with releasable commits updates npm automatically.
344
+ After that, every green push to `main` updates npm automatically (`feat`/`fix`/`BREAKING` pick the bump; anything else is a patch).
331
345
 
332
346
  ## License
333
347
 
@@ -11,8 +11,8 @@
11
11
  {
12
12
  "id": "snapshot-sqlm",
13
13
  "scope": "snapshot",
14
- "predicate": "snapshot() bytes are SQLM, not a .sqlite file",
15
- "specifiedBehavior": "Custom codec; logical Dump after restore matches pre-snapshot Dump.",
14
+ "predicate": "snapshot().encode() bytes are SQLM, not a .sqlite file",
15
+ "specifiedBehavior": "Custom codec; logical Dump after Snapshot.open matches pre-snapshot Dump.",
16
16
  "pinnedBy": ["SNP-hdr-01", "SNP-rt-01"]
17
17
  },
18
18
  {
@@ -82,7 +82,7 @@
82
82
  "id": "snapshot-exclusions",
83
83
  "scope": "snapshot",
84
84
  "predicate": "triggers, ATTACH, virtual tables, and user_version are not in SQLM",
85
- "specifiedBehavior": "restore() outcome is pinned per omitted feature.",
85
+ "specifiedBehavior": "decode().open() outcome is pinned per omitted feature.",
86
86
  "pinnedBy": ["SNP-omit-01", "SNP-omit-02", "SNP-omit-03", "SNP-omit-04", "TRG-snap-01", "ATT-snap-01", "FTS-snap-01"]
87
87
  },
88
88
  {
@@ -116,8 +116,8 @@
116
116
  {
117
117
  "id": "user-version-snapshot",
118
118
  "scope": "pragma",
119
- "predicate": "user_version is not restored from SQLM",
120
- "specifiedBehavior": "PRAGMA user_version after restore is the default unless re-set.",
119
+ "predicate": "user_version is not encoded in SQLM",
120
+ "specifiedBehavior": "PRAGMA user_version after decode().open() is the default unless re-set.",
121
121
  "pinnedBy": ["PRG-beh-05", "SNP-omit-04"]
122
122
  },
123
123
  {
@@ -371,7 +371,7 @@ const TAIL: CatalogSection[] = [
371
371
  ["now-03", "column DEFAULT CURRENT_TIMESTAMP", D, "README"],
372
372
  ["now-04", "now system tracks wall clock", D, "README"],
373
373
  ["now-05", "now fn called per statement", D, "README"],
374
- ["now-06", "restore freezes clock", D, "README"],
374
+ ["now-06", "open freezes clock", D, "README"],
375
375
  ]),
376
376
  section("JSN", "JSON", true, [
377
377
  ["json-01", "json() minify/validate"],
@@ -756,15 +756,21 @@ const TAIL: CatalogSection[] = [
756
756
  ["hdr-02", "corrupt magic error"],
757
757
  ["hdr-03", "truncated blob error"],
758
758
  ["hdr-04", "future version snapshot_version"],
759
- ["txn-01", "restore during txn errors"],
760
- ["rep-01", "restore replaces entire state"],
761
- ["now-01", "restore keeps system clock live", D],
762
- ["now-02", "restore overwrites Date fn", D],
763
- ["rng-01", "restore with random os does not rewind", D],
759
+ ["txn-01", "snapshot during txn errors"],
760
+ ["now-01", "open with system clock stays live", D],
761
+ ["now-02", "open overwrites Date fn with snapshot clock", D],
762
+ ["rng-01", "open with random os does not rewind", D],
764
763
  ["omit-01", "triggers not encoded", D],
765
764
  ["omit-02", "ATTACH not encoded", D],
766
765
  ["omit-03", "virtual tables not encoded", D],
767
766
  ["omit-04", "user_version not encoded", D],
767
+ ["open-01", "Snapshot.open CoW fork"],
768
+ ["open-02", "encode does not mutate; decode reuses buffer"],
769
+ ["prop-01", "snapshot restore idempotence", F, undefined, ["tests/fuzz/snapshot.test.ts"]],
770
+ ["prop-02", "insert-then-delete probe preservation", F, undefined, ["tests/fuzz/snapshot.test.ts"]],
771
+ ["prop-03", "index probe equivalence after restore", F, undefined, ["tests/fuzz/snapshot.test.ts"]],
772
+ ["obj-01", "object round-trip corpus", F, undefined, ["tests/contract/snapshots/objects.test.ts"]],
773
+ ["obj-02", "view and index probes after restore", F, undefined, ["tests/contract/snapshots/views-indexes.test.ts"]],
768
774
  ]),
769
775
  section("DET", "Determinism invariants", true, [
770
776
  ["seed-01", "same seed identical random streams", D],
@@ -828,9 +834,10 @@ const TAIL: CatalogSection[] = [
828
834
  ["robust-01", "SqliteError-only / timeout / SQLM bit-flip", F],
829
835
  ["slt-01", "sqllogictest vendor corpus differential", F],
830
836
  ["dst-01", "mixed dump-after-each DST engine", F],
831
- ["prop-01", "snapshot restore idempotence", P],
832
- ["prop-02", "insert then delete snapshot bytes", P],
833
- ["prop-03", "index-added vs index-free equivalence", P],
837
+ ["snap-01", "snapshot restore probe fuzz", F, undefined, ["tests/fuzz/snapshot.test.ts"]],
838
+ ["prop-01", "classifyDiff equal outcome", P, undefined, ["tests/contract/catalog/fzz.test.ts"]],
839
+ ["prop-02", "classifyDiff failure outcome", P, undefined, ["tests/contract/catalog/fzz.test.ts"]],
840
+ ["prop-03", "classifyDiff known-divergence outcome", P, undefined, ["tests/contract/catalog/fzz.test.ts"]],
834
841
  ["prop-04", "transaction throw never ran", P],
835
842
  ["prop-05", "exec a;b equivalent split exec", P],
836
843
  ["seed-01", "default seed 0x5a17e0e1", F],
@@ -1,5 +1,6 @@
1
1
  import { type DatabaseOptions, type RandomMode } from "../runtime/index.js";
2
2
  import type { BindValue, QueryRow } from "../types/value.js";
3
+ import { type Snapshot } from "./snapshot.js";
3
4
  import { Statement } from "./statement.js";
4
5
  /**
5
6
  * Pure TypeScript in-memory SQLite database.
@@ -72,24 +73,14 @@ export declare class Database {
72
73
  */
73
74
  transaction<T>(fn: () => T): T;
74
75
  /**
75
- * Serialize schema, rows, PRNG state, and clock into a custom snapshot blob.
76
+ * Freeze this database into a reusable {@link Snapshot} template.
76
77
  *
77
- * This is not a `.sqlite` file. Restore it with {@link restore}.
78
+ * Does not encode SQLM bytes. Call {@link Snapshot.encode} to persist, or
79
+ * {@link Snapshot.open} for a copy-on-write fork.
78
80
  *
79
- * @throws {SqliteError} If the database is closed.
80
- */
81
- snapshot(): Uint8Array;
82
- /**
83
- * Replace this database's contents with a blob from {@link snapshot}.
84
- *
85
- * Restores PRNG state and the clock when the snapshot includes them (v2).
86
- * Newer library versions can restore older snapshots; older libraries cannot
87
- * restore newer format versions.
88
- *
89
- * @param snapshot - Bytes previously returned by {@link snapshot}.
90
- * @throws {SqliteError} If the database is closed, a transaction is open, or the blob is invalid.
81
+ * @throws {SqliteError} If the database is closed or a transaction is open.
91
82
  */
92
- restore(snapshot: Uint8Array): void;
83
+ snapshot(): Snapshot;
93
84
  /**
94
85
  * Close the database. Further SQL throws {@link SqliteError}. Idempotent.
95
86
  *
@@ -117,4 +108,5 @@ export declare class Database {
117
108
  get totalChanges(): number;
118
109
  private prepareSingle;
119
110
  }
111
+ export { Snapshot } from "./snapshot.js";
120
112
  export type { DatabaseOptions };
@@ -0,0 +1,21 @@
1
+ import { type DatabaseOptions } from "../runtime/index.js";
2
+ import { type Database } from "./database.js";
3
+ /**
4
+ * Frozen in-memory database template. {@link open} is a copy-on-write fork.
5
+ * Encoded SQLM bytes are produced lazily via {@link encode}.
6
+ */
7
+ export declare class Snapshot {
8
+ private cachedBytes;
9
+ /** Encoded SQLM blob. Computed once; never mutates a buffer passed to {@link decode}. */
10
+ encode(): Uint8Array;
11
+ /**
12
+ * Copy-on-write database from this frozen template. Does not re-encode or re-decode.
13
+ */
14
+ open(options?: DatabaseOptions): Database;
15
+ /**
16
+ * Decode `bytes` once and freeze the result. The same `Uint8Array` object
17
+ * returns the same {@link Snapshot} (WeakMap), so later {@link open} calls
18
+ * are copy-on-write forks after the first hydrate.
19
+ */
20
+ static decode(bytes: Uint8Array): Snapshot;
21
+ }
@@ -1,11 +1,11 @@
1
1
  import type { Expr } from "../ast/nodes.js";
2
2
  import type { IndexStore } from "../indexes/index.js";
3
3
  import type { Row, Rowid } from "../storage/row.js";
4
- import type { ColumnInfo, Table } from "../storage/table.js";
4
+ import type { Table } from "../storage/table.js";
5
5
  import type { SqlValue } from "../types/value.js";
6
6
  export type CheckEvaluator = (expr: Expr, row: Row) => SqlValue;
7
- export declare function checkNotNull(columns: readonly ColumnInfo[], row: Row, tableName?: string): void;
8
- export declare function checkPrimaryKey(columns: readonly ColumnInfo[], row: Row, tableName?: string): void;
7
+ export declare function checkNotNull(table: Table, row: Row): void;
8
+ export declare function checkPrimaryKey(table: Table, row: Row): void;
9
9
  export declare function checkUnique(index: IndexStore, values: readonly SqlValue[], rowid?: Rowid): void;
10
10
  export declare function checkExpressions(expressions: readonly Expr[], row: Row, evaluate: CheckEvaluator, constraintName?: string): void;
11
11
  export declare function checkTableConstraints(table: Table, row: Row, evaluate: CheckEvaluator): void;
package/dist/index.d.ts CHANGED
@@ -21,7 +21,7 @@
21
21
  *
22
22
  * @module
23
23
  */
24
- export { Database, type DatabaseOptions } from "./api/database.js";
24
+ export { Database, Snapshot, type DatabaseOptions } from "./api/database.js";
25
25
  export { type RunResult, Statement } from "./api/statement.js";
26
26
  export { type ErrorCategory, SqliteError } from "./errors/index.js";
27
27
  export type { ResultSet } from "./executor/result.js";