@orkestrel/sqlite 0.0.1 → 0.0.2

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/README.md CHANGED
@@ -1,9 +1,13 @@
1
1
  # @orkestrel/sqlite
2
2
 
3
- A typed, synchronous SQLite wrapper for the `@orkestrel` line — a thin,
4
- zero-dependency skin over Node's built-in `node:sqlite` (`DatabaseSync` /
5
- `StatementSync`) giving prepared statements, transactions, and pragmas. Built
6
- on `@orkestrel/contract` for its boundary narrowing.
3
+ A typed, synchronous SQLite wrapper for the `@orkestrel` line — a thin skin
4
+ over Node's built-in `node:sqlite` (`DatabaseSync` / `StatementSync`) giving
5
+ prepared statements, transactions, and pragmas, with a single runtime
6
+ dependency: `@orkestrel/contract`, used for its boundary narrowing.
7
+
8
+ `node:sqlite` is experimental on current Node versions — importing this
9
+ package emits an `ExperimentalWarning` at runtime until Node stabilizes the
10
+ module.
7
11
 
8
12
  ## Install
9
13
 
@@ -112,21 +112,32 @@ function bindParameters(parameters) {
112
112
  * wrapper runs SQL.
113
113
  *
114
114
  * @remarks
115
- * Created by `database.prepare(sql)`. Bare named parameters are enabled on
116
- * construction so a record's keys bind without the SQL prefix character. Each
117
- * method binds the optional parameters (an array spread to `?` placeholders, a
118
- * record passed as a single named object) and executes synchronously, mapping any
119
- * native fault to a `SQLiteError`. Row values arrive as the native
120
- * {@link SQLiteRow} types; the typed layer above (the driver) imposes a precise
121
- * shape through a contract rather than re-narrowing here (AGENTS §14).
115
+ * Created by `database.prepare(sql)`, which threads a liveness check (internal —
116
+ * this constructor's second parameter is not part of the documented surface).
117
+ * Bare named parameters are enabled on construction so a record's keys bind
118
+ * without the SQL prefix character. Each method first gates on that liveness
119
+ * check, throwing a `CLOSED` `SQLiteError` once the owning connection has been
120
+ * closed a statement prepared on a connection that is later closed and then
121
+ * reconnected stays `CLOSED`; a fresh statement must be prepared on the new
122
+ * connection. Each method then binds the optional parameters (an array spread
123
+ * to `?` placeholders, a record passed as a single named object) and executes
124
+ * synchronously, mapping any native fault to a `SQLiteError` — including a
125
+ * mid-stream fault from `iterate`'s lazy native iterator, stepped inside its own
126
+ * try/catch so a fault on a later row is mapped exactly like an eager one. Row
127
+ * values arrive as the native {@link SQLiteRow} types; the typed layer above
128
+ * (the driver) imposes a precise shape through a contract rather than
129
+ * re-narrowing here (AGENTS §14).
122
130
  */
123
131
  var SQLiteStatement = class {
124
132
  #statement;
125
- constructor(statement) {
133
+ #closed;
134
+ constructor(statement, closed) {
126
135
  this.#statement = statement;
136
+ this.#closed = closed;
127
137
  this.#statement.setAllowBareNamedParameters(true);
128
138
  }
129
139
  run(parameters) {
140
+ this.#require();
130
141
  try {
131
142
  const bound = bindParameters(parameters);
132
143
  const result = "named" in bound ? this.#statement.run(bound.named) : this.#statement.run(...bound.positional);
@@ -139,6 +150,7 @@ var SQLiteStatement = class {
139
150
  }
140
151
  }
141
152
  get(parameters) {
153
+ this.#require();
142
154
  try {
143
155
  const bound = bindParameters(parameters);
144
156
  return "named" in bound ? this.#statement.get(bound.named) : this.#statement.get(...bound.positional);
@@ -147,6 +159,7 @@ var SQLiteStatement = class {
147
159
  }
148
160
  }
149
161
  all(parameters) {
162
+ this.#require();
150
163
  try {
151
164
  const bound = bindParameters(parameters);
152
165
  return "named" in bound ? this.#statement.all(bound.named) : this.#statement.all(...bound.positional);
@@ -155,12 +168,30 @@ var SQLiteStatement = class {
155
168
  }
156
169
  }
157
170
  iterate(parameters) {
171
+ this.#require();
172
+ let native;
158
173
  try {
159
174
  const bound = bindParameters(parameters);
160
- return "named" in bound ? this.#statement.iterate(bound.named) : this.#statement.iterate(...bound.positional);
175
+ native = "named" in bound ? this.#statement.iterate(bound.named) : this.#statement.iterate(...bound.positional);
161
176
  } catch (error) {
162
177
  throw wrapError(error);
163
178
  }
179
+ return this.#stream(native);
180
+ }
181
+ #require() {
182
+ if (this.#closed()) throw new SQLiteError("CLOSED", "Statement is closed — its connection was closed; prepare a new statement");
183
+ }
184
+ *#stream(native) {
185
+ for (;;) {
186
+ let result;
187
+ try {
188
+ result = native.next();
189
+ } catch (error) {
190
+ throw wrapError(error);
191
+ }
192
+ if (result.done === true) return;
193
+ yield result.value;
194
+ }
164
195
  }
165
196
  };
166
197
  //#endregion
@@ -174,10 +205,13 @@ var SQLiteStatement = class {
174
205
  * private gate that throws a `CLOSED` `SQLiteError` before `connect` or after
175
206
  * `close`. `exec` runs result-less SQL; `prepare` compiles a `SQLiteStatement`;
176
207
  * `transaction` wraps a scope in `BEGIN` / `COMMIT`, rolling back on a throw;
177
- * `pragma` reads (or sets then reads) one PRAGMA value `name` is trusted
208
+ * `begin` / `commit` / `rollback` expose those same primitives directly for a
209
+ * long-lived or externally-driven transaction; `pragma` reads (or sets then
210
+ * reads) one PRAGMA value — `name` is trusted
178
211
  * internal use only, never untrusted input, since pragma names cannot be bound
179
- * as parameters. A native fault surfaces as a `SQLiteError` mapped at the
180
- * boundary.
212
+ * as parameters. `transacting` reports whether a transaction is currently open
213
+ * (node:sqlite's `isTransaction`), `false` when not connected. A native fault
214
+ * surfaces as a `SQLiteError` mapped at the boundary.
181
215
  */
182
216
  var SQLiteDatabase = class {
183
217
  #path;
@@ -199,6 +233,9 @@ var SQLiteDatabase = class {
199
233
  get connected() {
200
234
  return this.#database !== void 0;
201
235
  }
236
+ get transacting() {
237
+ return this.#database?.isTransaction ?? false;
238
+ }
202
239
  connect() {
203
240
  if (this.#database === void 0) this.#database = new node_sqlite.DatabaseSync(this.#path, {
204
241
  readOnly: this.#readonly,
@@ -224,23 +261,40 @@ var SQLiteDatabase = class {
224
261
  }
225
262
  prepare(sql) {
226
263
  try {
227
- return new SQLiteStatement(this.#require().prepare(sql));
264
+ const database = this.#require();
265
+ return new SQLiteStatement(database.prepare(sql), () => this.#database !== database);
228
266
  } catch (error) {
229
267
  throw wrapError(error);
230
268
  }
231
269
  }
232
270
  transaction(scope) {
233
- this.exec("BEGIN");
271
+ this.begin();
272
+ let result;
234
273
  try {
235
- const result = scope();
236
- this.exec("COMMIT");
237
- return result;
274
+ result = scope();
238
275
  } catch (error) {
239
276
  try {
240
- this.exec("ROLLBACK");
277
+ this.rollback();
241
278
  } catch {}
242
279
  throw error;
243
280
  }
281
+ if ((0, _orkestrel_contract.isPromiseLike)(result)) {
282
+ try {
283
+ this.rollback();
284
+ } catch {}
285
+ throw new SQLiteError("UNKNOWN", "transaction(scope) requires a synchronous scope — an async or Promise-returning scope cannot commit or roll back before its awaited work runs; use begin() / commit() / rollback() directly for a transaction that spans async caller code");
286
+ }
287
+ this.commit();
288
+ return result;
289
+ }
290
+ begin() {
291
+ this.exec("BEGIN");
292
+ }
293
+ commit() {
294
+ this.exec("COMMIT");
295
+ }
296
+ rollback() {
297
+ this.exec("ROLLBACK");
244
298
  }
245
299
  pragma(name, value) {
246
300
  if (value !== void 0) this.exec("PRAGMA " + name + " = " + value);
@@ -268,7 +322,7 @@ var SQLiteDatabase = class {
268
322
  *
269
323
  * @example
270
324
  * ```ts
271
- * import { createSQLiteDatabase } from '@src/server'
325
+ * import { createSQLiteDatabase } from '@orkestrel/sqlite'
272
326
  *
273
327
  * const db = createSQLiteDatabase({ path: ':memory:' })
274
328
  * db.connect()
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["#statement","#path","#readonly","#timeout","#foreignKeys","#bigints","#database","#require"],"sources":["../../../src/server/constants.ts","../../../src/server/errors.ts","../../../src/server/helpers.ts","../../../src/server/SQLiteStatement.ts","../../../src/server/SQLiteDatabase.ts","../../../src/server/factories.ts"],"sourcesContent":["// The wrapper's numeric SQLite result codes (AGENTS §5 constants file).\n\n/**\n * SQLite result code for a constraint violation (`SQLITE_CONSTRAINT`).\n *\n * @remarks\n * A native `errcode` packs the primary result in its low byte, with extended codes\n * in the high bits (e.g. `SQLITE_CONSTRAINT_UNIQUE`), so the low byte is masked off\n * before comparing. Read only by `wrapError`.\n */\nexport const SQLITE_CONSTRAINT = 19\n\n/**\n * SQLite result code for a locked-database fault (`SQLITE_BUSY`).\n *\n * @remarks\n * A native `errcode` packs the primary result in its low byte, with extended codes\n * in the high bits, so the low byte is masked off before comparing. Read only by\n * `wrapError`.\n */\nexport const SQLITE_BUSY = 5\n","import type { SQLiteErrorCode } from './types.js'\n\n// Errors for the SQLite wrapper. A single `SQLiteError` carries a\n// machine-readable `code` mapped from the native `node:sqlite` fault at the\n// boundary (`wrapError`), so a `catch` branches on `error.code` rather than\n// parsing a message. Mirrors the IndexedDB wrapper's `IndexedDBError`; its three\n// codes are deliberately lean — the wrapper sits right on the raw SQLite surface,\n// where the constraint fault is the one worth naming, `CLOSED` is the\n// wrapper-lifecycle fault, and everything else is `UNKNOWN` (AGENTS §12).\n\n/**\n * An error thrown by the SQLite wrapper.\n *\n * @remarks\n * Carries a {@link SQLiteErrorCode} and an optional `context` record (e.g. the\n * native SQLite `errcode`). Construct it directly for the `CLOSED`\n * wrapper-lifecycle fault; the internal `wrapError` maps a native `node:sqlite`\n * error to the right code at the boundary. Narrow a caught value with\n * {@link isSQLiteError}.\n *\n * @example\n * ```ts\n * try {\n * \tstatement.run({ id: 'u1' })\n * } catch (error) {\n * \tif (isSQLiteError(error) && error.code === 'CONSTRAINT') {\n * \t\t// a UNIQUE / PRIMARY KEY violation\n * \t}\n * }\n * ```\n */\nexport class SQLiteError extends Error {\n\treadonly code: SQLiteErrorCode\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(code: SQLiteErrorCode, message: string, context?: Readonly<Record<string, unknown>>) {\n\t\tsuper(message)\n\t\tthis.name = 'SQLiteError'\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/**\n * Whether a value is a {@link SQLiteError}.\n *\n * @param value - The value to test\n * @returns `true` when `value` is a `SQLiteError`\n */\nexport function isSQLiteError(value: unknown): value is SQLiteError {\n\treturn value instanceof SQLiteError\n}\n","import type { SQLiteParameters, SQLiteValue } from './types.js'\nimport { isArray, isObject } from '@orkestrel/contract'\nimport { SQLITE_BUSY, SQLITE_CONSTRAINT } from './constants.js'\nimport { SQLiteError } from './errors.js'\n\n// The wrapper's boundary helpers, shared by `SQLiteDatabase` and `SQLiteStatement`:\n// `wrapError` maps a thrown native `node:sqlite` error to a typed `SQLiteError`\n// (the one honest narrowing point — `isObject` + `in`, never `as`, per AGENTS\n// §14), and `bindParameters` normalizes the wrapper's `SQLiteParameters` to the\n// shape a native `StatementSync` call expects (positional spread vs. a single\n// named record). Both are pure.\n\n/**\n * Convert a thrown native `node:sqlite` error into a typed {@link SQLiteError}.\n *\n * @remarks\n * The single boundary mapping for the wrapper. The thrown value arrives as\n * `unknown` and is narrowed with `isObject` + the `in` operator (never `as`, and\n * not `isRecord` — a native `node:sqlite` error is an `Error` instance, so its\n * prototype fails the plain-record test) to read its `errcode` — a numeric SQLite\n * result code whose low byte identifies a constraint violation\n * (`SQLITE_CONSTRAINT`), mapped to code `'CONSTRAINT'`; a locked-database fault\n * (`SQLITE_BUSY`) is mapped to `'BUSY'`; anything else is `'UNKNOWN'`. The\n * original message is preserved and `{ errcode }` carried in `context` when\n * present. An already-typed `SQLiteError` is returned unchanged.\n *\n * @param error - The thrown value to convert\n * @returns The equivalent `SQLiteError`\n */\nexport function wrapError(error: unknown): SQLiteError {\n\tif (error instanceof SQLiteError) return error\n\tconst errcode =\n\t\tisObject(error) && 'errcode' in error && typeof error.errcode === 'number'\n\t\t\t? error.errcode\n\t\t\t: undefined\n\tconst message = error instanceof Error ? error.message : 'Unknown SQLite error'\n\tconst code =\n\t\terrcode !== undefined && (errcode & 0xff) === SQLITE_CONSTRAINT\n\t\t\t? 'CONSTRAINT'\n\t\t\t: errcode !== undefined && (errcode & 0xff) === SQLITE_BUSY\n\t\t\t\t? 'BUSY'\n\t\t\t\t: 'UNKNOWN'\n\treturn new SQLiteError(code, message, errcode !== undefined ? { errcode } : undefined)\n}\n\n/**\n * Normalize {@link SQLiteParameters} to the binding shape a native `StatementSync`\n * call expects.\n *\n * @remarks\n * Positional parameters (an array) bind to `?` placeholders and are spread into\n * the call; named parameters (a record) bind to bare `:name` placeholders and are\n * passed as a single leading object. Returning a discriminated result keeps the\n * `SQLiteStatement` dispatch typed against the native overloads without `as`.\n *\n * @param parameters - The wrapper parameters, or `undefined` for none\n * @returns `{ positional }` for an array (empty when omitted) or `{ named }` for a record\n */\nexport function bindParameters(\n\tparameters?: SQLiteParameters,\n):\n\t| { readonly positional: readonly SQLiteValue[] }\n\t| { readonly named: Readonly<Record<string, SQLiteValue>> } {\n\tif (parameters === undefined) return { positional: [] }\n\tif (isArray<SQLiteValue>(parameters)) return { positional: parameters }\n\treturn { named: parameters }\n}\n","import type { StatementSync } from 'node:sqlite'\nimport type {\n\tSQLiteParameters,\n\tSQLiteRow,\n\tSQLiteRunResult,\n\tSQLiteStatementInterface,\n} from './types.js'\nimport { bindParameters, wrapError } from './helpers.js'\n\n/**\n * A prepared statement over `node:sqlite`'s `StatementSync` — the only way the\n * wrapper runs SQL.\n *\n * @remarks\n * Created by `database.prepare(sql)`. Bare named parameters are enabled on\n * construction so a record's keys bind without the SQL prefix character. Each\n * method binds the optional parameters (an array spread to `?` placeholders, a\n * record passed as a single named object) and executes synchronously, mapping any\n * native fault to a `SQLiteError`. Row values arrive as the native\n * {@link SQLiteRow} types; the typed layer above (the driver) imposes a precise\n * shape through a contract rather than re-narrowing here (AGENTS §14).\n */\nexport class SQLiteStatement implements SQLiteStatementInterface {\n\treadonly #statement: StatementSync\n\n\tconstructor(statement: StatementSync) {\n\t\tthis.#statement = statement\n\t\tthis.#statement.setAllowBareNamedParameters(true)\n\t}\n\n\trun(parameters?: SQLiteParameters): SQLiteRunResult {\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\tconst result =\n\t\t\t\t'named' in bound\n\t\t\t\t\t? this.#statement.run(bound.named)\n\t\t\t\t\t: this.#statement.run(...bound.positional)\n\t\t\treturn { changes: Number(result.changes), rowid: Number(result.lastInsertRowid) }\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\tget(parameters?: SQLiteParameters): SQLiteRow | undefined {\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\treturn 'named' in bound\n\t\t\t\t? this.#statement.get(bound.named)\n\t\t\t\t: this.#statement.get(...bound.positional)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\tall(parameters?: SQLiteParameters): readonly SQLiteRow[] {\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\treturn 'named' in bound\n\t\t\t\t? this.#statement.all(bound.named)\n\t\t\t\t: this.#statement.all(...bound.positional)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\titerate(parameters?: SQLiteParameters): IterableIterator<SQLiteRow> {\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\treturn 'named' in bound\n\t\t\t\t? this.#statement.iterate(bound.named)\n\t\t\t\t: this.#statement.iterate(...bound.positional)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n}\n","import { DatabaseSync } from 'node:sqlite'\nimport type {\n\tSQLiteDatabaseInterface,\n\tSQLiteDatabaseOptions,\n\tSQLiteStatementInterface,\n\tSQLiteValue,\n} from './types.js'\nimport { SQLiteError } from './errors.js'\nimport { wrapError } from './helpers.js'\nimport { SQLiteStatement } from './SQLiteStatement.js'\n\n/**\n * A synchronous SQLite database over `node:sqlite`'s `DatabaseSync`.\n *\n * @remarks\n * Created by `createSQLiteDatabase`. It connects lazily (`connect` opens the\n * underlying `DatabaseSync`, idempotent) and every operation routes through a\n * private gate that throws a `CLOSED` `SQLiteError` before `connect` or after\n * `close`. `exec` runs result-less SQL; `prepare` compiles a `SQLiteStatement`;\n * `transaction` wraps a scope in `BEGIN` / `COMMIT`, rolling back on a throw;\n * `pragma` reads (or sets then reads) one PRAGMA value — `name` is trusted\n * internal use only, never untrusted input, since pragma names cannot be bound\n * as parameters. A native fault surfaces as a `SQLiteError` mapped at the\n * boundary.\n */\nexport class SQLiteDatabase implements SQLiteDatabaseInterface {\n\treadonly #path: string\n\treadonly #readonly: boolean | undefined\n\treadonly #timeout: number | undefined\n\treadonly #foreignKeys: boolean | undefined\n\treadonly #bigints: boolean | undefined\n\t#database: DatabaseSync | undefined\n\n\tconstructor(options: SQLiteDatabaseOptions) {\n\t\tthis.#path = options.path ?? ':memory:'\n\t\tthis.#readonly = options.readonly\n\t\tthis.#timeout = options.timeout\n\t\tthis.#foreignKeys = options.foreignKeys\n\t\tthis.#bigints = options.bigints\n\t}\n\n\tget path(): string {\n\t\treturn this.#path\n\t}\n\n\tget connected(): boolean {\n\t\treturn this.#database !== undefined\n\t}\n\n\tconnect(): void {\n\t\tif (this.#database === undefined) {\n\t\t\tthis.#database = new DatabaseSync(this.#path, {\n\t\t\t\treadOnly: this.#readonly,\n\t\t\t\ttimeout: this.#timeout,\n\t\t\t\tenableForeignKeyConstraints: this.#foreignKeys,\n\t\t\t\treadBigInts: this.#bigints,\n\t\t\t})\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tthis.#database?.close()\n\t\tthis.#database = undefined\n\t}\n\n\t/** Close the connection — enables `using db = createSQLiteDatabase(...)`. */\n\t[Symbol.dispose](): void {\n\t\tthis.close()\n\t}\n\n\texec(sql: string): void {\n\t\ttry {\n\t\t\tthis.#require().exec(sql)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\tprepare(sql: string): SQLiteStatementInterface {\n\t\ttry {\n\t\t\treturn new SQLiteStatement(this.#require().prepare(sql))\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\ttransaction<R>(scope: () => R): R {\n\t\tthis.exec('BEGIN')\n\t\ttry {\n\t\t\tconst result = scope()\n\t\t\tthis.exec('COMMIT')\n\t\t\treturn result\n\t\t} catch (error) {\n\t\t\t// A ROLLBACK fault (e.g. the database was closed by the scope) must never\n\t\t\t// mask the scope's own error — the caller needs to see why it failed.\n\t\t\ttry {\n\t\t\t\tthis.exec('ROLLBACK')\n\t\t\t} catch {\n\t\t\t\t// swallowed — the original `error` is what the caller needs to see\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t// Pragmas cannot use bind parameters, so the value is interpolated — safe for\n\t// the trusted internal names this layer is called with.\n\tpragma(name: string, value?: string | number): SQLiteValue | undefined {\n\t\tif (value !== undefined) this.exec('PRAGMA ' + name + ' = ' + value)\n\t\tconst row = this.prepare('PRAGMA ' + name).get()\n\t\treturn row ? Object.values(row)[0] : undefined\n\t}\n\n\t// The single connection gate — every operation requires an open database.\n\t#require(): DatabaseSync {\n\t\tif (this.#database === undefined) {\n\t\t\tthrow new SQLiteError('CLOSED', 'Database is not connected — call connect() first')\n\t\t}\n\t\treturn this.#database\n\t}\n}\n","import type { SQLiteDatabaseInterface, SQLiteDatabaseOptions } from './types.js'\nimport { SQLiteDatabase } from './SQLiteDatabase.js'\n\n/**\n * Create a synchronous SQLite database over `node:sqlite`.\n *\n * @remarks\n * The wrapper connects lazily — call `connect` (or it is required by the first\n * operation, which throws `CLOSED` until then). This is the lower-level native\n * handle a higher-level typed database engine would be built on; here it ships\n * as the standalone, server-native SQLite surface.\n *\n * @param options - The database `path` (a file path, or `':memory:'` by default)\n * @returns A typed {@link SQLiteDatabaseInterface}\n *\n * @example\n * ```ts\n * import { createSQLiteDatabase } from '@src/server'\n *\n * const db = createSQLiteDatabase({ path: ':memory:' })\n * db.connect()\n * db.exec('CREATE TABLE users (id TEXT PRIMARY KEY, name TEXT)')\n * db.prepare('INSERT INTO users VALUES (?, ?)').run(['u1', 'Ada'])\n * db.prepare('SELECT name FROM users WHERE id = ?').get(['u1']) // { name: 'Ada' }\n * ```\n */\nexport function createSQLiteDatabase(options?: SQLiteDatabaseOptions): SQLiteDatabaseInterface {\n\treturn new SQLiteDatabase(options ?? {})\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["#statement","#closed","#require","#stream","#path","#readonly","#timeout","#foreignKeys","#bigints","#database","#require"],"sources":["../../../src/server/constants.ts","../../../src/server/errors.ts","../../../src/server/helpers.ts","../../../src/server/SQLiteStatement.ts","../../../src/server/SQLiteDatabase.ts","../../../src/server/factories.ts"],"sourcesContent":["// The wrapper's numeric SQLite result codes (AGENTS §5 constants file).\n\n/**\n * SQLite result code for a constraint violation (`SQLITE_CONSTRAINT`).\n *\n * @remarks\n * A native `errcode` packs the primary result in its low byte, with extended codes\n * in the high bits (e.g. `SQLITE_CONSTRAINT_UNIQUE`), so the low byte is masked off\n * before comparing. Read only by `wrapError`.\n */\nexport const SQLITE_CONSTRAINT = 19\n\n/**\n * SQLite result code for a locked-database fault (`SQLITE_BUSY`).\n *\n * @remarks\n * A native `errcode` packs the primary result in its low byte, with extended codes\n * in the high bits, so the low byte is masked off before comparing. Read only by\n * `wrapError`.\n */\nexport const SQLITE_BUSY = 5\n","import type { SQLiteErrorCode } from './types.js'\n\n// Errors for the SQLite wrapper. A single `SQLiteError` carries a\n// machine-readable `code` mapped from the native `node:sqlite` fault at the\n// boundary (`wrapError`), so a `catch` branches on `error.code` rather than\n// parsing a message. Mirrors the IndexedDB wrapper's `IndexedDBError`; its three\n// codes are deliberately lean — the wrapper sits right on the raw SQLite surface,\n// where the constraint fault is the one worth naming, `CLOSED` is the\n// wrapper-lifecycle fault, and everything else is `UNKNOWN` (AGENTS §12).\n\n/**\n * An error thrown by the SQLite wrapper.\n *\n * @remarks\n * Carries a {@link SQLiteErrorCode} and an optional `context` record (e.g. the\n * native SQLite `errcode`). Construct it directly for the `CLOSED`\n * wrapper-lifecycle fault; the internal `wrapError` maps a native `node:sqlite`\n * error to the right code at the boundary. Narrow a caught value with\n * {@link isSQLiteError}.\n *\n * @example\n * ```ts\n * try {\n * \tstatement.run({ id: 'u1' })\n * } catch (error) {\n * \tif (isSQLiteError(error) && error.code === 'CONSTRAINT') {\n * \t\t// a UNIQUE / PRIMARY KEY violation\n * \t}\n * }\n * ```\n */\nexport class SQLiteError extends Error {\n\treadonly code: SQLiteErrorCode\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(code: SQLiteErrorCode, message: string, context?: Readonly<Record<string, unknown>>) {\n\t\tsuper(message)\n\t\tthis.name = 'SQLiteError'\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/**\n * Whether a value is a {@link SQLiteError}.\n *\n * @param value - The value to test\n * @returns `true` when `value` is a `SQLiteError`\n */\nexport function isSQLiteError(value: unknown): value is SQLiteError {\n\treturn value instanceof SQLiteError\n}\n","import type { SQLiteParameters, SQLiteValue } from './types.js'\nimport { isArray, isObject } from '@orkestrel/contract'\nimport { SQLITE_BUSY, SQLITE_CONSTRAINT } from './constants.js'\nimport { SQLiteError } from './errors.js'\n\n// The wrapper's boundary helpers, shared by `SQLiteDatabase` and `SQLiteStatement`:\n// `wrapError` maps a thrown native `node:sqlite` error to a typed `SQLiteError`\n// (the one honest narrowing point — `isObject` + `in`, never `as`, per AGENTS\n// §14), and `bindParameters` normalizes the wrapper's `SQLiteParameters` to the\n// shape a native `StatementSync` call expects (positional spread vs. a single\n// named record). Both are pure.\n\n/**\n * Convert a thrown native `node:sqlite` error into a typed {@link SQLiteError}.\n *\n * @remarks\n * The single boundary mapping for the wrapper. The thrown value arrives as\n * `unknown` and is narrowed with `isObject` + the `in` operator (never `as`, and\n * not `isRecord` — a native `node:sqlite` error is an `Error` instance, so its\n * prototype fails the plain-record test) to read its `errcode` — a numeric SQLite\n * result code whose low byte identifies a constraint violation\n * (`SQLITE_CONSTRAINT`), mapped to code `'CONSTRAINT'`; a locked-database fault\n * (`SQLITE_BUSY`) is mapped to `'BUSY'`; anything else is `'UNKNOWN'`. The\n * original message is preserved and `{ errcode }` carried in `context` when\n * present. An already-typed `SQLiteError` is returned unchanged.\n *\n * @param error - The thrown value to convert\n * @returns The equivalent `SQLiteError`\n */\nexport function wrapError(error: unknown): SQLiteError {\n\tif (error instanceof SQLiteError) return error\n\tconst errcode =\n\t\tisObject(error) && 'errcode' in error && typeof error.errcode === 'number'\n\t\t\t? error.errcode\n\t\t\t: undefined\n\tconst message = error instanceof Error ? error.message : 'Unknown SQLite error'\n\tconst code =\n\t\terrcode !== undefined && (errcode & 0xff) === SQLITE_CONSTRAINT\n\t\t\t? 'CONSTRAINT'\n\t\t\t: errcode !== undefined && (errcode & 0xff) === SQLITE_BUSY\n\t\t\t\t? 'BUSY'\n\t\t\t\t: 'UNKNOWN'\n\treturn new SQLiteError(code, message, errcode !== undefined ? { errcode } : undefined)\n}\n\n/**\n * Normalize {@link SQLiteParameters} to the binding shape a native `StatementSync`\n * call expects.\n *\n * @remarks\n * Positional parameters (an array) bind to `?` placeholders and are spread into\n * the call; named parameters (a record) bind to bare `:name` placeholders and are\n * passed as a single leading object. Returning a discriminated result keeps the\n * `SQLiteStatement` dispatch typed against the native overloads without `as`.\n *\n * @param parameters - The wrapper parameters, or `undefined` for none\n * @returns `{ positional }` for an array (empty when omitted) or `{ named }` for a record\n */\nexport function bindParameters(\n\tparameters?: SQLiteParameters,\n):\n\t| { readonly positional: readonly SQLiteValue[] }\n\t| { readonly named: Readonly<Record<string, SQLiteValue>> } {\n\tif (parameters === undefined) return { positional: [] }\n\tif (isArray<SQLiteValue>(parameters)) return { positional: parameters }\n\treturn { named: parameters }\n}\n","import type { StatementSync } from 'node:sqlite'\nimport type {\n\tSQLiteParameters,\n\tSQLiteRow,\n\tSQLiteRunResult,\n\tSQLiteStatementInterface,\n} from './types.js'\nimport { SQLiteError } from './errors.js'\nimport { bindParameters, wrapError } from './helpers.js'\n\n/**\n * A prepared statement over `node:sqlite`'s `StatementSync` — the only way the\n * wrapper runs SQL.\n *\n * @remarks\n * Created by `database.prepare(sql)`, which threads a liveness check (internal —\n * this constructor's second parameter is not part of the documented surface).\n * Bare named parameters are enabled on construction so a record's keys bind\n * without the SQL prefix character. Each method first gates on that liveness\n * check, throwing a `CLOSED` `SQLiteError` once the owning connection has been\n * closed — a statement prepared on a connection that is later closed and then\n * reconnected stays `CLOSED`; a fresh statement must be prepared on the new\n * connection. Each method then binds the optional parameters (an array spread\n * to `?` placeholders, a record passed as a single named object) and executes\n * synchronously, mapping any native fault to a `SQLiteError` — including a\n * mid-stream fault from `iterate`'s lazy native iterator, stepped inside its own\n * try/catch so a fault on a later row is mapped exactly like an eager one. Row\n * values arrive as the native {@link SQLiteRow} types; the typed layer above\n * (the driver) imposes a precise shape through a contract rather than\n * re-narrowing here (AGENTS §14).\n */\nexport class SQLiteStatement implements SQLiteStatementInterface {\n\treadonly #statement: StatementSync\n\treadonly #closed: () => boolean\n\n\tconstructor(statement: StatementSync, closed: () => boolean) {\n\t\tthis.#statement = statement\n\t\tthis.#closed = closed\n\t\tthis.#statement.setAllowBareNamedParameters(true)\n\t}\n\n\trun(parameters?: SQLiteParameters): SQLiteRunResult {\n\t\tthis.#require()\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\tconst result =\n\t\t\t\t'named' in bound\n\t\t\t\t\t? this.#statement.run(bound.named)\n\t\t\t\t\t: this.#statement.run(...bound.positional)\n\t\t\treturn { changes: Number(result.changes), rowid: Number(result.lastInsertRowid) }\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\tget(parameters?: SQLiteParameters): SQLiteRow | undefined {\n\t\tthis.#require()\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\treturn 'named' in bound\n\t\t\t\t? this.#statement.get(bound.named)\n\t\t\t\t: this.#statement.get(...bound.positional)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\tall(parameters?: SQLiteParameters): readonly SQLiteRow[] {\n\t\tthis.#require()\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\treturn 'named' in bound\n\t\t\t\t? this.#statement.all(bound.named)\n\t\t\t\t: this.#statement.all(...bound.positional)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\titerate(parameters?: SQLiteParameters): IterableIterator<SQLiteRow> {\n\t\tthis.#require()\n\t\tlet native: IterableIterator<SQLiteRow>\n\t\ttry {\n\t\t\tconst bound = bindParameters(parameters)\n\t\t\tnative =\n\t\t\t\t'named' in bound\n\t\t\t\t\t? this.#statement.iterate(bound.named)\n\t\t\t\t\t: this.#statement.iterate(...bound.positional)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t\treturn this.#stream(native)\n\t}\n\n\t// The single liveness gate — every operation requires the owning connection\n\t// to still be open (mirrors SQLiteDatabase#require).\n\t#require(): void {\n\t\tif (this.#closed()) {\n\t\t\tthrow new SQLiteError(\n\t\t\t\t'CLOSED',\n\t\t\t\t'Statement is closed — its connection was closed; prepare a new statement',\n\t\t\t)\n\t\t}\n\t}\n\n\t// Pulls from the native lazy iterator one step at a time, each step inside\n\t// its own try/catch — a mid-stream native fault (e.g. an out-of-range\n\t// integer on a later row) is mapped to a SQLiteError exactly like an eager\n\t// fault, instead of escaping raw from the caller's for...of.\n\t*#stream(native: IterableIterator<SQLiteRow>): IterableIterator<SQLiteRow> {\n\t\tfor (;;) {\n\t\t\tlet result: IteratorResult<SQLiteRow>\n\t\t\ttry {\n\t\t\t\tresult = native.next()\n\t\t\t} catch (error) {\n\t\t\t\tthrow wrapError(error)\n\t\t\t}\n\t\t\tif (result.done === true) return\n\t\t\tyield result.value\n\t\t}\n\t}\n}\n","import { DatabaseSync } from 'node:sqlite'\nimport type {\n\tSQLiteDatabaseInterface,\n\tSQLiteDatabaseOptions,\n\tSQLiteStatementInterface,\n\tSQLiteValue,\n} from './types.js'\nimport { isPromiseLike } from '@orkestrel/contract'\nimport { SQLiteError } from './errors.js'\nimport { wrapError } from './helpers.js'\nimport { SQLiteStatement } from './SQLiteStatement.js'\n\n/**\n * A synchronous SQLite database over `node:sqlite`'s `DatabaseSync`.\n *\n * @remarks\n * Created by `createSQLiteDatabase`. It connects lazily (`connect` opens the\n * underlying `DatabaseSync`, idempotent) and every operation routes through a\n * private gate that throws a `CLOSED` `SQLiteError` before `connect` or after\n * `close`. `exec` runs result-less SQL; `prepare` compiles a `SQLiteStatement`;\n * `transaction` wraps a scope in `BEGIN` / `COMMIT`, rolling back on a throw;\n * `begin` / `commit` / `rollback` expose those same primitives directly for a\n * long-lived or externally-driven transaction; `pragma` reads (or sets then\n * reads) one PRAGMA value — `name` is trusted\n * internal use only, never untrusted input, since pragma names cannot be bound\n * as parameters. `transacting` reports whether a transaction is currently open\n * (node:sqlite's `isTransaction`), `false` when not connected. A native fault\n * surfaces as a `SQLiteError` mapped at the boundary.\n */\nexport class SQLiteDatabase implements SQLiteDatabaseInterface {\n\treadonly #path: string\n\treadonly #readonly: boolean | undefined\n\treadonly #timeout: number | undefined\n\treadonly #foreignKeys: boolean | undefined\n\treadonly #bigints: boolean | undefined\n\t#database: DatabaseSync | undefined\n\n\tconstructor(options: SQLiteDatabaseOptions) {\n\t\tthis.#path = options.path ?? ':memory:'\n\t\tthis.#readonly = options.readonly\n\t\tthis.#timeout = options.timeout\n\t\tthis.#foreignKeys = options.foreignKeys\n\t\tthis.#bigints = options.bigints\n\t}\n\n\tget path(): string {\n\t\treturn this.#path\n\t}\n\n\tget connected(): boolean {\n\t\treturn this.#database !== undefined\n\t}\n\n\tget transacting(): boolean {\n\t\treturn this.#database?.isTransaction ?? false\n\t}\n\n\tconnect(): void {\n\t\tif (this.#database === undefined) {\n\t\t\tthis.#database = new DatabaseSync(this.#path, {\n\t\t\t\treadOnly: this.#readonly,\n\t\t\t\ttimeout: this.#timeout,\n\t\t\t\tenableForeignKeyConstraints: this.#foreignKeys,\n\t\t\t\treadBigInts: this.#bigints,\n\t\t\t})\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tthis.#database?.close()\n\t\tthis.#database = undefined\n\t}\n\n\t/** Close the connection — enables `using db = createSQLiteDatabase(...)`. */\n\t[Symbol.dispose](): void {\n\t\tthis.close()\n\t}\n\n\texec(sql: string): void {\n\t\ttry {\n\t\t\tthis.#require().exec(sql)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\tprepare(sql: string): SQLiteStatementInterface {\n\t\ttry {\n\t\t\tconst database = this.#require()\n\t\t\t// Capture this specific connection instance — a later `close()` clears\n\t\t\t// `#database`, and a subsequent `connect()` creates a NEW instance, so\n\t\t\t// identity comparison (not just \"is a connection open\") keeps a statement\n\t\t\t// prepared on the OLD connection permanently CLOSED after reconnect.\n\t\t\treturn new SQLiteStatement(database.prepare(sql), () => this.#database !== database)\n\t\t} catch (error) {\n\t\t\tthrow wrapError(error)\n\t\t}\n\t}\n\n\ttransaction<R>(scope: () => R): R {\n\t\tthis.begin()\n\t\tlet result: R\n\t\ttry {\n\t\t\tresult = scope()\n\t\t} catch (error) {\n\t\t\t// A ROLLBACK fault (e.g. the database was closed by the scope) must never\n\t\t\t// mask the scope's own error — the caller needs to see why it failed.\n\t\t\ttry {\n\t\t\t\tthis.rollback()\n\t\t\t} catch {\n\t\t\t\t// swallowed — the original `error` is what the caller needs to see\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t\tif (isPromiseLike(result)) {\n\t\t\t// An async scope returns before its awaited work runs, so committing here\n\t\t\t// would commit prematurely — roll back and reject instead of silently\n\t\t\t// racing the caller's still-pending work.\n\t\t\ttry {\n\t\t\t\tthis.rollback()\n\t\t\t} catch {\n\t\t\t\t// swallowed — the guard error below is what the caller needs to see\n\t\t\t}\n\t\t\tthrow new SQLiteError(\n\t\t\t\t'UNKNOWN',\n\t\t\t\t'transaction(scope) requires a synchronous scope — an async or Promise-returning scope cannot commit or roll back before its awaited work runs; use begin() / commit() / rollback() directly for a transaction that spans async caller code',\n\t\t\t)\n\t\t}\n\t\tthis.commit()\n\t\treturn result\n\t}\n\n\tbegin(): void {\n\t\tthis.exec('BEGIN')\n\t}\n\n\tcommit(): void {\n\t\tthis.exec('COMMIT')\n\t}\n\n\trollback(): void {\n\t\tthis.exec('ROLLBACK')\n\t}\n\n\t// Pragmas cannot use bind parameters, so the value is interpolated — safe for\n\t// the trusted internal names this layer is called with.\n\tpragma(name: string, value?: string | number): SQLiteValue | undefined {\n\t\tif (value !== undefined) this.exec('PRAGMA ' + name + ' = ' + value)\n\t\tconst row = this.prepare('PRAGMA ' + name).get()\n\t\treturn row ? Object.values(row)[0] : undefined\n\t}\n\n\t// The single connection gate — every operation requires an open database.\n\t#require(): DatabaseSync {\n\t\tif (this.#database === undefined) {\n\t\t\tthrow new SQLiteError('CLOSED', 'Database is not connected — call connect() first')\n\t\t}\n\t\treturn this.#database\n\t}\n}\n","import type { SQLiteDatabaseInterface, SQLiteDatabaseOptions } from './types.js'\nimport { SQLiteDatabase } from './SQLiteDatabase.js'\n\n/**\n * Create a synchronous SQLite database over `node:sqlite`.\n *\n * @remarks\n * The wrapper connects lazily — call `connect` (or it is required by the first\n * operation, which throws `CLOSED` until then). This is the lower-level native\n * handle a higher-level typed database engine would be built on; here it ships\n * as the standalone, server-native SQLite surface.\n *\n * @param options - The database `path` (a file path, or `':memory:'` by default)\n * @returns A typed {@link SQLiteDatabaseInterface}\n *\n * @example\n * ```ts\n * import { createSQLiteDatabase } from '@orkestrel/sqlite'\n *\n * const db = createSQLiteDatabase({ path: ':memory:' })\n * db.connect()\n * db.exec('CREATE TABLE users (id TEXT PRIMARY KEY, name TEXT)')\n * db.prepare('INSERT INTO users VALUES (?, ?)').run(['u1', 'Ada'])\n * db.prepare('SELECT name FROM users WHERE id = ?').get(['u1']) // { name: 'Ada' }\n * ```\n */\nexport function createSQLiteDatabase(options?: SQLiteDatabaseOptions): SQLiteDatabaseInterface {\n\treturn new SQLiteDatabase(options ?? {})\n}\n"],"mappings":"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"}
@@ -0,0 +1,316 @@
1
+ import { StatementSync } from 'node:sqlite';
2
+
3
+ /**
4
+ * Normalize {@link SQLiteParameters} to the binding shape a native `StatementSync`
5
+ * call expects.
6
+ *
7
+ * @remarks
8
+ * Positional parameters (an array) bind to `?` placeholders and are spread into
9
+ * the call; named parameters (a record) bind to bare `:name` placeholders and are
10
+ * passed as a single leading object. Returning a discriminated result keeps the
11
+ * `SQLiteStatement` dispatch typed against the native overloads without `as`.
12
+ *
13
+ * @param parameters - The wrapper parameters, or `undefined` for none
14
+ * @returns `{ positional }` for an array (empty when omitted) or `{ named }` for a record
15
+ */
16
+ export declare function bindParameters(parameters?: SQLiteParameters): {
17
+ readonly positional: readonly SQLiteValue[];
18
+ } | {
19
+ readonly named: Readonly<Record<string, SQLiteValue>>;
20
+ };
21
+
22
+ /**
23
+ * Create a synchronous SQLite database over `node:sqlite`.
24
+ *
25
+ * @remarks
26
+ * The wrapper connects lazily — call `connect` (or it is required by the first
27
+ * operation, which throws `CLOSED` until then). This is the lower-level native
28
+ * handle a higher-level typed database engine would be built on; here it ships
29
+ * as the standalone, server-native SQLite surface.
30
+ *
31
+ * @param options - The database `path` (a file path, or `':memory:'` by default)
32
+ * @returns A typed {@link SQLiteDatabaseInterface}
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createSQLiteDatabase } from '@orkestrel/sqlite'
37
+ *
38
+ * const db = createSQLiteDatabase({ path: ':memory:' })
39
+ * db.connect()
40
+ * db.exec('CREATE TABLE users (id TEXT PRIMARY KEY, name TEXT)')
41
+ * db.prepare('INSERT INTO users VALUES (?, ?)').run(['u1', 'Ada'])
42
+ * db.prepare('SELECT name FROM users WHERE id = ?').get(['u1']) // { name: 'Ada' }
43
+ * ```
44
+ */
45
+ export declare function createSQLiteDatabase(options?: SQLiteDatabaseOptions): SQLiteDatabaseInterface;
46
+
47
+ /**
48
+ * Whether a value is a {@link SQLiteError}.
49
+ *
50
+ * @param value - The value to test
51
+ * @returns `true` when `value` is a `SQLiteError`
52
+ */
53
+ export declare function isSQLiteError(value: unknown): value is SQLiteError;
54
+
55
+ /**
56
+ * SQLite result code for a locked-database fault (`SQLITE_BUSY`).
57
+ *
58
+ * @remarks
59
+ * A native `errcode` packs the primary result in its low byte, with extended codes
60
+ * in the high bits, so the low byte is masked off before comparing. Read only by
61
+ * `wrapError`.
62
+ */
63
+ export declare const SQLITE_BUSY = 5;
64
+
65
+ /**
66
+ * SQLite result code for a constraint violation (`SQLITE_CONSTRAINT`).
67
+ *
68
+ * @remarks
69
+ * A native `errcode` packs the primary result in its low byte, with extended codes
70
+ * in the high bits (e.g. `SQLITE_CONSTRAINT_UNIQUE`), so the low byte is masked off
71
+ * before comparing. Read only by `wrapError`.
72
+ */
73
+ export declare const SQLITE_CONSTRAINT = 19;
74
+
75
+ /**
76
+ * A synchronous SQLite database over `node:sqlite`'s `DatabaseSync`.
77
+ *
78
+ * @remarks
79
+ * Created by `createSQLiteDatabase`. It connects lazily (`connect` opens the
80
+ * underlying `DatabaseSync`, idempotent) and every operation routes through a
81
+ * private gate that throws a `CLOSED` `SQLiteError` before `connect` or after
82
+ * `close`. `exec` runs result-less SQL; `prepare` compiles a `SQLiteStatement`;
83
+ * `transaction` wraps a scope in `BEGIN` / `COMMIT`, rolling back on a throw;
84
+ * `begin` / `commit` / `rollback` expose those same primitives directly for a
85
+ * long-lived or externally-driven transaction; `pragma` reads (or sets then
86
+ * reads) one PRAGMA value — `name` is trusted
87
+ * internal use only, never untrusted input, since pragma names cannot be bound
88
+ * as parameters. `transacting` reports whether a transaction is currently open
89
+ * (node:sqlite's `isTransaction`), `false` when not connected. A native fault
90
+ * surfaces as a `SQLiteError` mapped at the boundary.
91
+ */
92
+ export declare class SQLiteDatabase implements SQLiteDatabaseInterface {
93
+ #private;
94
+ constructor(options: SQLiteDatabaseOptions);
95
+ get path(): string;
96
+ get connected(): boolean;
97
+ get transacting(): boolean;
98
+ connect(): void;
99
+ close(): void;
100
+ /** Close the connection — enables `using db = createSQLiteDatabase(...)`. */
101
+ [Symbol.dispose](): void;
102
+ exec(sql: string): void;
103
+ prepare(sql: string): SQLiteStatementInterface;
104
+ transaction<R>(scope: () => R): R;
105
+ begin(): void;
106
+ commit(): void;
107
+ rollback(): void;
108
+ pragma(name: string, value?: string | number): SQLiteValue | undefined;
109
+ }
110
+
111
+ /**
112
+ * A synchronous SQLite database over `node:sqlite`'s `DatabaseSync` — a lean,
113
+ * typed, zero-dependency layer exposing prepared statements, transactions, and
114
+ * pragmas. Synchronous because `node:sqlite` is; the SQLite *driver* (Chunk 3)
115
+ * adapts it to the async `DriverInterface`.
116
+ *
117
+ * @remarks
118
+ * Connects lazily — `connect` opens the underlying `DatabaseSync` (idempotent),
119
+ * and every operation requires an open connection, throwing a `CLOSED`
120
+ * {@link SQLiteError} before `connect` or after `close`. `exec` runs SQL with no
121
+ * results (DDL, pragmas); `prepare` compiles a {@link SQLiteStatementInterface};
122
+ * `transaction` runs a scope between `BEGIN` and `COMMIT`, rolling back on a
123
+ * throw; `pragma` reads (or sets then reads) a single PRAGMA value — `name` is
124
+ * trusted internal use only, never untrusted input, since pragma names cannot
125
+ * be bound as parameters. `transacting` reports whether a transaction is
126
+ * currently open on this connection — node:sqlite's `isTransaction` (wraps
127
+ * `sqlite3_get_autocommit()`); `false` when not connected. `begin` / `commit` /
128
+ * `rollback` are the same `BEGIN` / `COMMIT` / `ROLLBACK` primitives
129
+ * `transaction` composes internally, exposed directly for a long-lived or
130
+ * externally-driven transaction that a single synchronous scope cannot
131
+ * express — `transaction(scope)` remains the right tool whenever the whole
132
+ * transaction fits in one synchronous scope. `[Symbol.dispose]` closes the
133
+ * connection (same as `close`), enabling `using` to release it
134
+ * deterministically at the end of a block.
135
+ */
136
+ export declare interface SQLiteDatabaseInterface {
137
+ readonly path: string;
138
+ readonly connected: boolean;
139
+ readonly transacting: boolean;
140
+ connect(): void;
141
+ close(): void;
142
+ exec(sql: string): void;
143
+ prepare(sql: string): SQLiteStatementInterface;
144
+ transaction<R>(scope: () => R): R;
145
+ /**
146
+ * Open a transaction (`BEGIN`). Throws the native fault — including a
147
+ * nested `BEGIN` while one is already open — as a {@link SQLiteError}; a
148
+ * caller composing its own transaction alongside others should branch on
149
+ * {@link SQLiteDatabaseInterface.transacting} first rather than catch this
150
+ * (see the Practices section in `guides/src/sqlite.md`).
151
+ */
152
+ begin(): void;
153
+ /** Commit the currently open transaction (`COMMIT`); throws the native fault as a {@link SQLiteError} when none is open. */
154
+ commit(): void;
155
+ /** Roll back the currently open transaction (`ROLLBACK`); throws the native fault as a {@link SQLiteError} when none is open. */
156
+ rollback(): void;
157
+ pragma(name: string, value?: string | number): SQLiteValue | undefined;
158
+ [Symbol.dispose](): void;
159
+ }
160
+
161
+ /**
162
+ * Options for `createSQLiteDatabase`.
163
+ *
164
+ * @remarks
165
+ * `path` is the database file path, or the special name `':memory:'` for an
166
+ * in-memory database (the default when omitted). `readonly` opens the
167
+ * connection read-only (native `readOnly`) — an absent file fails to open
168
+ * rather than being created. `timeout` is the busy-timeout in milliseconds
169
+ * (native `timeout`) — how long SQLite retries a locked database before
170
+ * failing with a `BUSY` {@link SQLiteError}; defaults to `0` (fail
171
+ * immediately) when omitted. `foreignKeys` enables foreign-key constraint
172
+ * enforcement (native `enableForeignKeyConstraints`); `node:sqlite` defaults
173
+ * this to `true` when omitted. `bigints` reads `INTEGER` columns back as
174
+ * `bigint` (native `readBigInts`) — writes already accept `bigint` regardless
175
+ * of this option, so a stored integer beyond `Number.MAX_SAFE_INTEGER` throws
176
+ * on read unless `bigints` is enabled; enabling it returns EVERY integer
177
+ * column as `bigint`, not just out-of-range ones, closing that read/write
178
+ * asymmetry at the cost of `bigint` values for ordinary small integers too.
179
+ */
180
+ export declare interface SQLiteDatabaseOptions {
181
+ readonly path?: string;
182
+ readonly readonly?: boolean;
183
+ readonly timeout?: number;
184
+ readonly foreignKeys?: boolean;
185
+ readonly bigints?: boolean;
186
+ }
187
+
188
+ /**
189
+ * An error thrown by the SQLite wrapper.
190
+ *
191
+ * @remarks
192
+ * Carries a {@link SQLiteErrorCode} and an optional `context` record (e.g. the
193
+ * native SQLite `errcode`). Construct it directly for the `CLOSED`
194
+ * wrapper-lifecycle fault; the internal `wrapError` maps a native `node:sqlite`
195
+ * error to the right code at the boundary. Narrow a caught value with
196
+ * {@link isSQLiteError}.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * try {
201
+ * statement.run({ id: 'u1' })
202
+ * } catch (error) {
203
+ * if (isSQLiteError(error) && error.code === 'CONSTRAINT') {
204
+ * // a UNIQUE / PRIMARY KEY violation
205
+ * }
206
+ * }
207
+ * ```
208
+ */
209
+ export declare class SQLiteError extends Error {
210
+ readonly code: SQLiteErrorCode;
211
+ readonly context?: Readonly<Record<string, unknown>>;
212
+ constructor(code: SQLiteErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
213
+ }
214
+
215
+ /**
216
+ * A machine-readable {@link SQLiteError} code.
217
+ *
218
+ * @remarks
219
+ * `'BUSY'` is retryable — it means a locked database was still held by another
220
+ * connection when the `timeout` (see {@link SQLiteDatabaseOptions}) elapsed; a
221
+ * caller may retry the operation, typically after backing off briefly.
222
+ */
223
+ export declare type SQLiteErrorCode = 'CLOSED' | 'CONSTRAINT' | 'BUSY' | 'UNKNOWN';
224
+
225
+ /**
226
+ * Bind parameters for a prepared statement — positional (an array, bound to `?`)
227
+ * or named (a record, bound to bare `:name` placeholders).
228
+ */
229
+ export declare type SQLiteParameters = readonly SQLiteValue[] | Readonly<Record<string, SQLiteValue>>;
230
+
231
+ /** A result row — a record of column name to {@link SQLiteValue}. */
232
+ export declare type SQLiteRow = Record<string, SQLiteValue>;
233
+
234
+ /** The outcome of a non-query statement (`INSERT` / `UPDATE` / `DELETE` / DDL). */
235
+ export declare interface SQLiteRunResult {
236
+ readonly changes: number;
237
+ readonly rowid: number;
238
+ }
239
+
240
+ /**
241
+ * A prepared statement over `node:sqlite`'s `StatementSync` — the only way the
242
+ * wrapper runs SQL.
243
+ *
244
+ * @remarks
245
+ * Created by `database.prepare(sql)`, which threads a liveness check (internal —
246
+ * this constructor's second parameter is not part of the documented surface).
247
+ * Bare named parameters are enabled on construction so a record's keys bind
248
+ * without the SQL prefix character. Each method first gates on that liveness
249
+ * check, throwing a `CLOSED` `SQLiteError` once the owning connection has been
250
+ * closed — a statement prepared on a connection that is later closed and then
251
+ * reconnected stays `CLOSED`; a fresh statement must be prepared on the new
252
+ * connection. Each method then binds the optional parameters (an array spread
253
+ * to `?` placeholders, a record passed as a single named object) and executes
254
+ * synchronously, mapping any native fault to a `SQLiteError` — including a
255
+ * mid-stream fault from `iterate`'s lazy native iterator, stepped inside its own
256
+ * try/catch so a fault on a later row is mapped exactly like an eager one. Row
257
+ * values arrive as the native {@link SQLiteRow} types; the typed layer above
258
+ * (the driver) imposes a precise shape through a contract rather than
259
+ * re-narrowing here (AGENTS §14).
260
+ */
261
+ export declare class SQLiteStatement implements SQLiteStatementInterface {
262
+ #private;
263
+ constructor(statement: StatementSync, closed: () => boolean);
264
+ run(parameters?: SQLiteParameters): SQLiteRunResult;
265
+ get(parameters?: SQLiteParameters): SQLiteRow | undefined;
266
+ all(parameters?: SQLiteParameters): readonly SQLiteRow[];
267
+ iterate(parameters?: SQLiteParameters): IterableIterator<SQLiteRow>;
268
+ }
269
+
270
+ /**
271
+ * A prepared statement — the only way the wrapper runs SQL (no query DSL; the
272
+ * core database layer owns querying, exactly as the IndexedDB wrapper does).
273
+ *
274
+ * @remarks
275
+ * Reached through `database.prepare(sql)`. Each method binds the optional
276
+ * `parameters` (an array spread to positional `?` placeholders, or a record bound
277
+ * to bare named placeholders) and executes synchronously: `run` for a non-query,
278
+ * `get` for the first row, `all` for every row, `iterate` for a lazy stream. A
279
+ * native fault surfaces as a {@link SQLiteError}.
280
+ */
281
+ export declare interface SQLiteStatementInterface {
282
+ run(parameters?: SQLiteParameters): SQLiteRunResult;
283
+ get(parameters?: SQLiteParameters): SQLiteRow | undefined;
284
+ all(parameters?: SQLiteParameters): readonly SQLiteRow[];
285
+ iterate(parameters?: SQLiteParameters): IterableIterator<SQLiteRow>;
286
+ }
287
+
288
+ /**
289
+ * A value SQLite stores and returns natively — the SQL ↔ JS bridge.
290
+ *
291
+ * @remarks
292
+ * `node:sqlite` maps `NULL` / `INTEGER` / `REAL` / `TEXT` / `BLOB` to exactly
293
+ * these JS types (integers arrive as `number`, or `bigint` only past 2^53).
294
+ */
295
+ export declare type SQLiteValue = null | number | bigint | string | Uint8Array;
296
+
297
+ /**
298
+ * Convert a thrown native `node:sqlite` error into a typed {@link SQLiteError}.
299
+ *
300
+ * @remarks
301
+ * The single boundary mapping for the wrapper. The thrown value arrives as
302
+ * `unknown` and is narrowed with `isObject` + the `in` operator (never `as`, and
303
+ * not `isRecord` — a native `node:sqlite` error is an `Error` instance, so its
304
+ * prototype fails the plain-record test) to read its `errcode` — a numeric SQLite
305
+ * result code whose low byte identifies a constraint violation
306
+ * (`SQLITE_CONSTRAINT`), mapped to code `'CONSTRAINT'`; a locked-database fault
307
+ * (`SQLITE_BUSY`) is mapped to `'BUSY'`; anything else is `'UNKNOWN'`. The
308
+ * original message is preserved and `{ errcode }` carried in `context` when
309
+ * present. An already-typed `SQLiteError` is returned unchanged.
310
+ *
311
+ * @param error - The thrown value to convert
312
+ * @returns The equivalent `SQLiteError`
313
+ */
314
+ export declare function wrapError(error: unknown): SQLiteError;
315
+
316
+ export { }