← Public packages
@kentcdodds/world-builder
Build a shared 3D voxel world with friends and your AI agents, live.
src/lib/db.ts
51 lines · 1.7 KB · TypeScriptimport { credential } from 'kody:runtime'
import { NEON_SQL_URL } from './config.ts'
/**
* Minimal Neon serverless-HTTP client. The `neon-postgres` credential injects the
* Postgres connection string as the `Neon-Connection-String` header, only to
* the approved Neon endpoint host. Code never sees the value.
*/
export type Row = Record<string, unknown>
export type Query = { query: string; params?: Array<unknown> }
async function post(body: unknown, batch: boolean) {
const db = await credential('neon-postgres')
const response = await db.fetch(NEON_SQL_URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
'Neon-Array-Mode': 'false',
'Neon-Raw-Text-Output': 'true',
...(batch ? { 'Neon-Batch-Isolation-Level': 'ReadCommitted' } : {}),
},
body: JSON.stringify(body),
})
const text = await response.text()
if (!response.ok) {
let message = text.slice(0, 300)
try {
message = (JSON.parse(text) as { message?: string }).message ?? message
} catch {}
throw new Error(`Database error (${response.status}): ${message}`)
}
return JSON.parse(text) as unknown
}
export async function sql(query: string, params: Array<unknown> = []) {
const out = (await post({ query, params }, false)) as { rows: Array<Row> }
return out.rows
}
/** Run queries in one transaction; returns rows per query. */
export async function transaction(queries: Array<Query>) {
if (queries.length === 0) return []
const out = (await post(
{ queries: queries.map((q) => ({ query: q.query, params: q.params ?? [] })) },
true,
)) as { results: Array<{ rows: Array<Row> }> }
return out.results.map((r) => r.rows)
}
export const num = (value: unknown) => (value == null ? 0 : Number(value))