@cutils/sqlite 0.0.0-stage → 0.2.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.
@@ -0,0 +1,8 @@
1
+ export declare class Scratch {
2
+ buf: Uint8Array;
3
+ constructor();
4
+ /** Grow until `cap` bytes fit. */
5
+ ensure(cap: number): void;
6
+ /** Copy the first `n` bytes out (for blob returns — scratch is reused). */
7
+ copyOut(n: number): Uint8Array;
8
+ }
@@ -0,0 +1,27 @@
1
+ // Reusable scratch buffer for the shim's mutable-bytes out params.
2
+ // Strings/blobs arrive as "required bytes" return values; when the buffer is
3
+ // too small it doubles until the call fits.
4
+ export class Scratch {
5
+ buf;
6
+ constructor() {
7
+ this.buf = new Uint8Array(4096);
8
+ }
9
+ /** Grow until `cap` bytes fit. */
10
+ ensure(cap) {
11
+ let n = this.buf.length;
12
+ while (n < cap) {
13
+ n = n * 2;
14
+ }
15
+ if (n !== this.buf.length) {
16
+ this.buf = new Uint8Array(n);
17
+ }
18
+ }
19
+ /** Copy the first `n` bytes out (for blob returns — scratch is reused). */
20
+ copyOut(n) {
21
+ const out = new Uint8Array(n);
22
+ for (let i = 0; i < n; i++) {
23
+ out[i] = this.buf[i];
24
+ }
25
+ return out;
26
+ }
27
+ }
@@ -0,0 +1,34 @@
1
+ export declare function ffiOpen(path: string, flags: number): bigint;
2
+ export declare function ffiClose(db: bigint): number;
3
+ export declare function ffiErrcode(db: bigint): number;
4
+ export declare function ffiErrmsg(db: bigint, buf: Uint8Array): number;
5
+ export declare function ffiInTransaction(db: bigint): number;
6
+ export declare function ffiExec(db: bigint, sql: string): number;
7
+ export declare function ffiBegin(db: bigint): number;
8
+ export declare function ffiCommit(db: bigint): number;
9
+ export declare function ffiRollback(db: bigint): number;
10
+ export declare function ffiSavepoint(db: bigint, name: string, op: number): number;
11
+ export declare function ffiPrepare(db: bigint, sql: string): bigint;
12
+ export declare function ffiStep(stmt: bigint): number;
13
+ export declare function ffiReset(stmt: bigint): number;
14
+ export declare function ffiFinalize(stmt: bigint): number;
15
+ export declare function ffiClearBindings(stmt: bigint): number;
16
+ export declare function ffiStmtReadonly(stmt: bigint): number;
17
+ export declare function ffiExpandedSql(stmt: bigint, buf: Uint8Array): number;
18
+ export declare function ffiBindCount(stmt: bigint): number;
19
+ export declare function ffiBindIndex(stmt: bigint, name: string): number;
20
+ export declare function ffiBindInt(stmt: bigint, idx: number, val: bigint): number;
21
+ export declare function ffiBindDbl(stmt: bigint, idx: number, val: number): number;
22
+ export declare function ffiBindText(stmt: bigint, idx: number, val: string): number;
23
+ export declare function ffiBindBlob(stmt: bigint, idx: number, val: Uint8Array): number;
24
+ export declare function ffiBindNull(stmt: bigint, idx: number): number;
25
+ export declare function ffiColumnCount(stmt: bigint): number;
26
+ export declare function ffiColumnName(stmt: bigint, idx: number, buf: Uint8Array): number;
27
+ export declare function ffiColumnMeta(stmt: bigint, idx: number, which: number, buf: Uint8Array): number;
28
+ export declare function ffiColumnType(stmt: bigint, idx: number): number;
29
+ export declare function ffiColumnInt64(stmt: bigint, idx: number): bigint;
30
+ export declare function ffiColumnDbl(stmt: bigint, idx: number): number;
31
+ export declare function ffiColumnText(stmt: bigint, idx: number, buf: Uint8Array): number;
32
+ export declare function ffiColumnBlob(stmt: bigint, idx: number, buf: Uint8Array): number;
33
+ export declare function ffiLastInsertRowid(db: bigint): bigint;
34
+ export declare function ffiChanges(db: bigint): number;
@@ -0,0 +1,110 @@
1
+ // declare-function bindings for vendor/shim/sqlite_shim.c.
2
+ // These must match vendor/manifest.json exactly (names, arity, types).
3
+ // Span ABI: `string` params marshal as (ptr,len) — the declares pass only
4
+ // the JS string; `mutable-bytes` out params marshal as (buf,len) — the
5
+ // declares pass only the Uint8Array. Thin exported wrappers re-expose the
6
+ // bindings: ambient declarations cannot be exported. Under plain Node the
7
+ // emitted calls resolve on globalThis — test/koffi-binding.mjs installs
8
+ // matching globals loaded through koffi.
9
+ export function ffiOpen(path, flags) {
10
+ return shim_open(path, flags);
11
+ }
12
+ export function ffiClose(db) {
13
+ return shim_close(db);
14
+ }
15
+ export function ffiErrcode(db) {
16
+ return shim_errcode(db);
17
+ }
18
+ export function ffiErrmsg(db, buf) {
19
+ return shim_errmsg(db, buf);
20
+ }
21
+ export function ffiInTransaction(db) {
22
+ return shim_in_transaction(db);
23
+ }
24
+ export function ffiExec(db, sql) {
25
+ return shim_exec(db, sql);
26
+ }
27
+ export function ffiBegin(db) {
28
+ return shim_begin(db);
29
+ }
30
+ export function ffiCommit(db) {
31
+ return shim_commit(db);
32
+ }
33
+ export function ffiRollback(db) {
34
+ return shim_rollback(db);
35
+ }
36
+ export function ffiSavepoint(db, name, op) {
37
+ return shim_savepoint(db, name, op);
38
+ }
39
+ export function ffiPrepare(db, sql) {
40
+ return shim_prepare(db, sql);
41
+ }
42
+ export function ffiStep(stmt) {
43
+ return shim_step(stmt);
44
+ }
45
+ export function ffiReset(stmt) {
46
+ return shim_reset(stmt);
47
+ }
48
+ export function ffiFinalize(stmt) {
49
+ return shim_finalize(stmt);
50
+ }
51
+ export function ffiClearBindings(stmt) {
52
+ return shim_clear_bindings(stmt);
53
+ }
54
+ export function ffiStmtReadonly(stmt) {
55
+ return shim_stmt_readonly(stmt);
56
+ }
57
+ export function ffiExpandedSql(stmt, buf) {
58
+ return shim_expanded_sql(stmt, buf);
59
+ }
60
+ export function ffiBindCount(stmt) {
61
+ return shim_bind_count(stmt);
62
+ }
63
+ export function ffiBindIndex(stmt, name) {
64
+ return shim_bind_index(stmt, name);
65
+ }
66
+ export function ffiBindInt(stmt, idx, val) {
67
+ return shim_bind_int(stmt, idx, val);
68
+ }
69
+ export function ffiBindDbl(stmt, idx, val) {
70
+ return shim_bind_dbl(stmt, idx, val);
71
+ }
72
+ export function ffiBindText(stmt, idx, val) {
73
+ return shim_bind_text(stmt, idx, val);
74
+ }
75
+ export function ffiBindBlob(stmt, idx, val) {
76
+ return shim_bind_blob(stmt, idx, val);
77
+ }
78
+ export function ffiBindNull(stmt, idx) {
79
+ return shim_bind_null(stmt, idx);
80
+ }
81
+ export function ffiColumnCount(stmt) {
82
+ return shim_column_count(stmt);
83
+ }
84
+ export function ffiColumnName(stmt, idx, buf) {
85
+ return shim_column_name(stmt, idx, buf);
86
+ }
87
+ export function ffiColumnMeta(stmt, idx, which, buf) {
88
+ return shim_column_meta(stmt, idx, which, buf);
89
+ }
90
+ export function ffiColumnType(stmt, idx) {
91
+ return shim_column_type(stmt, idx);
92
+ }
93
+ export function ffiColumnInt64(stmt, idx) {
94
+ return shim_column_int64(stmt, idx);
95
+ }
96
+ export function ffiColumnDbl(stmt, idx) {
97
+ return shim_column_dbl(stmt, idx);
98
+ }
99
+ export function ffiColumnText(stmt, idx, buf) {
100
+ return shim_column_text(stmt, idx, buf);
101
+ }
102
+ export function ffiColumnBlob(stmt, idx, buf) {
103
+ return shim_column_blob(stmt, idx, buf);
104
+ }
105
+ export function ffiLastInsertRowid(db) {
106
+ return shim_last_insert_rowid(db);
107
+ }
108
+ export function ffiChanges(db) {
109
+ return shim_changes(db);
110
+ }
@@ -0,0 +1 @@
1
+ export declare function nextSavepoint(): string;
@@ -0,0 +1,7 @@
1
+ // Savepoint name generation for nested transactions.
2
+ // Names must satisfy the shim's identifier whitelist [A-Za-z0-9_].
3
+ let counter = 0;
4
+ export function nextSavepoint() {
5
+ counter += 1;
6
+ return "sp_" + String(counter);
7
+ }
@@ -0,0 +1,3 @@
1
+ export declare function utf8Encode(s: string): Uint8Array;
2
+ /** Decode the first `n` bytes of `buf` as UTF-8. */
3
+ export declare function utf8Decode(buf: Uint8Array, n: number): string;
@@ -0,0 +1,10 @@
1
+ // string <-> UTF-8 helpers over TextEncoder/TextDecoder (subset-clean).
2
+ const encoder = new TextEncoder();
3
+ const decoder = new TextDecoder();
4
+ export function utf8Encode(s) {
5
+ return encoder.encode(s);
6
+ }
7
+ /** Decode the first `n` bytes of `buf` as UTF-8. */
8
+ export function utf8Decode(buf, n) {
9
+ return decoder.decode(buf.slice(0, n));
10
+ }
@@ -0,0 +1,120 @@
1
+ // Installs the `shim_*` globals the emitted dist/esm/internal/ffi.js calls,
2
+ // backed by the shared build (build/libcutils_sqlite.so) through koffi.
3
+ // The scriptc span ABI means string/bytes params cross as (ptr,len) pairs —
4
+ // koffi can't produce that layout from a JS string, so each binding is
5
+ // wrapped in a JS adapter that encodes the span explicitly. Handles cross
6
+ // as uint64 bigints (pointer-sized on x86_64/aarch64).
7
+
8
+ import koffi from "koffi";
9
+ import { fileURLToPath } from "node:url";
10
+ import path from "node:path";
11
+
12
+ const dir = path.dirname(fileURLToPath(import.meta.url));
13
+ const lib = koffi.load(path.join(dir, "..", "..", "build", "libcutils_sqlite.so"));
14
+
15
+ const g = globalThis;
16
+ const enc = new TextEncoder();
17
+
18
+ const f = {
19
+ open: lib.func("uint64 shim_open(const uint8_t *path, uint64 plen, int32 flags)"),
20
+ close: lib.func("int32 shim_close(uint64 db)"),
21
+ errcode: lib.func("int32 shim_errcode(uint64 db)"),
22
+ errmsg: lib.func("int32 shim_errmsg(uint64 db, uint8_t *buf, uint64 len)"),
23
+ inTransaction: lib.func("int32 shim_in_transaction(uint64 db)"),
24
+ exec: lib.func("int32 shim_exec(uint64 db, const uint8_t *sql, uint64 slen)"),
25
+ begin: lib.func("int32 shim_begin(uint64 db)"),
26
+ commit: lib.func("int32 shim_commit(uint64 db)"),
27
+ rollback: lib.func("int32 shim_rollback(uint64 db)"),
28
+ savepoint: lib.func(
29
+ "int32 shim_savepoint(uint64 db, const uint8_t *name, uint64 nlen, int32 op)",
30
+ ),
31
+ prepare: lib.func("uint64 shim_prepare(uint64 db, const uint8_t *sql, uint64 slen)"),
32
+ step: lib.func("int32 shim_step(uint64 stmt)"),
33
+ reset: lib.func("int32 shim_reset(uint64 stmt)"),
34
+ finalize: lib.func("int32 shim_finalize(uint64 stmt)"),
35
+ clearBindings: lib.func("int32 shim_clear_bindings(uint64 stmt)"),
36
+ stmtReadonly: lib.func("int32 shim_stmt_readonly(uint64 stmt)"),
37
+ expandedSql: lib.func("int32 shim_expanded_sql(uint64 stmt, uint8_t *buf, uint64 len)"),
38
+ bindCount: lib.func("int32 shim_bind_count(uint64 stmt)"),
39
+ bindIndex: lib.func("int32 shim_bind_index(uint64 stmt, const uint8_t *name, uint64 nlen)"),
40
+ bindInt: lib.func("int32 shim_bind_int(uint64 stmt, int32 idx, int64 val)"),
41
+ bindDbl: lib.func("int32 shim_bind_dbl(uint64 stmt, int32 idx, double val)"),
42
+ bindText: lib.func(
43
+ "int32 shim_bind_text(uint64 stmt, int32 idx, const uint8_t *val, uint64 vlen)",
44
+ ),
45
+ bindBlob: lib.func(
46
+ "int32 shim_bind_blob(uint64 stmt, int32 idx, const uint8_t *val, uint64 vlen)",
47
+ ),
48
+ bindNull: lib.func("int32 shim_bind_null(uint64 stmt, int32 idx)"),
49
+ columnCount: lib.func("int32 shim_column_count(uint64 stmt)"),
50
+ columnName: lib.func("int32 shim_column_name(uint64 stmt, int32 idx, uint8_t *buf, uint64 len)"),
51
+ columnMeta: lib.func(
52
+ "int32 shim_column_meta(uint64 stmt, int32 idx, int32 which, uint8_t *buf, uint64 len)",
53
+ ),
54
+ columnType: lib.func("int32 shim_column_type(uint64 stmt, int32 idx)"),
55
+ columnInt64: lib.func("int64 shim_column_int64(uint64 stmt, int32 idx)"),
56
+ columnDbl: lib.func("double shim_column_dbl(uint64 stmt, int32 idx)"),
57
+ columnText: lib.func("int32 shim_column_text(uint64 stmt, int32 idx, uint8_t *buf, uint64 len)"),
58
+ columnBlob: lib.func("int32 shim_column_blob(uint64 stmt, int32 idx, uint8_t *buf, uint64 len)"),
59
+ lastInsertRowid: lib.func("int64 shim_last_insert_rowid(uint64 db)"),
60
+ changes: lib.func("int32 shim_changes(uint64 db)"),
61
+ };
62
+
63
+ function span(s) {
64
+ const b = enc.encode(s);
65
+ return [b, BigInt(b.length)];
66
+ }
67
+
68
+ g.shim_open = (path, flags) => {
69
+ const [b, n] = span(path);
70
+ return f.open(b, n, flags);
71
+ };
72
+ g.shim_close = (db) => f.close(db);
73
+ g.shim_errcode = (db) => f.errcode(db);
74
+ g.shim_errmsg = (db, buf) => f.errmsg(db, buf, BigInt(buf.length));
75
+ g.shim_in_transaction = (db) => f.inTransaction(db);
76
+ g.shim_exec = (db, sql) => {
77
+ const [b, n] = span(sql);
78
+ return f.exec(db, b, n);
79
+ };
80
+ g.shim_begin = (db) => f.begin(db);
81
+ g.shim_commit = (db) => f.commit(db);
82
+ g.shim_rollback = (db) => f.rollback(db);
83
+ g.shim_savepoint = (db, name, op) => {
84
+ const [b, n] = span(name);
85
+ return f.savepoint(db, b, n, op);
86
+ };
87
+ g.shim_prepare = (db, sql) => {
88
+ const [b, n] = span(sql);
89
+ return f.prepare(db, b, n);
90
+ };
91
+ g.shim_step = (stmt) => f.step(stmt);
92
+ g.shim_reset = (stmt) => f.reset(stmt);
93
+ g.shim_finalize = (stmt) => f.finalize(stmt);
94
+ g.shim_clear_bindings = (stmt) => f.clearBindings(stmt);
95
+ g.shim_stmt_readonly = (stmt) => f.stmtReadonly(stmt);
96
+ g.shim_expanded_sql = (stmt, buf) => f.expandedSql(stmt, buf, BigInt(buf.length));
97
+ g.shim_bind_count = (stmt) => f.bindCount(stmt);
98
+ g.shim_bind_index = (stmt, name) => {
99
+ const [b, n] = span(name);
100
+ return f.bindIndex(stmt, b, n);
101
+ };
102
+ g.shim_bind_int = (stmt, idx, val) => f.bindInt(stmt, idx, val);
103
+ g.shim_bind_dbl = (stmt, idx, val) => f.bindDbl(stmt, idx, val);
104
+ g.shim_bind_text = (stmt, idx, val) => {
105
+ const [b, n] = span(val);
106
+ return f.bindText(stmt, idx, b, n);
107
+ };
108
+ g.shim_bind_blob = (stmt, idx, val) => f.bindBlob(stmt, idx, val, BigInt(val.length));
109
+ g.shim_bind_null = (stmt, idx) => f.bindNull(stmt, idx);
110
+ g.shim_column_count = (stmt) => f.columnCount(stmt);
111
+ g.shim_column_name = (stmt, idx, buf) => f.columnName(stmt, idx, buf, BigInt(buf.length));
112
+ g.shim_column_meta = (stmt, idx, which, buf) =>
113
+ f.columnMeta(stmt, idx, which, buf, BigInt(buf.length));
114
+ g.shim_column_type = (stmt, idx) => f.columnType(stmt, idx);
115
+ g.shim_column_int64 = (stmt, idx) => f.columnInt64(stmt, idx);
116
+ g.shim_column_dbl = (stmt, idx) => f.columnDbl(stmt, idx);
117
+ g.shim_column_text = (stmt, idx, buf) => f.columnText(stmt, idx, buf, BigInt(buf.length));
118
+ g.shim_column_blob = (stmt, idx, buf) => f.columnBlob(stmt, idx, buf, BigInt(buf.length));
119
+ g.shim_last_insert_rowid = (db) => f.lastInsertRowid(db);
120
+ g.shim_changes = (db) => f.changes(db);
@@ -0,0 +1,66 @@
1
+ /** Standard Typed `types` member shape (valibot-style). */
2
+ export interface StdTypes<Input, Output> {
3
+ input: Input;
4
+ output: Output;
5
+ }
6
+ /**
7
+ * Standard Schema `~standard` props — a CLASS, not an interface:
8
+ * interface-typed class fields erase to `unknown` under scriptc (SC1090),
9
+ * so the seam shape is declared as classes (the same trick `@chttp/val`
10
+ * uses). Structurally every conforming validator still satisfies it:
11
+ * `version` is `number` (not literal `1`, so `@chttp/val`'s
12
+ * `version: number` field assigns) and `validate` returns `unknown` so
13
+ * both sync results and spec-conformant `Result | Promise<Result>`
14
+ * signatures are compatible. Async validators are rejected at call time.
15
+ */
16
+ export declare class StdProps {
17
+ version: number;
18
+ vendor: string;
19
+ validate(input: unknown): unknown;
20
+ }
21
+ /** Standard Schema v1 shape (local mirror of the spec). */
22
+ export declare class StandardSchemaV1 {
23
+ "~standard": StdProps;
24
+ }
25
+ /**
26
+ * Row output inference: reads the optional `types` member when the schema
27
+ * carries it (valibot and other spec-complete validators), else `unknown`
28
+ * (`@chttp/val` today — its coarse inference is a val-side ticket).
29
+ */
30
+ export type InferOutput<S extends StandardSchemaV1> = S extends {
31
+ "~standard": {
32
+ types: {
33
+ output: infer O;
34
+ };
35
+ };
36
+ } ? O : unknown;
37
+ /** A value SQLite can store / return. */
38
+ export type SqlValue = number | bigint | string | null | Uint8Array;
39
+ /** A bindable value; booleans bind as INTEGER 0/1. */
40
+ export type BindValue = SqlValue | boolean;
41
+ /** A row as returned by `get`/`all` before schema validation. */
42
+ export type Row = Record<string, SqlValue>;
43
+ /** Write-side parameters for named binds (`@x`, `:x`, `$x`). */
44
+ export type BindRecord = Record<string, BindValue>;
45
+ export interface RunResult {
46
+ changes: number;
47
+ lastInsertRowid: number;
48
+ }
49
+ export interface OpenOpts {
50
+ /** Open read-only (fails if the file does not exist). */
51
+ readonly?: boolean;
52
+ /** Fail instead of creating the file when it does not exist. */
53
+ fileMustExist?: boolean;
54
+ }
55
+ export interface ColumnInfo {
56
+ /** Column name as the statement returns it. */
57
+ name: string;
58
+ /** Origin column name, or null for expressions / metadata off. */
59
+ column: string | null;
60
+ /** Origin table name. */
61
+ table: string | null;
62
+ /** Origin database name ("main", "temp", or an ATTACH alias). */
63
+ database: string | null;
64
+ /** Declared column type from the DDL, or null for expressions. */
65
+ type: string | null;
66
+ }
@@ -0,0 +1,29 @@
1
+ // Public value/row types and the Standard Schema v1 seam types.
2
+ //
3
+ // The Standard Schema types are a LOCAL MIRROR of `@standard-schema/spec`,
4
+ // not an import: scriptc 0.3.3 refuses to analyze the spec package's shipped
5
+ // JS even for a type-only import, so the package owns a structural copy of
6
+ // the spec surface (props + validate signature + InferOutput inference).
7
+ // Structurally every conforming validator satisfies it — `@chttp/val` schemas,
8
+ // valibot schemas, anything with `~standard.validate`.
9
+ /**
10
+ * Standard Schema `~standard` props — a CLASS, not an interface:
11
+ * interface-typed class fields erase to `unknown` under scriptc (SC1090),
12
+ * so the seam shape is declared as classes (the same trick `@chttp/val`
13
+ * uses). Structurally every conforming validator still satisfies it:
14
+ * `version` is `number` (not literal `1`, so `@chttp/val`'s
15
+ * `version: number` field assigns) and `validate` returns `unknown` so
16
+ * both sync results and spec-conformant `Result | Promise<Result>`
17
+ * signatures are compatible. Async validators are rejected at call time.
18
+ */
19
+ export class StdProps {
20
+ version = 0;
21
+ vendor = "";
22
+ validate(input) {
23
+ return { value: input, issues: null };
24
+ }
25
+ }
26
+ /** Standard Schema v1 shape (local mirror of the spec). */
27
+ export class StandardSchemaV1 {
28
+ "~standard" = new StdProps();
29
+ }
@@ -0,0 +1,7 @@
1
+ import { StandardSchemaV1 } from "./types.ts";
2
+ /**
3
+ * Run `schema["~standard"].validate(value)` synchronously. Returns the
4
+ * validator's (possibly transformed) output. Throws `SqliteError` with
5
+ * `code: "VALIDATION"` on failure.
6
+ */
7
+ export declare function validateRow(schema: StandardSchemaV1, value: unknown): unknown;
@@ -0,0 +1,44 @@
1
+ // Standard-Schema seam: `schema["~standard"].validate(row)` with structural
2
+ // result handling — val returns `{ value, issues: null }`, spec-conformant
3
+ // validators return `{ value }` (issues member absent) or `{ issues }`.
4
+ // A Promise result (async validator) is rejected: this FFI surface is sync.
5
+ import { SqliteError } from "./errors.js";
6
+ function summarizeIssues(issues) {
7
+ if (typeof issues !== "object" || issues === null) {
8
+ return "schema validation failed";
9
+ }
10
+ const list = issues;
11
+ const first = list[0];
12
+ if (typeof first !== "object" || first === null) {
13
+ return "schema validation failed";
14
+ }
15
+ let msg = first.message;
16
+ if (typeof msg !== "string" || msg.length === 0) {
17
+ msg = "schema validation failed";
18
+ }
19
+ if (list.length > 1) {
20
+ return msg + " (+" + String(list.length - 1) + " more issues)";
21
+ }
22
+ return msg;
23
+ }
24
+ /**
25
+ * Run `schema["~standard"].validate(value)` synchronously. Returns the
26
+ * validator's (possibly transformed) output. Throws `SqliteError` with
27
+ * `code: "VALIDATION"` on failure.
28
+ */
29
+ export function validateRow(schema, value) {
30
+ const res = schema["~standard"].validate(value);
31
+ if (typeof res !== "object" || res === null) {
32
+ throw new SqliteError("VALIDATION", "validator returned a non-standard result");
33
+ }
34
+ // Promise results (async validators) land here: no `value`/`issues`
35
+ // members, so both checks below fail into the non-standard throw.
36
+ const iss = res.issues;
37
+ if (iss !== null && typeof iss !== "undefined") {
38
+ throw new SqliteError("VALIDATION", summarizeIssues(iss));
39
+ }
40
+ if (typeof res.value === "undefined") {
41
+ throw new SqliteError("VALIDATION", "validator returned a non-standard result (async validators are not supported)");
42
+ }
43
+ return res.value;
44
+ }
package/package.json CHANGED
@@ -1,6 +1,74 @@
1
1
  {
2
2
  "name": "@cutils/sqlite",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Embedded SQLite for chttp/scriptc apps — vendored amalgamation, FFI shim, Standard-Schema row seam. Compiles to a single static ELF.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/sigilco/cutils.git",
9
+ "directory": "packages/sqlite"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src",
14
+ "vendor",
15
+ "build/libsqlite3-shim.a"
16
+ ],
17
+ "type": "module",
18
+ "main": "./dist/esm/index.js",
19
+ "types": "./dist/esm/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/esm/index.d.ts",
23
+ "import": "./dist/esm/index.js"
24
+ },
25
+ "./package.json": "./package.json",
26
+ "./node-binding": "./dist/esm/node-binding.mjs"
27
+ },
28
+ "devDependencies": {
29
+ "@chttp/val": "^0.2.1",
30
+ "@standard-schema/spec": "^1.1.0",
31
+ "@types/node": "^24.0.0",
32
+ "koffi": "^2.14.1",
33
+ "typescript": "^5.9.0",
34
+ "valibot": "^1.1.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=22"
38
+ },
39
+ "peerDependencies": {
40
+ "koffi": "^2.14.1"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "koffi": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "author": "Joaquin Terrasa & contributors",
48
+ "keywords": [
49
+ "sqlite",
50
+ "database",
51
+ "standard-schema",
52
+ "scriptc",
53
+ "native",
54
+ "elf"
55
+ ],
56
+ "homepage": "https://github.com/sigilco/cutils/tree/main/packages/sqlite#readme",
57
+ "bugs": {
58
+ "url": "https://github.com/sigilco/cutils/issues"
59
+ },
60
+ "sideEffects": false,
61
+ "scripts": {
62
+ "build:c": "cc -O2 -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_COLUMN_METADATA -c vendor/shim/sqlite_shim.c -o build/sqlite_shim.o",
63
+ "build:sqlite": "cc -O2 -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_COLUMN_METADATA -c vendor/sqlite-amalgamation/sqlite3.c -o build/sqlite3.o",
64
+ "build:archive": "ar rcs build/libsqlite3-shim.a build/sqlite_shim.o build/sqlite3.o",
65
+ "build:lib": "ranlib build/libsqlite3-shim.a",
66
+ "build:shared": "cc -O2 -fPIC -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_COLUMN_METADATA -Wl,-Bsymbolic -shared vendor/shim/sqlite_shim.c vendor/sqlite-amalgamation/sqlite3.c -o build/libcutils_sqlite.so",
67
+ "build:ts": "tsc -p tsconfig.json",
68
+ "build": "mkdir -p build && npm run build:c && npm run build:sqlite && npm run build:archive && npm run build:lib && npm run build:ts && sed 's|\"\\.\\.\", \"build\"|\"..\", \"..\", \"build\"|' test/koffi-binding.mjs > dist/esm/node-binding.mjs",
69
+ "typecheck": "tsc -p tsconfig.json --noEmit",
70
+ "test": "npm run build && npm run build:shared && npm run test:c && npm run test:node && bash test/elf.test.sh",
71
+ "test:c": "cc -O2 -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_COLUMN_METADATA test/shim.test.c build/libsqlite3-shim.a -o build/shim_test -lm && ./build/shim_test",
72
+ "test:node": "node --test test/*.test.js test/*.test.mjs"
73
+ }
6
74
  }
package/src/errors.ts ADDED
@@ -0,0 +1,108 @@
1
+ // SqliteError + the numeric-result-code → name mapping.
2
+
3
+ export class SqliteError extends Error {
4
+ code: string;
5
+ constructor(code: string, message: string) {
6
+ super(message);
7
+ this.name = "SqliteError";
8
+ this.code = code;
9
+ }
10
+ }
11
+
12
+ // Primary result codes (rc & 0xFF) plus the constraint extended codes —
13
+ // the names better-sqlite3 users will recognize from `err.code`.
14
+ export function sqliteCodeName(rc: number): string {
15
+ switch (rc) {
16
+ case 275:
17
+ return "SQLITE_CONSTRAINT_CHECK";
18
+ case 531:
19
+ return "SQLITE_CONSTRAINT_COMMITHOOK";
20
+ case 787:
21
+ return "SQLITE_CONSTRAINT_FOREIGNKEY";
22
+ case 803:
23
+ return "SQLITE_CONSTRAINT_FUNCTION";
24
+ case 1027:
25
+ return "SQLITE_CONSTRAINT_TRIGGER";
26
+ case 1043:
27
+ return "SQLITE_CONSTRAINT_VTAB";
28
+ case 1299:
29
+ return "SQLITE_CONSTRAINT_NOTNULL";
30
+ case 1555:
31
+ return "SQLITE_CONSTRAINT_PRIMARYKEY";
32
+ case 2067:
33
+ return "SQLITE_CONSTRAINT_UNIQUE";
34
+ case 2579:
35
+ return "SQLITE_CONSTRAINT_ROWID";
36
+ case 2835:
37
+ return "SQLITE_CONSTRAINT_PINNED";
38
+ case 3091:
39
+ return "SQLITE_CONSTRAINT_DATATYPE";
40
+ default:
41
+ break;
42
+ }
43
+ const primary = rc & 255;
44
+ switch (primary) {
45
+ case 1:
46
+ return "SQLITE_ERROR";
47
+ case 2:
48
+ return "SQLITE_INTERNAL";
49
+ case 3:
50
+ return "SQLITE_PERM";
51
+ case 4:
52
+ return "SQLITE_ABORT";
53
+ case 5:
54
+ return "SQLITE_BUSY";
55
+ case 6:
56
+ return "SQLITE_LOCKED";
57
+ case 7:
58
+ return "SQLITE_NOMEM";
59
+ case 8:
60
+ return "SQLITE_READONLY";
61
+ case 9:
62
+ return "SQLITE_INTERRUPT";
63
+ case 10:
64
+ return "SQLITE_IOERR";
65
+ case 11:
66
+ return "SQLITE_CORRUPT";
67
+ case 12:
68
+ return "SQLITE_NOTFOUND";
69
+ case 13:
70
+ return "SQLITE_FULL";
71
+ case 14:
72
+ return "SQLITE_CANTOPEN";
73
+ case 15:
74
+ return "SQLITE_PROTOCOL";
75
+ case 16:
76
+ return "SQLITE_EMPTY";
77
+ case 17:
78
+ return "SQLITE_SCHEMA";
79
+ case 18:
80
+ return "SQLITE_TOOBIG";
81
+ case 19:
82
+ return "SQLITE_CONSTRAINT";
83
+ case 20:
84
+ return "SQLITE_MISMATCH";
85
+ case 21:
86
+ return "SQLITE_MISUSE";
87
+ case 22:
88
+ return "SQLITE_NOLFS";
89
+ case 23:
90
+ return "SQLITE_AUTH";
91
+ case 24:
92
+ return "SQLITE_FORMAT";
93
+ case 25:
94
+ return "SQLITE_RANGE";
95
+ case 26:
96
+ return "SQLITE_NOTADB";
97
+ case 27:
98
+ return "SQLITE_NOTICE";
99
+ case 28:
100
+ return "SQLITE_WARNING";
101
+ case 100:
102
+ return "SQLITE_ROW";
103
+ case 101:
104
+ return "SQLITE_DONE";
105
+ default:
106
+ return "SQLITE_ERROR";
107
+ }
108
+ }