@bitcobblers/wod-wiki-storage 0.35.2129 → 0.36.2133
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/dist/chunk-6ZTAWTAP.mjs +58 -0
- package/dist/chunk-6ZTAWTAP.mjs.map +1 -0
- package/dist/chunk-XRQKLSOT.mjs +15 -0
- package/dist/chunk-XRQKLSOT.mjs.map +1 -0
- package/dist/{chunk-7ZCBM5NS.mjs → chunk-YESCCCRF.mjs} +4 -15
- package/dist/chunk-YESCCCRF.mjs.map +1 -0
- package/dist/connection-DxuCLpRc.d.cts +38 -0
- package/dist/connection-DxuCLpRc.d.ts +38 -0
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/sql/index.cjs +72 -4
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +11 -37
- package/dist/sql/index.d.ts +11 -37
- package/dist/sql/index.mjs +77 -60
- package/dist/sql/index.mjs.map +1 -1
- package/dist/sql/node.cjs +197 -0
- package/dist/sql/node.cjs.map +1 -0
- package/dist/sql/node.d.cts +17 -0
- package/dist/sql/node.d.ts +17 -0
- package/dist/sql/node.mjs +129 -0
- package/dist/sql/node.mjs.map +1 -0
- package/package.json +14 -6
- package/dist/chunk-7ZCBM5NS.mjs.map +0 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var client = require('@libsql/client');
|
|
4
|
+
var promises = require('fs/promises');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
|
|
7
|
+
// src/sql/node.ts
|
|
8
|
+
|
|
9
|
+
// src/sql/errors.ts
|
|
10
|
+
var StorageError = class extends Error {
|
|
11
|
+
constructor(status, message, code) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.name = "StorageError";
|
|
16
|
+
}
|
|
17
|
+
status;
|
|
18
|
+
code;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/sql/connection.ts
|
|
22
|
+
function libsqlRows(result) {
|
|
23
|
+
return result.rows;
|
|
24
|
+
}
|
|
25
|
+
function libsqlDatabase(client) {
|
|
26
|
+
let chain = Promise.resolve();
|
|
27
|
+
const serialize = (fn) => {
|
|
28
|
+
const next = chain.then(fn, fn);
|
|
29
|
+
chain = next.then(() => void 0, () => void 0);
|
|
30
|
+
return next;
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
dialect: "sqlite",
|
|
34
|
+
query: (sql, params = []) => serialize(() => client.execute({ sql, args: params }).then(libsqlRows)),
|
|
35
|
+
exec: async (sql, params = []) => {
|
|
36
|
+
await serialize(() => client.execute({ sql, args: params }));
|
|
37
|
+
},
|
|
38
|
+
transaction(fn) {
|
|
39
|
+
return serialize(async () => {
|
|
40
|
+
const tx = await client.transaction("write");
|
|
41
|
+
try {
|
|
42
|
+
const txConn = {
|
|
43
|
+
query: (sql, params = []) => tx.execute({ sql, args: params }).then(libsqlRows),
|
|
44
|
+
exec: async (sql, params = []) => {
|
|
45
|
+
await tx.execute({ sql, args: params });
|
|
46
|
+
},
|
|
47
|
+
batch: async (statements) => (await tx.batch(statements.map(({ sql, params = [] }) => ({ sql, args: params })))).map(libsqlRows)
|
|
48
|
+
};
|
|
49
|
+
const result = await fn(txConn);
|
|
50
|
+
await tx.commit();
|
|
51
|
+
return result;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
try {
|
|
54
|
+
await tx.rollback();
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
58
|
+
for (const code of ["revision_conflict", "transaction_conflict", "invalid_session_pin"]) {
|
|
59
|
+
if (message.includes(code)) throw new StorageError(409, message, code);
|
|
60
|
+
}
|
|
61
|
+
throw err;
|
|
62
|
+
} finally {
|
|
63
|
+
tx.close();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
close: async () => {
|
|
68
|
+
await chain;
|
|
69
|
+
client.close();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/sql/node.ts
|
|
75
|
+
var SQLITE_URL_SCHEMES = /^(libsql|https?|wss?|file):\/\//;
|
|
76
|
+
function driverEnv(env) {
|
|
77
|
+
const driver = env.DB_DRIVER || "sqlite";
|
|
78
|
+
const dbUrl = env.DATABASE_URL;
|
|
79
|
+
if (driver === "postgres") {
|
|
80
|
+
if (!dbUrl || !/^postgres(ql)?:\/\//.test(dbUrl)) {
|
|
81
|
+
throw new StorageError(500, "DB_DRIVER=postgres requires DATABASE_URL starting with postgres:// or postgresql://", "bad_db_env");
|
|
82
|
+
}
|
|
83
|
+
return { dialect: "postgres", url: dbUrl };
|
|
84
|
+
}
|
|
85
|
+
if (driver !== "sqlite" && driver !== "turso") {
|
|
86
|
+
throw new StorageError(500, `Unsupported DB_DRIVER: ${driver} (expected sqlite|turso|postgres)`, "bad_db_env");
|
|
87
|
+
}
|
|
88
|
+
if (dbUrl) {
|
|
89
|
+
if (/^postgres(ql)?:\/\//.test(dbUrl)) {
|
|
90
|
+
throw new StorageError(500, `DB_DRIVER=${driver} cannot use a postgres:// DATABASE_URL`, "bad_db_env");
|
|
91
|
+
}
|
|
92
|
+
if (!SQLITE_URL_SCHEMES.test(dbUrl)) {
|
|
93
|
+
throw new StorageError(500, "DB_DRIVER=" + driver + " requires a libsql://, https://, http://, wss:// or file:// DATABASE_URL", "bad_db_env");
|
|
94
|
+
}
|
|
95
|
+
if (driver === "turso" && dbUrl.startsWith("file:")) {
|
|
96
|
+
throw new StorageError(500, "DB_DRIVER=turso requires a remote DATABASE_URL (libsql:// or https://)", "bad_db_env");
|
|
97
|
+
}
|
|
98
|
+
return { dialect: "sqlite", url: dbUrl, authToken: env.LIBSQL_AUTH_TOKEN || void 0 };
|
|
99
|
+
}
|
|
100
|
+
if (driver === "turso") {
|
|
101
|
+
throw new StorageError(500, "DB_DRIVER=turso requires DATABASE_URL (libsql:// or https://)", "bad_db_env");
|
|
102
|
+
}
|
|
103
|
+
return { dialect: "sqlite", url: "file:" + (env.SQLITE_PATH || "./data/wodwiki.db") };
|
|
104
|
+
}
|
|
105
|
+
function pgSql(sql) {
|
|
106
|
+
let i = 0;
|
|
107
|
+
return sql.replace(/\?/g, () => `$${++i}`);
|
|
108
|
+
}
|
|
109
|
+
function pgConnection(sql) {
|
|
110
|
+
const conn = {
|
|
111
|
+
query: async (statement, params = []) => await sql.unsafe(pgSql(statement), params),
|
|
112
|
+
exec: async (statement, params = []) => {
|
|
113
|
+
await sql.unsafe(pgSql(statement), params);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
...conn,
|
|
118
|
+
dialect: "postgres",
|
|
119
|
+
async transaction(fn) {
|
|
120
|
+
return sql.begin(async (tx) => {
|
|
121
|
+
const txConn = {
|
|
122
|
+
query: (statement, params = []) => tx.unsafe(pgSql(statement), params),
|
|
123
|
+
exec: async (statement, params = []) => {
|
|
124
|
+
await tx.unsafe(pgSql(statement), params);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
return fn(txConn);
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
close: async () => {
|
|
131
|
+
await sql.close({ timeout: 0 });
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async function openPgSql(url) {
|
|
136
|
+
let SQL;
|
|
137
|
+
try {
|
|
138
|
+
const bun = await import('bun');
|
|
139
|
+
SQL = bun.SQL;
|
|
140
|
+
} catch {
|
|
141
|
+
throw new StorageError(500, "PostgreSQL requires the Bun runtime (built-in Bun.SQL driver); run the server or CLI with bun \u2014 no Node.js PostgreSQL driver is bundled", "bad_db_env");
|
|
142
|
+
}
|
|
143
|
+
return new SQL({ url });
|
|
144
|
+
}
|
|
145
|
+
function adminUrl(url) {
|
|
146
|
+
const u = new URL(url);
|
|
147
|
+
u.pathname = "/postgres";
|
|
148
|
+
for (const key of [...u.searchParams.keys()]) {
|
|
149
|
+
if (/^(database|dbname|db)$/i.test(key)) u.searchParams.delete(key);
|
|
150
|
+
}
|
|
151
|
+
return u.toString();
|
|
152
|
+
}
|
|
153
|
+
function targetDatabase(url) {
|
|
154
|
+
const name = decodeURIComponent(new URL(url).pathname.replace(/^\/+|\/+$/g, ""));
|
|
155
|
+
const bytes = Buffer.byteLength(name, "utf8");
|
|
156
|
+
if (name === "" || name.includes("\0") || bytes > 63) {
|
|
157
|
+
throw new StorageError(500, "PostgreSQL database name must be 1..63 UTF-8 bytes without NUL", "bad_db_env");
|
|
158
|
+
}
|
|
159
|
+
return name;
|
|
160
|
+
}
|
|
161
|
+
function isMissingDatabase(error) {
|
|
162
|
+
if (typeof error !== "object" || error === null) return false;
|
|
163
|
+
return "errno" in error && error.errno === "3D000" || "code" in error && error.code === "3D000";
|
|
164
|
+
}
|
|
165
|
+
async function openDatabase(env = process.env, opts = {}) {
|
|
166
|
+
const cfg = driverEnv(env);
|
|
167
|
+
if (cfg.dialect === "postgres") {
|
|
168
|
+
let sql = await openPgSql(cfg.url);
|
|
169
|
+
if (opts.create) {
|
|
170
|
+
try {
|
|
171
|
+
await sql.unsafe("SELECT 1");
|
|
172
|
+
} catch (error) {
|
|
173
|
+
await sql.close({ timeout: 0 }).catch(() => {
|
|
174
|
+
});
|
|
175
|
+
if (!isMissingDatabase(error)) throw error;
|
|
176
|
+
const database = targetDatabase(cfg.url);
|
|
177
|
+
const admin = await openPgSql(adminUrl(cfg.url));
|
|
178
|
+
try {
|
|
179
|
+
await admin.unsafe(`CREATE DATABASE "${database.replace(/"/g, '""')}"`);
|
|
180
|
+
} finally {
|
|
181
|
+
await admin.close({ timeout: 0 });
|
|
182
|
+
}
|
|
183
|
+
sql = await openPgSql(cfg.url);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return pgConnection(sql);
|
|
187
|
+
}
|
|
188
|
+
if (cfg.url.startsWith("file:")) {
|
|
189
|
+
const fsPath = decodeURIComponent(cfg.url.slice("file:".length).split("?")[0]);
|
|
190
|
+
await promises.mkdir(path.dirname(fsPath), { recursive: true });
|
|
191
|
+
}
|
|
192
|
+
return libsqlDatabase(client.createClient({ url: cfg.url, authToken: cfg.authToken }));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
exports.openDatabase = openDatabase;
|
|
196
|
+
//# sourceMappingURL=node.cjs.map
|
|
197
|
+
//# sourceMappingURL=node.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/sql/errors.ts","../../src/sql/connection.ts","../../src/sql/node.ts"],"names":["mkdir","dirname","createClient"],"mappings":"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","file":"node.cjs","sourcesContent":["/**\n * StorageError — the single error type every shared SQL layer throws.\n * Replaces the API server's HTTP-specific error: `status` keeps the wire\n * mapping for the HTTP surface, `code` carries a stable machine identifier\n * (e.g. 'domain_projection_unavailable') for browser callers.\n */\nexport class StorageError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message);\n this.name = 'StorageError';\n }\n}\n","/**\n * Connection contracts + a generic libsql adapter. The adapter takes a\n * *structural* client so the browser passes @libsql/client/web and the server\n * passes @libsql/client (node) — this module never imports either, keeping\n * the browser graph free of native drivers.\n *\n * All operations are serialized through one promise chain: the underlying\n * client shares a single connection, so concurrent transactions/reads could\n * otherwise interleave on it. Transactions run on a transaction-owned\n * connection (libsql interactive transaction), so writes inside a transaction\n * commit or roll back atomically and are not visible outside it.\n */\n\nimport type { Client } from '@libsql/client';\n\nimport { StorageError } from './errors';\nexport type SqlValue = string | number | null; // booleans bound as 1/0 by callers\nexport type SqlRow = Record<string, unknown>;\n\nexport interface SqlStatement { sql: string; params?: SqlValue[] }\nexport interface SqlConnection {\n query(sql: string, params?: SqlValue[]): Promise<SqlRow[]>;\n exec(sql: string, params?: SqlValue[]): Promise<void>;\n batch?(statements: SqlStatement[]): Promise<SqlRow[][]>;\n}\n\nexport interface Database extends SqlConnection {\n readonly dialect: 'sqlite' | 'postgres';\n transaction<T>(fn: (tx: SqlConnection) => Promise<T>): Promise<T>;\n close(): Promise<void>;\n}\n\n/** Minimal surface used from a libsql client (node or web build) — the real\n * @libsql/client types, type-only so the browser graph stays driver-free. */\nexport type LibsqlClient = Pick<Client, 'execute' | 'transaction' | 'close'>;\n\nfunction libsqlRows(result: { rows: ArrayLike<Record<string, unknown>> }): SqlRow[] {\n return result.rows as unknown as SqlRow[];\n}\n\n/** Wrap a libsql client (node or web build) into the shared Database surface. */\nexport function libsqlDatabase(client: LibsqlClient): Database {\n let chain: Promise<unknown> = Promise.resolve();\n const serialize = <T>(fn: () => Promise<T>): Promise<T> => {\n const next = chain.then(fn, fn);\n chain = next.then(() => undefined, () => undefined);\n return next;\n };\n return {\n dialect: 'sqlite',\n query: (sql, params = []) => serialize(() => client.execute({ sql, args: params }).then(libsqlRows)),\n exec: async (sql, params = []) => {\n await serialize(() => client.execute({ sql, args: params }));\n },\n transaction<T>(fn: (tx: SqlConnection) => Promise<T>): Promise<T> {\n return serialize(async () => {\n const tx = await client.transaction('write');\n try {\n const txConn: SqlConnection = {\n query: (sql, params = []) => tx.execute({ sql, args: params }).then(libsqlRows),\n exec: async (sql, params = []) => {\n await tx.execute({ sql, args: params });\n },\n batch: async (statements) => (await tx.batch(statements.map(({ sql, params = [] }) => ({ sql, args: params })))).map(libsqlRows),\n };\n const result = await fn(txConn);\n await tx.commit();\n return result;\n } catch (err) {\n try {\n await tx.rollback();\n } catch {\n // transaction already closed by the failed statement\n }\n const message = err instanceof Error ? err.message : String(err);\n for (const code of ['revision_conflict', 'transaction_conflict', 'invalid_session_pin']) {\n if (message.includes(code)) throw new StorageError(409, message, code);\n }\n throw err;\n } finally {\n tx.close();\n }\n });\n },\n close: async () => {\n await chain;\n client.close();\n },\n };\n}\n","/**\n * @bitcobblers/wod-wiki-storage/sql/node — server-only database opening,\n * extracted from the API server: env-driven driver selection (node libsql\n * client for local SQLite / remote Turso, native Bun.SQL for PostgreSQL).\n * Importing this subpath pulls the node @libsql/client — never from browser\n * code. All SQL is generated internally with `?` placeholders; only the\n * PostgreSQL adapter rewrites them to $1..$n.\n */\nimport { createClient } from '@libsql/client';\nimport { mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { StorageError } from './errors';\nimport {\n libsqlDatabase,\n type Database,\n type SqlConnection,\n type SqlRow,\n} from './connection';\n\nconst SQLITE_URL_SCHEMES = /^(libsql|https?|wss?|file):\\/\\//;\n\n/** Structural Bun.SQL surface (bun-types is not a dependency of this package). */\ninterface PgSql {\n unsafe(query: string, params?: unknown[]): Promise<unknown[]>;\n begin<T>(fn: (tx: { unsafe(query: string, params?: unknown[]): Promise<unknown[]> }) => Promise<T>): Promise<T>;\n close(options?: { timeout?: number }): Promise<void>;\n}\n\nfunction driverEnv(env: Record<string, string | undefined>): {\n dialect: 'sqlite' | 'postgres';\n url: string;\n authToken?: string;\n} {\n const driver = env.DB_DRIVER || 'sqlite';\n const dbUrl = env.DATABASE_URL;\n if (driver === 'postgres') {\n if (!dbUrl || !/^postgres(ql)?:\\/\\//.test(dbUrl)) {\n throw new StorageError(500, 'DB_DRIVER=postgres requires DATABASE_URL starting with postgres:// or postgresql://', 'bad_db_env');\n }\n return { dialect: 'postgres', url: dbUrl };\n }\n if (driver !== 'sqlite' && driver !== 'turso') {\n throw new StorageError(500, `Unsupported DB_DRIVER: ${driver} (expected sqlite|turso|postgres)`, 'bad_db_env');\n }\n if (dbUrl) {\n if (/^postgres(ql)?:\\/\\//.test(dbUrl)) {\n throw new StorageError(500, `DB_DRIVER=${driver} cannot use a postgres:// DATABASE_URL`, 'bad_db_env');\n }\n if (!SQLITE_URL_SCHEMES.test(dbUrl)) {\n throw new StorageError(500, 'DB_DRIVER=' + driver + ' requires a libsql://, https://, http://, wss:// or file:// DATABASE_URL', 'bad_db_env');\n }\n if (driver === 'turso' && dbUrl.startsWith('file:')) {\n throw new StorageError(500, 'DB_DRIVER=turso requires a remote DATABASE_URL (libsql:// or https://)', 'bad_db_env');\n }\n return { dialect: 'sqlite', url: dbUrl, authToken: env.LIBSQL_AUTH_TOKEN || undefined };\n }\n if (driver === 'turso') {\n throw new StorageError(500, 'DB_DRIVER=turso requires DATABASE_URL (libsql:// or https://)', 'bad_db_env');\n }\n return { dialect: 'sqlite', url: 'file:' + (env.SQLITE_PATH || './data/wodwiki.db') };\n}\n\n/** '?' → '$1..$n' in order, counter reset per query. SQL is self-generated\n * (identifiers whitelist-sanitized); data values are always bound. */\nfunction pgSql(sql: string): string {\n let i = 0;\n return sql.replace(/\\?/g, () => `$${++i}`);\n}\n\nfunction pgConnection(sql: PgSql): Database {\n const conn: SqlConnection = {\n query: async (statement, params = []) =>\n (await sql.unsafe(pgSql(statement), params)) as unknown as SqlRow[],\n exec: async (statement, params = []) => {\n await sql.unsafe(pgSql(statement), params);\n },\n };\n return {\n ...conn,\n dialect: 'postgres',\n async transaction<T>(fn: (tx: SqlConnection) => Promise<T>): Promise<T> {\n // begin() leases a dedicated connection; throw → rollback, resolve → commit.\n return sql.begin(async (tx) => {\n const txConn: SqlConnection = {\n query: (statement, params = []) => tx.unsafe(pgSql(statement), params) as unknown as Promise<SqlRow[]>,\n exec: async (statement, params = []) => {\n await tx.unsafe(pgSql(statement), params);\n },\n };\n return fn(txConn);\n });\n },\n close: async () => {\n await sql.close({ timeout: 0 });\n },\n };\n}\n\n/** Lazy Bun.SQL import — under Node.js this fails with a clear\n * Bun-required error instead of a module-resolution crash (no Node\n * PostgreSQL driver dependency is bundled). */\nasync function openPgSql(url: string): Promise<PgSql> {\n let SQL: new (options: { url: string }) => PgSql;\n try {\n // Dynamic on purpose: 'bun' exists only under the Bun runtime, and Node\n // must reach the catch path (there is no bun-types dependency here to\n // type a static import — a static one would crash Node at module load).\n const bun = (await import('bun' as string)) as { SQL: new (options: { url: string }) => PgSql };\n SQL = bun.SQL;\n } catch {\n throw new StorageError(500, 'PostgreSQL requires the Bun runtime (built-in Bun.SQL driver); run the server or CLI with bun — no Node.js PostgreSQL driver is bundled', 'bad_db_env');\n }\n return new SQL({ url });\n}\n\n/** Same credentials, admin \"postgres\" database — only used to CREATE the\n * configured target when it is missing (postgres://host/db → host/postgres).\n * A query \"database\" parameter would override the admin pathname, so it is\n * dropped (ssl/sslmode and friends are kept). */\nfunction adminUrl(url: string): string {\n const u = new URL(url);\n u.pathname = '/postgres';\n for (const key of [...u.searchParams.keys()]) {\n if (/^(database|dbname|db)$/i.test(key)) u.searchParams.delete(key);\n }\n return u.toString();\n}\n\nfunction targetDatabase(url: string): string {\n const name = decodeURIComponent(new URL(url).pathname.replace(/^\\/+|\\/+$/g, ''));\n // Postgres identifiers: ≤63 UTF-8 bytes, no NUL — CREATE DATABASE would\n // silently truncate longer names, so init would recreate a different one.\n const bytes = Buffer.byteLength(name, 'utf8');\n if (name === '' || name.includes('\\0') || bytes > 63) {\n throw new StorageError(500, 'PostgreSQL database name must be 1..63 UTF-8 bytes without NUL', 'bad_db_env');\n }\n return name;\n}\n\nfunction isMissingDatabase(error: unknown): boolean {\n // Ground truth from Bun.SQL: server errors surface as code\n // ERR_POSTGRES_SERVER_ERROR with the SQLSTATE in errno.\n if (typeof error !== 'object' || error === null) return false;\n return ('errno' in error && error.errno === '3D000') || ('code' in error && error.code === '3D000');\n}\n\n/** Open the database selected by env. Validates DB_DRIVER/URL pairing and\n * never falls back after failure — the first query surfaces connection\n * errors to startup.\n *\n * opts.create (explicit init requests only): when the configured PostgreSQL\n * database is missing (SQLSTATE 3D000), CREATE it through the admin\n * \"postgres\" database with the same credentials (identifier safely quoted)\n * and reconnect. Any other backend/error is untouched; Turso has no\n * management API — the hosted target must already exist. */\nexport async function openDatabase(\n env: Record<string, string | undefined> = process.env,\n opts: { create?: boolean } = {},\n): Promise<Database> {\n const cfg = driverEnv(env);\n if (cfg.dialect === 'postgres') {\n let sql = await openPgSql(cfg.url);\n if (opts.create) {\n try {\n await sql.unsafe('SELECT 1');\n } catch (error) {\n await sql.close({ timeout: 0 }).catch(() => {});\n if (!isMissingDatabase(error)) throw error;\n const database = targetDatabase(cfg.url);\n const admin = await openPgSql(adminUrl(cfg.url));\n try {\n // Identifier quote-escaping; data values are always bound parameters.\n await admin.unsafe(`CREATE DATABASE \"${database.replace(/\"/g, '\"\"')}\"`);\n } finally {\n await admin.close({ timeout: 0 });\n }\n sql = await openPgSql(cfg.url);\n }\n }\n return pgConnection(sql);\n }\n if (cfg.url.startsWith('file:')) {\n const fsPath = decodeURIComponent(cfg.url.slice('file:'.length).split('?')[0]);\n await mkdir(dirname(fsPath), { recursive: true });\n }\n return libsqlDatabase(createClient({ url: cfg.url, authToken: cfg.authToken }));\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { D as Database } from '../connection-DxuCLpRc.cjs';
|
|
2
|
+
import '@libsql/client';
|
|
3
|
+
|
|
4
|
+
/** Open the database selected by env. Validates DB_DRIVER/URL pairing and
|
|
5
|
+
* never falls back after failure — the first query surfaces connection
|
|
6
|
+
* errors to startup.
|
|
7
|
+
*
|
|
8
|
+
* opts.create (explicit init requests only): when the configured PostgreSQL
|
|
9
|
+
* database is missing (SQLSTATE 3D000), CREATE it through the admin
|
|
10
|
+
* "postgres" database with the same credentials (identifier safely quoted)
|
|
11
|
+
* and reconnect. Any other backend/error is untouched; Turso has no
|
|
12
|
+
* management API — the hosted target must already exist. */
|
|
13
|
+
declare function openDatabase(env?: Record<string, string | undefined>, opts?: {
|
|
14
|
+
create?: boolean;
|
|
15
|
+
}): Promise<Database>;
|
|
16
|
+
|
|
17
|
+
export { openDatabase };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { D as Database } from '../connection-DxuCLpRc.js';
|
|
2
|
+
import '@libsql/client';
|
|
3
|
+
|
|
4
|
+
/** Open the database selected by env. Validates DB_DRIVER/URL pairing and
|
|
5
|
+
* never falls back after failure — the first query surfaces connection
|
|
6
|
+
* errors to startup.
|
|
7
|
+
*
|
|
8
|
+
* opts.create (explicit init requests only): when the configured PostgreSQL
|
|
9
|
+
* database is missing (SQLSTATE 3D000), CREATE it through the admin
|
|
10
|
+
* "postgres" database with the same credentials (identifier safely quoted)
|
|
11
|
+
* and reconnect. Any other backend/error is untouched; Turso has no
|
|
12
|
+
* management API — the hosted target must already exist. */
|
|
13
|
+
declare function openDatabase(env?: Record<string, string | undefined>, opts?: {
|
|
14
|
+
create?: boolean;
|
|
15
|
+
}): Promise<Database>;
|
|
16
|
+
|
|
17
|
+
export { openDatabase };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { libsqlDatabase } from '../chunk-6ZTAWTAP.mjs';
|
|
2
|
+
import { StorageError } from '../chunk-XRQKLSOT.mjs';
|
|
3
|
+
import { createClient } from '@libsql/client';
|
|
4
|
+
import { mkdir } from 'fs/promises';
|
|
5
|
+
import { dirname } from 'path';
|
|
6
|
+
|
|
7
|
+
var SQLITE_URL_SCHEMES = /^(libsql|https?|wss?|file):\/\//;
|
|
8
|
+
function driverEnv(env) {
|
|
9
|
+
const driver = env.DB_DRIVER || "sqlite";
|
|
10
|
+
const dbUrl = env.DATABASE_URL;
|
|
11
|
+
if (driver === "postgres") {
|
|
12
|
+
if (!dbUrl || !/^postgres(ql)?:\/\//.test(dbUrl)) {
|
|
13
|
+
throw new StorageError(500, "DB_DRIVER=postgres requires DATABASE_URL starting with postgres:// or postgresql://", "bad_db_env");
|
|
14
|
+
}
|
|
15
|
+
return { dialect: "postgres", url: dbUrl };
|
|
16
|
+
}
|
|
17
|
+
if (driver !== "sqlite" && driver !== "turso") {
|
|
18
|
+
throw new StorageError(500, `Unsupported DB_DRIVER: ${driver} (expected sqlite|turso|postgres)`, "bad_db_env");
|
|
19
|
+
}
|
|
20
|
+
if (dbUrl) {
|
|
21
|
+
if (/^postgres(ql)?:\/\//.test(dbUrl)) {
|
|
22
|
+
throw new StorageError(500, `DB_DRIVER=${driver} cannot use a postgres:// DATABASE_URL`, "bad_db_env");
|
|
23
|
+
}
|
|
24
|
+
if (!SQLITE_URL_SCHEMES.test(dbUrl)) {
|
|
25
|
+
throw new StorageError(500, "DB_DRIVER=" + driver + " requires a libsql://, https://, http://, wss:// or file:// DATABASE_URL", "bad_db_env");
|
|
26
|
+
}
|
|
27
|
+
if (driver === "turso" && dbUrl.startsWith("file:")) {
|
|
28
|
+
throw new StorageError(500, "DB_DRIVER=turso requires a remote DATABASE_URL (libsql:// or https://)", "bad_db_env");
|
|
29
|
+
}
|
|
30
|
+
return { dialect: "sqlite", url: dbUrl, authToken: env.LIBSQL_AUTH_TOKEN || void 0 };
|
|
31
|
+
}
|
|
32
|
+
if (driver === "turso") {
|
|
33
|
+
throw new StorageError(500, "DB_DRIVER=turso requires DATABASE_URL (libsql:// or https://)", "bad_db_env");
|
|
34
|
+
}
|
|
35
|
+
return { dialect: "sqlite", url: "file:" + (env.SQLITE_PATH || "./data/wodwiki.db") };
|
|
36
|
+
}
|
|
37
|
+
function pgSql(sql) {
|
|
38
|
+
let i = 0;
|
|
39
|
+
return sql.replace(/\?/g, () => `$${++i}`);
|
|
40
|
+
}
|
|
41
|
+
function pgConnection(sql) {
|
|
42
|
+
const conn = {
|
|
43
|
+
query: async (statement, params = []) => await sql.unsafe(pgSql(statement), params),
|
|
44
|
+
exec: async (statement, params = []) => {
|
|
45
|
+
await sql.unsafe(pgSql(statement), params);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
...conn,
|
|
50
|
+
dialect: "postgres",
|
|
51
|
+
async transaction(fn) {
|
|
52
|
+
return sql.begin(async (tx) => {
|
|
53
|
+
const txConn = {
|
|
54
|
+
query: (statement, params = []) => tx.unsafe(pgSql(statement), params),
|
|
55
|
+
exec: async (statement, params = []) => {
|
|
56
|
+
await tx.unsafe(pgSql(statement), params);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
return fn(txConn);
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
close: async () => {
|
|
63
|
+
await sql.close({ timeout: 0 });
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function openPgSql(url) {
|
|
68
|
+
let SQL;
|
|
69
|
+
try {
|
|
70
|
+
const bun = await import('bun');
|
|
71
|
+
SQL = bun.SQL;
|
|
72
|
+
} catch {
|
|
73
|
+
throw new StorageError(500, "PostgreSQL requires the Bun runtime (built-in Bun.SQL driver); run the server or CLI with bun \u2014 no Node.js PostgreSQL driver is bundled", "bad_db_env");
|
|
74
|
+
}
|
|
75
|
+
return new SQL({ url });
|
|
76
|
+
}
|
|
77
|
+
function adminUrl(url) {
|
|
78
|
+
const u = new URL(url);
|
|
79
|
+
u.pathname = "/postgres";
|
|
80
|
+
for (const key of [...u.searchParams.keys()]) {
|
|
81
|
+
if (/^(database|dbname|db)$/i.test(key)) u.searchParams.delete(key);
|
|
82
|
+
}
|
|
83
|
+
return u.toString();
|
|
84
|
+
}
|
|
85
|
+
function targetDatabase(url) {
|
|
86
|
+
const name = decodeURIComponent(new URL(url).pathname.replace(/^\/+|\/+$/g, ""));
|
|
87
|
+
const bytes = Buffer.byteLength(name, "utf8");
|
|
88
|
+
if (name === "" || name.includes("\0") || bytes > 63) {
|
|
89
|
+
throw new StorageError(500, "PostgreSQL database name must be 1..63 UTF-8 bytes without NUL", "bad_db_env");
|
|
90
|
+
}
|
|
91
|
+
return name;
|
|
92
|
+
}
|
|
93
|
+
function isMissingDatabase(error) {
|
|
94
|
+
if (typeof error !== "object" || error === null) return false;
|
|
95
|
+
return "errno" in error && error.errno === "3D000" || "code" in error && error.code === "3D000";
|
|
96
|
+
}
|
|
97
|
+
async function openDatabase(env = process.env, opts = {}) {
|
|
98
|
+
const cfg = driverEnv(env);
|
|
99
|
+
if (cfg.dialect === "postgres") {
|
|
100
|
+
let sql = await openPgSql(cfg.url);
|
|
101
|
+
if (opts.create) {
|
|
102
|
+
try {
|
|
103
|
+
await sql.unsafe("SELECT 1");
|
|
104
|
+
} catch (error) {
|
|
105
|
+
await sql.close({ timeout: 0 }).catch(() => {
|
|
106
|
+
});
|
|
107
|
+
if (!isMissingDatabase(error)) throw error;
|
|
108
|
+
const database = targetDatabase(cfg.url);
|
|
109
|
+
const admin = await openPgSql(adminUrl(cfg.url));
|
|
110
|
+
try {
|
|
111
|
+
await admin.unsafe(`CREATE DATABASE "${database.replace(/"/g, '""')}"`);
|
|
112
|
+
} finally {
|
|
113
|
+
await admin.close({ timeout: 0 });
|
|
114
|
+
}
|
|
115
|
+
sql = await openPgSql(cfg.url);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return pgConnection(sql);
|
|
119
|
+
}
|
|
120
|
+
if (cfg.url.startsWith("file:")) {
|
|
121
|
+
const fsPath = decodeURIComponent(cfg.url.slice("file:".length).split("?")[0]);
|
|
122
|
+
await mkdir(dirname(fsPath), { recursive: true });
|
|
123
|
+
}
|
|
124
|
+
return libsqlDatabase(createClient({ url: cfg.url, authToken: cfg.authToken }));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export { openDatabase };
|
|
128
|
+
//# sourceMappingURL=node.mjs.map
|
|
129
|
+
//# sourceMappingURL=node.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/sql/node.ts"],"names":[],"mappings":";;;;;;AAmBA,IAAM,kBAAA,GAAqB,iCAAA;AAS3B,SAAS,UAAU,GAAA,EAIjB;AACA,EAAA,MAAM,MAAA,GAAS,IAAI,SAAA,IAAa,QAAA;AAChC,EAAA,MAAM,QAAQ,GAAA,CAAI,YAAA;AAClB,EAAA,IAAI,WAAW,UAAA,EAAY;AACzB,IAAA,IAAI,CAAC,KAAA,IAAS,CAAC,qBAAA,CAAsB,IAAA,CAAK,KAAK,CAAA,EAAG;AAChD,MAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,qFAAA,EAAuF,YAAY,CAAA;AAAA,IACjI;AACA,IAAA,OAAO,EAAE,OAAA,EAAS,UAAA,EAAY,GAAA,EAAK,KAAA,EAAM;AAAA,EAC3C;AACA,EAAA,IAAI,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,OAAA,EAAS;AAC7C,IAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,CAAA,uBAAA,EAA0B,MAAM,qCAAqC,YAAY,CAAA;AAAA,EAC/G;AACA,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,IAAI,qBAAA,CAAsB,IAAA,CAAK,KAAK,CAAA,EAAG;AACrC,MAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,CAAA,UAAA,EAAa,MAAM,0CAA0C,YAAY,CAAA;AAAA,IACvG;AACA,IAAA,IAAI,CAAC,kBAAA,CAAmB,IAAA,CAAK,KAAK,CAAA,EAAG;AACnC,MAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,YAAA,GAAe,MAAA,GAAS,4EAA4E,YAAY,CAAA;AAAA,IAC9I;AACA,IAAA,IAAI,MAAA,KAAW,OAAA,IAAW,KAAA,CAAM,UAAA,CAAW,OAAO,CAAA,EAAG;AACnD,MAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,wEAAA,EAA0E,YAAY,CAAA;AAAA,IACpH;AACA,IAAA,OAAO,EAAE,SAAS,QAAA,EAAU,GAAA,EAAK,OAAO,SAAA,EAAW,GAAA,CAAI,qBAAqB,MAAA,EAAU;AAAA,EACxF;AACA,EAAA,IAAI,WAAW,OAAA,EAAS;AACtB,IAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,+DAAA,EAAiE,YAAY,CAAA;AAAA,EAC3G;AACA,EAAA,OAAO,EAAE,OAAA,EAAS,QAAA,EAAU,KAAK,OAAA,IAAW,GAAA,CAAI,eAAe,mBAAA,CAAA,EAAqB;AACtF;AAIA,SAAS,MAAM,GAAA,EAAqB;AAClC,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,IAAI,OAAA,CAAQ,KAAA,EAAO,MAAM,CAAA,CAAA,EAAI,EAAE,CAAC,CAAA,CAAE,CAAA;AAC3C;AAEA,SAAS,aAAa,GAAA,EAAsB;AAC1C,EAAA,MAAM,IAAA,GAAsB;AAAA,IAC1B,KAAA,EAAO,OAAO,SAAA,EAAW,MAAA,GAAS,EAAC,KAChC,MAAM,GAAA,CAAI,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,EAAG,MAAM,CAAA;AAAA,IAC5C,IAAA,EAAM,OAAO,SAAA,EAAW,MAAA,GAAS,EAAC,KAAM;AACtC,MAAA,MAAM,GAAA,CAAI,MAAA,CAAO,KAAA,CAAM,SAAS,GAAG,MAAM,CAAA;AAAA,IAC3C;AAAA,GACF;AACA,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,OAAA,EAAS,UAAA;AAAA,IACT,MAAM,YAAe,EAAA,EAAmD;AAEtE,MAAA,OAAO,GAAA,CAAI,KAAA,CAAM,OAAO,EAAA,KAAO;AAC7B,QAAA,MAAM,MAAA,GAAwB;AAAA,UAC5B,KAAA,EAAO,CAAC,SAAA,EAAW,MAAA,GAAS,EAAC,KAAM,EAAA,CAAG,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,EAAG,MAAM,CAAA;AAAA,UACrE,IAAA,EAAM,OAAO,SAAA,EAAW,MAAA,GAAS,EAAC,KAAM;AACtC,YAAA,MAAM,EAAA,CAAG,MAAA,CAAO,KAAA,CAAM,SAAS,GAAG,MAAM,CAAA;AAAA,UAC1C;AAAA,SACF;AACA,QAAA,OAAO,GAAG,MAAM,CAAA;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,OAAO,YAAY;AACjB,MAAA,MAAM,GAAA,CAAI,KAAA,CAAM,EAAE,OAAA,EAAS,GAAG,CAAA;AAAA,IAChC;AAAA,GACF;AACF;AAKA,eAAe,UAAU,GAAA,EAA6B;AACpD,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AAIF,IAAA,MAAM,GAAA,GAAO,MAAM,OAAO,KAAe,CAAA;AACzC,IAAA,GAAA,GAAM,GAAA,CAAI,GAAA;AAAA,EACZ,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,8IAAA,EAA2I,YAAY,CAAA;AAAA,EACrL;AACA,EAAA,OAAO,IAAI,GAAA,CAAI,EAAE,GAAA,EAAK,CAAA;AACxB;AAMA,SAAS,SAAS,GAAA,EAAqB;AACrC,EAAA,MAAM,CAAA,GAAI,IAAI,GAAA,CAAI,GAAG,CAAA;AACrB,EAAA,CAAA,CAAE,QAAA,GAAW,WAAA;AACb,EAAA,KAAA,MAAW,OAAO,CAAC,GAAG,EAAE,YAAA,CAAa,IAAA,EAAM,CAAA,EAAG;AAC5C,IAAA,IAAI,0BAA0B,IAAA,CAAK,GAAG,GAAG,CAAA,CAAE,YAAA,CAAa,OAAO,GAAG,CAAA;AAAA,EACpE;AACA,EAAA,OAAO,EAAE,QAAA,EAAS;AACpB;AAEA,SAAS,eAAe,GAAA,EAAqB;AAC3C,EAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,IAAI,GAAA,CAAI,GAAG,EAAE,QAAA,CAAS,OAAA,CAAQ,YAAA,EAAc,EAAE,CAAC,CAAA;AAG/E,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,UAAA,CAAW,IAAA,EAAM,MAAM,CAAA;AAC5C,EAAA,IAAI,SAAS,EAAA,IAAM,IAAA,CAAK,SAAS,IAAI,CAAA,IAAK,QAAQ,EAAA,EAAI;AACpD,IAAA,MAAM,IAAI,YAAA,CAAa,GAAA,EAAK,gEAAA,EAAkE,YAAY,CAAA;AAAA,EAC5G;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,kBAAkB,KAAA,EAAyB;AAGlD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,KAAA;AACxD,EAAA,OAAQ,OAAA,IAAW,SAAS,KAAA,CAAM,KAAA,KAAU,WAAa,MAAA,IAAU,KAAA,IAAS,MAAM,IAAA,KAAS,OAAA;AAC7F;AAWA,eAAsB,aACpB,GAAA,GAA0C,OAAA,CAAQ,GAAA,EAClD,IAAA,GAA6B,EAAC,EACX;AACnB,EAAA,MAAM,GAAA,GAAM,UAAU,GAAG,CAAA;AACzB,EAAA,IAAI,GAAA,CAAI,YAAY,UAAA,EAAY;AAC9B,IAAA,IAAI,GAAA,GAAM,MAAM,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA;AACjC,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,CAAI,OAAO,UAAU,CAAA;AAAA,MAC7B,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,GAAA,CAAI,MAAM,EAAE,OAAA,EAAS,GAAG,CAAA,CAAE,MAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAC9C,QAAA,IAAI,CAAC,iBAAA,CAAkB,KAAK,CAAA,EAAG,MAAM,KAAA;AACrC,QAAA,MAAM,QAAA,GAAW,cAAA,CAAe,GAAA,CAAI,GAAG,CAAA;AACvC,QAAA,MAAM,QAAQ,MAAM,SAAA,CAAU,QAAA,CAAS,GAAA,CAAI,GAAG,CAAC,CAAA;AAC/C,QAAA,IAAI;AAEF,UAAA,MAAM,KAAA,CAAM,OAAO,CAAA,iBAAA,EAAoB,QAAA,CAAS,QAAQ,IAAA,EAAM,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,QACxE,CAAA,SAAE;AACA,UAAA,MAAM,KAAA,CAAM,KAAA,CAAM,EAAE,OAAA,EAAS,GAAG,CAAA;AAAA,QAClC;AACA,QAAA,GAAA,GAAM,MAAM,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA;AAAA,MAC/B;AAAA,IACF;AACA,IAAA,OAAO,aAAa,GAAG,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,GAAA,CAAI,GAAA,CAAI,UAAA,CAAW,OAAO,CAAA,EAAG;AAC/B,IAAA,MAAM,MAAA,GAAS,kBAAA,CAAmB,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAC7E,IAAA,MAAM,MAAM,OAAA,CAAQ,MAAM,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,EAClD;AACA,EAAA,OAAO,cAAA,CAAe,YAAA,CAAa,EAAE,GAAA,EAAK,GAAA,CAAI,KAAK,SAAA,EAAW,GAAA,CAAI,SAAA,EAAW,CAAC,CAAA;AAChF","file":"node.mjs","sourcesContent":["/**\n * @bitcobblers/wod-wiki-storage/sql/node — server-only database opening,\n * extracted from the API server: env-driven driver selection (node libsql\n * client for local SQLite / remote Turso, native Bun.SQL for PostgreSQL).\n * Importing this subpath pulls the node @libsql/client — never from browser\n * code. All SQL is generated internally with `?` placeholders; only the\n * PostgreSQL adapter rewrites them to $1..$n.\n */\nimport { createClient } from '@libsql/client';\nimport { mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { StorageError } from './errors';\nimport {\n libsqlDatabase,\n type Database,\n type SqlConnection,\n type SqlRow,\n} from './connection';\n\nconst SQLITE_URL_SCHEMES = /^(libsql|https?|wss?|file):\\/\\//;\n\n/** Structural Bun.SQL surface (bun-types is not a dependency of this package). */\ninterface PgSql {\n unsafe(query: string, params?: unknown[]): Promise<unknown[]>;\n begin<T>(fn: (tx: { unsafe(query: string, params?: unknown[]): Promise<unknown[]> }) => Promise<T>): Promise<T>;\n close(options?: { timeout?: number }): Promise<void>;\n}\n\nfunction driverEnv(env: Record<string, string | undefined>): {\n dialect: 'sqlite' | 'postgres';\n url: string;\n authToken?: string;\n} {\n const driver = env.DB_DRIVER || 'sqlite';\n const dbUrl = env.DATABASE_URL;\n if (driver === 'postgres') {\n if (!dbUrl || !/^postgres(ql)?:\\/\\//.test(dbUrl)) {\n throw new StorageError(500, 'DB_DRIVER=postgres requires DATABASE_URL starting with postgres:// or postgresql://', 'bad_db_env');\n }\n return { dialect: 'postgres', url: dbUrl };\n }\n if (driver !== 'sqlite' && driver !== 'turso') {\n throw new StorageError(500, `Unsupported DB_DRIVER: ${driver} (expected sqlite|turso|postgres)`, 'bad_db_env');\n }\n if (dbUrl) {\n if (/^postgres(ql)?:\\/\\//.test(dbUrl)) {\n throw new StorageError(500, `DB_DRIVER=${driver} cannot use a postgres:// DATABASE_URL`, 'bad_db_env');\n }\n if (!SQLITE_URL_SCHEMES.test(dbUrl)) {\n throw new StorageError(500, 'DB_DRIVER=' + driver + ' requires a libsql://, https://, http://, wss:// or file:// DATABASE_URL', 'bad_db_env');\n }\n if (driver === 'turso' && dbUrl.startsWith('file:')) {\n throw new StorageError(500, 'DB_DRIVER=turso requires a remote DATABASE_URL (libsql:// or https://)', 'bad_db_env');\n }\n return { dialect: 'sqlite', url: dbUrl, authToken: env.LIBSQL_AUTH_TOKEN || undefined };\n }\n if (driver === 'turso') {\n throw new StorageError(500, 'DB_DRIVER=turso requires DATABASE_URL (libsql:// or https://)', 'bad_db_env');\n }\n return { dialect: 'sqlite', url: 'file:' + (env.SQLITE_PATH || './data/wodwiki.db') };\n}\n\n/** '?' → '$1..$n' in order, counter reset per query. SQL is self-generated\n * (identifiers whitelist-sanitized); data values are always bound. */\nfunction pgSql(sql: string): string {\n let i = 0;\n return sql.replace(/\\?/g, () => `$${++i}`);\n}\n\nfunction pgConnection(sql: PgSql): Database {\n const conn: SqlConnection = {\n query: async (statement, params = []) =>\n (await sql.unsafe(pgSql(statement), params)) as unknown as SqlRow[],\n exec: async (statement, params = []) => {\n await sql.unsafe(pgSql(statement), params);\n },\n };\n return {\n ...conn,\n dialect: 'postgres',\n async transaction<T>(fn: (tx: SqlConnection) => Promise<T>): Promise<T> {\n // begin() leases a dedicated connection; throw → rollback, resolve → commit.\n return sql.begin(async (tx) => {\n const txConn: SqlConnection = {\n query: (statement, params = []) => tx.unsafe(pgSql(statement), params) as unknown as Promise<SqlRow[]>,\n exec: async (statement, params = []) => {\n await tx.unsafe(pgSql(statement), params);\n },\n };\n return fn(txConn);\n });\n },\n close: async () => {\n await sql.close({ timeout: 0 });\n },\n };\n}\n\n/** Lazy Bun.SQL import — under Node.js this fails with a clear\n * Bun-required error instead of a module-resolution crash (no Node\n * PostgreSQL driver dependency is bundled). */\nasync function openPgSql(url: string): Promise<PgSql> {\n let SQL: new (options: { url: string }) => PgSql;\n try {\n // Dynamic on purpose: 'bun' exists only under the Bun runtime, and Node\n // must reach the catch path (there is no bun-types dependency here to\n // type a static import — a static one would crash Node at module load).\n const bun = (await import('bun' as string)) as { SQL: new (options: { url: string }) => PgSql };\n SQL = bun.SQL;\n } catch {\n throw new StorageError(500, 'PostgreSQL requires the Bun runtime (built-in Bun.SQL driver); run the server or CLI with bun — no Node.js PostgreSQL driver is bundled', 'bad_db_env');\n }\n return new SQL({ url });\n}\n\n/** Same credentials, admin \"postgres\" database — only used to CREATE the\n * configured target when it is missing (postgres://host/db → host/postgres).\n * A query \"database\" parameter would override the admin pathname, so it is\n * dropped (ssl/sslmode and friends are kept). */\nfunction adminUrl(url: string): string {\n const u = new URL(url);\n u.pathname = '/postgres';\n for (const key of [...u.searchParams.keys()]) {\n if (/^(database|dbname|db)$/i.test(key)) u.searchParams.delete(key);\n }\n return u.toString();\n}\n\nfunction targetDatabase(url: string): string {\n const name = decodeURIComponent(new URL(url).pathname.replace(/^\\/+|\\/+$/g, ''));\n // Postgres identifiers: ≤63 UTF-8 bytes, no NUL — CREATE DATABASE would\n // silently truncate longer names, so init would recreate a different one.\n const bytes = Buffer.byteLength(name, 'utf8');\n if (name === '' || name.includes('\\0') || bytes > 63) {\n throw new StorageError(500, 'PostgreSQL database name must be 1..63 UTF-8 bytes without NUL', 'bad_db_env');\n }\n return name;\n}\n\nfunction isMissingDatabase(error: unknown): boolean {\n // Ground truth from Bun.SQL: server errors surface as code\n // ERR_POSTGRES_SERVER_ERROR with the SQLSTATE in errno.\n if (typeof error !== 'object' || error === null) return false;\n return ('errno' in error && error.errno === '3D000') || ('code' in error && error.code === '3D000');\n}\n\n/** Open the database selected by env. Validates DB_DRIVER/URL pairing and\n * never falls back after failure — the first query surfaces connection\n * errors to startup.\n *\n * opts.create (explicit init requests only): when the configured PostgreSQL\n * database is missing (SQLSTATE 3D000), CREATE it through the admin\n * \"postgres\" database with the same credentials (identifier safely quoted)\n * and reconnect. Any other backend/error is untouched; Turso has no\n * management API — the hosted target must already exist. */\nexport async function openDatabase(\n env: Record<string, string | undefined> = process.env,\n opts: { create?: boolean } = {},\n): Promise<Database> {\n const cfg = driverEnv(env);\n if (cfg.dialect === 'postgres') {\n let sql = await openPgSql(cfg.url);\n if (opts.create) {\n try {\n await sql.unsafe('SELECT 1');\n } catch (error) {\n await sql.close({ timeout: 0 }).catch(() => {});\n if (!isMissingDatabase(error)) throw error;\n const database = targetDatabase(cfg.url);\n const admin = await openPgSql(adminUrl(cfg.url));\n try {\n // Identifier quote-escaping; data values are always bound parameters.\n await admin.unsafe(`CREATE DATABASE \"${database.replace(/\"/g, '\"\"')}\"`);\n } finally {\n await admin.close({ timeout: 0 });\n }\n sql = await openPgSql(cfg.url);\n }\n }\n return pgConnection(sql);\n }\n if (cfg.url.startsWith('file:')) {\n const fsPath = decodeURIComponent(cfg.url.slice('file:'.length).split('?')[0]);\n await mkdir(dirname(fsPath), { recursive: true });\n }\n return libsqlDatabase(createClient({ url: cfg.url, authToken: cfg.authToken }));\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitcobblers/wod-wiki-storage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.2133",
|
|
4
4
|
"description": "Storage contract for WOD Wiki — entity types, IStorage, IndexedDB schema spec, wire DTOs, the HTTP ApiStorage backend, and the shared SQL (SqlStorage/BrowserTursoStorage) backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -8,14 +8,22 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"bun": "./src/index.ts",
|
|
11
12
|
"types": "./dist/index.d.ts",
|
|
12
13
|
"import": "./dist/index.mjs",
|
|
13
14
|
"require": "./dist/index.cjs"
|
|
14
15
|
},
|
|
15
16
|
"./sql": {
|
|
17
|
+
"bun": "./src/sql/index.ts",
|
|
16
18
|
"types": "./dist/sql/index.d.ts",
|
|
17
19
|
"import": "./dist/sql/index.mjs",
|
|
18
20
|
"require": "./dist/sql/index.cjs"
|
|
21
|
+
},
|
|
22
|
+
"./sql/node": {
|
|
23
|
+
"bun": "./src/sql/node.ts",
|
|
24
|
+
"types": "./dist/sql/node.d.ts",
|
|
25
|
+
"import": "./dist/sql/node.mjs",
|
|
26
|
+
"require": "./dist/sql/node.cjs"
|
|
19
27
|
}
|
|
20
28
|
},
|
|
21
29
|
"files": [
|
|
@@ -30,16 +38,16 @@
|
|
|
30
38
|
"typecheck": "tsc --noEmit"
|
|
31
39
|
},
|
|
32
40
|
"dependencies": {
|
|
33
|
-
"@bitcobblers/wod-wiki-wql": "^0.
|
|
41
|
+
"@bitcobblers/wod-wiki-wql": "^0.36.2133",
|
|
34
42
|
"@libsql/client": "^0.18.0"
|
|
35
43
|
},
|
|
36
44
|
"devDependencies": {
|
|
37
|
-
"@bitcobblers/wod-wiki-core": "^0.
|
|
38
|
-
"@bitcobblers/wod-wiki-lang": "^0.
|
|
45
|
+
"@bitcobblers/wod-wiki-core": "^0.36.2133",
|
|
46
|
+
"@bitcobblers/wod-wiki-lang": "^0.36.2133"
|
|
39
47
|
},
|
|
40
48
|
"peerDependencies": {
|
|
41
|
-
"@bitcobblers/wod-wiki-core": "^0.
|
|
42
|
-
"@bitcobblers/wod-wiki-lang": "^0.
|
|
49
|
+
"@bitcobblers/wod-wiki-core": "^0.36.2133",
|
|
50
|
+
"@bitcobblers/wod-wiki-lang": "^0.36.2133"
|
|
43
51
|
},
|
|
44
52
|
"peerDependenciesMeta": {
|
|
45
53
|
"@bitcobblers/wod-wiki-lang": {
|