@palbase/backend 25.0.2 → 25.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/engine/index.ts","../../src/runtime.ts","../../src/db/tx-plan.ts","../../src/errors.ts","../../src/engine/config.ts","../../src/engine/auth.ts","../../src/engine/ratelimit.ts","../../src/engine/cache.ts","../../src/db/input-guards.ts","../../src/engine/db.ts","../../src/decorators/registry.ts","../../src/decorators/controller.ts","../../src/engine/router.ts","../../src/engine/upload.ts","../../src/engine/sse.ts","../../src/engine/fence.ts"],"sourcesContent":["/**\n * engine/index.ts — the engine: a backend that boots itself.\n *\n * `createApp` turns a set of `@Controller` classes into a `fetch(Request)`\n * handler. No V8 isolate, no capability hop: this process owns its database\n * pool, verifies its own tokens, applies its own rate limits, and calls the\n * modules directly.\n *\n * import { createApp, loadConfig } from \"@palbase/backend/engine\";\n *\n * const app = await createApp({\n * config: loadConfig(process.env),\n * controllers: [TodosController],\n * schema,\n * });\n * Bun.serve({ port: app.config.port, fetch: app.handle });\n *\n * The Web-standard `fetch` signature is the point: the same handler runs under\n * Bun, Deno and any host that speaks Request/Response, so \"works locally\" and\n * \"works in the cloud\" are the same code path rather than two.\n */\nimport type { ZodError, ZodTypeAny } from \"zod\";\n\nimport { __runWithRuntime, __requestALS, __runStartHooks } from \"../runtime.js\";\nimport type { RuntimeServices, ShutdownRunner } from \"../runtime.js\";\nimport { isHttpError, isEngineRaised } from \"../errors.js\";\nimport type { CacheClient, ClientInfo } from \"../endpoint.js\";\n\nimport { loadConfig, BootRefused } from \"./config.js\";\nimport type { EngineConfig } from \"./config.js\";\nimport { AuthVerifier, effectiveAuth } from \"./auth.js\";\nimport type { VerifiedClaims } from \"./auth.js\";\nimport { RateLimiter } from \"./ratelimit.js\";\nimport { makeMemoryCache } from \"./cache.js\";\nimport { createRequestDatabase, setSchema, setSecretReader } from \"./db.js\";\nimport type { SqlDriver } from \"./db.js\";\nimport { buildRouteTable, matchRoute } from \"./router.js\";\nimport {\n AUTHORIZE_PATH,\n SIGNATURE_HEADER,\n grantFor,\n verifySignature,\n CompletionLedger,\n type CompletionEnvelope,\n} from \"./upload.js\";\nimport {\n SSE_CONTENT_TYPE,\n encodeErrorFrame,\n makeSseWriter,\n type EngineSseWriter,\n} from \"./sse.js\";\nimport type { RouteEntry } from \"./router.js\";\n\nexport { loadConfig, BootRefused } from \"./config.js\";\nexport type { EngineConfig } from \"./config.js\";\nexport { AuthVerifier, effectiveAuth } from \"./auth.js\";\nexport { RateLimiter } from \"./ratelimit.js\";\nexport { makeMemoryCache } from \"./cache.js\";\nexport { createLazyTransaction, createOps, withTables, createRequestDatabase, quoteIdent } from \"./db.js\";\nexport type { SqlDriver, SqlTx, RequestDatabase } from \"./db.js\";\nexport { buildRouteTable, matchRoute } from \"./router.js\";\nexport type { RouteEntry } from \"./router.js\";\nexport { scrubSecrets, installEgressFence, hostAllowed } from \"./fence.js\";\nexport type { EgressPolicy, ScrubResult } from \"./fence.js\";\n\n/** The `__`-prefixed request-scope seam, as re-exported by a deployed bundle. */\nexport interface RuntimeHooks {\n __runWithRuntime: typeof __runWithRuntime;\n __requestALS: typeof __requestALS;\n}\n\n/** The module singletons the engine injects, minus the two it owns itself. */\nexport type ModuleClients = Partial<\n Pick<\n RuntimeServices,\n \"Documents\" | \"Storage\" | \"Notifications\" | \"Flags\" | \"Realtime\" | \"Secrets\"\n >\n>;\n\nexport interface CreateAppOptions {\n /**\n * Vault'tan TEK secret okuma (FR-025): sorgu-anı embedding'in anahtarı\n * buradan akar. Verilmezse auto-embed'li search({query}) adlandırılmış\n * hatayla düşer — sessiz boş sonuç asla (FR-015).\n */\n secretReader?: (name: string) => Promise<string | null>;\n config: EngineConfig;\n /** `@Controller` classes. A class that collected zero routes is fatal. */\n controllers: readonly unknown[];\n /** The project's `defineSchema()` result, for the typed `.tables` surface. */\n schemas?: readonly unknown[];\n /** The SQL driver. Omitted ⇒ built from `Bun.sql` when running under Bun. */\n sql?: SqlDriver;\n /** Module clients. Omitted ⇒ each corresponding singleton throws when used. */\n modules?: ModuleClients;\n /** Cache. Omitted ⇒ this process's own memory. */\n cache?: CacheClient;\n /**\n * The request-scope hooks to run handlers inside.\n *\n * MUST come from the SAME `@palbase/backend` module instance the loaded\n * controllers were bundled against. A deployed bundle inlines its own copy of\n * the SDK and re-exports these two; the engine here has its own. Two copies\n * mean two AsyncLocalStorage instances, and the store this engine sets is not\n * the store the handler's `Database` proxy reads — every service would be\n * undefined at the first call, with nothing in the logs to say why. So the\n * host passes the BUNDLE's hooks and the seam closes.\n *\n * Omitted ⇒ this module's own, which is correct only when the controllers\n * were built against this same instance (tests, a single-package project).\n */\n runtimeHooks?: RuntimeHooks;\n logger?: Pick<Console, \"info\" | \"warn\" | \"error\" | \"debug\">;\n}\n\nexport interface App {\n handle: (req: Request) => Promise<Response>;\n routes: readonly RouteEntry[];\n config: EngineConfig;\n /**\n * Run work that has no request behind it — a scheduled job — inside the same\n * request scope a handler gets, with its own transaction.\n */\n runInServiceScope: <T>(fn: () => T | Promise<T>) => Promise<T>;\n /** Close the pool and release resources. */\n shutdown: () => Promise<void>;\n}\n\nconst JSON_HEADERS = { \"content-type\": \"application/json\" } as const;\n\n/** Flatten a zod failure into the `{ field, message }[]` the SDK's own\n * `BadRequest` payload declares — one shape for the engine's automatic\n * refusals and for `throw new BadRequest({ fields })` alike. */\nfunction fieldErrors(err: ZodError): Array<{ field: string; message: string }> {\n return err.issues.map((i) => ({ field: i.path.join(\".\"), message: i.message }));\n}\n\n/** Re-key the header map onto the names an `@Headers` schema declares.\n *\n * HTTP HEADER NAMES ARE CASE-INSENSITIVE (RFC 9110 §5.1); a zod key is a\n * literal. `Headers` iteration lowercases, so `Object.fromEntries(req.headers)`\n * only ever carries `x-tenant` — while the deploy gate lowercases a declared\n * name only for its RESERVED check (`extract_meta.js` validateHeadersSchema),\n * so `z.object({ \"X-Tenant\": … })` ships. That is also the spelling every HTTP\n * document uses and the one the iOS/Android generators emit into the generated\n * call's signature, so the caller really does send it.\n *\n * Comparing case-sensitively would answer 400 on a header the caller DID send,\n * on every request, forever — the schema was inert before it was enforced, so\n * the refusal would arrive with the SDK upgrade and name a header the client\n * can see itself sending. The lowercase twin stays in the map (zod strips\n * unknown keys), so the parsed value carries exactly the declared spelling.\n */\nfunction headersFor(raw: Record<string, string>, schema: ZodTypeAny): Record<string, string> {\n const shape = (schema as { shape?: Record<string, unknown> }).shape;\n if (typeof shape !== \"object\" || shape === null) return raw;\n let aliased: Record<string, string> | null = null;\n for (const declared of Object.keys(shape)) {\n const lower = declared.toLowerCase();\n if (lower === declared) continue;\n const value = raw[lower];\n if (value === undefined) continue;\n aliased ??= { ...raw };\n aliased[declared] = value;\n }\n return aliased ?? raw;\n}\n\nfunction envelope(\n error: string,\n description: string,\n status: number,\n requestId: string,\n extra?: Record<string, unknown>,\n): Response {\n return new Response(\n JSON.stringify({ error, error_description: description, status, request_id: requestId, ...extra }),\n { status, headers: JSON_HEADERS },\n );\n}\n\n/** A module that was never configured must say so by name on first use, not\n * fail with \"Cannot read properties of undefined\". */\n/**\n * A module singleton nobody injected.\n *\n * The message names TWO causes because there are two, and pointing at only one\n * sends an operator to check a setting that is already correct. Measured on\n * 2026-08-15: a handler reaching for `Purchases` was told to set\n * MODULE_BASE_URL — which was set. Purchases is simply not part of this\n * backend, and an error that hides that costs the reader the afternoon.\n */\nfunction unavailable(name: string): never {\n throw new Error(\n `${name} is unavailable. Either this backend was started without module clients ` +\n `(set MODULE_BASE_URL and the API keys so the engine can reach the module surface), ` +\n `or ${name} is not one of the modules this backend provides.`,\n );\n}\n\nfunction stubModule(name: string): unknown {\n return new Proxy(\n {},\n {\n get: () => unavailable(name),\n apply: () => unavailable(name),\n },\n );\n}\n\nasync function defaultSqlDriver(config: EngineConfig): Promise<SqlDriver> {\n const g = globalThis as { Bun?: { SQL: new (o: { url: string; max: number }) => SqlDriver } };\n if (!g.Bun?.SQL) {\n throw new BootRefused(\n [],\n \"boot refused: no SQL driver. Running outside Bun means the driver must be supplied — \" +\n \"pass `sql` to createApp().\",\n );\n }\n return new g.Bun.SQL({ url: config.databaseUrl, max: config.poolMax });\n}\n\n/** The statuses an author THROWS to answer a request. Everything else that\n * reaches the catch is unplanned and gets logged — see the branch that reads\n * this. Kept beside nothing else so there is one list, not a condition spread\n * across two files.\n *\n * 409 IS IN THIS LIST, and the reason is the whole shape of the check. The\n * scaffold teaches `throw new Conflict(\"title already taken\")` as the way to\n * answer with a 409 (template/AGENTS.md), and the engine raises\n * `UniqueViolation` — also a 409 — from a duplicate write. The status cannot\n * tell them apart, so intent is read from ORIGIN instead: the engine MARKS what\n * it built (`markEngineRaised`), and the branch below logs on that mark\n * regardless of status. Splitting on the status alone wrote an \"unhandled\" line\n * every time an author took the documented path — measured. */\nconst AUTHOR_ANSWERED: ReadonlySet<number> = new Set([400, 401, 403, 404, 409, 429]);\n\n/**\n * Build the app. Fails fast: the database is reached here, at boot, rather than\n * on the first request that needs it.\n */\n\nexport async function createApp(opts: CreateAppOptions): Promise<App> {\n const { config, controllers } = opts;\n setSchema(opts.schemas ?? []);\n setSecretReader(opts.secretReader ?? null);\n\n const routes = buildRouteTable(controllers);\n if (routes.length === 0) {\n throw new BootRefused([], \"boot refused: zero endpoints collected — nothing would answer.\");\n }\n\n const sql = opts.sql ?? (await defaultSqlDriver(config));\n await sql.unsafe(\"select 1\");\n\n const auth = new AuthVerifier({ jwksUrl: config.authJwksUrl, issuer: config.authIssuer });\n const limiter = new RateLimiter();\n const cache = opts.cache ?? makeMemoryCache();\n const log = opts.logger ?? console;\n const modules = opts.modules ?? {};\n const runWithRuntime = opts.runtimeHooks?.__runWithRuntime ?? __runWithRuntime;\n const requestALS = opts.runtimeHooks?.__requestALS ?? __requestALS;\n\n // The secret storage signs its internal calls with. Absent means uploads are\n // not wired, and authorize REFUSES rather than answering with a grant anybody\n // could have asked for.\n const uploadSecret = config.uploadSecret ?? \"\";\n\n /**\n * Answer \"which bucket and path does this route write to?\".\n *\n * Storage cannot know: the answer is `@Upload({bucket, pathTemplate})`, which\n * lives in the deployed bundle. Asking the process that HAS the routes is\n * what keeps the client from naming its own bucket — the request carries the\n * route it wants to use, and this decides what that means.\n */\n // One ledger per app: a completion retried against this process must find\n // its own first answer, and a process restart legitimately forgets — the\n // window a retry lives in is far shorter than an uptime.\n const completions = new CompletionLedger();\n\n /**\n * The service bundle a scope binds, built around ONE request-scoped database.\n *\n * Extracted so the request path and the job path cannot drift: a second copy\n * of this object is a second definition of what a handler can reach, and the\n * one that goes stale is always the one nobody is looking at.\n */\n /** `db === null` is the BOOT scope: everything else is available, and\n * `Database` refuses by name because a start hook runs before any request and\n * there is no transaction for a query to belong to. One writer, so the boot\n * scope cannot drift from the request one. */\n function buildServices(db: ReturnType<typeof createRequestDatabase> | null): RuntimeServices {\n return {\n Database:\n db?.client ??\n stubModule(\"Database (a start hook runs before any request — open your own connection here)\"),\n Cache: cache,\n Log: log,\n Documents: modules.Documents ?? stubModule(\"Documents\"),\n Storage: modules.Storage ?? stubModule(\"Storage\"),\n Notifications: modules.Notifications ?? stubModule(\"Notifications\"),\n Flags: modules.Flags ?? stubModule(\"Flags\"),\n Realtime: modules.Realtime ?? stubModule(\"Realtime\"),\n // Named, never undefined. A backend started without a secrets client\n // that returned `undefined` here would fail inside the handler as\n // \"Cannot read properties of undefined\", which says nothing about what\n // to configure — the stub says the name and the variable.\n Secrets: modules.Secrets ?? stubModule(\"Secrets\"),\n } as unknown as RuntimeServices;\n }\n\n /**\n * Run `fn` as the system, with no request behind it.\n *\n * Scheduled jobs need exactly what a handler needs — Database, Log,\n * Notifications, resolved out of the request scope — but there is no request\n * to take an identity from. So the claims are EMPTY: a job is nobody, and\n * `Database` here satisfies no owner-scoped RLS policy. That is why a job\n * reaches for `Database.asService()`, and why this does not quietly hand it\n * service_role by default.\n *\n * The transaction settles the same way a request's does: commit on return,\n * rollback on throw. A job that fails halfway leaves nothing behind that the\n * next run has to reason about.\n */\n async function runInServiceScope<T>(fn: () => T | Promise<T>): Promise<T> {\n const db = createRequestDatabase(sql, {\n role: config.dbRole,\n serviceRole: config.dbServiceRole,\n claimsJson: \"{}\",\n });\n try {\n const out = await runWithRuntime(buildServices(db), fn as () => Promise<T>);\n await db.commit();\n return out;\n } catch (err) {\n await db.rollback(err);\n throw err;\n }\n }\n\n async function handleAuthorize(req: Request, requestId: string): Promise<Response> {\n if (uploadSecret === \"\" ||\n !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? \"\", uploadSecret)) {\n return envelope(\"unauthorized\", \"This endpoint is not callable directly\", 401, requestId);\n }\n const body = (await req.json().catch(() => null)) as {\n method?: string;\n path?: string;\n userId?: string | null;\n uploadId?: string;\n filename?: string;\n } | null;\n if (!body?.path || !body.uploadId) {\n return envelope(\"bad_request\", \"authorize needs a path and an uploadId\", 400, requestId);\n }\n const target = matchRoute(routes, body.method ?? \"POST\", body.path);\n\n // THE AUTH DECISION HAPPENS HERE, BEFORE A SINGLE BYTE IS ACCEPTED.\n //\n // Storage asks this question precisely so it can refuse early: without it,\n // an anonymous caller could push a file at a route that requires a user,\n // have it written and its variants rendered, and only then be turned away\n // by the completion — the bytes were still accepted, and the work still\n // done, once per attempt.\n //\n // The credential is the caller's own, forwarded by storage, and it is\n // verified HERE rather than trusted: the userId that ends up in the path\n // template comes from these claims and from nothing else, so neither the\n // client nor storage can name a folder that belongs to somebody else.\n const spec = effectiveAuth(target?.entry.meta.options?.auth, target?.entry.controllerAuth);\n const callerClaims = await auth.verify(req.headers.get(\"authorization\"));\n if (spec.required && !callerClaims) {\n return envelope(\"unauthorized\", \"A valid access token is required\", 401, requestId);\n }\n if (callerClaims && spec.role && callerClaims.role !== spec.role) {\n return envelope(\"forbidden\", `This endpoint requires the \"${spec.role}\" role`, 403, requestId);\n }\n\n const grant = grantFor(target?.entry, {\n userId: typeof callerClaims?.sub === \"string\" ? callerClaims.sub : null,\n uploadId: body.uploadId,\n filename: body.filename,\n });\n if (!grant) {\n // A route with no @Upload never offered to accept a file. Refusing by\n // NAME rather than 404 so an operator reading storage's log learns which\n // route was asked for.\n return envelope(\"not_an_upload_route\",\n `${body.method ?? \"POST\"} ${body.path} does not declare @Upload`, 400, requestId);\n }\n return new Response(JSON.stringify(grant), { status: 200, headers: JSON_HEADERS });\n }\n\n async function handle(req: Request): Promise<Response> {\n const requestId = `req_${crypto.randomUUID()}`;\n const url = new URL(req.url);\n\n // ── storage's two internal calls, before ordinary routing ───────────────\n //\n // They are not the tenant's routes and must not be reachable as one: an\n // app that declared `POST /__palbase/upload/authorize` would otherwise\n // shadow the mechanism that decides where uploads land.\n if (url.pathname === AUTHORIZE_PATH) {\n return handleAuthorize(req, requestId);\n }\n\n const hit = matchRoute(routes, req.method, url.pathname);\n if (!hit) return envelope(\"not_found\", \"No route matches this method and path\", 404, requestId);\n const { meta } = hit.entry;\n\n // ── auth ────────────────────────────────────────────────────────────────\n const spec = effectiveAuth(meta.options?.auth, hit.entry.controllerAuth);\n const claims: VerifiedClaims | null = await auth.verify(req.headers.get(\"authorization\"));\n if (spec.required && !claims) {\n return envelope(\"unauthorized\", \"A valid access token is required\", 401, requestId);\n }\n const userId = typeof claims?.sub === \"string\" ? claims.sub : undefined;\n if (claims && spec.role && claims.role !== spec.role) {\n return envelope(\"forbidden\", `This endpoint requires the \"${spec.role}\" role`, 403, requestId);\n }\n if (claims && spec.verifiedEmail && claims.email_verified !== true) {\n return envelope(\"email_not_verified\", \"A verified email address is required\", 403, requestId);\n }\n\n // ── rate limit ──────────────────────────────────────────────────────────\n const retryAfter = limiter.check(\n meta.options?.rateLimit,\n RateLimiter.key(hit.entry.id, userId, req.headers),\n Date.now(),\n );\n if (retryAfter !== null) {\n // THE HINT GOES IN THE BODY TOO, under the name this SDK already\n // publishes for it. `error-registry.ts` declares\n // `too_many_requests: { retryAfter: number }`, so codegen types\n // `error.data.retryAfter` on every generated client and a thrown\n // `new TooManyRequests({ retryAfter })` already answers in that shape.\n // This limiter answered with the header ALONE, so the one 429 the engine\n // itself produces was the one shape no generated client could read — and\n // a browser behind a CORS gateway cannot see `Retry-After` at all unless\n // it is explicitly exposed. The header stays: it is the HTTP-correct\n // signal, and `@palbase/core`'s retry loop reads it.\n return new Response(\n JSON.stringify({\n error: \"too_many_requests\",\n error_description: \"Rate limit exceeded for this endpoint\",\n status: 429,\n request_id: requestId,\n data: { retryAfter },\n }),\n { status: 429, headers: { ...JSON_HEADERS, \"retry-after\": String(retryAfter) } },\n );\n }\n\n // ── arguments ───────────────────────────────────────────────────────────\n // Set when this request IS a completion, so its answer can be remembered.\n let completionUploadId: string | null = null;\n\n const args: unknown[] = [];\n let parsedBody: unknown;\n let bodyRead = false;\n\n // The SSE writer has to exist BEFORE the parameter loop (that is where it is\n // injected) but its two collaborators only exist later: the transport queue\n // is created when the ReadableStream starts, and the transaction it settles\n // is opened further down. So both are reached through holders the SSE branch\n // fills in — the writer itself stays ignorant of either.\n let sseEnqueue: ((chunk: string) => void) | null = null;\n let sseSettle: () => Promise<void> = async () => {};\n const sseWriter: EngineSseWriter = makeSseWriter({\n enqueue: (chunk) => sseEnqueue?.(chunk),\n onFirstWrite: () => sseSettle(),\n });\n for (const p of meta.params ?? []) {\n switch (p.kind) {\n case \"body\": {\n if (!bodyRead) {\n parsedBody = await req.json().catch(() => ({}));\n bodyRead = true;\n }\n const r = p.schema!.safeParse(parsedBody);\n if (!r.success) {\n return envelope(\"bad_request\", \"Request body failed validation\", 400, requestId, {\n data: { fields: fieldErrors(r.error) },\n });\n }\n args[p.index] = r.data;\n break;\n }\n case \"query\": {\n const r = p.schema!.safeParse(Object.fromEntries(url.searchParams));\n if (!r.success) {\n return envelope(\"bad_request\", \"Query parameters failed validation\", 400, requestId, {\n data: { fields: fieldErrors(r.error) },\n });\n }\n args[p.index] = r.data;\n break;\n }\n case \"param\":\n args[p.index] = hit.params[p.name!];\n break;\n case \"headers\": {\n // A DECLARED HEADER SCHEMA IS A CONTRACT, and three other systems\n // already treat it as one: the deploy gate REFUSES a build whose\n // schema names a reserved or non-string header\n // (cli/internal/backend/devjs/extract_meta.js), the OpenAPI document\n // lists it as an `in: header` parameter, and the iOS/Android\n // generators put it in the generated call's signature. The runtime\n // was the only one that read the schema and did nothing with it, so a\n // request with the header missing or malformed answered 200 and the\n // handler read `undefined` off a value whose type says `string`.\n //\n // Keys arrive LOWERCASE — `Headers` iteration lowercases them — so\n // the declared names are matched case-insensitively (`headersFor`)\n // and `x-tenant` and `X-Tenant` both work, as HTTP says they must.\n const raw = Object.fromEntries(req.headers);\n if (!p.schema) {\n args[p.index] = raw;\n break;\n }\n const r = p.schema.safeParse(headersFor(raw, p.schema));\n if (!r.success) {\n return envelope(\"bad_request\", \"Request headers failed validation\", 400, requestId, {\n data: { fields: fieldErrors(r.error) },\n });\n }\n // The PARSED value, matching @Body/@QueryParams: the parameter's type\n // is `z.infer<Schema>`, and injecting the whole header map made the\n // value wider than its own declared type. An author who wants every\n // header still writes `@Headers()` with no schema.\n args[p.index] = r.data;\n break;\n }\n case \"user\":\n case \"optionalUser\":\n args[p.index] = claims\n ? {\n id: userId,\n email: claims.email,\n role: claims.role,\n emailVerified: claims.email_verified === true,\n metadata: (claims.metadata as Record<string, unknown>) ?? {},\n }\n : null;\n break;\n case \"uploadedObject\": {\n // An @Upload route runs as a COMPLETION handler: the bytes went to\n // storage, and what arrives here is what storage recorded about them.\n // The call must be signed, or anyone who knows the route path could\n // invent an upload that never happened and make the handler write a\n // row for it.\n if (uploadSecret === \"\" ||\n !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? \"\", uploadSecret)) {\n return envelope(\"unauthorized\",\n \"This endpoint accepts uploads through storage, not directly\", 401, requestId);\n }\n if (!bodyRead) {\n parsedBody = await req.json().catch(() => ({}));\n bodyRead = true;\n }\n const envelopeIn = parsedBody as CompletionEnvelope | null;\n if (!envelopeIn?.uploadedObject) {\n return envelope(\"bad_request\", \"the completion call carried no uploaded object\", 400, requestId);\n }\n // A RETRY MUST NOT RUN THE HANDLER AGAIN.\n //\n // Storage retries a completion it did not hear back from, and the\n // handler is a mutation: run twice, one uploaded photo becomes two\n // posts. The first answer is replayed instead, which is what makes\n // the retry invisible to the client waiting on the other end.\n const uploadId = envelopeIn.uploadedObject.uploadId;\n if (typeof uploadId === \"string\" && uploadId !== \"\") {\n const already = completions.recall(uploadId);\n if (already) {\n return new Response(already.body, {\n status: already.status,\n headers: already.contentType ? { \"content-type\": already.contentType } : undefined,\n });\n }\n completionUploadId = uploadId;\n }\n args[p.index] = envelopeIn.uploadedObject;\n // The author's @Body sees THEIR payload, not the envelope around it.\n parsedBody = envelopeIn.body ?? {};\n break;\n }\n case \"requestId\":\n args[p.index] = requestId;\n break;\n case \"traceId\":\n args[p.index] = requestId;\n break;\n case \"client\":\n // The data was always on the wire; nothing read it. Every shipped\n // client SDK stamps these four on every request (iOS\n // Palbe/Core/ClientInfo.swift, web core/src/http.ts), and the\n // platform already reads the same names in Go\n // (user-flags/internal/middleware/clientcontext.go). Header names are\n // canonical here, not invented: the deploy gate REFUSES an\n // `@Headers` schema that names an `x-palbase-*` key, which makes\n // `@Client()` the only sanctioned reader of them.\n //\n // `Headers.get()` answers `string | null`, which is exactly what\n // `ClientInfo` declares — a non-SDK caller (curl, server-to-server)\n // sends none of these and gets four nulls rather than a throw.\n args[p.index] = {\n sdkVersion: req.headers.get(\"x-palbase-sdk-version\"),\n appVersion: req.headers.get(\"x-palbase-client-version\"),\n platform: req.headers.get(\"x-platform\"),\n osVersion: req.headers.get(\"x-os-version\"),\n } satisfies ClientInfo;\n break;\n case \"req\":\n args[p.index] = req;\n break;\n // `@Signal()` — the raw request's AbortSignal, which enters the aborted\n // state when the client disconnects. Measured on Bun: an infinite\n // producer guarded by it stops within a few frames of the client dying.\n // It is deliberately NOT reachable through `@Req()`: PBRequest carries\n // request-scoped data and no signal.\n case \"signal\":\n args[p.index] = req.signal;\n break;\n // `@SseOut()` — the frame writer. Meaningful only on an `@Sse` route;\n // on any other route it is an inert writer whose frames go nowhere,\n // which is the same shape `@UploadedObject()` has off an `@Upload`\n // route.\n case \"sseOut\":\n args[p.index] = sseWriter;\n break;\n default:\n args[p.index] = undefined;\n }\n }\n\n // ── dispatch, inside the request's transaction(s) ───────────────────────\n //\n // One for the caller's identity, and — only if the handler asks for it —\n // one more for `Database.asService()`. Both settle here, together.\n const db = createRequestDatabase(sql, {\n role: config.dbRole,\n serviceRole: config.dbServiceRole,\n claimsJson: JSON.stringify(claims ?? {}),\n });\n try {\n const services = buildServices(db);\n\n // ── the streaming branch ────────────────────────────────────────────────\n //\n // An `@Sse` route answers with `text/event-stream` and a body that stays\n // open; its return value is discarded. What makes this more than \"return a\n // stream\" is the moment of commitment: once ONE frame has gone out, the\n // 200 and the headers are spent, so a later throw can only be reported\n // in-band (FR-011). Before that first frame the status line is still ours\n // and an ordinary error envelope is both possible and much more useful\n // (FR-010). So the handler is started, and the decision waits for whichever\n // comes first — its first write, or its own completion.\n if (meta.options?.sseConfig !== undefined) {\n // The transport is built BEFORE the handler starts, so there is never a\n // window in which a written frame has nowhere to go. An unused stream\n // costs nothing: if the handler turns out never to write, the response\n // below is an ordinary envelope and this object is simply dropped.\n // (An earlier version created the stream only after the first frame and\n // held frames in a buffer meanwhile. That buffer's correctness depended\n // on microtask timing, so no test could pin it — mutation-checked: the\n // flush could be deleted with the suite still green. Untestable\n // defensive code is worse than no window at all.)\n let sseController!: ReadableStreamDefaultController<Uint8Array>;\n const sseEncoder = new TextEncoder();\n const stream = new ReadableStream<Uint8Array>({\n start(c) {\n sseController = c;\n },\n });\n sseEnqueue = (chunk) => {\n // Same exposure as the close below: a frame written after the client\n // left has nowhere to go, and saying so by throwing would kill the\n // process rather than the request.\n try {\n sseController.enqueue(sseEncoder.encode(chunk));\n } catch {\n // The reader is gone. The handler's own signal is what stops it.\n }\n };\n\n let sawFirstFrame!: () => void;\n const firstFrame = new Promise<void>((r) => (sawFirstFrame = r));\n\n // THE FIRST FRAME ENDS THE REQUEST PHASE.\n //\n // The handler runs inside the request's transaction, and a stream may\n // live for minutes. Holding a transaction that long exhausts the\n // connection pool — a failure no unit test sees, that appears only under\n // load, and that looks like \"the database is slow\" when it arrives. So\n // the transaction settles HERE, in the hook the writer awaits before it\n // emits anything: the ordering is structural, not a happy accident of\n // microtask scheduling.\n sseSettle = async () => {\n await db.commit();\n sawFirstFrame();\n };\n\n // …and afterwards the database is refused BY NAME. The alternative is a\n // settled transaction quietly answering a query, which is a correctness\n // bug the author would never find. The message says what happened and\n // what to do instead.\n const guarded: RuntimeServices = {\n ...services,\n Database: new Proxy(services.Database as object, {\n get(target, prop, recv) {\n // `started()` flips SYNCHRONOUSLY inside `write()`, which is the\n // only reading that works: `write` returns immediately, so a\n // handler's next line runs before the commit has finished. The\n // author's own call is the boundary, not the commit's completion.\n if (sseWriter.started()) {\n throw new Error(\n `sse_db_after_write: ${hit.entry.id} touched the database after its ` +\n `first write(). A streaming response settles its transaction with the ` +\n `first frame — do the database work before the first write.`,\n );\n }\n return Reflect.get(target, prop, recv);\n },\n }) as RuntimeServices[\"Database\"],\n };\n\n let thrown: unknown = null;\n const ran = Promise.resolve(runWithRuntime(guarded, () => {\n const box = requestALS.getStore();\n if (box) {\n box.userId = userId ?? null;\n box.requestId = requestId;\n box.idempotencyKey = req.headers.get(\"idempotency-key\");\n }\n const method = hit.entry.instance[meta.fnName];\n if (typeof method !== \"function\") {\n throw new Error(\n `route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`,\n );\n }\n return method.apply(hit.entry.instance, args);\n })).then(\n () => undefined,\n (err: unknown) => {\n thrown = err;\n },\n );\n\n await Promise.race([firstFrame, ran]);\n\n if (!sseWriter.started()) {\n // Nothing was ever written. The handler either finished silently or\n // threw before its first frame — either way the response shape is\n // still a free choice, so it gets the ordinary one.\n await ran;\n await db.commit();\n if (thrown !== null) throw thrown;\n return new Response(null, { status: 204 });\n }\n\n void (async () => {\n await ran;\n await sseWriter.drained();\n // THE CLIENT LEAVING IS A NORMAL ENDING, NOT AN ERROR.\n //\n // When the client disconnects the runtime closes this controller\n // itself, so the terminal write and close below arrive at a stream\n // that is already gone. Left unguarded they throw\n // `ERR_INVALID_STATE: Controller is already closed` from inside a\n // detached async task — which is an unhandled rejection, and under Bun\n // that KILLS THE SERVER PROCESS. One user closing a tab would take the\n // backend down with them.\n //\n // Measured 2026-08-29 against real OpenAI: curl was killed mid-stream\n // and the process exited with code 1 at this line. No unit test could\n // have caught it — in a test the client never disconnects at the\n // transport layer, so the controller is always still open here.\n try {\n if (thrown !== null) {\n log.error(`[engine] ${hit.entry.id} threw mid-stream`, thrown);\n sseController.enqueue(sseEncoder.encode(encodeErrorFrame(requestId)));\n }\n sseController.close();\n } catch {\n // Already closed: the client is gone and there is nobody to tell.\n }\n })();\n return new Response(stream, {\n status: 200,\n headers: { \"content-type\": SSE_CONTENT_TYPE, \"cache-control\": \"no-cache\" },\n });\n }\n\n const result = await runWithRuntime(services, () => {\n // The ALS box carries the caller's identity beside the services; Flags'\n // auto-bind reads it, and so does anything else that needs a\n // server-owned user id rather than one the caller supplied.\n const box = requestALS.getStore();\n if (box) {\n box.userId = userId ?? null;\n box.requestId = requestId;\n box.idempotencyKey = req.headers.get(\"idempotency-key\");\n }\n const method = hit.entry.instance[meta.fnName];\n if (typeof method !== \"function\") {\n throw new Error(\n `route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`,\n );\n }\n return method.apply(hit.entry.instance, args);\n });\n await db.commit();\n\n if (meta.returnSchema) {\n const v = meta.returnSchema.safeParse(result);\n if (!v.success) {\n log.error(`[engine] ${hit.entry.id} returned a value its declared type rejects`, v.error.issues);\n return envelope(\n \"output_invalid\",\n \"The handler returned a value its declared return type rejects\",\n 500,\n requestId,\n );\n }\n }\n if (result === undefined || result === null) {\n if (completionUploadId) {\n completions.remember(completionUploadId, { status: 204, body: null, contentType: null });\n }\n return new Response(null, { status: 204 });\n }\n const payload = JSON.stringify(result);\n if (completionUploadId) {\n completions.remember(completionUploadId, {\n status: 200,\n body: payload,\n contentType: JSON_HEADERS[\"content-type\"] ?? \"application/json\",\n });\n }\n return new Response(payload, { status: 200, headers: JSON_HEADERS });\n } catch (err) {\n // The handler threw after writing: nothing it wrote may survive.\n await db.rollback(err);\n // Branded, not `instanceof`: the tenant's bundle carries its own copy of\n // this SDK, so class identity does not survive the hop from the handler\n // to this catch. See HTTP_ERROR_BRAND.\n if (isHttpError(err)) {\n // AN UNCAUGHT HttpError LEFT NO TRACE. A `NotFound` is the handler\n // ANSWERING — logging every one of those is noise nobody reads. But an\n // error the handler did not mean to answer with — the `UniqueViolation`\n // the engine raised from a duplicate write, say — became an HTTP\n // response and vanished server-side, which is BLINDER than the bare 500\n // it replaced: that one at least logged.\n //\n // The split is on INTENT, and intent has TWO readings because one is\n // not enough: the engine MARKS the errors it built out of driver\n // failures (those always log, whatever their status), and beyond that\n // the codes an author throws to answer a request stay quiet. 409 needs\n // both — see AUTHOR_ANSWERED.\n if (isEngineRaised(err) || !AUTHOR_ANSWERED.has(err.status)) {\n log.error(`[engine] unhandled ${err.error} in ${hit.entry.id}`, err);\n }\n return envelope(\n err.error,\n err.errorDescription,\n err.status,\n requestId,\n err.data !== undefined ? { data: err.data } : undefined,\n );\n }\n log.error(`[engine] unhandled error in ${hit.entry.id}`, err);\n return envelope(\"internal_error\", \"The request could not be completed\", 500, requestId);\n }\n }\n\n // The author's own long-lived resources come up HERE: after the pool has been\n // proven (`select 1` above) and before anything can be served. A hook that\n // throws REFUSES THE BOOT — an app that answers with a half-open resource\n // behind it is the silence `onStart` exists to replace — and the pool this\n // function opened is closed on the way out, because nobody will ever get the\n // `shutdown` below to close it.\n // START HOOKS RUN IN A SCOPE — a BOOT one, not a request one.\n //\n // A start hook is where a long-lived resource comes up, and the credential\n // that resource needs lives in the vault. `Secrets.get()` threw \"outside a\n // request scope\" here, so the one place an author is TOLD to open a pool could\n // not read the password for it (D-19).\n //\n // Everything that is genuinely boot-level — Secrets, Cache, Log, the module\n // clients — is handed over. `Database` is NOT, and refuses BY NAME: a start\n // hook runs before anything is served, so there is no request and no\n // transaction for a query to belong to. Handing out a real one would open a\n // transaction on the boot path that nobody closes; saying so is the honest\n // answer and the one an author can act on.\n const bootServices = buildServices(null);\n\n let runShutdownHooks: ShutdownRunner;\n try {\n runShutdownHooks = await runWithRuntime(bootServices, () => __runStartHooks());\n } catch (err) {\n await closeDriver(sql);\n throw err;\n }\n\n return {\n handle,\n routes,\n config,\n runInServiceScope,\n async shutdown() {\n // The author's resource is released BEFORE the pool: a driver standing on\n // this pool cannot close after the pool is gone.\n await runShutdownHooks();\n await closeDriver(sql);\n },\n };\n}\n\n/** Let go of the driver — `close` or `end`, whichever it carries. */\nasync function closeDriver(sql: SqlDriver): Promise<void> {\n const closable = sql as { close?: () => Promise<void> | void; end?: () => Promise<void> | void };\n await closable.close?.();\n await closable.end?.();\n}\n","/**\n * runtime.ts — request-scoped service singletons.\n *\n * The backend SDK no longer threads a `ctx` god-object through every handler.\n * Instead, controller methods import PascalCase service singletons directly:\n *\n * import { Controller, Post, Body, Database } from \"@palbase/backend\";\n *\n * \\@Controller(\"/todos\")\n * export default class TodosController {\n * \\@Post(\"\") create(\\@Body(CreateTodoBody) body: CreateTodoBody): unknown {\n * return Database.insert(\"todos\", { title: body.title });\n * }\n * }\n *\n * The singletons are thin Proxies. Every property access forwards to the live\n * client for the CURRENT request scope, resolved through {@link __getRuntime}.\n *\n * # Request-scope resolution (persistent app-server)\n *\n * The runtime is a long-running Node process that serves many concurrent\n * requests on one event loop (NOT a fresh subprocess per request). A single\n * module-global slot would let one in-flight request's services bleed into\n * another's. So the services are carried in an {@link AsyncLocalStorage} store\n * ({@link __requestALS}) that the runtime sets per request with\n * {@link __runWithRuntime}; every async continuation of that request reads its\n * own store. `__getRuntime` reads the ALS store first; the module-global slot\n * (set by {@link __setRuntime}) is only a fallback for callers that run OUTSIDE\n * an ALS scope (dev-server, unit tests, the legacy single-shot path). Because\n * each `br-<ref>` pod is single-tenant, there is no cross-tenant leakage; the\n * ALS store is what prevents cross-REQUEST leakage within the shared process.\n *\n * The seam that makes `import { Database } from \"@palbase/backend\"` resolve to\n * the runtime-injected client: `@palbase/backend` is marked esbuild-EXTERNAL\n * when the tenant bundle is built, and the package is installed globally in the\n * pod (NODE_PATH=/usr/local/lib/node_modules). So worker.js's\n * `require('@palbase/backend')` and the bundle's `import` resolve to ONE shared\n * module instance — the ALS store and `__setRuntime` slot on that instance are\n * visible to the singletons the bundle imported.\n */\n\nimport type { PalbaseFlagKey } from \"./stack.js\";\nimport type { Buckets, BucketTypes, Schemas } from \"./db/env.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type {\n DBClient,\n DBOps,\n CacheClient,\n Logger,\n PalbaseDocsClient,\n SecretsService,\n} from \"./endpoint.js\";\nimport type {\n PalbaseStorageClient,\n PalbaseBucketClient,\n PalbaseNotificationsClient,\n PalbaseFlagsClient,\n PalbaseFlagsServiceClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseFlagValue,\n PalbaseSetOverrideResult,\n PalbaseRealtimeClient,\n} from \"./clients.js\";\nimport type { PalbaseResult } from \"./endpoint.js\";\nimport type {\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvSchemas,\n EnvTables,\n TxPlan,\n TxTables,\n} from \"./db/typed-db.js\";\nimport type { Materialized } from \"./db/tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./db/tx-plan.js\";\n\n/** The set of live clients the runtime injects per request scope.\n *\n * Realtime is BROADCAST-ONLY here (a stateless handler can push an event but\n * cannot hold a subscription socket — `subscribe()` lives on the client SDK).\n *\n * EXCLUDED on purpose: Functions, Links, Analytics, Auth. They are not\n * exposed as backend handler singletons (auth lives on the client SDK; the rest\n * are out of scope for backend endpoints). */\nexport interface RuntimeServices {\n Database: DBClient;\n Secrets: SecretsService;\n Documents: PalbaseDocsClient;\n Storage: PalbaseStorageClient;\n Cache: CacheClient;\n Log: Logger;\n Notifications: PalbaseNotificationsClient;\n Flags: PalbaseFlagsClient;\n Realtime: PalbaseRealtimeClient;\n}\n\n/**\n * The per-request ALS box.\n *\n * `runtime` is the service bundle. `userId` is the request's authenticated user\n * id, written by the runtime immediately after it assembles the request object\n * (worker.js: `requestALS.getStore().userId = pbReq.user?.id || null`) and\n * `null` on an anonymous request. It was already being written there for the\n * Flags client's auto-bind; declaring it here makes the existing contract typed\n * instead of implicit, which is what lets `currentSubjectId()` read a\n * server-owned identity rather than trusting anything the caller sent.\n */\nexport interface RequestStore {\n runtime: RuntimeServices;\n userId?: string | null;\n /** This request's id (`req_…`), written by the runtime. Used as the spend\n * idempotency scope when the caller supplied no `Idempotency-Key`. */\n requestId?: string;\n /** The caller's `Idempotency-Key` header, or `null` when absent. What makes a\n * client's retry replay its first result instead of charging twice. */\n idempotencyKey?: string | null;\n}\n\n/**\n * Per-request store. The persistent runtime runs each request inside\n * {@link __runWithRuntime}, so every async continuation of that request reads\n * its OWN `runtime` (and any other request-scoped fields the runtime adds).\n *\n * Exported with a `__` prefix so the runtime (worker.js) shares the SAME ALS\n * instance across the one module instance — two ALS instances would silently\n * not see each other's stores. NOT part of the public author-facing API.\n */\nexport const __requestALS = new AsyncLocalStorage<RequestStore>();\n\n/** Process-global fallback slot. Used only OUTSIDE an ALS scope (dev-server,\n * unit tests, legacy single-shot worker). Inside the persistent server every\n * request runs in {@link __requestALS}, which takes precedence. */\nlet runtime: RuntimeServices | null = null;\n\n/** Install the live clients in the process-global fallback slot.\n *\n * Persistent-server requests should use {@link __runWithRuntime} instead; this\n * remains for dev-server / tests / the legacy single-shot path that run without\n * an ALS scope. NOT part of the public author-facing API. */\nexport function __setRuntime(services: RuntimeServices): void {\n runtime = services;\n}\n\n/** Run `fn` with `services` bound as the request-scoped runtime.\n *\n * The persistent worker calls this once per request so concurrent requests\n * never share a services slot. NOT part of the public author-facing API. */\nexport function __runWithRuntime<T>(services: RuntimeServices, fn: () => T): T {\n return __requestALS.run({ runtime: services }, fn);\n}\n\n/** Read the live clients, throwing if accessed outside a request scope.\n *\n * Resolves the ALS store first (persistent server, per-request), then the\n * process-global fallback (dev-server / tests). NOT part of the public\n * author-facing API — used by the runtime and the singleton Proxies. */\nexport function __getRuntime(): RuntimeServices {\n const scoped = __requestALS.getStore();\n if (scoped) return scoped.runtime;\n if (runtime === null) {\n throw new Error(\n \"Palbase services accessed outside a request scope. The Database/Documents/… \" +\n \"singletons are only available inside an endpoint handler (or after the \" +\n \"runtime has called __runWithRuntime / __setRuntime).\",\n );\n }\n return runtime;\n}\n\n// ─── lifecycle: where a long-lived resource lives (FR-013) ─────────────────\n//\n// `Resource` was removed in 23.0.0 and nothing replaced the LIFECYCLE half of\n// it. What that left behind is measurable: a connection pool (the driver in\n// `docs/resources.md`'s own example was Neo4j) had no documented place to be\n// opened and NO WAY AT ALL to be closed, so every deploy left the pool it\n// opened behind. These two hooks are that half — and only that half. The\n// secret-distribution half does not come back: a handler reads `Secrets.get`,\n// and a start hook, which runs before any request scope exists, reads the\n// `process.env` the runtime mirrors the vault into at boot.\n\n/** A lifecycle hook. Sync or async; the runtime awaits what it returns. */\nexport type LifecycleHook = () => void | Promise<void>;\n\n/** Runs one release's shutdown hooks. Handed back by {@link __runStartHooks}\n * and called by the engine's `app.shutdown()`. Idempotent. */\nexport type ShutdownRunner = () => Promise<void>;\n\ninterface DeclaredHook {\n name: string;\n run: LifecycleHook;\n}\n\ninterface DeclaredLifecycle {\n start: DeclaredHook[];\n shutdown: DeclaredHook[];\n}\n\n/**\n * What has been DECLARED and not yet claimed by an app.\n *\n * On globalThis under a well-known Symbol for the reason the controller\n * registry is (`decorators/controller.ts`): a deployed bundle inlines its own\n * copy of this package, and the engine that has to RUN these hooks holds the\n * other copy. Two module-local arrays would mean the engine reads the empty one\n * and every declared hook is silently never run — which is exactly how\n * `Resource`'s `init(env)` died.\n */\nconst LIFECYCLE: unique symbol = Symbol.for(\"palbase.backend.lifecycleHooks\") as never;\n\nfunction declaredLifecycle(): DeclaredLifecycle {\n const g = globalThis as unknown as Record<symbol, DeclaredLifecycle | undefined>;\n return (g[LIFECYCLE] ??= { start: [], shutdown: [] });\n}\n\n/**\n * Run `hook` ONCE while the application comes up, before it serves anything.\n *\n * Call it at MODULE SCOPE in a file the application imports — the same rule\n * `defineDefaultAuth` and `@Controller` follow, and for the same reason: the\n * declaration is claimed when the app boots, which is after module loading and\n * before the first request. `name` is not decoration: a hook that throws is\n * reported by that name and the boot is REFUSED, so it is what tells an\n * operator which resource did not come up.\n *\n * There is no request scope yet, so the `Database`/`Secrets`/… singletons are\n * NOT available inside a start hook. A secret is read from `process.env` here\n * (the runtime mirrors the vault into it at boot).\n *\n * @example\n * // resources/graph.ts\n * import neo4j from \"neo4j-driver\";\n * import { onStart, onShutdown } from \"@palbase/backend\";\n *\n * export let graph: Driver;\n * onStart(\"graph\", () => {\n * graph = neo4j.driver(process.env.NEO4J_URL!, neo4j.auth.basic(\"neo4j\", process.env.NEO4J_PASSWORD!));\n * });\n * onShutdown(\"graph\", () => graph.close());\n */\nexport function onStart(name: string, hook: LifecycleHook): void {\n declaredLifecycle().start.push({ name, run: hook });\n}\n\n/**\n * Run `hook` while the application shuts down — the place a pool opened in\n * {@link onStart} is closed.\n *\n * Shutdown is BEST-EFFORT by design: a hook that throws is reported by name and\n * the rest still run. A drain that abandoned the remaining hooks on the first\n * failure would leak exactly what this exists to release, and the process is\n * leaving anyway.\n *\n * Hooks run in REVERSE declaration order, so a resource is released before what\n * it was built on.\n */\nexport function onShutdown(name: string, hook: LifecycleHook): void {\n declaredLifecycle().shutdown.push({ name, run: hook });\n}\n\nfunction reason(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Best-effort drain: every hook runs, a failure is reported, none is silent. */\nasync function drain(hooks: DeclaredHook[]): Promise<void> {\n for (const h of [...hooks].reverse()) {\n try {\n await h.run();\n } catch (err) {\n console.error(`[palbase] shutdown hook \"${h.name}\" failed: ${reason(err)}`, err);\n }\n }\n}\n\n/**\n * CLAIM what has been declared, run the start hooks, and hand back the runner\n * for this release's shutdown hooks. Called by the engine's `createApp`; the\n * `App.shutdown()` it builds calls what comes back. NOT part of the public\n * author-facing API.\n *\n * IT CLAIMS RATHER THAN READS, which is what makes it correct in this runtime:\n * a candidate release is loaded BESIDE the live one in one process\n * (`v2/runtime/src/registry-scope.ts`), and both bundles append to the one\n * shared slot above. If each app read the whole list, the live app's shutdown\n * would close the candidate's pool and the candidate's would close the live\n * app's. Taking the declarations leaves each app holding exactly its own.\n *\n * A start hook that throws REFUSES THE BOOT — with the hook's name in the\n * message — after releasing whatever the earlier hooks already opened. Serving\n * from a half-initialised app is the silence this whole surface replaces, and a\n * boot that dies holding an open pool is the leak it replaces.\n */\nexport async function __runStartHooks(): Promise<ShutdownRunner> {\n const slot = declaredLifecycle();\n const start = slot.start.splice(0);\n const shutdown = slot.shutdown.splice(0);\n\n for (const h of start) {\n try {\n await h.run();\n } catch (err) {\n await drain(shutdown);\n throw new Error(`[palbase] start hook \"${h.name}\" failed: ${reason(err)}`, { cause: err });\n }\n }\n\n let drained = false;\n return async () => {\n // SIGTERM racing a redeploy asks twice; a pool is closed once.\n if (drained) return;\n drained = true;\n await drain(shutdown);\n };\n}\n\n/** Drop every declaration. For tests, which declare repeatedly in one process.\n * NOT part of the public author-facing API. */\nexport function __resetLifecycleHooks(): void {\n const g = globalThis as unknown as Record<symbol, DeclaredLifecycle | undefined>;\n delete g[LIFECYCLE];\n}\n\n/**\n * Build a Proxy singleton that forwards every property access to the live\n * client named `key` on the current runtime.\n *\n * The single `as RuntimeServices[K]` is the only contained cast in the surface:\n * `Reflect.get` on a typed object returns `unknown` for a `string | symbol`\n * key, but `prop` is constrained to keys of the client interface at the call\n * sites (the exported singletons are typed below), so the forward is sound.\n */\nfunction makeServiceProxy<K extends keyof RuntimeServices>(key: K): RuntimeServices[K] {\n const handler: ProxyHandler<RuntimeServices[K]> = {\n get(_target, prop, receiver) {\n const client = __getRuntime()[key];\n const value = Reflect.get(client as object, prop, receiver) as unknown;\n // Bind methods to their owning client so `this` stays correct when the\n // author destructures or calls `Database.query(...)`.\n return typeof value === \"function\" ? value.bind(client) : value;\n },\n };\n // The Proxy target is irrelevant (all access goes through `get`); the cast\n // names the surface type the singleton presents to authors.\n return new Proxy({} as RuntimeServices[K], handler);\n}\n\n/**\n * Build the `.tables` accessor for the top-level `Database`. Each\n * `tables.<name>` access returns a small object that forwards the five CRUD ops\n * to the underlying client using `name` as the string table identifier. The\n * shapes are typed against the generated `palbase-env.d.ts` (`EnvTables`); at\n * runtime they are plain string-keyed calls, so no schema value is needed here.\n *\n * Returns `EnvTables` — TS cannot infer the mapped type through the Proxy, so\n * a single structural narrowing names the surface (the proxy returns a\n * correctly-shaped accessor for whatever string member is read).\n */\n/** T018 (C-8): similar/recommend'in string-keyed yüzü. DBOps'a (endpoint.ts)\n * BİLEREK eklenmedi — search-param imza üçlüsü (engine/db + typed-db +\n * endpoint) büyümesin: proxy dispatch runtime'da engine ops'una zaten ulaşır,\n * derleme güvenliğini typed yüzey (EnvTypedTable) verir. */\ninterface RecoOps {\n similar(table: string, id: string, params?: Record<string, unknown>): Promise<Record<string, unknown>[]>;\n recommend(table: string, params: Record<string, unknown>): Promise<Record<string, unknown>[]>;\n}\n\n/**\n * The Proxy behind EVERY `.tables` map — public's and every other schema's.\n *\n * `prefix` is what the wire name is built from: `\"\"` for `public`, so its tables\n * stay BARE, and `\"<schema>.\"` for any other, so `schema(\"billing\").tables\n * .invoices` reaches the broker as `billing.invoices` (D-10 — the same\n * schema-qualified key `toSchemaJSON` and the generated `relations` use).\n *\n * One trap for both surfaces: two copies would be two op lists that can drift,\n * and the one that forgets an op does not complain — it answers `undefined`.\n */\nfunction makeTableProxy(ops: () => DBOps & RecoOps, prefix: string): object {\n return new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n const name = `${prefix}${prop}`;\n return {\n insert: (data: Record<string, unknown>) => ops().insert(name, data),\n update: (id: string, data: Record<string, unknown>) => ops().update(name, id, data),\n delete: (id: string) => ops().delete(name, id),\n findById: (id: string) => ops().findById(name, id),\n findMany: (query?: Record<string, unknown>, opts?: Parameters<DBOps[\"findMany\"]>[2]) =>\n ops().findMany(name, query, opts),\n upsert: (data: Record<string, unknown>, opts: { onConflict: readonly string[] }) =>\n ops().upsert(name, data, opts),\n search: (params?: Record<string, unknown>) => ops().search(name, params),\n similar: (id: string, params?: Record<string, unknown>) => ops().similar(name, id, params),\n recommend: (params: Record<string, unknown>) => ops().recommend(name, params),\n facets: (params: { facets: string[] } & Record<string, unknown>) => ops().facets(name, params),\n supersede: (id: string, row: Record<string, unknown>) => ops().supersede(name, id, row),\n };\n },\n },\n );\n}\n\nfunction makeTablesAccessor(ops: () => DBOps & RecoOps): EnvTables {\n return makeTableProxy(ops, \"\") as EnvTables;\n}\n\n/**\n * The `.tables` map of ONE schema other than `public`, as\n * `Database.schema(\"billing\")` returns it.\n *\n * Same accessor, one difference: the wire name is schema-qualified. Nothing here\n * decides whether the schema is reachable — `exposed` is the schema's own\n * declaration and the broker checks it.\n */\nfunction makeSchemaAccessor<S extends keyof Schemas>(\n ops: () => DBOps & RecoOps,\n schema: S,\n): EnvSchemas[S] {\n return { tables: makeTableProxy(ops, `${String(schema)}.`) } as EnvSchemas[S];\n}\n\n/** The raw string-keyed `DBClient` for the current request scope. */\nconst rawDatabase: DBClient = makeServiceProxy(\"Database\");\n\n/**\n * Wrap a raw `DBClient` into the typed `{ ...ops, tables, transaction }`\n * surface. The five string ops forward straight through; `tables` is the\n * env-typed accessor; `transaction` yields typed tables. Reused for both the\n * default (RLS-enforced) `Database` and the `asService()` sibling — each is\n * fed its own raw client (the default proxy vs `rawDatabase.asService()`).\n *\n * The `satisfies` pins the op surface so a missing/renamed op is a compile\n * error; the assembled object carries `tables`/`transaction` alongside.\n */\nfunction makeTypedSurface(raw: Omit<DBClient, \"asService\">): EnvServiceDatabase {\n // Proxy dispatch her üyeyi taşır; RecoOps tipi DBClient'a eklenmediğinden\n // (yukarıdaki karar) similar/recommend erişimi bu daraltmadan geçer.\n const reco = raw as Omit<DBClient, \"asService\"> & RecoOps;\n const ops = {\n query: (sql: string, params?: unknown[]) => raw.query(sql, params),\n insert: (table: string, data: Record<string, unknown>) => raw.insert(table, data),\n update: (table: string, id: string, data: Record<string, unknown>) =>\n raw.update(table, id, data),\n delete: (table: string, id: string) => raw.delete(table, id),\n findById: (table: string, id: string) => raw.findById(table, id),\n findMany: (table: string, query?: Record<string, unknown>, opts?: Parameters<DBOps[\"findMany\"]>[2]) =>\n raw.findMany(table, query, opts),\n upsert: (table: string, data: Record<string, unknown>, opts: { onConflict: readonly string[] }) =>\n raw.upsert(table, data, opts),\n updateMany: (table: string, where: Record<string, unknown>, set: Record<string, unknown>) =>\n raw.updateMany(table, where, set),\n deleteMany: (table: string, where: Record<string, unknown>) => raw.deleteMany(table, where),\n count: (table: string, where?: Record<string, unknown>) => raw.count(table, where),\n search: (table: string, params?: Record<string, unknown>) => raw.search(table, params),\n similar: (table: string, id: string, params?: Record<string, unknown>) =>\n reco.similar(table, id, params),\n recommend: (table: string, params: Record<string, unknown>) => reco.recommend(table, params),\n facets: (table: string, params: { facets: string[] } & Record<string, unknown>) => reco.facets(table, params),\n supersede: (table: string, id: string, row: Record<string, unknown>) =>\n raw.supersede(table, id, row),\n } satisfies DBOps & RecoOps;\n return Object.assign(ops, {\n // Both surfaces get it: a savepoint on the service transaction is as useful\n // as one on the request's, and each is bound to its own connection.\n attempt: <T,>(fn: (tx: DBOps) => Promise<T>) => raw.attempt(fn),\n tables: makeTablesAccessor(() => reco),\n schema: <S extends keyof Schemas>(name: S): EnvSchemas[S] =>\n makeSchemaAccessor(() => reco, name),\n transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n // A FRESH builder per call: it holds this transaction's ops and its error\n // slot table, and the runtime serves concurrent requests on one event loop.\n // A shared builder would splice one request's writes into another's plan.\n const builder = new TxPlanBuilder();\n return runTxPlan(raw, makeTxTablesAccessor(builder), builder, fn) as Promise<\n Materialized<T>\n >;\n },\n });\n}\n\n/**\n * The transaction twin of {@link makeTablesAccessor}: `tables.<name>` yields the\n * table's PLAN operations, recorded into `builder` instead of sent one by one.\n *\n * Same Proxy shape and same reason for the single narrowing — TS cannot infer a\n * mapped type through a Proxy, so the cast names what the trap returns.\n */\nfunction makeTxTablesAccessor(builder: TxPlanBuilder): TxTables {\n const tablesProxy = new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n return builder.table(prop);\n },\n },\n );\n return tablesProxy as TxTables;\n}\n\n/**\n * The project's own Postgres (pgx, schema `env_<envId>`).\n *\n * Typed by default: `Database.tables.<name>.insert({...})` is typed against\n * the project's generated `palbase-env.d.ts` with NO import and NO generic.\n * The raw string ops (`query`/`insert`/`update`/`delete`/`findById`/`findMany`)\n * are also available for dynamic table names and read-only SQL.\n *\n * RLS is enforced by default (the runtime runs each op as `authenticated` with\n * the verified user's claims). To bypass RLS, call `Database.asService()` —\n * explicit and greppable — which runs as the `service_role` (BYPASSRLS).\n *\n * @example\n * import { Database } from \"@palbase/backend\";\n *\n * const todo = await Database.tables.todos.insert({ title: req.input.title });\n * todo.id; // string ✓\n * const rows = await Database.query(\"SELECT id FROM todos WHERE done = $1\", [false]);\n * const all = await Database.asService().tables.todos.findMany({}); // RLS bypass\n */\nexport const Database: EnvTypedDatabase = Object.assign(makeTypedSurface(rawDatabase), {\n /**\n * Lazily resolve the runtime's service-role sibling on each call. We do NOT\n * cache it: `rawDatabase.asService()` reads the CURRENT request scope through\n * the runtime proxy, and the per-request runtime injects a service client\n * bound to that request's identity headers — caching would leak one request's\n * sibling into another concurrent request.\n */\n asService(): EnvServiceDatabase {\n return makeTypedSurface(rawDatabase.asService());\n },\n});\n\n/** Firestore-like document client (PalDocs). */\nexport const Documents: PalbaseDocsClient = makeServiceProxy(\"Documents\");\n\n/**\n * `buckets.<name>` — the storage twin of `Database.tables.<name>`, and the same\n * mechanism: `config/storage.ts` generates a `Buckets` augmentation into\n * `palbase-env.d.ts`, so a bucket name is a property with no import and no\n * generic, and a typo is a compile error.\n *\n * The intermediate `.buckets` is there for the reason `.tables` is: bucket\n * names must not share a namespace with the client's own methods, or the day\n * somebody declares a bucket called `bucket` the surface breaks.\n */\nexport type EnvBuckets = {\n [K in keyof Buckets]: TypedBucketClient<Buckets[K] extends BucketTypes ? Buckets[K] : BucketTypes>;\n};\n\n/** One bucket, with its declared variant names in the type. */\nexport interface TypedBucketClient<B extends BucketTypes> extends Omit<PalbaseBucketClient, \"getPublicUrl\"> {\n /** The public URL for the object, or for one of THIS bucket's declared\n * renditions. A name the bucket does not declare is a compile error. */\n getPublicUrl(path: string, options?: { variant?: B[\"variants\"] }): string;\n}\n\nfunction makeBucketsAccessor(storage: () => PalbaseStorageClient): EnvBuckets {\n return new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n return storage().bucket(prop);\n },\n },\n ) as EnvBuckets;\n}\n\nconst rawStorage: PalbaseStorageClient = makeServiceProxy(\"Storage\");\n\n/**\n * Object storage: buckets, objects, renditions and signed URLs.\n *\n * `Storage.buckets.posts.upload(...)` is the typed path. `Storage.bucket(name)`\n * remains for a name computed at runtime — rare, and it gives up the typing,\n * which is the honest trade rather than a second blessed way to do it.\n */\nexport const Storage: PalbaseStorageClient & { buckets: EnvBuckets } = Object.assign(\n {\n // FORWARDED explicitly, not assigned onto the service proxy.\n //\n // `Object.assign(rawStorage, {buckets})` writes onto the proxy's TARGET, and\n // the proxy's only trap is `get`, which forwards every read to the module\n // client — so the property landed somewhere nothing reads and\n // `Storage.buckets.docs` was `undefined` in a deployed handler. It\n // typechecked, every test passed, and the live call answered\n // \"TypeError: undefined is not an object\". `Database` never had the bug\n // because it builds a plain surface the same way this now does.\n bucket: (name: string) => rawStorage.bucket(name),\n },\n { buckets: makeBucketsAccessor(() => rawStorage) },\n);\n\n/** JSON-typed cache (get/set/incr/getOrSet). */\nexport const Cache: CacheClient = makeServiceProxy(\"Cache\");\n\n\n/**\n * This tenant's secrets — API keys, provider credentials, signing material the\n * BACKEND owns.\n *\n * `await Secrets.get(\"STRIPE_KEY\")` in a handler. There is no `.env` to read\n * and no file to mount: a secret is written through the vault's authenticated\n * API (or the CLI/MCP that calls it), and this is how the deployed code reads\n * it back. A name this tenant has not set answers null — as does every name\n * the STACK holds, because no route returns a platform secret's value at all.\n */\nexport const Secrets: SecretsService = makeServiceProxy(\"Secrets\");\n\n/** Structured logger. */\nexport const Log: Logger = makeServiceProxy(\"Log\");\n\n/** Push / email / SMS / in-app notifications. */\nexport const Notifications: PalbaseNotificationsClient = makeServiceProxy(\"Notifications\");\n\n\n/**\n * The raw runtime Flags client for the current request scope. Carries the\n * default-surface reads + `setOverride` AND the runtime's `asService()` sibling\n * (the br-pod's `buildFlagsClient` returns both). The default `Flags` singleton\n * below forwards reads + `setOverride` through here; `Flags.asService()`\n * forwards to this client's own `asService()`.\n */\nconst rawFlags: PalbaseFlagsClient = makeServiceProxy(\"Flags\");\n\n/**\n * Feature flags.\n *\n * Mirrors the `Database` / `Database.asService()` model. The default surface is\n * RLS-equivalent for flags: reads resolve against the CURRENT request user and\n * `Flags.setOverride(key, value)` writes an override for that same signed-in\n * user (no userId argument, no admin power). Cross-user admin writes\n * (`setOverrideForUser`, …) live behind `Flags.asService()` — explicit and\n * greppable, just like `Database.asService()`.\n *\n * @example\n * import { Flags } from \"@palbase/backend\";\n *\n * if (await Flags.isEnabled(\"new_checkout\")) { ... } // current user\n * await Flags.setOverride(\"new_checkout\", true); // current user\n * await Flags.asService().setOverrideForUser(\"u_9\", \"x\", true); // cross-user\n */\nexport const Flags: PalbaseFlagsClient = Object.assign(\n {\n isEnabled(\n flagName: PalbaseFlagKey,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<boolean>> {\n return rawFlags.isEnabled(flagName, context);\n },\n getVariant(\n flagName: PalbaseFlagKey,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<PalbaseFlagVariant>> {\n return rawFlags.getVariant(flagName, context);\n },\n getAll(context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlag[]>> {\n return rawFlags.getAll(context);\n },\n /**\n * Resolve a flag's value, with an optional fallback.\n *\n * FORWARDED as of 2026-08-15. This surface is written out by hand, method\n * by method, and `get` was missing from it — so the client implemented it,\n * thirty assertions covered it, and `Flags.get(\"x\")` was `undefined` in a\n * deployed handler. Exactly the shape of the `Storage.buckets` defect found\n * the same day: a hand-maintained forwarding list is a list somebody has to\n * remember to update.\n */\n get(\n flagName: PalbaseFlagKey,\n defaultOrContext?: PalbaseFlagValue | PalbaseFlagContext,\n maybeContext?: PalbaseFlagContext,\n ): Promise<PalbaseResult<PalbaseFlagValue>> {\n return rawFlags.get(flagName, defaultOrContext, maybeContext);\n },\n setOverride(\n key: PalbaseFlagKey,\n value: PalbaseFlagValue,\n ): Promise<PalbaseResult<PalbaseSetOverrideResult>> {\n return rawFlags.setOverride(key, value);\n },\n },\n {\n /**\n * Lazily resolve the runtime's cross-user sibling on each call. We do NOT\n * cache it: `rawFlags.asService()` reads the CURRENT request scope through\n * the runtime proxy, so caching would leak one request's sibling into\n * another concurrent request. Mirrors `Database.asService()`.\n */\n asService(): PalbaseFlagsServiceClient {\n return rawFlags.asService();\n },\n },\n);\n\n/**\n * The Realtime broadcast singleton for the current request scope. Backend-side\n * Realtime is BROADCAST-ONLY (a stateless handler can push but not subscribe —\n * `subscribe()` lives on the client SDK's `pb.realtime`). Fire-and-forget:\n * `broadcast` resolves once accepted (or with an `error`), never blocking the\n * handler on subscribers.\n *\n * @example\n * import { Realtime } from \"@palbase/backend\";\n *\n * await Realtime.broadcast(\"room:42\", \"message\", { text, from: user.id });\n */\nexport const Realtime: PalbaseRealtimeClient = makeServiceProxy(\"Realtime\");\n","/**\n * tx-plan.ts — `Database.transaction()` as a PLAN, not a pinned session.\n *\n * A transaction used to be a conversation: BEGIN, then one network round trip\n * per operation, then COMMIT. Each of those round trips cost ~4 ms and, because\n * the pooler runs in transaction mode, an open transaction pinned a Postgres\n * backend for the whole conversation. A 121-operation statement upload pinned\n * one backend for ~490 ms.\n *\n * So the callback no longer TALKS to the database. It DESCRIBES what should\n * happen; the description is serialised and sent once; the broker runs the whole\n * thing inside one transaction and answers once. Committing on return and\n * rolling back on throw is unchanged — that is the only property tenant code\n * actually asked for.\n *\n * The consequences, stated plainly, because they are the whole design:\n *\n * - The callback is SYNCHRONOUS. There is nothing to await: no statement has\n * run yet when it returns. `async` on the callback and `await` inside it are\n * both compile errors (see {@link TxPlan} and {@link NotAwaitable}).\n * - `insert()` does not hand back a row, it hands back {@link TxRows}. Reading\n * a field requires `.expectOne(err)` first, which makes \"what if the row\n * isn't there\" a question you cannot route around: it is the argument.\n * - A field read from a row is a {@link Ref} — a PROMISE OF A VALUE THE SERVER\n * WILL PRODUCE, not the value. It can be written into a later operation and\n * it can be returned from the callback (it is substituted for the real value\n * before `transaction()` resolves). It cannot be branched on. See the\n * \"Truthiness\" note below — this is the sharp edge of the whole design.\n * - Control flow that needs a real value must move OUT of the callback: read\n * before the transaction, or express the condition as a guard\n * (`updateWhere({ id, accepted_at: null }, …).expectOne(new Conflict(…))`)\n * which the server evaluates and which rolls the whole plan back.\n *\n * # Truthiness — the hole this file CANNOT close\n *\n * JavaScript does not let a Proxy trap truthiness. `if (ref)` takes the true\n * branch, always, for every Ref, and no `get` handler ever runs. `tsc` is silent\n * because a Ref is a perfectly good object. So:\n *\n * const pot = tx.tables.pots.select({ id }, { limit: 1 }).expectOne(e);\n * if (!pot.balance) { … } // ← ALWAYS false. Silently wrong data.\n *\n * What this file does close: coercion (`Symbol.toPrimitive`/`valueOf`/\n * `toString`), awaiting (`then` is a callable member with a non-thenable\n * signature, which is a *compile* error), serialisation (`toJSON`), and nesting\n * a Ref inside a literal value where the server would store it as data. What it\n * cannot close is a bare truthiness test. The real defence is the build-time\n * static analysis (`tx_analysis.js`, phase P4); until that ships, this hole is\n * open and this comment is the only warning.\n *\n * # Wire contract\n *\n * The JSON this file emits is consumed by\n * the plan executor in `engine/db.ts`. That executor rejects\n * unknown fields at every level, so an op carries EXACTLY the fields its kind\n * takes. Everything here that looks like a needless restriction is one of the\n * server's rules made visible early:\n *\n * - `$ref` only points BACKWARDS, and only at an op statically known to yield\n * at most one row (insert, or a `one`/`atMost 1` guard, or `select limit 1`).\n * `.expectOne()` is what this file uses to satisfy that, always.\n * - `$expr` is a closed set: `inc`/`dec` (update only — they read the column's\n * current value) and `now()`.\n * - `update`/`delete` require a `where`; `insert` refuses one.\n * - `insertMany` rows must all set the same columns.\n * - ≤1000 ops, ≤5000 rows per insertMany, ≤8 MiB of JSON.\n *\n * Column keys are emitted SORTED, so the same callback always produces byte-\n * identical JSON. That is what lets the Go decoder be locked to golden files\n * this SDK emits (`testdata/tx_plan_golden/`).\n */\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * A plan handle was used as if it were a value: awaited, coerced to a string or\n * number, serialised, or nested inside another value.\n *\n * Thrown while the callback is still BUILDING the plan, so nothing has been sent\n * and nothing has been written.\n */\nexport class TxRefError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxRefError\";\n }\n}\n\n/**\n * The plan the callback described cannot be sent: it breaks a rule the server\n * would reject, and rejecting it here names the line that wrote it instead of\n * returning a 400 about an op index.\n */\nexport class TxPlanError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxPlanError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wire types — mirror the plan executor in `engine/db.ts` exactly.\n// ---------------------------------------------------------------------------\n\n/** A backwards reference to an earlier op's single-row result. */\nexport interface TxWireRef {\n $ref: { op: number; field: string };\n}\n\n/** A call from the server's closed function set. */\nexport interface TxWireExpr {\n $expr: { fn: \"inc\" | \"dec\"; by: number } | { fn: \"now\" };\n}\n\n/** One value in a `values`/`set`/`where` map: a literal, a `$ref` or a `$expr`. */\nexport type TxWireValue = TxWireRef | TxWireExpr | unknown;\n\n/** The tenant's declared expectation about an op's row count. `slot` indexes the\n * client-side error table — the error OBJECT never travels. */\nexport interface TxWireGuard {\n kind: \"one\" | \"none\" | \"atLeast\" | \"atMost\";\n n: number;\n slot: number;\n}\n\n/** One operation in the wire plan. Fields are omitted, never null: the decoder\n * rejects a field that does not belong to the op's kind. */\nexport interface TxWireOp {\n /** upsert and insertMany: the columns Postgres matches on. */\n onConflict?: readonly string[];\n /** insertMany only: what a collision does. Absent means no ON CONFLICT clause\n * at all, which is what every insertMany did before this option existed. */\n action?: \"ignore\" | \"update\";\n op: \"insert\" | \"insertMany\" | \"upsert\" | \"update\" | \"delete\" | \"select\";\n table: string;\n values?: Record<string, TxWireValue>;\n rows?: Record<string, TxWireValue>[];\n set?: Record<string, TxWireValue>;\n where?: Record<string, TxWireValue>;\n limit?: number;\n lock?: \"update\";\n guard?: TxWireGuard;\n}\n\n/** The plan the engine executes on the request's own transaction. */\nexport interface TxPlanBody {\n ops: TxWireOp[];\n}\n\n/** One op's outcome, positionally matched to the plan's ops. */\nexport interface TxPlanOpResult {\n rows: Record<string, unknown>[];\n rows_affected: number;\n}\n\n/** One result per op, in plan order. */\nexport interface TxPlanResponse {\n results: TxPlanOpResult[];\n}\n\n/**\n * The fields the runtime must copy from the broker's error envelope onto the\n * rejection it throws out of {@link DBClient.txPlan}.\n *\n * `slot` is the whole point: on a guard failure the server answers with the\n * INDEX of the expectation that did not hold, never with an error message of its\n * own, and this SDK maps that index back to the `Error` the callback handed to\n * `.expectOne(…)`. Without `slot` a guard failure degrades to a generic 409.\n */\nexport interface TxPlanRejection {\n status?: number;\n /** `tx_plan_invalid` | `tx_guard_failed` | `tx_ref_unresolved` | a pg class. */\n error_code?: string;\n /** Present only for `tx_guard_failed`: the client-side error table index. */\n slot?: number;\n /** Present on a database error: which op failed. */\n op?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Handle types\n// ---------------------------------------------------------------------------\n\ndeclare const refBrand: unique symbol;\ndeclare const rowBrand: unique symbol;\ndeclare const rowsBrand: unique symbol;\n\n/**\n * Makes a handle a compile error to `await`.\n *\n * `then` is declared as a CALLABLE member whose signature is not `PromiseLike`,\n * which is precisely the shape TypeScript rejects: `await handle` is TS1320 and\n * `async () => handle` is TS1058. A non-callable `then` would not do it — the\n * compiler simply ignores those.\n */\nexport interface NotAwaitable {\n /** Not a promise. Nothing here has run yet; there is nothing to await. */\n then(doNotAwaitAPlanHandle: \"a transaction plan is built synchronously\"): never;\n}\n\n/**\n * A value the SERVER will produce, standing in for a column of a row this plan\n * writes or reads.\n *\n * Legal uses: write it into a later operation's `values`/`set`/`where`, or\n * return it from the callback (it is replaced by the real value before\n * `transaction()` resolves).\n *\n * Illegal, and caught: `await`, `String(ref)`, `` `${ref}` ``, `ref + 1`,\n * `JSON.stringify(ref)`, burying it inside a jsonb object.\n *\n * Illegal, and NOT caught: `if (ref)`. See the truthiness note at the top.\n */\nexport interface Ref<T> extends NotAwaitable {\n readonly [refBrand]: T;\n}\n\n/** The brand carried by a single-row handle, and the seam `Materialized` reads\n * to turn `return st` into the whole row. */\nexport interface TxRowHandle<Row> extends NotAwaitable {\n readonly [rowBrand]: Row;\n}\n\n/**\n * A row this plan is known to produce exactly one of. Every property is a\n * {@link Ref}; returning the handle itself yields the whole row.\n *\n * Only `.expectOne(err)` produces one — which is the design: a row you can read\n * fields from is a row whose absence you have already answered for.\n */\nexport type TxRow<Row> = { readonly [K in keyof Row]: Ref<Row[K]> } & TxRowHandle<Row>;\n\n/**\n * The result of one operation, before any expectation is declared about it.\n *\n * Deliberately not a row and not a list: an operation's row count is not known\n * until the server runs it, so the only thing that can be said about it here is\n * an EXPECTATION. Declaring one is also the only way to get a readable row.\n *\n * At most one expectation per operation — the wire carries one guard per op, and\n * a second call throws rather than silently dropping the first.\n */\nexport interface TxRows<Row> extends NotAwaitable {\n readonly [rowsBrand]: Row;\n /**\n * Require exactly one row, and read it. On any other count the server rolls\n * the whole transaction back and this `error` is thrown to the caller.\n *\n * This is the only way to reach a row's fields, and the only shape a `$ref`\n * may point at.\n */\n expectOne(error: Error): TxRow<Row>;\n /** Require zero rows (e.g. \"this membership must not already exist\"). */\n expectNone(error: Error): void;\n /** Require at least `n` rows. */\n expectAtLeast(n: number, error: Error): void;\n /** Require at most `n` rows. */\n expectAtMost(n: number, error: Error): void;\n}\n\n/** `now()` — the server's clock, usable wherever a value is. */\nexport interface TxNow extends NotAwaitable {\n readonly $expr: { fn: \"now\" };\n}\n\n/** `inc(n)` / `dec(n)` — read the column's CURRENT value and write it back\n * changed. Only meaningful in an update's `set`, which is where the types allow\n * it and where the server allows it. */\nexport interface TxColumnExpr extends NotAwaitable {\n readonly $expr: { fn: \"inc\" | \"dec\"; by: number };\n}\n\n/**\n * Resolve a callback's return type against what actually comes back: every\n * {@link Ref} becomes its value, every {@link TxRow} becomes its row, and\n * anything else keeps its shape.\n *\n * A {@link TxRows} resolves to an explanatory string type rather than a row\n * list: it has no single answer to give, and saying so in the type is louder\n * than a runtime throw.\n */\nexport type Materialized<T> = T extends Ref<infer U>\n ? U\n : T extends TxRowHandle<infer R>\n ? R\n : T extends TxRows<unknown>\n ? \"a TxRows cannot leave the transaction callback — read a row with .expectOne(err) first\"\n : T extends Date\n ? T\n : T extends object\n ? { [K in keyof T]: Materialized<T[K]> }\n : T;\n\n// ---------------------------------------------------------------------------\n// Author-facing value types\n// ---------------------------------------------------------------------------\n\n/** A value written by an INSERT: a literal, an earlier row's field, or `now()`.\n * `inc`/`dec` are absent on purpose — they read a current value, and an inserted\n * row has none. */\nexport type TxInsertValue<V> = V | Ref<V> | TxNow;\n\n/** A value written by an UPDATE's `set`: everything an insert takes, plus the\n * read-modify-write expressions. */\nexport type TxSetValue<V> = V | Ref<V> | TxNow | TxColumnExpr;\n\n/** An insert payload: the table's insert shape, with refs and `now()` allowed. */\nexport type TxInsertShape<Insert> = { [K in keyof Insert]: TxInsertValue<Insert[K]> };\n\n/** An update's `set`: any subset of the insert shape, with expressions allowed. */\nexport type TxSetShape<Insert> = { [K in keyof Insert]?: TxSetValue<Insert[K]> };\n\n/**\n * A filter. Every entry is an equality test and they are AND-ed; a `null`\n * becomes `IS NULL`, which is what makes `{ accepted_at: null }` a usable\n * \"not yet accepted\" guard rather than a clause that matches nothing.\n */\nexport type TxWhere<Row> = { [K in keyof Row]?: Row[K] | Ref<Row[K]> };\n\n/** Options for a plan `select`. */\nexport interface TxSelectOptions {\n /** Cap the rows read. */\n limit?: number;\n /** Take a real `FOR UPDATE` row lock for the rest of the transaction. */\n lock?: \"update\";\n}\n\n/** One table, as the plan sees it. */\nexport interface TxTable<Row, Insert> {\n /** Insert one row. Returns a handle — call `.expectOne(err)` to read fields. */\n insert(values: TxInsertShape<Insert>): TxRows<Row>;\n /**\n * Insert many rows in ONE statement. Every row must set the same columns\n * (a row that omits one would silently take the column's default).\n *\n * An empty list writes nothing and sends nothing.\n */\n /**\n * Insert many rows in ONE statement, optionally choosing what a collision does.\n *\n * Without `opts` this is a plain multi-row INSERT and a collision aborts the\n * transaction — the behaviour every call had before the option existed.\n *\n * `action: \"ignore\"` emits `ON CONFLICT DO NOTHING`, which is how \"insert the\n * ones that are new\" becomes one round-trip instead of one per row with a\n * 23505 caught around each. **The returned rows are the ones actually\n * INSERTED**: a row that collided is skipped, so it is absent from the result\n * — Postgres does not return what it did not write.\n *\n * `action: \"update\"` emits `ON CONFLICT DO UPDATE`, setting every non-conflict\n * column from the incoming row, and every row comes back.\n */\n insertMany(\n rows: readonly TxInsertShape<Insert>[],\n opts?: {\n onConflict: readonly Extract<keyof Row, string>[];\n action?: \"ignore\" | \"update\";\n },\n ): TxRows<Row>;\n /**\n * Insert the row, or update it when it collides on `onConflict` — inside the\n * plan's savepoint, with the same meaning `tables.<t>.upsert()` has outside it.\n *\n * It is an operation because the alternative is not writable here: a failed\n * insert aborts the whole transaction, so \"try, then fall back\" cannot be two\n * plan steps.\n */\n upsert(\n values: TxInsertShape<Insert>,\n options: { onConflict: readonly Extract<keyof Row, string>[] },\n ): TxRows<Row>;\n /**\n * Update every row matching `where`. The filter comes first because it is the\n * dangerous half: an update whose `where` you got wrong rewrites rows you\n * never looked at. The server refuses an update with no `where` at all.\n */\n updateWhere(where: TxWhere<Row>, set: TxSetShape<Insert>): TxRows<Row>;\n /** Delete every row matching `where`. The server refuses an unfiltered delete. */\n deleteWhere(where: TxWhere<Row>): TxRows<Row>;\n /** Read rows, optionally locking them for the rest of the transaction. */\n select(where?: TxWhere<Row>, options?: TxSelectOptions): TxRows<Row>;\n}\n\n/**\n * The handle a transaction callback receives.\n *\n * It carries tables and nothing else: no `query`, no `findById`, no `asService`.\n * A read whose value the plan does not write belongs OUTSIDE the transaction,\n * where it costs one round trip and can be branched on like an ordinary value.\n */\nexport interface TxPlanHandle<TTables> {\n tables: TTables;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — expressions\n// ---------------------------------------------------------------------------\n\n/** Internal marker read by the serialiser. */\nconst EXPR = Symbol.for(\"palbase.tx.expr\");\nconst REF = Symbol.for(\"palbase.tx.ref\");\nconst ROW = Symbol.for(\"palbase.tx.row\");\nconst ROWS = Symbol.for(\"palbase.tx.rows\");\n\ninterface RefDescriptor {\n op: number;\n field: string;\n}\n\n/** Property reads that must not silently produce a value on a plan handle.\n * `then` is the one that matters for correctness (it makes `await` a compile\n * error AND stops a handle from being adopted by a promise); the rest turn a\n * silent wrong answer — `\"[object Object]\"`, `NaN`, `{}` — into a thrown one. */\nconst TRAPPED_PROPS: readonly (string | symbol)[] = [\n \"then\",\n \"valueOf\",\n \"toString\",\n \"toJSON\",\n Symbol.toPrimitive,\n];\n\nfunction trap(prop: string | symbol, what: string, hint: string): never {\n const name = typeof prop === \"symbol\" ? prop.description ?? String(prop) : prop;\n throw new TxRefError(\n `${what} was used as a value (via \\`${name}\\`). Nothing in a transaction ` +\n `callback has run yet, so there is no value to read. ${hint}`,\n );\n}\n\n/** The server's `now()`. */\nexport function now(): TxNow {\n return makeExpr({ fn: \"now\" }) as TxNow;\n}\n\n/** Add `by` to the column's current value. Only valid in an update's `set`. */\nexport function inc(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"inc\");\n return makeExpr({ fn: \"inc\", by }) as TxColumnExpr;\n}\n\n/** Subtract `by` from the column's current value. Only valid in an update's `set`. */\nexport function dec(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"dec\");\n return makeExpr({ fn: \"dec\", by }) as TxColumnExpr;\n}\n\nfunction assertFiniteNumber(by: number, fn: string): void {\n if (typeof by !== \"number\" || !Number.isFinite(by)) {\n // JSON has no NaN/Infinity: they would serialise to `null` and the server\n // would reject the plan with an unhelpful decode error.\n throw new TxPlanError(`${fn}() needs a finite number, got ${String(by)}`);\n }\n}\n\nfunction makeExpr(expr: TxWireExpr[\"$expr\"]): unknown {\n return new Proxy(\n { [EXPR]: expr } as Record<string | symbol, unknown>,\n {\n get(target, prop) {\n if (prop === EXPR) return target[EXPR];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(prop, \"A plan expression\", \"Write it into an operation instead.\");\n }\n return undefined;\n },\n },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — refs and row handles\n// ---------------------------------------------------------------------------\n\nfunction makeRef(op: number, field: string): unknown {\n const target: Record<string | symbol, unknown> = { [REF]: { op, field } satisfies RefDescriptor };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === REF) return t[REF];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n `\\`${field}\\` of a row this transaction has not written yet`,\n \"Pass it to another operation in the same plan, or return it from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n return undefined;\n },\n });\n}\n\nfunction makeRowHandle(op: number): unknown {\n const target: Record<string | symbol, unknown> = { [ROW]: op };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === ROW) return t[ROW];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n \"A row this transaction has not written yet\",\n \"Read one of its columns to reference it, or return the row from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n if (typeof prop === \"symbol\") return undefined;\n return makeRef(op, prop);\n },\n });\n}\n\nfunction refDescriptor(v: unknown): RefDescriptor | null {\n if (typeof v !== \"object\" || v === null) return null;\n const d = (v as Record<symbol, unknown>)[REF];\n return isRefDescriptor(d) ? d : null;\n}\n\nfunction isRefDescriptor(d: unknown): d is RefDescriptor {\n return (\n typeof d === \"object\" &&\n d !== null &&\n typeof (d as RefDescriptor).op === \"number\" &&\n typeof (d as RefDescriptor).field === \"string\"\n );\n}\n\nfunction rowOpIndex(v: unknown): number | null {\n if (typeof v !== \"object\" || v === null) return null;\n const op = (v as Record<symbol, unknown>)[ROW];\n return typeof op === \"number\" ? op : null;\n}\n\nfunction exprOf(v: unknown): TxWireExpr[\"$expr\"] | null {\n if (typeof v !== \"object\" || v === null) return null;\n const e = (v as Record<symbol, unknown>)[EXPR];\n return typeof e === \"object\" && e !== null ? (e as TxWireExpr[\"$expr\"]) : null;\n}\n\nfunction isRowsHandle(v: unknown): boolean {\n return typeof v === \"object\" && v !== null && (v as Record<symbol, unknown>)[ROWS] !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — value encoding\n// ---------------------------------------------------------------------------\n\n/**\n * Encode one value of a `values`/`set`/`where` map.\n *\n * The nesting check is not defensive tidiness. The server treats `$ref` as a\n * tagged value only at the TOP of a column's value; a ref buried inside a jsonb\n * payload is just data, and would be stored as the literal object\n * `{\"$ref\":{...}}` — a write that succeeds, commits, and is wrong. So a nested\n * handle is a hard error here, where the line that wrote it is still on the\n * stack.\n */\nfunction encodeValue(value: unknown, column: string, allowColumnExpr: boolean): TxWireValue {\n const ref = refDescriptor(value);\n if (ref) return { $ref: { op: ref.op, field: ref.field } } satisfies TxWireRef;\n\n const expr = exprOf(value);\n if (expr) {\n if (expr.fn !== \"now\" && !allowColumnExpr) {\n throw new TxPlanError(\n `\\`${column}\\`: ${expr.fn}() reads the column's current value, so it is ` +\n `only valid in updateWhere(where, set).`,\n );\n }\n return { $expr: expr } satisfies TxWireExpr;\n }\n\n if (rowOpIndex(value) !== null) {\n throw new TxPlanError(\n `\\`${column}\\`: a row handle is not a value. Read the column you meant ` +\n `(e.g. \\`row.id\\`).`,\n );\n }\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: an operation result is not a value. Declare an expectation ` +\n `first (\\`.expectOne(err)\\`) and read a column from the row.`,\n );\n }\n\n assertNoNestedHandles(value, column);\n return value;\n}\n\nfunction assertNoNestedHandles(value: unknown, column: string): void {\n if (typeof value !== \"object\" || value === null) return;\n if (value instanceof Date) return;\n if (refDescriptor(value) || exprOf(value) || rowOpIndex(value) !== null || isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: a plan handle is nested inside a value. The server would ` +\n `store it as literal JSON, not resolve it. Put the reference directly in ` +\n `the column.`,\n );\n }\n if (Array.isArray(value)) {\n for (const item of value) assertNoNestedHandles(item, column);\n return;\n }\n for (const item of Object.values(value as Record<string, unknown>)) {\n assertNoNestedHandles(item, column);\n }\n}\n\n/**\n * Encode a column map, dropping `undefined` and emitting keys SORTED.\n *\n * Sorting is what makes the same callback produce byte-identical JSON every\n * time, which is what lets the Go decoder be locked to goldens this SDK emits.\n * Dropping `undefined` mirrors what `JSON.stringify` would do anyway, but does\n * it where the resulting column list is still checkable.\n */\nfunction encodeMap(\n map: Record<string, unknown>,\n allowColumnExpr: boolean,\n): Record<string, TxWireValue> {\n const out: Record<string, TxWireValue> = {};\n for (const key of Object.keys(map).sort()) {\n const value = map[key];\n if (value === undefined) continue;\n out[key] = encodeValue(value, key, allowColumnExpr);\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the builder\n// ---------------------------------------------------------------------------\n\n/** How many rows an op can produce, as far as the CLIENT can tell before it\n * runs. Only the empty `insertMany` is knowable, and knowing it is what lets a\n * doomed expectation fail on the line that declared it. */\nconst SKIPPED_OP = -1;\n\nclass TxRowsImpl<Row> implements TxRows<Row> {\n // Present so `isRowsHandle` recognises the object; never read for its value.\n readonly [ROWS] = true;\n // Phantom: the type brand that stops a bare object passing as a TxRows. Never\n // present at run time, which is what `declare` says.\n declare readonly [rowsBrand]: Row;\n private guarded = false;\n\n constructor(\n private readonly builder: TxPlanBuilder,\n private readonly opIndex: number,\n private readonly what: string,\n ) {}\n\n // The type-level `await` guard made real: TS rejects `await rows` at compile\n // time, and reaching this means someone called `.then(...)` by hand.\n then(): never {\n throw new TxRefError(\n `${this.what} cannot be awaited: a transaction callback builds a plan, it ` +\n `does not run statements. Remove the \\`await\\`.`,\n );\n }\n\n expectOne(error: Error): TxRow<Row> {\n this.declareGuard(\"one\", 1, error);\n if (this.opIndex === SKIPPED_OP) throw error;\n return makeRowHandle(this.opIndex) as TxRow<Row>;\n }\n\n expectNone(error: Error): void {\n this.declareGuard(\"none\", 0, error);\n }\n\n expectAtLeast(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtLeast\");\n this.declareGuard(\"atLeast\", n, error);\n if (this.opIndex === SKIPPED_OP && n > 0) throw error;\n }\n\n expectAtMost(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtMost\");\n this.declareGuard(\"atMost\", n, error);\n }\n\n private declareGuard(kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n if (!(error instanceof Error)) {\n // The error object is the ONLY thing that describes this failure to the\n // caller — the server sends back an index, never a message.\n throw new TxPlanError(\n `${this.what}: an expectation needs the Error to throw when it does not ` +\n `hold (e.g. \\`.expect…(new Conflict(\"already accepted\"))\\`).`,\n );\n }\n if (this.guarded) {\n throw new TxPlanError(\n `${this.what} already has an expectation. One operation carries one ` +\n `expectation; declare the second one on its own operation.`,\n );\n }\n this.guarded = true;\n if (this.opIndex === SKIPPED_OP) return;\n this.builder.attachGuard(this.opIndex, kind, n, error);\n }\n}\n\nfunction assertGuardCount(n: number, fn: string): void {\n if (!Number.isInteger(n) || n < 0) {\n throw new TxPlanError(`${fn}(n) needs a non-negative integer, got ${String(n)}`);\n }\n}\n\n/** Bounds mirrored from the plan executor so an over-sized plan is named here rather\n * than rejected as an opaque 400 after it has crossed the network. */\nconst MAX_OPS = 1000;\nconst MAX_ROWS = 5000;\n\n/**\n * Accumulates ops and the client-side error table while the callback runs.\n *\n * Exported for the runtime and for tests that need the serialised plan without\n * a server; author code never sees it.\n */\nexport class TxPlanBuilder {\n private readonly ops: TxWireOp[] = [];\n /** Errors handed to expectations, indexed by the `slot` the server echoes. */\n private readonly slots: Error[] = [];\n\n /** The table surface handed to the callback. Untyped here; the public\n * `transaction()` signatures put the schema types on top. */\n table(name: string): TxTable<Record<string, unknown>, Record<string, unknown>> {\n return {\n insert: (values) => {\n const encoded = encodeMap(values as Record<string, unknown>, false);\n if (Object.keys(encoded).length === 0) {\n throw new TxPlanError(`${name}.insert() needs at least one column`);\n }\n return this.push({ op: \"insert\", table: name, values: encoded }, `${name}.insert()`);\n },\n\n upsert: (values, options) => {\n const encoded = encodeMap(values as Record<string, unknown>, false);\n if (Object.keys(encoded).length === 0) {\n throw new TxPlanError(`${name}.upsert() needs at least one column`);\n }\n if (options.onConflict.length === 0) {\n throw new TxPlanError(`${name}.upsert() needs at least one onConflict column`);\n }\n return this.push(\n { op: \"upsert\", table: name, values: encoded, onConflict: options.onConflict },\n `${name}.upsert()`,\n );\n },\n\n insertMany: (rows, opts) => {\n if (rows.length === 0) {\n // Nothing to write. Emitting an op would be a guaranteed 400 (the\n // server requires rows), and refusing outright would punish the\n // ordinary \"filtered every candidate out\" case.\n return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);\n }\n if (rows.length > MAX_ROWS) {\n throw new TxPlanError(\n `${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. ` +\n `Split the write across requests.`,\n );\n }\n const encoded = rows.map((row) => encodeMap(row as Record<string, unknown>, false));\n assertUniformRows(encoded, name);\n if (opts !== undefined && opts.onConflict.length === 0) {\n throw new TxPlanError(\n `${name}.insertMany() was given a conflict action with no onConflict ` +\n `columns. Postgres matches a collision on columns, so name them.`,\n );\n }\n return this.push(\n {\n op: \"insertMany\",\n table: name,\n rows: encoded,\n // Omitted entirely when no options were given, so the op a plain\n // insertMany produces is byte-identical to the one it produced\n // before this option existed.\n ...(opts !== undefined\n ? { onConflict: opts.onConflict, action: opts.action ?? \"ignore\" }\n : {}),\n },\n `${name}.insertMany()`,\n );\n },\n\n updateWhere: (where, set) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n const encodedSet = encodeMap(set as Record<string, unknown>, true);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.updateWhere() needs a filter. An update with no filter ` +\n `rewrites the whole table.`,\n );\n }\n if (Object.keys(encodedSet).length === 0) {\n throw new TxPlanError(`${name}.updateWhere() needs at least one column to set`);\n }\n return this.push(\n { op: \"update\", table: name, set: encodedSet, where: encodedWhere },\n `${name}.updateWhere()`,\n );\n },\n\n deleteWhere: (where) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.deleteWhere() needs a filter. A delete with no filter empties ` +\n `the table.`,\n );\n }\n return this.push(\n { op: \"delete\", table: name, where: encodedWhere },\n `${name}.deleteWhere()`,\n );\n },\n\n select: (where, options) => {\n const op: TxWireOp = { op: \"select\", table: name };\n const encodedWhere = encodeMap((where ?? {}) as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length > 0) op.where = encodedWhere;\n if (options?.limit !== undefined) {\n if (!Number.isInteger(options.limit) || options.limit < 0) {\n throw new TxPlanError(\n `${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`,\n );\n }\n op.limit = options.limit;\n }\n if (options?.lock !== undefined) op.lock = options.lock;\n return this.push(op, `${name}.select()`);\n },\n };\n }\n\n private push(op: TxWireOp, what: string): TxRows<Record<string, unknown>> {\n if (this.ops.length >= MAX_OPS) {\n throw new TxPlanError(\n `this transaction has ${MAX_OPS} operations, which is the limit. Use ` +\n `insertMany() for bulk writes, or split the work across requests.`,\n );\n }\n const index = this.ops.length;\n this.ops.push(op);\n return new TxRowsImpl(this, index, what);\n }\n\n /** Attach an expectation to an op and record its error in the slot table. */\n attachGuard(opIndex: number, kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n const op = this.ops[opIndex];\n // Unreachable: the index came from `push`. A loud failure beats a silently\n // unguarded write if that ever stops being true.\n if (!op) throw new TxPlanError(`internal: expectation on unknown operation ${opIndex}`);\n const slot = this.slots.length;\n this.slots.push(error);\n op.guard = { kind, n, slot };\n }\n\n /** The serialisable plan. Empty when the callback described no writes. */\n body(): TxPlanBody {\n return { ops: this.ops };\n }\n\n /** The error the server's `slot` selects, or `null` when it names one this\n * plan never declared (a server/client disagreement, not a tenant error). */\n errorForSlot(slot: number): Error | null {\n return this.slots[slot] ?? null;\n }\n}\n\nfunction assertUniformRows(rows: Record<string, TxWireValue>[], table: string): void {\n const first = rows[0];\n if (!first) return;\n const want = Object.keys(first);\n const wantKey = want.join(\",\");\n for (let i = 1; i < rows.length; i++) {\n const got = Object.keys(rows[i] as Record<string, TxWireValue>);\n if (got.join(\",\") !== wantKey) {\n // One statement, one column list. A ragged row would take the DB default\n // for the column it omitted — a write that succeeds and is wrong.\n throw new TxPlanError(\n `${table}.insertMany(): every row must set the same columns. Row 0 sets ` +\n `[${want.join(\", \")}] but row ${i} sets [${got.join(\", \")}]. ` +\n `(A property set to \\`undefined\\` counts as absent — use \\`null\\`.)`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — materialisation\n// ---------------------------------------------------------------------------\n\n/**\n * Replace every handle in the callback's return value with what the server\n * actually produced.\n *\n * Walks arrays and PLAIN objects only. Class instances (a Date, a Zod schema, a\n * domain object) are returned untouched — recursing into them would rebuild them\n * as bare objects, and nothing inside one can be a handle that this SDK created.\n */\nexport function materializeResult(value: unknown, results: TxPlanOpResult[]): unknown {\n const ref = refDescriptor(value);\n if (ref) {\n const row = rowOf(results, ref.op, `\\`${ref.field}\\``);\n if (!(ref.field in row)) {\n throw new TxPlanError(\n `the transaction's operation ${ref.op} returned no column \\`${ref.field}\\`.`,\n );\n }\n return row[ref.field];\n }\n\n const rowOp = rowOpIndex(value);\n if (rowOp !== null) return rowOf(results, rowOp, \"a row\");\n\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n \"an operation result cannot be returned from a transaction callback: its \" +\n \"row count is not known until the plan runs. Declare an expectation \" +\n \"(`.expectOne(err)`) and return the row, or a column of it.\",\n );\n }\n\n if (Array.isArray(value)) return value.map((item) => materializeResult(item, results));\n\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) out[key] = materializeResult(item, results);\n return out;\n }\n\n return value;\n}\n\nfunction rowOf(results: TxPlanOpResult[], opIndex: number, what: string): Record<string, unknown> {\n const result = results[opIndex];\n if (!result) {\n throw new TxPlanError(\n `the transaction returned no result for operation ${opIndex}, so ${what} ` +\n `cannot be read.`,\n );\n }\n const row = result.rows[0];\n if (!row) {\n // Unreachable through the public API: a handle only exists behind an\n // `expectOne`, and the server rolls back rather than answering 200 with a\n // guard unmet. Loud, because the alternative is `undefined` in tenant data.\n throw new TxPlanError(\n `the transaction's operation ${opIndex} returned no row, so ${what} cannot ` +\n `be read.`,\n );\n }\n return row;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the driver\n// ---------------------------------------------------------------------------\n\n/** What {@link runTxPlan} needs from the runtime: one call, one transaction. */\nexport interface TxPlanTransport {\n txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;\n}\n\n/**\n * Build the plan, send it, and resolve the callback's return value.\n *\n * A callback that throws never reaches the network: there is nothing to roll\n * back because nothing was sent. A callback that describes no writes also skips\n * the round trip entirely.\n *\n * The RETURN type is `unknown` here on purpose. `Materialized<T>` is a compile-\n * time rewrite of the callback's return type, and it belongs on the public\n * `transaction()` signatures where `T` is inferred from the author's callback;\n * threading it through this driver as well would mean inferring `T` twice, from\n * two different positions, and reconciling them. The public wrappers narrow\n * once, at the seam where the value types were erased anyway.\n */\nexport async function runTxPlan<TTables>(\n transport: TxPlanTransport,\n tables: TTables,\n builder: TxPlanBuilder,\n fn: (tx: TxPlanHandle<TTables>) => unknown,\n): Promise<unknown> {\n const returned = fn({ tables });\n const body = builder.body();\n if (body.ops.length === 0) {\n return materializeResult(returned, []);\n }\n\n let response: TxPlanResponse;\n try {\n response = await transport.txPlan(body);\n } catch (err) {\n throw translateRejection(err, builder);\n }\n return materializeResult(returned, response.results);\n}\n\n/**\n * Turn the broker's rejection back into the tenant's own error.\n *\n * The server never sees the `Error` an expectation was given — only its slot\n * index — so this is the only place the intended error can be produced. A\n * rejection this SDK does not recognise passes through untouched: inventing an\n * error for it would hide the real failure.\n */\nfunction translateRejection(err: unknown, builder: TxPlanBuilder): unknown {\n if (typeof err !== \"object\" || err === null) return err;\n const rejection = err as TxPlanRejection;\n if (rejection.error_code !== \"tx_guard_failed\" || typeof rejection.slot !== \"number\") {\n return err;\n }\n return builder.errorForSlot(rejection.slot) ?? err;\n}\n","/**\n * The brand that identifies an HttpError ACROSS SDK instances.\n *\n * A process legitimately holds more than one copy of this SDK — the runtime\n * loads the engine from its own node_modules while the tenant's bundle carries\n * an inlined copy, which is why the controller registry and the error registry\n * are both anchored on `Symbol.for`. The one place that did not follow the\n * pattern was the engine's catch: `err instanceof HttpError` compares CLASS\n * IDENTITY, so a `throw new NotFound()` from the bundle's copy did not match\n * the engine's copy and every typed error in every deployed backend degraded to\n * `500 internal_error`. Measured through the edge on a real deploy: a route\n * throwing `NotFound` answered 500 while the runtime's own log printed the\n * error object with `status: 404` right beside it.\n *\n * `Symbol.for` puts this in the cross-realm registry, so every copy of the SDK\n * agrees on it by VALUE rather than by identity.\n */\nexport const HTTP_ERROR_BRAND: unique symbol = Symbol.for(\"palbase.backend.httpError\");\n\n/**\n * Set on an `HttpError` the ENGINE built out of a driver failure, as opposed to\n * one the author constructed to ANSWER a request.\n *\n * The distinction cannot be read off the status, and 409 is why. The scaffold\n * teaches `throw new Conflict(\"title already taken\")` as the way to answer\n * (template/AGENTS.md), and the engine raises `UniqueViolation` — also a 409 —\n * when a write hits a unique index. Logging by status therefore either loses the\n * engine's event or writes an \"unhandled\" line every time an author takes the\n * documented path. Measured: it did the second.\n *\n * `Symbol.for` so the mark survives the bundle/runtime SDK split, the same way\n * {@link HTTP_ERROR_BRAND} does.\n */\nexport const ENGINE_RAISED: unique symbol = Symbol.for(\"palbase.backend.engineRaised\") as never;\n\n/** Mark `e` as engine-raised and return it, so a conversion site reads as one expression. */\nexport function markEngineRaised<E extends object>(e: E): E {\n (e as Record<symbol, unknown>)[ENGINE_RAISED] = true;\n return e;\n}\n\n/** Whether the engine built this error, rather than the author throwing it to answer. */\nexport function isEngineRaised(e: unknown): boolean {\n return typeof e === \"object\" && e !== null && (e as Record<symbol, unknown>)[ENGINE_RAISED] === true;\n}\n\n/**\n * Whether a thrown value is an HttpError from ANY copy of this SDK.\n *\n * The shape is checked as well as the brand: the brand says \"this claims to be\n * one of ours\", the fields say the envelope can actually be built from it, and\n * a half-formed object must fall through to the 500 path rather than produce a\n * malformed response.\n */\nexport function isHttpError(err: unknown): err is HttpError {\n if (typeof err !== \"object\" || err === null) return false;\n const e = err as Record<PropertyKey, unknown>;\n return (\n e[HTTP_ERROR_BRAND] === true &&\n typeof e.status === \"number\" &&\n typeof e.error === \"string\" &&\n typeof e.errorDescription === \"string\"\n );\n}\n\n/** HTTP error with structured error response format.\n *\n * The base class for the throwable error classes (`PalError`, `Conflict`,\n * `NotFound`, …). Construct one directly with `throw new HttpError(404,\n * \"todo_not_found\", \"No such todo\")`, or throw a named subclass\n * (`throw new NotFound(\"todo not found\")`). The runtime catches any `HttpError`\n * and emits the standard envelope; on the wire (and to iOS) it surfaces as\n * `BackendError.server(code, status, message, requestId)`.\n *\n * The optional `data` field carries a structured payload alongside the\n * standard envelope — for errors that need to ship extra context\n * (e.g. `new Conflict(\"locked\", \"title_locked\", { retryAfter: 30 })`). It rides\n * through to the iOS typed enum's associated value.\n */\nexport class HttpError extends Error {\n public readonly status: number;\n public readonly error: string;\n public readonly errorDescription: string;\n public readonly data?: unknown;\n /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */\n public readonly [HTTP_ERROR_BRAND] = true;\n\n constructor(status: number, error: string, errorDescription: string, data?: unknown) {\n super(errorDescription);\n this.name = \"HttpError\";\n this.status = status;\n this.error = error;\n this.errorDescription = errorDescription;\n if (data !== undefined) {\n this.data = data;\n }\n }\n\n /**\n * Serialize to the standard Palbase error response format.\n * The `requestId` is injected by the runtime layer from the request context.\n * When called without arguments (e.g. JSON.stringify), request_id is omitted.\n * When `data` is set, it is appended as a strict-superset field.\n */\n toJSON(requestId?: string): {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } {\n const result: {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } = {\n error: this.error,\n error_description: this.errorDescription,\n status: this.status,\n };\n if (requestId) {\n result.request_id = requestId;\n }\n if (this.data !== undefined) {\n result.data = this.data;\n }\n return result;\n }\n}\n\n/**\n * Throw with a custom HTTP status + wire code. The general-purpose escape hatch\n * when none of the named classes (`Conflict`/`NotFound`/…) fits.\n *\n * @example\n * throw new PalError(418, \"teapot\", \"I'm a teapot\");\n */\nexport class PalError extends HttpError {\n constructor(status: number, code: string, description: string, data?: unknown) {\n super(status, code, description, data);\n this.name = \"PalError\";\n }\n}\n\n/** Base for the named status classes. Each subclass fixes its HTTP status; the\n * `code` defaults to the class's canonical wire code (overridable), and the\n * `message` defaults to a human-readable label (overridable). */\nabstract class NamedHttpError extends HttpError {\n protected constructor(\n status: number,\n defaultCode: string,\n name: string,\n message?: string,\n code?: string,\n data?: unknown,\n ) {\n super(status, code ?? defaultCode, message ?? defaultMessage(name), data);\n this.name = name;\n }\n}\n\n/** Derive a default human-readable message from a class name\n * (\"NotFound\" → \"Not found\", \"TooManyRequests\" → \"Too many requests\"). */\nfunction defaultMessage(name: string): string {\n const spaced = name.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\");\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\n/**\n * 400 — the request was malformed or failed validation. Carries a fixed typed\n * payload: `new BadRequest({ fields: [{ field: \"email\", message: \"invalid\" }] })`.\n * The shape is declared once in the SDK so codegen surfaces `error.data.fields`\n * typed on the client.\n */\nexport class BadRequest extends NamedHttpError {\n public declare readonly data: BadRequestData;\n constructor(data: BadRequestData, message?: string) {\n super(400, \"bad_request\", \"BadRequest\", message, undefined, data);\n }\n}\n\n/** 401 — the caller is not authenticated. */\nexport class Unauthorized extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(401, \"unauthorized\", \"Unauthorized\", message, code, data);\n }\n}\n\n/** 403 — the caller is authenticated but not allowed. */\nexport class Forbidden extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(403, \"forbidden\", \"Forbidden\", message, code, data);\n }\n}\n\n/** 404 — the requested resource does not exist. */\nexport class NotFound extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(404, \"not_found\", \"NotFound\", message, code, data);\n }\n}\n\n/** 409 — the request conflicts with the current state. */\nexport class Conflict extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(409, \"conflict\", \"Conflict\", message, code, data);\n }\n}\n\n/**\n * 409 — a write was refused because it would duplicate an existing row.\n * Carries the NAME of the unique constraint Postgres named (`users_email_key`).\n *\n * The engine produces it: a statement rejected with SQLSTATE `23505` is\n * converted here rather than surfacing as an opaque driver error (see\n * `engine/db.ts`, `diagnosingDriver`). What that removes is the string match —\n * before this, the only way to act on a duplicate was to test the driver\n * message for \"duplicate key value violates unique constraint\", a contract\n * nobody signed that breaks on a Postgres upgrade, a locale, or a constraint\n * rename, silently and in production.\n *\n * THE NAME IS A FIELD AND STAYS OUT OF THE DEFAULT MESSAGE. The two are not\n * the same audience. `constraint` is read by the code that catches this — the\n * developer, who already knows the schema. `errorDescription` is the HTTP\n * response body, and an UNCAUGHT duplicate puts it in front of the\n * application's end user: `users_email_key` there discloses how the schema is\n * built to whoever sent the request. The platform's own data API took the same\n * decision one surface over and wrote down why —\n * `v2/internal/modules/database/internal/handler/pgerror.go:83-87` collapses\n * every 23xxx to a generic conflict, \"never disclose the constraint/column\n * name\". A thrower who WANTS the name on the wire passes it deliberately\n * (`new UniqueViolation(c, \\`\\${c} already exists\\`)`, or through `data`).\n *\n * @example\n * try {\n * await Database.tables.users.insert({ email });\n * } catch (e) {\n * if (UniqueViolation.is(e) && e.constraint === \"users_email_key\") {\n * throw new Conflict(\"That email is taken\", \"email_taken\");\n * }\n * throw e;\n * }\n */\nexport class UniqueViolation extends Conflict {\n /**\n * Whether `e` is a unique violation — REGARDLESS of which copy of this SDK\n * constructed it.\n *\n * Use this instead of `instanceof`. Measured on a live stack: a controller\n * bundle INLINES its own copy of `@palbase/backend`, and the engine that\n * raises this error is the runtime's copy. Two copies, two class identities,\n * and `e instanceof UniqueViolation` is false in the one place a caller\n * writes it — a check that reads as correct and silently never matches.\n */\n static is(e: unknown): e is UniqueViolation {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as { name?: unknown }).name === \"UniqueViolation\" &&\n typeof (e as { constraint?: unknown }).constraint === \"string\"\n );\n }\n\n /** The unique constraint the statement violated, as Postgres named it.\n * `\"\"` when the driver did not say which — see `engine/db.ts`. */\n public readonly constraint: string;\n\n constructor(constraint: string, message?: string, code?: string, data?: unknown) {\n super(message ?? \"Unique constraint violated\", code ?? \"unique_violation\", data);\n this.name = \"UniqueViolation\";\n this.constraint = constraint;\n }\n}\n\n/** A single field-level validation failure carried by {@link BadRequest}. */\nexport interface FieldError {\n /** The offending field's name (dotted path for nested fields). */\n field: string;\n /** Human-readable reason the field failed. */\n message: string;\n}\n\n/** The fixed, typed payload {@link BadRequest} ships. */\nexport interface BadRequestData {\n /** The fields that failed validation. */\n fields: FieldError[];\n}\n\n/** The fixed, typed payload {@link TooManyRequests} ships. */\nexport interface TooManyRequestsData {\n /** Seconds the caller should wait before retrying. */\n retryAfter: number;\n}\n\n/**\n * 429 — the caller has exceeded the rate limit. Carries a fixed typed payload:\n * `new TooManyRequests({ retryAfter: 30 })`. The shape is declared once in the\n * SDK (error-registry pre-seed) so codegen surfaces `error.data.retryAfter`\n * typed on the client — no per-project definition needed.\n */\nexport class TooManyRequests extends NamedHttpError {\n public declare readonly data: TooManyRequestsData;\n constructor(data: TooManyRequestsData, message?: string) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, undefined, data);\n }\n}\n","/**\n * engine/config.ts — settings from the environment, and the gate that refuses\n * to boot without them.\n *\n * A mandatory module that is not configured must stop the process, by name.\n * The failure this prevents is the expensive one: a stack that boots, passes\n * its probes, and answers 500 on first contact — where the missing value is\n * discovered by a customer rather than by the operator who could fix it.\n *\n * Database and Auth are mandatory. That is a product decision (2026-08-14), not\n * a technical necessity: a backend whose data layer or whose notion of \"who is\n * calling\" is undefined has nothing safe to do with a request.\n */\n\n/** Everything the engine needs to serve. Built once, at boot, never re-read. */\nexport interface EngineConfig {\n /** Postgres connection string. MANDATORY. */\n databaseUrl: string;\n /** Where this stack publishes its token signing keys. MANDATORY. */\n authJwksUrl: string;\n /** When set, a token whose `iss` differs is rejected. */\n authIssuer?: string;\n /** Base URL of the module surface (`/v1/*`, `/auth/*`). Empty ⇒ module\n * singletons throw a named error on first use rather than silently no-op. */\n moduleBaseUrl: string;\n /**\n * The address CLIENTS reach this stack at — `https://<ref>.palbase.studio` in\n * the cloud, whatever domain the certificate is for when self-hosted.\n *\n * NOT `moduleBaseUrl`, and the distinction is the whole point: that one is\n * this process's internal route to palsvc (`http://127.0.0.1:8080`), which\n * resolves nowhere outside the pod. A public object URL has to survive\n * leaving the response body, so it cannot be built from the internal one.\n *\n * Only the operator knows this value, so only the operator sets it\n * (`PALBASE_PUBLIC_ORIGIN`). Empty ⇒ `Storage…getPublicUrl()` throws a named\n * error, the same way an unconfigured module does.\n */\n publicOrigin: string;\n /** Shared secret storage signs its internal upload calls with. Empty means\n * uploads are not wired, and those calls are refused. */\n uploadSecret: string;\n /** Publishable key, sent as `apikey` on module calls. */\n anonKey: string;\n /** Secret key. Used for privileged module calls. */\n serviceRoleKey: string;\n /** HMAC the realtime broadcast token is signed with. Empty ⇒ broadcast\n * returns a clear `realtime_unconfigured` error instead of failing silently. */\n realtimeSecret: string;\n port: number;\n /** The Postgres role each request is bound to. RLS policies are written\n * against it, so changing it changes who the database thinks is asking. */\n dbRole: string;\n /**\n * The Postgres role `Database.asService()` is bound to. It is the one that\n * carries BYPASSRLS, which is the whole of what \"as service\" means — a name\n * pointing at a role without it does not fail, it returns fewer rows.\n *\n * Configurable for the same reason `dbRole` is, and beside it on purpose: a\n * stack that renames one of the pair must rename both, or the request and its\n * service sibling stop being two identities of the same installation.\n */\n dbServiceRole: string;\n poolMax: number;\n}\n\n/** Thrown when a mandatory module is unconfigured. Carries the missing names. */\nexport class BootRefused extends Error {\n readonly missing: readonly string[];\n constructor(missing: readonly string[], message: string) {\n super(message);\n this.name = \"BootRefused\";\n this.missing = missing;\n }\n}\n\nconst MANDATORY: ReadonlyArray<{ key: string; what: string }> = [\n { key: \"DATABASE_URL\", what: \"the stack's Postgres (Database module)\" },\n { key: \"AUTH_JWKS_URL\", what: \"where this stack publishes its token signing keys (Auth module)\" },\n];\n\n/**\n * Read the engine's settings, or refuse.\n *\n * @throws {BootRefused} naming every missing mandatory value at once — one\n * restart per missing variable is a bad way to learn what a stack needs.\n */\nexport function loadConfig(env: Record<string, string | undefined>): EngineConfig {\n const missing = MANDATORY.filter((m) => !env[m.key]?.trim()).map((m) => m.key);\n if (missing.length > 0) {\n const detail = MANDATORY.filter((m) => missing.includes(m.key))\n .map((m) => ` ${m.key.padEnd(16)}${m.what}`)\n .join(\"\\n\");\n throw new BootRefused(\n missing,\n `boot refused: mandatory module not configured — missing ${missing.join(\", \")}.\\n${detail}`,\n );\n }\n\n const port = Number(env.PORT ?? 3000);\n if (!Number.isInteger(port) || port < 0 || port > 65535) {\n throw new BootRefused([], `boot refused: PORT is not a valid port number (got ${env.PORT}).`);\n }\n const poolMax = Number(env.DB_POOL_MAX ?? 10);\n if (!Number.isInteger(poolMax) || poolMax < 1) {\n throw new BootRefused([], `boot refused: DB_POOL_MAX must be a positive integer (got ${env.DB_POOL_MAX}).`);\n }\n\n return {\n databaseUrl: env.DATABASE_URL!.trim(),\n authJwksUrl: env.AUTH_JWKS_URL!.trim(),\n authIssuer: env.AUTH_ISSUER?.trim() || undefined,\n moduleBaseUrl: (env.MODULE_BASE_URL ?? \"\").replace(/\\/+$/, \"\"),\n publicOrigin: (env.PALBASE_PUBLIC_ORIGIN ?? \"\").trim().replace(/\\/+$/, \"\"),\n // The secret storage signs its two internal calls with (authorize, and the\n // completion that runs an @Upload handler). Empty means uploads are not\n // wired, and both calls REFUSE — an unsigned completion would let anyone\n // who knows a route path invent an upload that never happened.\n uploadSecret: env.PALBASE_UPLOAD_SECRET ?? \"\",\n anonKey: env.PALBASE_ANON_KEY ?? \"\",\n serviceRoleKey: env.PALBASE_SERVICE_ROLE_KEY ?? \"\",\n realtimeSecret: env.REALTIME_INGESTION_SECRET ?? \"\",\n port,\n dbRole: env.DB_ROLE ?? \"backend_authenticated\",\n // Verified against the stack that provisions them, not from memory: the six\n // roles and their attributes are declared in v2/internal/migrate/provision.go\n // (`roleBackendServiceRole = \"backend_service_role\"`, NOLOGIN BYPASSRLS),\n // and the live database agrees (pg_roles.rolbypassrls = true).\n dbServiceRole: env.DB_SERVICE_ROLE ?? \"backend_service_role\",\n poolMax,\n };\n}\n","/**\n * engine/auth.ts — verifying the stack's own access tokens.\n *\n * The engine does this itself rather than trusting a header stamped upstream.\n * In the isolate architecture a gateway verified the token and the runtime read\n * the result; a backend that boots on its own has no such upstream, so the\n * verification lives here — against the keys the stack publishes.\n *\n * Deliberately narrow: ES256 over P-256, which is what palauth mints. An\n * unrecognised `alg` is refused rather than accommodated, because the classic\n * JWT break is a verifier that is helpful about algorithms.\n */\n\n/** A JSON Web Key, narrowed to the EC keys this verifier accepts. */\ninterface EcJwk {\n kid: string;\n kty: string;\n crv: string;\n x: string;\n y: string;\n}\n\n/** The claims the engine reads. Everything else rides along untyped. */\nexport interface VerifiedClaims extends Record<string, unknown> {\n sub?: string;\n role?: string;\n email?: string;\n email_verified?: boolean;\n exp?: number;\n iss?: string;\n}\n\nfunction b64urlToBytes(s: string): Uint8Array<ArrayBuffer> {\n const pad = s.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const full = pad.padEnd(Math.ceil(pad.length / 4) * 4, \"=\");\n const bin = atob(full);\n // Backed by a plain ArrayBuffer so the result satisfies BufferSource — a\n // Uint8Array over ArrayBufferLike could be shared memory, which the WebCrypto\n // signatures reject.\n const out = new Uint8Array(new ArrayBuffer(bin.length));\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\nexport interface AuthVerifierOptions {\n jwksUrl: string;\n issuer?: string;\n /** Injectable for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** How long a fetched keyset is trusted before it is fetched again. A key\n * rotation must become visible without a restart, and an unknown `kid` must\n * not be able to force a fetch per request (that is a free DoS lever). */\n keysetTtlMs?: number;\n}\n\nexport class AuthVerifier {\n private keys = new Map<string, CryptoKey>();\n private fetchedAt = 0;\n private inflight: Promise<void> | null = null;\n private readonly jwksUrl: string;\n private readonly issuer?: string;\n private readonly fetchImpl: typeof fetch;\n private readonly ttl: number;\n\n constructor(opts: AuthVerifierOptions) {\n this.jwksUrl = opts.jwksUrl;\n this.issuer = opts.issuer;\n this.fetchImpl = opts.fetchImpl ?? ((...a: Parameters<typeof fetch>) => fetch(...a));\n this.ttl = opts.keysetTtlMs ?? 5 * 60_000;\n }\n\n /** Fetch the keyset at most once per TTL, and at most once concurrently. */\n private async refresh(): Promise<void> {\n if (this.inflight) return this.inflight;\n this.inflight = (async () => {\n try {\n const res = await this.fetchImpl(this.jwksUrl);\n if (!res.ok) return;\n const body = (await res.json()) as { keys?: EcJwk[] };\n const next = new Map<string, CryptoKey>();\n for (const jwk of body.keys ?? []) {\n if (jwk.kty !== \"EC\" || jwk.crv !== \"P-256\") continue;\n try {\n next.set(\n jwk.kid,\n await crypto.subtle.importKey(\n \"jwk\",\n { kty: \"EC\", crv: jwk.crv, x: jwk.x, y: jwk.y, ext: true },\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"verify\"],\n ),\n );\n } catch {\n // A single malformed key must not blind the verifier to the rest.\n }\n }\n if (next.size > 0) {\n this.keys = next;\n this.fetchedAt = Date.now();\n }\n } finally {\n this.inflight = null;\n }\n })();\n return this.inflight;\n }\n\n private async key(kid: string): Promise<CryptoKey | null> {\n const stale = Date.now() - this.fetchedAt > this.ttl;\n if (!this.keys.has(kid) || stale) await this.refresh();\n return this.keys.get(kid) ?? null;\n }\n\n /**\n * Verify an `Authorization` header value.\n *\n * @returns the verified claims, or `null` for absent / malformed / expired /\n * wrong-issuer / bad-signature. One `null` for every failure on purpose:\n * the caller answers 401 either way, and a detailed reason is an oracle.\n */\n async verify(authorization: string | null | undefined): Promise<VerifiedClaims | null> {\n if (!authorization || !authorization.startsWith(\"Bearer \")) return null;\n const parts = authorization.slice(7).trim().split(\".\");\n if (parts.length !== 3) return null;\n const h = parts[0];\n const p = parts[1];\n const sig = parts[2];\n if (h === undefined || p === undefined || sig === undefined) return null;\n\n let header: { alg?: string; kid?: string };\n let claims: VerifiedClaims;\n try {\n header = JSON.parse(new TextDecoder().decode(b64urlToBytes(h)));\n claims = JSON.parse(new TextDecoder().decode(b64urlToBytes(p)));\n } catch {\n return null;\n }\n // `none`, `HS256`-with-the-public-key, and friends all die here.\n if (header.alg !== \"ES256\" || !header.kid) return null;\n\n const key = await this.key(header.kid);\n if (!key) return null;\n\n let ok = false;\n try {\n ok = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n key,\n b64urlToBytes(sig),\n new TextEncoder().encode(`${h}.${p}`),\n );\n } catch {\n return null;\n }\n if (!ok) return null;\n if (typeof claims.exp === \"number\" && claims.exp * 1000 <= Date.now()) return null;\n if (this.issuer && claims.iss !== this.issuer) return null;\n return claims;\n }\n}\n\n/** What a route demands, after the route's own spec and the controller's\n * default have been reconciled. */\nexport interface EffectiveAuth {\n required: boolean;\n role?: string;\n verifiedEmail: boolean;\n}\n\n/**\n * Reconcile route-level and controller-level auth.\n *\n * The route's own spec wins when it says anything at all; otherwise the\n * controller's default applies; when NEITHER speaks, the answer is `required`.\n * That last clause is the whole point — a route that forgot to declare must be\n * closed, not open. (Measured: an engine that only read the route level served\n * a controller marked `auth: false` as 401, and would have served the reverse\n * mistake as an open endpoint.)\n */\nexport function effectiveAuth(routeAuth: unknown, controllerAuth: unknown): EffectiveAuth {\n const spec = routeAuth !== undefined ? routeAuth : controllerAuth;\n if (spec === false) return { required: false, verifiedEmail: false };\n if (spec === true || spec === undefined || spec === null) return { required: true, verifiedEmail: false };\n if (typeof spec !== \"object\") return { required: true, verifiedEmail: false };\n\n const o = spec as { required?: unknown; role?: unknown; verifiedEmail?: unknown };\n const role = typeof o.role === \"string\" && o.role.trim() !== \"\" ? o.role.trim() : undefined;\n return {\n required: o.required !== false,\n role,\n verifiedEmail: o.verifiedEmail === true,\n };\n}\n","/**\n * engine/ratelimit.ts — the customer's own per-route limit, enforced here.\n *\n * This is the PRODUCT feature (`@Get(\"/x\", { rateLimit: { max, window } })`),\n * not a quota the platform imposes. It runs in this process, on this pod,\n * because the route table lives here: the edge proxies by path and has never\n * seen a route's options, so teaching it would mean shipping the table twice\n * and keeping the copies in step.\n *\n * Fixed window, in memory. A single-tenant backend is the whole stack rather\n * than a shard of it, so \"in process\" is not an approximation. A restart\n * forgets the window, which for an endpoint guard fails in the right\n * direction: it forgives, it never invents a refusal.\n */\n\nexport interface RateLimitRule {\n max: number;\n /** Seconds. */\n window: number;\n}\n\ninterface Bucket {\n count: number;\n resetAt: number;\n}\n\nexport class RateLimiter {\n private buckets = new Map<string, Bucket>();\n /** Bound on distinct keys held, so an attacker cycling identities cannot\n * grow this map without limit. On overflow the oldest windows are dropped —\n * forgiving, consistent with the restart behaviour above. */\n constructor(private readonly maxKeys = 100_000) {}\n\n /**\n * Identify the caller: the signed-in user when the route resolved one,\n * otherwise the address the edge forwarded. Callers the edge did not\n * identify share one bucket — deliberately conservative, since the\n * alternative is a limit anyone resets by omitting a header.\n */\n static key(routeId: string, userId: string | undefined, headers: Headers): string {\n if (userId) return `${routeId}\\x00u:${userId}`;\n const fwd = headers.get(\"x-forwarded-for\");\n const addr = (fwd ? (fwd.split(\",\")[0] ?? \"\") : (headers.get(\"x-real-ip\") ?? \"\")).trim();\n return `${routeId}\\x00a:${addr || \"anonymous\"}`;\n }\n\n /**\n * @returns `null` when the request may proceed, or the number of seconds to\n * wait (never 0 — a caller told to wait 0 comes straight back to the same\n * refusal).\n */\n check(rule: RateLimitRule | undefined, key: string, now: number): number | null {\n if (!rule || !(rule.max > 0) || !(rule.window > 0)) return null;\n\n const bucket = this.buckets.get(key);\n if (!bucket || now >= bucket.resetAt) {\n if (this.buckets.size >= this.maxKeys) this.evict(now);\n this.buckets.set(key, { count: 1, resetAt: now + rule.window * 1000 });\n return null;\n }\n if (bucket.count < rule.max) {\n bucket.count++;\n return null;\n }\n return Math.max(1, Math.ceil((bucket.resetAt - now) / 1000));\n }\n\n /** Drop expired windows; if none are expired, drop the earliest-resetting\n * quarter so the map cannot wedge at the ceiling. */\n private evict(now: number): void {\n let dropped = 0;\n for (const [k, b] of this.buckets) {\n if (now >= b.resetAt) {\n this.buckets.delete(k);\n dropped++;\n }\n }\n if (dropped > 0) return;\n const byReset = [...this.buckets.entries()].sort((a, b) => a[1].resetAt - b[1].resetAt);\n for (let i = 0; i < Math.ceil(byReset.length / 4); i++) {\n const victim = byReset[i];\n if (victim) this.buckets.delete(victim[0]);\n }\n }\n\n /** Test seam. */\n get size(): number {\n return this.buckets.size;\n }\n}\n","/**\n * engine/cache.ts — the cache, in this process's own memory.\n *\n * A stack that serves one tenant has nobody to share a cache with; palsvc drew\n * exactly this conclusion for itself when it dropped Redis, and a backend that\n * reaches over a network for a hash map is paying a round trip for nothing.\n *\n * JSON-typed, matching `CacheClient`: values round-trip as whatever was stored.\n */\nimport type { CacheClient } from \"../endpoint.js\";\n\ninterface Entry {\n value: unknown;\n /** Epoch ms, or 0 for \"no expiry\". */\n expiresAt: number;\n}\n\nexport interface MemoryCacheOptions {\n /** Bound on entries held. On overflow the soonest-to-expire are dropped. */\n maxEntries?: number;\n /** Injectable clock, for tests. */\n now?: () => number;\n}\n\n/**\n * Build an in-process cache.\n *\n * `getOrSet` is single-flight: concurrent misses on one key share one fill, so\n * a cold key under load does not become N identical expensive calls.\n */\nexport function makeMemoryCache(opts: MemoryCacheOptions = {}): CacheClient {\n const maxEntries = opts.maxEntries ?? 50_000;\n const now = opts.now ?? (() => Date.now());\n const store = new Map<string, Entry>();\n const inflight = new Map<string, Promise<unknown>>();\n\n const live = (key: string): Entry | undefined => {\n const e = store.get(key);\n if (!e) return undefined;\n if (e.expiresAt !== 0 && e.expiresAt <= now()) {\n store.delete(key);\n return undefined;\n }\n return e;\n };\n\n const evict = () => {\n const t = now();\n let dropped = 0;\n for (const [k, e] of store) {\n if (e.expiresAt !== 0 && e.expiresAt <= t) {\n store.delete(k);\n dropped++;\n }\n }\n if (dropped > 0) return;\n // Nothing expired: drop the soonest-to-expire quarter (entries with no\n // expiry sort last, so an unbounded writer sheds its own oldest first).\n const order = [...store.entries()].sort(\n (a, b) => (a[1].expiresAt || Infinity) - (b[1].expiresAt || Infinity),\n );\n for (let i = 0; i < Math.ceil(order.length / 4); i++) {\n const victim = order[i];\n if (victim) store.delete(victim[0]);\n }\n };\n\n const set = async (key: string, value: unknown, ttl?: number): Promise<void> => {\n if (store.size >= maxEntries && !store.has(key)) evict();\n store.set(key, { value, expiresAt: ttl && ttl > 0 ? now() + ttl * 1000 : 0 });\n };\n\n return {\n async get<T = unknown>(key: string): Promise<T | null> {\n const e = live(key);\n return e ? (e.value as T) : null;\n },\n set,\n async del(key: string): Promise<void> {\n store.delete(key);\n },\n async incr(key: string): Promise<number> {\n const e = live(key);\n const next = (typeof e?.value === \"number\" ? e.value : 0) + 1;\n store.set(key, { value: next, expiresAt: e?.expiresAt ?? 0 });\n return next;\n },\n async getOrSet<T>(key: string, ttl: number, fn: () => Promise<T> | T): Promise<T> {\n const hit = live(key);\n if (hit) return hit.value as T;\n\n const running = inflight.get(key);\n if (running) return running as Promise<T>;\n\n const fill = (async () => {\n try {\n const value = await fn();\n await set(key, value, ttl);\n return value;\n } finally {\n inflight.delete(key);\n }\n })();\n inflight.set(key, fill);\n return fill as Promise<T>;\n },\n };\n}\n","/**\n * The refusals a Database call gets BEFORE any SQL exists — written once, so the\n * engine and the test double cannot disagree about them.\n *\n * WHY THIS FILE EXISTS. `fakeDatabase()` is a second implementation of the same\n * surface (`__tests__/helpers/mock-db.ts`), and it never touched `compileWhere`\n * or `asBindParams`. Measured against the published 24.1.0: all four of the\n * calls that release had just started refusing went through the fake SILENTLY —\n * `update{title:undefined}`, `insert{title:undefined}`, `findMany{done:{}}`,\n * `deleteMany{owner,created_at:{}}`.\n *\n * The scaffold tells authors to test the service layer against exactly that\n * fake. So a test went green on a call production would throw on, and the\n * author found out in production instead — the same \"the surface does not match\n * the engine\" shape these refusals exist to end, arriving through the door the\n * SDK hands people for testing.\n *\n * These are pure and SQL-free on purpose: an in-memory store can run them as\n * easily as the driver path can.\n */\n\n/** The comparison operators a filter value may carry. Kept here because the\n * guard has to tell an operator object from a plain value. */\nconst KNOWN_OPS = new Set([\"gt\", \"gte\", \"lt\", \"lte\", \"neq\", \"eq\", \"in\"]);\n\n/**\n * Refuse a filter that would compile to something other than what it reads like.\n *\n * Three shapes, each measured in production before it was closed:\n *\n * `{ col: undefined }` binds NULL; `= NULL` matches no row, so the query\n * answered \"no records\" and said nothing.\n * `{ col: {} }` produces no term at all — every row on the read\n * path, a dropped condition on the write path.\n * `{ col: { gte: undefined } }` and an `undefined` inside `in`: the same NULL,\n * one level down.\n */\nexport function assertUsableFilter(\n caller: string,\n table: string,\n where: Record<string, unknown> | undefined,\n): void {\n if (!where) return;\n for (const [col, cond] of Object.entries(where)) {\n if (cond === undefined) {\n throw new Error(\n `${caller}(${table}): where.${col} değeri undefined — bu bir filtre değeri değil. ` +\n `Bağlanınca NULL olur ve '= NULL' hiçbir satıra uymaz, yani sorgu sessizce ` +\n `boş sonuç dönerdi. Değer yoksa anahtarı filtreye hiç koymayın.`,\n );\n }\n if (cond === null || typeof cond !== \"object\" || Array.isArray(cond)) continue;\n\n const entries = Object.entries(cond as Record<string, unknown>);\n if (entries.length === 0) {\n throw new Error(\n `${caller}(${table}): where.${col} boş bir operatör nesnesi ({}) — hiçbir koşul ` +\n `üretmez, yani bu alan filtreden sessizce DÜŞERDİ. Koşul kurulmayacaksa ` +\n `anahtarı filtreye hiç koymayın (D-21).`,\n );\n }\n for (const [op, v] of entries) {\n if (op === \"in\") {\n if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmalı`);\n if (v.some((x) => x === undefined)) {\n throw new Error(\n `${caller}(${table}): where.${col}.in listesinde undefined var — sessizce NULL'a ` +\n `bağlanır ve o eleman hiçbir satırla eşleşmez. Listeyi kurarken eleyin.`,\n );\n }\n continue;\n }\n if (!KNOWN_OPS.has(op)) {\n throw new Error(\n `${caller}(${table}): where.${col} bilinmeyen operatör \"${op}\" (gt/gte/lt/lte/neq/in)`,\n );\n }\n if (v === undefined) {\n throw new Error(\n `${caller}(${table}): where.${col}.${op} değeri undefined — karşılaştırmanın ` +\n `sağ tarafı NULL olur ve sonuç hiçbir satıra uymaz. Koşulu kurmayın.`,\n );\n }\n }\n }\n}\n\n/**\n * Refuse a write whose value never arrived.\n *\n * `{ title: req.body.title }` with no `title` in the body bound NULL and\n * answered 200 — the column was ERASED. `null` is untouched, and the difference\n * is the whole point: null is an author SAYING \"empty this column\"; undefined is\n * nobody saying anything.\n */\nexport function assertUsableWriteValues(\n caller: string,\n table: string,\n cols: readonly string[],\n data: Record<string, unknown>,\n): void {\n for (const c of cols) {\n if (data[c] === undefined) {\n throw new Error(\n `${caller}(${table}): \"${c}\" değeri undefined — bu bir yazma değeri değil. ` +\n `Kolonu boşaltmak istiyorsan null yaz; kolonu değiştirmek istemiyorsan nesneye hiç koyma ` +\n `(bir eksik istek alanı sessizce NULL yazıyordu — FR-016).`,\n );\n }\n }\n}\n","/**\n * engine/db.ts — a real pooled connection, and the identity every request is\n * bound to inside it.\n *\n * # Why one transaction per request\n *\n * In the isolate architecture every `Database.*` call was its own HTTP hop to a\n * capability surface, so two writes in one handler could not be atomic — a\n * handler that wrote and then threw left the first write behind. Here the whole\n * request runs inside one transaction: it commits when the handler returns and\n * rolls back when it throws. Atomicity stops being something the author has to\n * ask for.\n *\n * # Why it opens lazily\n *\n * A handler that touches no table must cost no round trip. Opening eagerly cost\n * four (BEGIN + bind + … + COMMIT) on endpoints that never query — measured at\n * 1,243 rps against 31,579 for the same endpoint once the open became lazy.\n *\n * # How the caller's identity reaches RLS\n *\n * One statement, not three:\n *\n * select set_config('role',$1,true),\n * set_config('search_path','public',true),\n * set_config('request.jwt.claims',$2,true)\n *\n * `set_config(..., is_local => true)` is transaction-scoped exactly like\n * `SET LOCAL`, but takes BOUND PARAMETERS, which `SET LOCAL` cannot. So the\n * role and the caller's claims travel as parameters — user identity is never\n * spliced into SQL text — and `auth.uid()` resolves inside RLS policies, which\n * means the row filter is enforced by Postgres rather than by our code.\n */\nimport type { DBClient, DBOps } from \"../endpoint.js\";\n// A VALUE import, not a type: the engine constructs one (23505 → 409).\nimport { UniqueViolation, markEngineRaised,\n} from \"../errors.js\";\nimport { assertUsableFilter, assertUsableWriteValues } from \"../db/input-guards.js\";\nimport type {\n TxPlanBody,\n TxPlanOpResult,\n TxPlanResponse,\n TxWireExpr,\n TxWireOp,\n TxWireRef,\n TxWireValue,\n} from \"../db/tx-plan.js\";\n\n/** The slice of a SQL driver the engine uses. `Bun.sql` satisfies it. */\nexport interface SqlDriver {\n /** Run a parameterised statement. */\n unsafe(sql: string, params?: unknown[]): Promise<unknown>;\n /** Open a transaction; the driver commits when `cb` resolves and rolls back\n * when it rejects. */\n begin<T>(cb: (tx: SqlTx) => Promise<T>): Promise<T>;\n}\n\nexport interface SqlTx {\n unsafe(sql: string, params?: unknown[]): Promise<unknown>;\n savepoint<T>(cb: (sp: SqlTx) => Promise<T>): Promise<T>;\n}\n\ntype Row = Record<string, unknown>;\n\n/** Quote an identifier. Table and column names reach here from the schema and\n * from handler arguments; neither is allowed to become syntax. */\nexport function quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Quote a TABLE KEY, which is one identifier or two — never one that contains\n * a dot.\n *\n * A table travels under this system's one key convention: `public` bare,\n * anything else `schema.table` (the same rule `qualifiedTableKey` writes on the\n * Go side). Handing that key to `quoteIdent` produces `\"billing.invoices\"`,\n * which Postgres reads as a PUBLIC table whose NAME contains a dot — so every\n * call through `Database.schema(\"billing\").tables.*` named a table that does\n * not exist, or, worse, a different one that does.\n *\n * The public half stays BYTE-IDENTICAL to the single-schema world, because\n * every existing query and golden asserts the bare form.\n */\nexport function quoteTable(key: string): string {\n const dot = key.indexOf(\".\");\n if (dot === -1) return quoteIdent(key);\n return `${quoteIdent(key.slice(0, dot))}.${quoteIdent(key.slice(dot + 1))}`;\n}\n\n/**\n * Render a JavaScript array as a Postgres array literal, so `= ANY($n::uuid[])`\n * works from `Database.query`.\n *\n * WHY THIS EXISTS. `Bun.SQL`'s `unsafe(text, params)` does NOT bind a JS array as\n * a Postgres array — it applies `Array.prototype.toString()`. `[\"a\",\"b\"]` arrives\n * as the text `a,b`, with no braces, and `$1::uuid[]` fails with \"malformed array\n * literal\" (measured 2026-08-29 against pgvector/pg16 + bun 1.3.9). Every fan-in\n * query a tenant writes therefore had to hand-build the literal; one of them did,\n * and reported it. node-postgres converts arrays for exactly this reason.\n *\n * Bun's own escape hatch, `sql.array()`, cannot be used here: it is a tagged-\n * template FRAGMENT that renders inline `ARRAY[...]` TEXT, and nothing that\n * travels in the `params` array can carry it.\n *\n * There is deliberately NO vector branch, and there cannot be one: this sees raw\n * SQL, so which column a parameter is destined for is unknowable. The single\n * uniform encoding is what makes a vector parameter writable at all —\n * `$n::float8[]::vector` round-trips (measured), where today nothing does.\n */\nexport function encodePgArray(value: readonly unknown[]): string {\n const element = (x: unknown): string => {\n // Unquoted NULL is the only spelling Postgres reads as the null element;\n // `\"NULL\"` would be the four-character string.\n if (x === null || x === undefined) return \"NULL\";\n if (Array.isArray(x)) return encodePgArray(x);\n return `\"${String(x).replace(/([\"\\\\])/g, \"\\\\$1\")}\"`;\n };\n return `{${value.map(element).join(\",\")}}`;\n}\n\nconst BIND_SQL =\n \"select set_config('role',$1,true), set_config('search_path','public',true), set_config('request.jwt.claims',$2,true)\";\n\n/**\n * A transaction that does not exist until somebody reads or writes.\n *\n * `begin(cb)` is callback-scoped, so to hold one open across a whole request\n * the callback parks on a promise this object controls: `commit()` resolves it\n * (the driver commits), `rollback()` rejects it (the driver rolls back). A\n * request that never touches the database never enters the callback at all.\n */\nexport function createLazyTransaction(\n sql: SqlDriver,\n role: string,\n claimsJson: string,\n options: { lockTimeout?: string } = {},\n) {\n const { lockTimeout } = options;\n // `lock_timeout` travels as a BOUND parameter like the other two, so a value\n // from configuration can never become SQL text.\n const bindSql = lockTimeout ? `${BIND_SQL}, set_config('lock_timeout',$3,true)` : BIND_SQL;\n const bindParams = lockTimeout ? [role, claimsJson, lockTimeout] : [role, claimsJson];\n\n let opening: Promise<SqlTx> | null = null;\n let release: (() => void) | null = null;\n let fail: ((e: unknown) => void) | null = null;\n let settled: Promise<unknown> | null = null;\n\n const ensure = (): Promise<SqlTx> => {\n if (opening) return opening;\n opening = new Promise<SqlTx>((resolveTx, rejectTx) => {\n const parked = new Promise<void>((res, rej) => {\n release = res;\n fail = rej;\n });\n settled = sql\n .begin(async (tx) => {\n await tx.unsafe(bindSql, bindParams);\n resolveTx(tx);\n await parked;\n })\n .catch((e: unknown) => {\n // Both paths matter: a caller awaiting `ensure()` must see the\n // failure, and `commit()` must not hang waiting for a dead driver.\n rejectTx(e);\n throw e;\n });\n });\n return opening;\n };\n\n return {\n ensure,\n get opened(): boolean {\n return opening !== null;\n },\n async commit(): Promise<void> {\n if (!opening) return;\n release!();\n await settled;\n },\n async rollback(reason: unknown): Promise<void> {\n if (!opening) return;\n fail!(reason);\n // The rejection is the mechanism, not an error to report twice.\n await settled?.catch(() => undefined);\n },\n };\n}\n\nexport type LazyTransaction = ReturnType<typeof createLazyTransaction>;\n\n/** Either a live driver transaction or the lazy holder above. */\ntype TxLike = SqlTx | LazyTransaction;\n\nconst resolveTx = async (tx: TxLike): Promise<SqlTx> =>\n typeof (tx as LazyTransaction).ensure === \"function\"\n ? await (tx as LazyTransaction).ensure()\n : (tx as SqlTx);\n\n/**\n * What a row LOOKS like to the code that reads it.\n *\n * The driver hands back a `Date` for every timestamp column, while the typed\n * surface this SDK generates for the same table says `string` — and so does the\n * response schema derived from a handler's return type, and so does the JSON on\n * the wire. So a handler that returned a row straight from `Database.tables.x`\n * failed its OWN declared type: measured on 2026-08-16, `POST /todos` answered\n * 500 `output_invalid` with \"expected string, received date\" for `created_at`,\n * from code that had done nothing wrong.\n *\n * ISO-8601, because that is what the schema, the generated client and every\n * JSON reader already agree on.\n */\nfunction asWireValue(value: unknown): unknown {\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map(asWireValue);\n return value;\n}\n\n/** Every row a caller receives passes through here. */\nfunction asWireRow<T>(row: T): T {\n if (row === null || typeof row !== \"object\") return row;\n const out: Row = {};\n for (const [key, value] of Object.entries(row as Row)) out[key] = asWireValue(value);\n return out as T;\n}\n\nfunction asWireRows(rows: Row[]): Row[] {\n return rows.map((row) => asWireRow(row));\n}\n\n/** pgvector text literal: '[v1,v2,...]' — the driver would otherwise bind a\n * Postgres ARRAY, which vector's input function refuses. (FR-008) */\nfunction toVectorLiteral(v: number[]): string {\n return `[${v.join(\",\")}]`;\n}\n\n/**\n * The vector-typed column names of one table, read from the installed schema.\n *\n * Ops receive the PHYSICAL table name (`withTables` maps key → `def.name`), so\n * the lookup matches `def.name ?? key`. A column arrives either as a\n * ColumnBuilder (with `_def`) or as the plain def — the same double reading\n * schema-json does, for the same reason: both shapes exist in the wild.\n */\nfunction vectorColumnsOf(schema: typeof currentSchema, table: string): Set<string> {\n const out = new Set<string>();\n const def = tableDefOf(table, schema);\n if (def) {\n for (const [col, c] of Object.entries(def.columns ?? {})) {\n const d = (c !== null && typeof c === \"object\" && \"_def\" in c\n ? (c as { _def: unknown })._def\n : c) as { type?: unknown } | null;\n if (d !== null && typeof d === \"object\" && d.type === \"vector\") out.add(col);\n }\n }\n return out;\n}\n\n/**\n * The one place that answers \"which declared table is this?\".\n *\n * Ops receive the table's WIRE KEY — public bare, anything else qualified —\n * and the installed schema is flattened under exactly those keys. There used to\n * be four separate scans here, each matching `def.name ?? key` against the\n * name, and every one of them missed a table outside public: the column\n * metadata (vectors, transforms, search config) came back EMPTY and the ops\n * fell through to their \"no schema to check against\" path without saying so.\n */\nfunction tableDefOf(\n key: string,\n schema: typeof currentSchema = currentSchema,\n): { name?: string; columns?: Record<string, unknown> } | null {\n return schema.tables?.[key] ?? null;\n}\n\n/** The driver hands a vector back as its text literal; JSON.parse restores the\n * number[] the typed surface declares — the literal is valid JSON (C-9). A null\n * (row without an embedding yet) passes through untouched. */\nfunction reviveVectors<T>(row: T, vectorCols: Set<string>): T {\n if (row === null || typeof row !== \"object\" || vectorCols.size === 0) return row;\n const out = row as Row;\n for (const col of vectorCols) {\n const v = out[col];\n if (typeof v === \"string\") out[col] = JSON.parse(v);\n }\n return row;\n}\n\n/** The declared `{ fromDb, toDb }` per column of `table`, empty when none.\n *\n * Read the same way vector columns are: a column is either a ColumnBuilder\n * (with `_def`) or the flat generated shape, and both are accepted.\n *\n * WITHOUT THIS the hook is a type-level promise the runtime does not keep — the\n * declaration would say `number` and the driver would still hand over the\n * string, which is the defect class this whole surface exists to remove. */\nfunction transformsOf(\n schema: typeof currentSchema,\n table: string,\n): Map<string, { fromDb?: (v: unknown) => unknown; toDb?: (v: unknown) => unknown }> {\n const out = new Map<string, { fromDb?: (v: unknown) => unknown; toDb?: (v: unknown) => unknown }>();\n const def = tableDefOf(table, schema);\n if (def) {\n for (const [col, c] of Object.entries(def.columns ?? {})) {\n const d = (c !== null && typeof c === \"object\" && \"_def\" in c\n ? (c as { _def: unknown })._def\n : c) as { transform?: unknown } | null;\n const t = d?.transform;\n if (t !== null && typeof t === \"object\") {\n out.set(col, t as { fromDb?: (v: unknown) => unknown; toDb?: (v: unknown) => unknown });\n }\n }\n }\n return out;\n}\n\n/** Apply every declared `fromDb` to one row. NULL is passed through untouched:\n * \"no value\" is not a value to convert, and a `fromDb` written for a string\n * would answer `0` for it. */\nfunction applyFromDb(row: Row, transforms: ReturnType<typeof transformsOf>): Row {\n if (transforms.size === 0) return row;\n for (const [col, t] of transforms) {\n if (t.fromDb === undefined) continue;\n const v = row[col];\n if (v === null || v === undefined) continue;\n row[col] = t.fromDb(v);\n }\n return row;\n}\n\n/** `asWireRow`, made table-aware: what the table's schema calls a vector comes\n * back as number[]. Rows from tables the schema does not know pass unchanged. */\nfunction asTableRow<T>(table: string, row: T): T {\n const revived = reviveVectors(asWireRow(row), vectorColumnsOf(currentSchema, table));\n return applyFromDb(revived as Row, transformsOf(currentSchema, table)) as T;\n}\n\nfunction asTableRows(table: string, rows: Row[]): Row[] {\n const vectorCols = vectorColumnsOf(currentSchema, table);\n const transforms = transformsOf(currentSchema, table);\n return rows.map((row) => applyFromDb(reviveVectors(asWireRow(row), vectorCols), transforms));\n}\n\n/** Bind parameters for one write: a value headed for a vector column becomes\n * the pgvector text literal; everything else binds as-is. (FR-008) */\nfunction asBindParams(table: string, cols: string[], data: Row, caller: string): unknown[] {\n // AN `undefined` VALUE IS NOT A WRITE — it is a value that never arrived.\n //\n // The read path already refuses one (see compileWhere): a filter nobody filled\n // in returned an empty list and said nothing. The WRITE half is the same shape\n // and a far more expensive result: `{ title: req.body.title }` with no `title`\n // in the body bound NULL and answered 200 — the column was ERASED, silently.\n // Measured on the 24.0.x line across insert, update, updateMany, upsert and\n // supersede, all of which bind through here.\n //\n // `null` is untouched, and the difference is the whole point: null is an author\n // SAYING \"empty this column\". undefined is nobody saying anything.\n assertUsableWriteValues(caller, table, cols, data);\n const vectorCols = vectorColumnsOf(currentSchema, table);\n const transforms = transformsOf(currentSchema, table);\n return cols.map((c) => {\n const v = data[c];\n if (Array.isArray(v) && vectorCols.has(c)) return toVectorLiteral(v);\n // `toDb` before the bind, and NULL straight through for the same reason\n // `fromDb` skips it.\n const t = transforms.get(c);\n if (t?.toDb !== undefined && v !== null && v !== undefined) return t.toDb(v);\n return v;\n });\n}\n\n// ---------------------------------------------------------------------------\n// search (T017, FR-013..016) — tek-SQL hibrit RRF.\n// ---------------------------------------------------------------------------\n\n/** Metrik → operatör. Tek kelimeden türetilir; opclass/operatör asla yüzeye\n * çıkmaz, uyumsuzluk yapısal olarak imkânsız (D-5, prod arıza #2). */\n// ≤ bu kadar satır eşleşiyorsa vektör kolu EXACT taranır (10K×1536d ≈ 10-20ms;\n// HNSW'nin seçici filtrede recall çöküşüne karşı — ölçüm: engine/db.ts NFR-005 yorumu).\nconst SELECTIVITY_EXACT_THRESHOLD = 10000;\n\nconst METRIC_OPERATOR: Record<string, string> = {\n cosine: \"<=>\",\n euclidean: \"<->\",\n inner_product: \"<#>\",\n};\n\ninterface SearchLeg {\n column: string;\n metric: string;\n /** Auto-embed beyanı (authoring EmbeddingModelRef — runtime şeması defineSchema çıktısıdır). */\n embed?: { model: string; apiKeyName: string; baseURL?: string; dimensions?: number };\n}\n\n/** Chunk-modu hedefi (D-010): arama bu türev tabloda koşar. */\ninterface ChunkTarget {\n table: string;\n metric: string;\n embed?: SearchLeg[\"embed\"];\n fts: boolean;\n}\n\ninterface SearchConfig {\n chunk?: ChunkTarget;\n pk: string;\n cols: string[];\n colSet: Set<string>;\n ftsCols: string[];\n legs: SearchLeg[];\n /** FR-026: beyandan gelen eş anlamlı haritası — websearch girdisi bununla genişler. */\n synonyms?: Record<string, string[]>;\n /** FR-029: beyanda validity:true — arama varsayılan yalnız günceli tarar,\n * supersede bu tabloda çalışır (T019 türev kolonları: valid_from/valid_to/superseded_by). */\n validity?: boolean;\n}\n\n/** Tablonun arama konfigürasyonu, runtime'ın kurduğu şemadan (setSchema — C-9).\n * `search` bloğu yoksa vector kolonlarının VARLIĞI yeter (D-3/FR-013): her\n * vector kolonu cosine metrikli bir leg olur. Tablo şemada yoksa null. */\nfunction searchConfigFor(table: string): SearchConfig | null {\n const t = tableDefOf(table);\n if (!t) return null;\n const columns = t.columns ?? {};\n const defOf = (c: unknown): { type?: string } =>\n c !== null && typeof c === \"object\" && \"_def\" in (c as Record<string, unknown>)\n ? ((c as { _def: { type?: string } })._def)\n : ((c ?? {}) as { type?: string });\n const cols = Object.keys(columns);\n const vectorCols = cols.filter((c) => defOf((columns as Record<string, unknown>)[c]).type === \"vector\");\n // PK adı ŞEMADAN (review I3): Go tarafı tek-kolon PK'nın adını bilinçli\n // serbest bırakır (FR-020 \"adı serbesttir\") — SQL'e 'id' gömmek, pk'sı\n // başka adla declare edilmiş searchable tabloyu runtime 500'üne çevirirdi.\n const defOfFull = (c: unknown): { type?: string; primaryKey?: boolean } =>\n c !== null && typeof c === \"object\" && \"_def\" in (c as Record<string, unknown>)\n ? ((c as { _def: { type?: string; primaryKey?: boolean } })._def)\n : ((c ?? {}) as { type?: string; primaryKey?: boolean });\n const pkCols = cols.filter((c) => defOfFull((columns as Record<string, unknown>)[c]).primaryKey === true);\n const pk = pkCols.length === 1 ? pkCols[0]! : cols.includes(\"id\") ? \"id\" : null;\n if (pk === null) {\n throw new Error(\n `search(${table}): tek-kolon primary key bulunamadı — arama sıralaması ve satır birleşimi PK ister (FR-020)`,\n );\n }\n const search = (t as {\n search?: { text?: string[] | boolean; vector?: unknown; from?: string[]; metric?: string;\n model?: { model: string; apiKeyName?: string; baseURL?: string; dimensions?: number };\n synonyms?: Record<string, string[]>; validity?: boolean };\n }).search;\n const synonyms =\n search?.synonyms !== undefined && Object.keys(search.synonyms).length > 0\n ? { synonyms: search.synonyms }\n : {};\n // T019 notu: validity beyanı wire'da SEARCH bloğunda yaşar (SearchJSON.Validity).\n const validity = search?.validity === true ? { validity: true } : {};\n // YENİ biçim (D-007/D-010): `from`+`model`. Vector kolonu varsa satır-modu\n // (tek leg, kolon o); yoksa CHUNK-modu — arama türev __palbase_chunks\n // tablosunda koşar, sonuç parent'a gruplanır (FR-015).\n if (search?.from !== undefined && search.model !== undefined) {\n const m = search.model;\n const embed = {\n model: m.model, apiKeyName: m.apiKeyName ?? \"OPENAI_API_KEY\",\n ...(m.baseURL !== undefined ? { baseURL: m.baseURL } : {}),\n ...(m.dimensions !== undefined ? { dimensions: m.dimensions } : {}),\n };\n const metric = search.metric ?? \"cosine\";\n const ftsOn = search.text !== false;\n const ftsColsNew = ftsOn\n ? (Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from)\n : [];\n if (vectorCols.length > 0) {\n return { pk, cols, colSet: new Set(cols), ftsCols: ftsColsNew,\n legs: [{ column: vectorCols[0]!, metric, embed }], ...synonyms, ...validity };\n }\n return { pk, cols, colSet: new Set(cols), ftsCols: ftsColsNew, legs: [],\n chunk: { table: `${table}__palbase_chunks`, metric, embed, fts: ftsOn }, ...synonyms, ...validity };\n }\n const ftsCols = (Array.isArray(search?.text) ? search.text : undefined) ?? [];\n const rawLegs = search?.vector === undefined ? [] : Array.isArray(search.vector) ? search.vector : [search.vector];\n let legs: SearchLeg[];\n if (rawLegs.length > 0) {\n legs = rawLegs.map((leg) => {\n const l = leg as { column?: string; metric?: string };\n const column = l.column ?? (vectorCols.length === 1 ? vectorCols[0]! : undefined);\n if (column === undefined) {\n throw new Error(`search(${table}): birden çok vector kolonu var — beyanda 'column' zorunlu (FR-010)`);\n }\n const model = (l as { model?: { model: string; apiKeyName?: string; baseURL?: string; dimensions?: number } }).model;\n return {\n column,\n metric: l.metric ?? \"cosine\",\n ...(model !== undefined\n ? { embed: { model: model.model, apiKeyName: model.apiKeyName ?? \"OPENAI_API_KEY\",\n ...(model.baseURL !== undefined ? { baseURL: model.baseURL } : {}),\n ...(model.dimensions !== undefined ? { dimensions: model.dimensions } : {}) } }\n : {}),\n };\n });\n } else {\n legs = vectorCols.map((column) => ({ column, metric: \"cosine\" }));\n }\n if (ftsCols.length === 0 && legs.length === 0) return null;\n return { pk, cols, colSet: new Set(cols), ftsCols, legs, ...synonyms, ...validity };\n}\n\n/** using → hedef leg. using yok + tek leg → o; using yok + çok leg → adlandırılmış\n * hata (model geçişinde seçim bilinçli olmalı); using yanlış → adlandırılmış hata. */\nfunction pickLeg(table: string, legs: SearchLeg[], using: string | undefined): SearchLeg | null {\n if (legs.length === 0) return null;\n if (using !== undefined) {\n const hit = legs.find((l) => l.column === using);\n if (!hit) {\n throw new Error(\n `search(${table}): using \"${using}\" bir vektör kolunu adlamıyor — mevcut: ${legs.map((l) => l.column).join(\", \")}`,\n );\n }\n return hit;\n }\n if (legs.length === 1) return legs[0]!;\n throw new Error(`search(${table}): birden çok vektör kolu var — 'using' ile seçin (FR-013) — salt metin arıyorsan mode:\\\"text\\\" kullan`);\n}\n\nconst HALF_LIFE_UNIT_SECONDS: Record<string, number> = { s: 1, m: 60, h: 3600, d: 86400 };\n\n/** \"30d\" gibi bir yarı ömrü saniyeye çevirir (FR-004). Biçim <sayı>(s|m|h|d);\n * çözülemeyen YA DA sıfır süre adıyla reddedilir — SQL'e sıfır bölen gitmez. */\nfunction parseHalfLife(s: string): number {\n const m = /^(\\d+)(s|m|h|d)$/.exec(s);\n const sec = m === null ? 0 : Number(m[1]) * HALF_LIFE_UNIT_SECONDS[m[2]!]!;\n if (!Number.isFinite(sec) || sec <= 0) {\n throw new Error(`recency.halfLife \"${s}\" çözümlenemedi — beklenen: pozitif <sayı>+(s|m|h|d), örn. \"30d\" (FR-004)`);\n }\n return sec;\n}\n\nconst WHERE_OPS: Record<string, string> = { gt: \">\", gte: \">=\", lt: \"<\", lte: \"<=\", neq: \"<>\" };\n\n/** FTS kolonlarının sorted coalesce birleşimi — typo-fallback trgm ifadesi ve\n * ts_headline kaynağı (FR-028) AYNI ifadeyi kullanır (Go türev index'iyle birebir). */\nfunction ftsExprOf(ftsCols: string[]): string {\n return [...ftsCols]\n .sort()\n .map((c) => `coalesce(t.${quoteIdent(c)},'')`)\n .join(\" || ' ' || \");\n}\n\n/**\n * expandSynonyms (T020, FR-026): websearch girdisinde tek yönlü eş anlamlı\n * genişletmesi — haritadaki kelime `(kelime OR eş1 OR eş2)` olur\n * (websearch_to_tsquery OR'u tanır). Çift tırnaklı kesimler AYNEN korunur\n * (yazar tam-ifade istedi); eşleşme küçük-harf üzerinden, orijinal token\n * çıktıda kalır. Saf fonksiyon — SQL'e değil bind DEĞERİNE uygulanır.\n */\nexport function expandSynonyms(query: string, map: Record<string, string[]>): string {\n const lower: Record<string, string[]> = {};\n for (const [word, alts] of Object.entries(map)) lower[word.toLowerCase()] = alts;\n return query\n .split(/(\"[^\"]*\")/)\n .map((seg) => {\n if (seg.startsWith('\"')) return seg;\n return seg\n .split(/(\\s+)/)\n .map((tok) => {\n if (tok === \"\" || /^\\s+$/.test(tok)) return tok;\n const alts = lower[tok.toLowerCase()];\n return alts !== undefined && alts.length > 0 ? `(${tok} OR ${alts.join(\" OR \")})` : tok;\n })\n .join(\"\");\n })\n .join(\"\");\n}\n\ntype SearchLogFn = (event: string, fields: Record<string, unknown>) => void;\n// Varsayılan console'a düşer: dikiş kurulmamış runtime'da bile no-results\n// sinyali kaybolmasın (FR-025; bölüm 25-f canlıda sessiz kalmıştı).\nlet searchLogger: SearchLogFn | null = (evt, fields) => {\n console.log(evt, JSON.stringify(fields));\n};\n/** Runtime boot'ta bağlanır (setSecretReader ile aynı kanal deseni): yapısal\n * arama telemetrisi. Varsayılan console.log'tur (a8d5a03: 0-sonuç görünür kalsın); null ile susturulur\n * (FR-025; db.ts'de başka log yolu yok, grep 2026-08-29 boş döndü). */\nexport function setSearchLogger(fn: SearchLogFn | null): void {\n searchLogger = fn;\n}\n\n/** FR-025: nihai dönüş boşsa (typo-fallback DAHİL denendikten sonra) yapısal\n * satır — query HAM haliyle ve 200'e kırpılıp yazılır, sinonim genişletmesi\n * telemetriyi kirletmez. Anahtar/vektör değeri asla loglanmaz. */\nfunction logNoResults(table: string, query: string | undefined, mode: string | undefined, n: number): void {\n if (n === 0) {\n searchLogger?.(\"palbase.search.no_results\", {\n table,\n query: (query ?? \"\").slice(0, 200),\n mode: mode ?? \"hybrid\",\n });\n }\n}\n\n/**\n * fetchFacets (T020, FR-027): filtrelenmiş küme üzerinde kolon başına değer\n * sayaçları — kolon başına top-20, tek UNION ALL sorgusu (parçalar LIMIT/ORDER\n * taşıdığından parantezli). Kolon adları çağıran tarafından şemadan doğrulanmış\n * gelir; where filtreleri sayaçlara da uygulanır (sayaç, kullanıcının gördüğü\n * kümeyi anlatır). Kendi bind listesiyle koşar — ana sorgunun parametreleriyle\n * karışmaz (kullanılmayan bind Postgres'te hatadır).\n */\nasync function fetchFacets(\n live: { unsafe(sql: string, params?: unknown[]): Promise<unknown> },\n table: string,\n colSet: Set<string>,\n facets: string[],\n where: Record<string, unknown>,\n extraWhere: (add: (v: unknown) => string) => string = () => \"\",\n): Promise<Record<string, { value: string | null; count: number }[]>> {\n const bind: unknown[] = [];\n const add = (v: unknown): string => {\n bind.push(v);\n return `$${bind.length}`;\n };\n const whereSql = compileWhere(table, colSet, where, add) + extraWhere(add);\n const parts = facets.map(\n (col) =>\n `(SELECT '${col.replace(/'/g, \"''\")}' AS f, t.${quoteIdent(col)}::text AS v, count(*) AS n ` +\n `FROM ${quoteTable(table)} t WHERE true${whereSql} GROUP BY 2 ORDER BY 3 DESC LIMIT 20)`,\n );\n const rows = (await live.unsafe(parts.join(\" UNION ALL \"), bind)) as\n { f?: string; v?: string | null; n?: unknown }[];\n const out: Record<string, { value: string | null; count: number }[]> = {};\n for (const col of facets) out[col] = [];\n for (const r of rows) {\n if (typeof r.f === \"string\" && out[r.f] !== undefined) {\n out[r.f]!.push({ value: r.v ?? null, count: Number(r.n) });\n }\n }\n return out;\n}\n\n/** C-8 iç kanalı (T018): similar/recommend kaynak id'lerini sonuçtan düşürür.\n * Public search imzasında BİLEREK yok — search-param imza üçlüsü (engine/db +\n * typed-db + endpoint) büyümesin; yalnız bu dosyadaki similar/recommend yazar. */\ninterface InternalSearchParams {\n __excludeIds?: unknown[];\n}\n\n/** FR-029: validity'li tabloda zaman filtresi (T019 türev kolonları sabit:\n * valid_from/valid_to). Varsayılan yalnız güncel satır; \"all\" filtreyi\n * kaldırır; {asOf} o anda geçerli olan versiyonu seçer (tek bind, iki kullanım).\n * Çağıran yalnız cfg.validity === true iken çağırır. */\nfunction validitySql(\n v: \"all\" | { asOf: string } | undefined,\n add: (x: unknown) => string,\n): string {\n if (v === \"all\") return \"\";\n if (v !== undefined) {\n const p = add(v.asOf);\n return ` AND t.\"valid_from\" <= ${p} AND (t.\"valid_to\" IS NULL OR t.\"valid_to\" > ${p})`;\n }\n return ` AND t.\"valid_to\" IS NULL`;\n}\n\n/** Kaynak satır(lar)ı eleyen SQL parçası. Tek id düz `<>`; çoklu\n * `<> ALL(ARRAY[...])` — elemanlar AYRI placeholder: dizi bind'i sürücüde\n * Postgres array literal'ine çevrilmiyor (verify 19-3b dersi, where.in ile aynı). */\nfunction excludeSql(pk: string, ids: unknown[], add: (v: unknown) => string): string {\n if (ids.length === 0) return \"\";\n if (ids.length === 1) return ` AND t.${quoteIdent(pk)} <> ${add(ids[0])}`;\n // ::text — pk uuid'yken text bind'lerle karşılaştırma \"operator does not\n // exist: uuid <> text\" veriyordu (bölüm 25-b canlı ölçümü).\n return ` AND t.${quoteIdent(pk)}::text <> ALL(ARRAY[${ids.map((x) => add(x)).join(\", \")}])`;\n}\n\n/** What `findMany` accepts beside its filter: an ordering, a row ceiling and a\n * page offset. All three used to require dropping to raw SQL, and the docs said\n * so — which is how a tenant's controllers filled up with hand-written SELECTs. */\nexport interface FindManyOptions {\n orderBy?: { column: string; direction?: \"asc\" | \"desc\" };\n limit?: number;\n /** Rows to skip before the page starts. Only meaningful with `limit`, and\n * refused without it — see `offsetClause`. */\n offset?: number;\n}\n\n/** The table's columns as the installed schema knows them, or null when this\n * process has no schema for it (unit tests, a table addressed by name alone).\n * Null means \"cannot validate\", never \"allow anything into SQL\": every\n * identifier still goes through quoteIdent. */\nfunction schemaColumns(table: string): Set<string> | null {\n const t = tableDefOf(table);\n const cols = t?.columns ? Object.keys(t.columns) : [];\n return cols.length > 0 ? new Set(cols) : null;\n}\n\n/** ORDER BY, with the column checked BEFORE it can reach SQL. Against a known\n * schema the check is membership; without one it is a conservative identifier\n * shape. Either way an ordering column is never interpolated on trust. */\nfunction orderClause(\n table: string,\n known: Set<string> | null,\n orderBy: FindManyOptions[\"orderBy\"],\n): string {\n if (!orderBy) return \"\";\n const col = orderBy.column;\n const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);\n if (known !== null ? !known.has(col) : !shapeOK) {\n throw new Error(`findMany(${table}): orderBy kolonu \"${col}\" tabloda yok`);\n }\n const dir = orderBy.direction === \"desc\" ? \"DESC\" : \"ASC\";\n return ` ORDER BY ${quoteIdent(col)} ${dir}`;\n}\n\n/** LIMIT, as a literal because it is a number this code produced — a bound must\n * not be bindable to something that is not one. */\nfunction limitClause(limit: number | undefined): string {\n if (limit === undefined) return \"\";\n if (!Number.isInteger(limit) || limit < 0) {\n throw new Error(`findMany: limit bir negatif olmayan tam sayı olmalı (geldi: ${String(limit)})`);\n }\n return ` LIMIT ${limit}`;\n}\n\n/** OFFSET, a literal for the same reason LIMIT is one.\n *\n * A bare `offset` — no `limit` — is refused BY NAME. Postgres accepts it, but\n * \"skip 10 rows of an unbounded result\" is not a page, and every caller that\n * writes `offset` means a page; letting it through would hand back the whole\n * tail and look like it worked. */\nfunction offsetClause(offset: number | undefined, limit: number | undefined): string {\n if (offset === undefined) return \"\";\n if (!Number.isInteger(offset) || offset < 0) {\n throw new Error(\n `findMany: offset bir negatif olmayan tam sayı olmalı (geldi: ${String(offset)})`,\n );\n }\n if (limit === undefined) {\n throw new Error(\n \"findMany: offset yalnız limit ile birlikte verilir — limitsiz offset bir sayfa değil, sınırsız bir kuyruğun kaydırılmışıdır\",\n );\n }\n return ` OFFSET ${offset}`;\n}\n\n/** where → SQL (FR-016): eşitlik + gt/gte/lt/lte/neq/in, AND'li. Kolon adı\n * şemadan doğrulanır — bilinmeyen ad SQL'e ulaşmadan, adıyla reddedilir. */\nfunction compileWhere(\n table: string,\n colSet: Set<string> | null,\n where: Record<string, unknown>,\n add: (v: unknown) => string,\n caller = \"search\",\n): string {\n const parts: string[] = [];\n // A column's `toDb` applies on the WHERE path too. Without it a transform is\n // half-wired: `insert` writes the converted value and `findMany({ at: date })`\n // binds the client-side shape, so the row that was just written does not come\n // back. The bind goes through `bind` below, never `add` directly.\n const transforms = transformsOf(currentSchema, table);\n const bindFor = (col: string) => {\n const t = transforms.get(col);\n return t?.toDb === undefined\n ? add\n : (v: unknown) => add(v === null || v === undefined ? v : t.toDb!(v));\n };\n // The refusals live in ONE place (db/input-guards.ts) because `fakeDatabase()`\n // is a second implementation of this surface and has to answer identically —\n // measured on 24.1.0: every call this function had just started refusing went\n // through the fake silently, so an author's test went green on code that\n // throws in production.\n assertUsableFilter(caller, table, where);\n for (const [col, cond] of Object.entries(where)) {\n // A null colSet means \"no schema to check against\" — the case `findMany`\n // reaches when a table is addressed by name alone. Identifiers still go\n // through quoteIdent, so an unknown name is a Postgres error, never syntax.\n if (colSet !== null && !colSet.has(col)) {\n throw new Error(`${caller}(${table}): where kolonu \"${col}\" tabloda yok (FR-016)`);\n }\n const q = `t.${quoteIdent(col)}`;\n const bind = bindFor(col);\n if (cond !== null && typeof cond === \"object\" && !Array.isArray(cond)) {\n for (const [op, v] of Object.entries(cond as Record<string, unknown>)) {\n if (op === \"in\") {\n if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmalı`);\n if (v.length === 0) {\n // Boş in-listesi \"hiçbir satır\" demektir — sessiz tam-tarama yerine\n // anlamı SQL'e açıkça yaz (review I5).\n parts.push(\"false\");\n continue;\n }\n // Placeholder genişletmesi: her eleman AYRI parametre. `= ANY($n)`\n // dizi bind'i sürücüde Postgres array literal'ine çevrilmiyor ve\n // canlıda `malformed array literal: \"ops,general\"` 500'ü veriyordu\n // (verify 19-3b, 2026-08-28). IN listesi tip-agnostik ve sürücüden\n // bağımsız; boş liste yukarıda açık `false`.\n parts.push(`${q} IN (${v.map((x) => bind(x)).join(\", \")})`);\n } else if (op in WHERE_OPS) {\n // NULL'a eşitlik SQL'de hiçbir zaman doğru değildir — `= NULL` ve\n // `<> NULL` ikisi de UNKNOWN, yani hiçbir satır. Yazarın YAZDIĞI bir\n // null'ı sessizce boş sonuca çevirmek, undefined'ın az önce kapatılan\n // hatasının aynısı. Soru IS NULL / IS NOT NULL ile sorulur.\n if (v === null && (op === \"neq\" || op === \"eq\")) {\n parts.push(`${q} IS ${op === \"neq\" ? \"NOT \" : \"\"}NULL`);\n continue;\n }\n parts.push(`${q} ${WHERE_OPS[op]} ${bind(v)}`);\n } else {\n throw new Error(`${caller}(${table}): where.${col} bilinmeyen operatör \"${op}\" (gt/gte/lt/lte/neq/in)`);\n }\n }\n } else if (cond === null) {\n // Aynı gerekçe, kısa yazılış: `{ deleted_at: null }` — \"silinmemiş\n // satırlar\" demenin en doğal yolu — `= $1` derlenip hiçbir satır\n // döndürüyordu.\n parts.push(`${q} IS NULL`);\n } else {\n parts.push(`${q} = ${bind(cond)}`);\n }\n }\n return parts.length === 0 ? \"\" : ` AND ${parts.join(\" AND \")}`;\n}\n\n/** The `ON CONFLICT …` tail shared by `upsert` and `insertMany`.\n *\n * ONE writer, deliberately: two hand-written ON CONFLICT clauses is how the\n * single-row and the many-row spellings come to disagree about what a collision\n * does — and a disagreement there is silent, because both statements succeed.\n *\n * `DO UPDATE` sets every column that is NOT part of the conflict key; those are\n * what matched, so assigning them to themselves is the no-op Postgres needs when\n * there is nothing else to set. */\nfunction onConflictTail(\n cols: string[],\n conflict: readonly string[],\n action: \"ignore\" | \"update\",\n): string {\n const target = `ON CONFLICT (${conflict.map(quoteIdent).join(\", \")})`;\n if (action === \"ignore\") return `${target} DO NOTHING`;\n const conflictSet = new Set(conflict);\n const sets = cols\n .filter((c) => !conflictSet.has(c))\n .map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);\n return sets.length\n ? `${target} DO UPDATE SET ${sets.join(\", \")}`\n : `${target} DO UPDATE SET ${quoteIdent(conflict[0]!)} = EXCLUDED.${quoteIdent(conflict[0]!)}`;\n}\n\n/** vector extension'ının yaşadığı şema (C-10): canlı stack'te public, taze\n * stack'te extensions — operatör bununla nitelenir, search_path'e GÜVENİLMEZ\n * (M-1 ölçümü; veri düzlemi search_path=public kurar, handler.go:101). */\nlet cachedVectorSchema: string | null = null;\n\n/** pg_trgm'in kurulu olduğu şema — typo-fallback operatörü bununla nitelenir\n * (search_path'e GÜVENİLMEZ, M-1 ile aynı gerekçe). Bağlanma başına bir kez. */\nlet cachedTrgmSchema: string | null = null;\nasync function trgmSchemaOf(live: { unsafe: (sql: string, params?: unknown[]) => Promise<unknown> }): Promise<string> {\n if (cachedTrgmSchema !== null) return cachedTrgmSchema;\n const rows = (await live.unsafe(\n \"select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'pg_trgm'\",\n )) as { nspname?: string }[];\n cachedTrgmSchema = rows?.[0]?.nspname ?? \"public\";\n return cachedTrgmSchema;\n}\n/** GUC + (soğukken) extension-şema çözümü TEK statement'ta (review I4). */\nasync function vectorSchemaWithGuc(runner: { unsafe(sql: string, params?: unknown[]): Promise<unknown> }): Promise<string> {\n if (cachedVectorSchema !== null) {\n // NFR-005 kapanışı, ÖLÇÜMLE (40K×384, %1 filtre, exact referans):\n // relaxed (vars. 20K tavan) → recall@20 0.62\n // relaxed + max_scan_tuples=200K → 0.64 (tavan tek başına YETMEZ:\n // iterative scan LIMIT dolunca durur, bulduğu ilk N \"en yakın N\" değil)\n // relaxed + 200K + ef_search=200 → 0.95 (asıl düğme aday genişliği)\n // ef_search=200 normal sorguya ms-mertebesi maliyet ekler; karşılığı\n // seçici filtrede doğru sonuç. strict_order ölçümde ek kazanç vermedi.\n await runner.unsafe(\n \"select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true)\",\n );\n return cachedVectorSchema;\n }\n const rows = (await runner.unsafe(\n \"select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true), \" +\n \"(select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'vector') as nspname\",\n )) as { nspname?: string }[];\n const name = rows?.[0]?.nspname;\n if (typeof name !== \"string\" || name === \"\") {\n throw new Error(\"pgvector extension kurulu değil — vector araması çalışamaz (extensions beyanı deploy'dan geçti mi?)\");\n }\n cachedVectorSchema = name;\n return name;\n}\n\n/** Test edilebilirlik: setSchema gibi, cache'i sıfırlar. */\nexport function resetVectorSchemaCache(): void {\n cachedVectorSchema = null;\n}\n\n// ---------------------------------------------------------------------------\n// Sorgu-anı embed (T024, FR-025) — CLAIM-N1: POST /v1/embeddings.\n// ---------------------------------------------------------------------------\n\ntype SecretReader = (name: string) => Promise<string | null>;\nlet secretReader: SecretReader | null = null;\n/** Runtime boot'ta bağlanır (setSchema ile AYNI kanal deseni): vault'tan\n * secret okuma. Engine anahtarın yalnız ADINI bilir, değeri buradan akar. */\nexport function setSecretReader(fn: SecretReader | null): void {\n secretReader = fn;\n}\n\ntype EmbedFetch = (url: string, init?: RequestInit) => Promise<Response>;\nlet embedFetch: EmbedFetch = (url, init) => fetch(url, init);\n/** Test dikişi: sağlayıcı çağrısının fetch'i. Üretimde global fetch. */\nexport function setEmbedFetch(fn: EmbedFetch | null): void {\n embedFetch = fn ?? ((url, init) => fetch(url, init));\n}\n\n/** Sorgu metnini beyan edilen modelle vektörler (CLAIM-N1). Tek deneme, 10s\n * timeout — retry worker'ın işidir, sorgu yolunun değil. Hata apiKeyName'i\n * ADLANDIRIR; anahtar yoksa sağlayıcı hiç aranmaz. */\nasync function embedQuery(\n embed: NonNullable<SearchLeg[\"embed\"]>,\n text: string,\n): Promise<number[]> {\n if (secretReader === null) {\n throw new Error(`query embed: secret reader bağlanmamış — ${embed.apiKeyName} okunamıyor`);\n }\n const key = await secretReader(embed.apiKeyName);\n if (key === null || key === \"\") {\n throw new Error(`query embed: vault'ta ${embed.apiKeyName} yok (FR-021/FR-025)`);\n }\n const url = (embed.baseURL ?? \"https://api.openai.com/v1\").replace(/\\/$/, \"\") + \"/embeddings\";\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10_000);\n try {\n const res = await embedFetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${key}` },\n body: JSON.stringify({\n model: embed.model,\n input: [text],\n ...(embed.dimensions !== undefined ? { dimensions: embed.dimensions } : {}),\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n throw new Error(`query embed: sağlayıcı ${res.status} döndü (${embed.apiKeyName} ile) — anahtar/model doğru mu?`);\n }\n const data = (await res.json()) as { data?: { embedding?: number[] }[] };\n const vec = data.data?.[0]?.embedding;\n if (!Array.isArray(vec)) {\n throw new Error(\"query embed: sağlayıcı yanıtında data[0].embedding yok (CLAIM-N1 şekli)\");\n }\n return vec;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** The six string-keyed operations, plus an interactive `transaction`. */\nexport function createOps(tx: TxLike) {\n const at = () => resolveTx(tx);\n\n const ops = {\n async query(sql: string, params: unknown[] = []): Promise<Row[]> {\n // Arrays become Postgres array literals; everything else is bound as-is.\n // See encodePgArray for what the driver does without this.\n const bound = params.map((p) => (Array.isArray(p) ? encodePgArray(p) : p));\n return asWireRows((await (await at()).unsafe(sql, bound)) as Row[]);\n },\n\n async insert(table: string, data: Row): Promise<Row> {\n const cols = Object.keys(data);\n if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);\n const placeholders = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const sql =\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) ` +\n `VALUES (${placeholders}) RETURNING *`;\n const rows = (await (await at()).unsafe(sql, asBindParams(table, cols, data, \"insert\"))) as Row[];\n const inserted = rows[0];\n if (!inserted) {\n // RETURNING * with no row back means the write was filtered away — an\n // RLS WITH CHECK that rejected it, most often. Silence here would hand\n // the author `undefined` and a 500 three lines later.\n throw new Error(\n `insert into ${table} returned no row — the write was rejected (an RLS policy, most likely).`,\n );\n }\n return asTableRow(table, inserted);\n },\n\n /**\n * INSERT the row, or UPDATE it when it collides on `onConflict`.\n *\n * WHY IT IS AN OPERATION rather than a recipe. \"Try the insert, catch the\n * unique violation, update instead\" does not work here: a request runs in ONE\n * Postgres transaction, so the failed insert aborts it and every later\n * statement answers `current transaction is aborted`. A tenant measured that\n * as 7 of 8 concurrent requests returning 500, gave up on upsert, and had a\n * trigger create the row instead — a workaround that needs a new trigger for\n * every table with a unique row.\n *\n * The conflict columns are excluded from the SET list: they are what MATCHED,\n * so writing them back is at best a no-op and at worst a surprise.\n */\n async upsert(table: string, data: Row, opts: { onConflict: readonly string[] }): Promise<Row> {\n const conflict = opts.onConflict;\n if (conflict.length === 0) {\n // A silent fall-through to a plain INSERT would be an upsert that is not\n // one: it would work until two callers raced, which is the only time it\n // matters.\n throw new Error(`upsert into ${table}: onConflict en az bir kolon adı ister`);\n }\n const cols = Object.keys(data);\n if (cols.length === 0) throw new Error(`upsert into ${table}: no columns given`);\n // D-020 eki (FR-020): validity'li tabloda \"aynı anahtarın yeni değeri\"\n // EZME değil SUPERSEDE'dir — geçmiş silinmez. Düz DO UPDATE burada iki\n // kez yanlıştır: geçerli satırı ezer VE partial arbiter'la (UNIQUE ...\n // WHERE valid_to IS NULL) düz ON CONFLICT eşleşmez (42P10). Desen:\n // partial-arbiter'lı DO NOTHING insert (abort'suz), çakışmada\n // kapat→ekle→bağla (worker writeMemoryFacts ile aynı sıra).\n if (searchConfigFor(table)?.validity) {\n const ph = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const insertSql =\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) VALUES (${ph}) ` +\n `ON CONFLICT (${conflict.map(quoteIdent).join(\", \")}) WHERE \"valid_to\" IS NULL DO NOTHING RETURNING *`;\n const live = await at();\n const bindData = asBindParams(table, cols, data, \"upsert\");\n const first = (await live.unsafe(insertSql, bindData)) as Row[];\n if (first[0]) return asTableRow(table, first[0]);\n const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(\" AND \");\n const condBind = conflict.map((c) => (data as Record<string, unknown>)[c]);\n const cur = (await live.unsafe(\n `SELECT * FROM ${quoteTable(table)} WHERE ${condSql} AND \"valid_to\" IS NULL`, condBind)) as Row[];\n const old = cur[0] as Record<string, unknown> | undefined;\n if (old === undefined) {\n throw new Error(`upsert into ${table}: eşzamanlı supersede yarışı — geçerli satır bulunamadı, isteği yineleyin (D-020)`);\n }\n const pk = Object.keys(old).includes(\"id\") ? \"id\" : Object.keys(old)[0]!;\n await live.unsafe(\n `UPDATE ${quoteTable(table)} SET \"valid_to\" = now() WHERE ${quoteIdent(pk)} = $1 AND \"valid_to\" IS NULL`,\n [old[pk]]);\n const second = (await live.unsafe(insertSql, bindData)) as Row[];\n if (!second[0]) {\n throw new Error(`upsert into ${table}: eşzamanlı supersede yarışı — yeni satır açılamadı, isteği yineleyin (D-020)`);\n }\n const fresh = second[0] as Record<string, unknown>;\n await live.unsafe(\n `UPDATE ${quoteTable(table)} SET \"superseded_by\" = $2 WHERE ${quoteIdent(pk)} = $1`,\n [old[pk], fresh[pk]]);\n return asTableRow(table, second[0]);\n }\n const placeholders = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const conflictSet = new Set(conflict);\n const assignments = cols\n .filter((c) => !conflictSet.has(c))\n .map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);\n // Nothing to update means the row's identity IS the row: keep it and hand\n // the existing one back rather than answering zero rows.\n const action = assignments.length\n ? `DO UPDATE SET ${assignments.join(\", \")}`\n : `DO UPDATE SET ${quoteIdent(conflict[0]!)} = EXCLUDED.${quoteIdent(conflict[0]!)}`;\n const sql =\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) ` +\n `VALUES (${placeholders}) ` +\n `ON CONFLICT (${conflict.map(quoteIdent).join(\", \")}) ${action} RETURNING *`;\n const rows = (await (await at()).unsafe(sql, asBindParams(table, cols, data, \"upsert\"))) as Row[];\n const row = rows[0];\n if (!row) {\n throw new Error(\n `upsert into ${table} returned no row — the write was rejected (an RLS policy, most likely).`,\n );\n }\n return asTableRow(table, row);\n },\n\n async update(table: string, id: string, data: Row): Promise<Row | null> {\n const cols = Object.keys(data);\n if (cols.length === 0) return ops.findById(table, id);\n const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(\", \");\n const sql = `UPDATE ${quoteTable(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;\n const rows = (await (await at()).unsafe(sql, [...asBindParams(table, cols, data, \"update\"), id])) as Row[];\n return rows[0] ? asTableRow(table, rows[0]) : null;\n },\n\n async delete(table: string, id: string): Promise<void> {\n await (await at()).unsafe(`DELETE FROM ${quoteTable(table)} WHERE id = $1`, [id]);\n },\n\n /**\n * Update every row the filter matches, in ONE statement.\n *\n * The capability was already here and only reachable from inside a\n * transaction plan (`tx.tables.x.updateWhere`, since 11.0.0). Outside it the\n * only door was `update(id, …)`, so \"mark every unapproved row in this\n * household\" was an N+1 loop or hand-written SQL — and hand-written SQL is\n * where the typed surface and RLS both stop helping.\n *\n * The filter language is `findMany`'s, compiled by the same `compileWhere`:\n * one filter language, or the two spellings drift.\n *\n * AN EMPTY FILTER IS REFUSED. `UPDATE … WHERE true` is a whole-table write,\n * and the shape that produces it by accident — a filter object built from\n * request input that happened to come back empty — is exactly the shape that\n * should not silently succeed. Callers who mean every row say so with a\n * predicate that is true for every row.\n */\n async updateMany(table: string, where: Row, set: Row): Promise<Row[]> {\n const cols = Object.keys(set);\n if (cols.length === 0) {\n // A silent `[]` here is indistinguishable from \"nothing matched\", and a\n // caller that turns an empty result into a 404 answers the wrong thing.\n throw new Error(\n `updateMany(${table}): nothing to set. An update with no columns is ` +\n `not a no-op worth pretending happened — pass the columns to write.`,\n );\n }\n // SET kolonları da WHERE kolonları gibi şemadan doğrulanır. Doğrulanmayan\n // yarı, bir yazım hatasını Postgres'e kadar taşıyordu: çağıran ham\n // `column \"dome\" of relation \"todos\" does not exist` görüyordu, SDK'nın\n // kendi diliyle değil. Null şema \"kontrol edemem\" demektir, \"serbest\"\n // değil — identifier yine quoteIdent'ten geçer (D-21).\n const known = schemaColumns(table);\n if (known !== null) {\n for (const c of cols) {\n if (!known.has(c)) {\n throw new Error(`updateMany(${table}): set kolonu \"${c}\" tabloda yok (FR-016)`);\n }\n }\n }\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n const assignments = cols\n .map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set, \"updateMany\")[0])}`)\n .join(\", \");\n const whereSql = compileWhere(table, known, where, add, \"updateMany\");\n assertHasPredicate(whereSql, \"updateMany\", table);\n // `AS t`, because compileWhere qualifies every column with the `t.` alias —\n // the same compiler findMany uses, and it must stay the same one. Without\n // the alias the predicate names a relation this statement never declared.\n const sql = `UPDATE ${quoteTable(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;\n return asTableRows(table, (await (await at()).unsafe(sql, params)) as Row[]);\n },\n\n /**\n * Delete every row the filter matches, in ONE statement; resolves to how\n * many went. Same filter language, same empty-filter refusal as\n * {@link updateMany} — and here the accident is worse.\n */\n async deleteMany(table: string, where: Row): Promise<number> {\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n const known = schemaColumns(table);\n const whereSql = compileWhere(table, known, where, add, \"deleteMany\");\n assertHasPredicate(whereSql, \"deleteMany\", table);\n const sql = `DELETE FROM ${quoteTable(table)} AS t WHERE true${whereSql} RETURNING 1`;\n const rows = (await (await at()).unsafe(sql, params)) as Row[];\n return rows.length;\n },\n\n /**\n * How many rows match — the half of pagination `limit`/`offset` cannot\n * supply. Without it a page count is either a guess or \"fetch everything and\n * read .length\", and the second one is the scale risk this surface exists to\n * remove.\n *\n * An empty filter is legitimate HERE: counting a whole table is a read, and\n * reads do not destroy anything.\n */\n async count(table: string, where: Row = {}): Promise<number> {\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n const known = schemaColumns(table);\n const whereSql = compileWhere(table, known, where, add, \"count\");\n const sql = `SELECT count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql}`;\n const rows = (await (await at()).unsafe(sql, params)) as Row[];\n // Postgres answers count() as bigint, which the driver hands over as a\n // STRING. Returning it unconverted would put the report's own A4 defect\n // into a brand-new surface: a \"number\" the caller cannot add to.\n return Number((rows[0] as Record<string, unknown> | undefined)?.n ?? 0);\n },\n\n async findById(table: string, id: string): Promise<Row | null> {\n const rows = (await (await at()).unsafe(\n `SELECT * FROM ${quoteTable(table)} WHERE id = $1`,\n [id],\n )) as Row[];\n return rows[0] ? asTableRow(table, rows[0]) : null;\n },\n\n async findMany(table: string, query: Row = {}, opts: FindManyOptions = {}): Promise<Row[]> {\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n // The SAME compiler `search` uses. Two builders for one filter language is\n // how the two spellings drift; the operator set (gt/gte/lt/lte/neq/in) was\n // already written and already tested, it was just never reachable from here.\n const known = schemaColumns(table);\n const whereSql = compileWhere(table, known, query, add, \"findMany\");\n const order = orderClause(table, known, opts.orderBy);\n const limit = limitClause(opts.limit);\n const offset = offsetClause(opts.offset, opts.limit);\n const sql =\n `SELECT * FROM ${quoteTable(table)} t WHERE true${whereSql}${order}${limit}${offset}`;\n return asTableRows(table, (await (await at()).unsafe(sql, params)) as Row[]);\n },\n\n /**\n * Tek-SQL hibrit arama (FR-014): iki kol CTE + FULL OUTER JOIN + RRF\n * (1/(50+rank), CLAIM-N4). Operatör şema-nitelikli (C-10, M-1); GUC\n * hnsw.iterative_scan=relaxed_order aynı tx'te set_config ile (CLAIM-N3 —\n * RLS/filtre altında LIMIT-altı dönüş açığını kapatır). Sorgu-anı embed\n * T024'te gelir; o zamana dek vector kolu yalnız params.vector ile koşar.\n */\n async search(\n table: string,\n params: {\n query?: string;\n vector?: number[];\n where?: Record<string, unknown>;\n limit?: number;\n using?: string;\n mode?: \"hybrid\" | \"text\" | \"vector\";\n /** Nihai (RRF-sonrası) skor alt eşiği — süzme LIMIT'ten ÖNCE (FR-001). */\n minScore?: number;\n /** RRF-sonrası üstel tazelik çürümesi: _score * exp(-ln(2)*yaş/halfLife) (FR-004). */\n recency?: { field: string; halfLife: string };\n /** Chunk-modunda satır başına dönen en iyi blok sayısı (1..10, vars. 3; FR-015). */\n blocksPerRow?: number;\n /** Filtrelenmiş küme üzerinde kolon başına top-20 değer sayacı —\n * dönüş dizisinin `_facets` özelliği (FR-027). */\n facets?: string[];\n /** Satır-modunda FTS eşleşme vurgusu: ts_headline ile `_highlight`\n * alanı; chunk-modda no-op — bloklar zaten eşleşen kesittir (FR-025). */\n highlight?: boolean;\n /** Validity'li tabloda zaman penceresi: varsayılan yalnız güncel;\n * \"all\" tüm versiyonlar; {asOf} o andaki geçerli versiyon (FR-029). */\n validity?: \"all\" | { asOf: string };\n /** Alan-boost (FR-030): skor * (1 + w·x/(1+x)) — sınırlı, dış servissiz. */\n boost?: { field: string; weight: number };\n } = {},\n ): Promise<Row[]> {\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`search(${table}): tablo aranabilir değil — ne vector kolonu ne search beyanı var (FR-013)`);\n }\n const excl = (params as InternalSearchParams).__excludeIds ?? [];\n // facets kolonları sorgu atılmadan doğrulanır (compileWhere deseni).\n if (params.facets !== undefined) {\n for (const col of params.facets) {\n if (!cfg.colSet.has(col)) {\n throw new Error(`search(${table}): facets kolonu \"${col}\" tabloda yok (FR-027)`);\n }\n }\n }\n if (params.validity !== undefined && cfg.validity !== true) {\n throw new Error(\n `search(${table}): validity parametresi verildi ama tablo validity beyanı taşımıyor (FR-029)`,\n );\n }\n // FR-029: validity filtresi where'lerle aynı bileşime girer — sem/kw/probe\n // ve chunk parent'ı; facets sayaçları da aynı pencereyi görür.\n const validityFor = (adder: (x: unknown) => string): string =>\n cfg.validity === true ? validitySql(params.validity, adder) : \"\";\n const rawLimit = params.limit ?? 20;\n if (typeof rawLimit !== \"number\" || !Number.isFinite(rawLimit)) {\n throw new Error(`search(${table}): limit sonlu bir sayı olmalı, ${String(rawLimit)} verildi (FR-013)`);\n }\n const limit = Math.min(Math.max(1, Math.trunc(rawLimit)), 100);\n const pool = Math.max(limit * 3, 30);\n if (params.minScore !== undefined && (typeof params.minScore !== \"number\" || !Number.isFinite(params.minScore))) {\n throw new Error(`search(${table}): minScore sonlu bir sayı olmalı, ${String(params.minScore)} verildi (FR-001)`);\n }\n // recency.field yalnız kolon-üyeliğiyle doğrulanır — cfg kolon TİPİ\n // taşımaz; timestamp olmayan kolon SQL'de kendi adıyla düşer (C-6).\n let recencyMul = \"\";\n if (params.recency !== undefined) {\n const { field, halfLife } = params.recency;\n if (!cfg.colSet.has(field)) {\n throw new Error(`search(${table}): recency.field \"${field}\" tabloda yok (FR-004)`);\n }\n recencyMul = ` * exp(-ln(2) * extract(epoch from (now() - t.${quoteIdent(field)})) / ${parseHalfLife(halfLife)})`;\n }\n // FR-030/D-017: alan-boost dış servissiz SINIRLI çarpandır — x/(1+x)\n // 0..1'e doyar, 1 + w·(...) hiçbir satırı sıfırlamaz; weight doğrulanmış\n // SONLU sayı olarak SQL'e literal iner (recency'nin halfLife'ı gibi).\n // Bileşim sırası FR-030: RRF → boost → recency → minScore.\n let boostMul = \"\";\n if (params.boost !== undefined) {\n const { field, weight } = params.boost;\n if (!cfg.colSet.has(field)) {\n throw new Error(`search(${table}): boost.field \"${field}\" tabloda yok (FR-030)`);\n }\n if (typeof weight !== \"number\" || !Number.isFinite(weight)) {\n throw new Error(`search(${table}): boost.weight sonlu bir sayı olmalı, ${String(weight)} verildi (FR-030)`);\n }\n const g = `greatest(t.${quoteIdent(field)},0)`;\n boostMul = ` * (1 + ${weight} * ${g}/(1+${g}))`;\n }\n const scoreMul = boostMul + recencyMul;\n if (cfg.chunk !== undefined) {\n // CHUNK-MODU (FR-015, D-010): arama türev tabloda koşar; RRF chunk\n // düzeyinde, sonra parent'a MAX-skor toplaması + en iyi blokların\n // json_agg'ı. minScore/recency GRUPLAMA-SONRASI parent skoruna\n // uygulanır (FR-018). `where` filtreleri parent satırına uygulanır;\n // RLS'i chunk tablosunun parent-mirror policy'si zaten süzer.\n const ck = cfg.chunk;\n const pidQ = quoteIdent(`parent_${cfg.pk}`);\n const bpr = Math.min(Math.max(1, Math.trunc(params.blocksPerRow ?? 3)), 10);\n const wantTextC =\n params.mode !== \"vector\" && ck.fts && typeof params.query === \"string\" && params.query !== \"\";\n let qvC: number[] | null = Array.isArray(params.vector) ? params.vector : null;\n if (qvC === null && ck.embed !== undefined && params.mode !== \"text\" &&\n typeof params.query === \"string\" && params.query !== \"\") {\n try {\n qvC = await embedQuery(ck.embed, params.query);\n } catch (e) {\n if (!wantTextC) throw e;\n qvC = null;\n }\n }\n if (!wantTextC && qvC === null) {\n throw new Error(\n `search(${table}): koşulabilir kol yok — metin için 'query' (FTS beyanı gerekir), semantik için 'vector' verin (FR-015)`,\n );\n }\n const bindC: unknown[] = [];\n const addC = (v: unknown): string => { bindC.push(v); return `$${bindC.length}`; };\n // where/validity/exclude ADAY ÜRETİMİNE gömülür (final-review C1):\n // küresel top-K chunk havuzu filtreli kümeden seçilmezse seçici bir\n // where'de eşleşen sayfa havuza hiç giremez ve arama sessizce boş\n // döner. Satır-modunun kanıtlı deseniyle simetri: filtrenin tek\n // yazarı aday CTE'leridir (sem/kw/trgm-retry); dış katman tekrarlamaz.\n const userWhereC = compileWhere(table, cfg.colSet, params.where ?? {}, addC);\n const whereC = userWhereC + excludeSql(cfg.pk, excl, addC) + validityFor(addC);\n const parentJoinC = ` JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = c.${pidQ} WHERE true${whereC} AND `;\n const liveC = await at();\n const K2 = 50;\n const cpool = Math.max(limit * 9, 90); // blok başına aday: parent-limit × blocksPerRow payı\n let semC = \"\";\n let kwC = \"\";\n if (qvC !== null) {\n const sch = await vectorSchemaWithGuc(liveC);\n const op = METRIC_OPERATOR[ck.metric] ?? METRIC_OPERATOR.cosine;\n // NFR-B4 kapanışı: satır-modu probe'unun chunk ikizi — filtreli chunk\n // kümesi ≤ eşikse HNSW yerine exact tarama (+ 0.0 sıralama ifadesini\n // index-eşleşmesinden düşürür); recall=1.0, ms'ler. Probe RLS'li aynı\n // tx'te, C1'in parent-JOIN'li filtresiyle aynı kümeyi sayar.\n let exactOrderC = \"\";\n if (userWhereC !== \"\") {\n const probeRows = (await liveC.unsafe(\n `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteIdent(ck.table)} c${parentJoinC}c.embedding IS NOT NULL LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,\n bindC.slice(),\n )) as { n?: number }[];\n const n = probeRows?.[0]?.n;\n if (typeof n === \"number\" && n <= SELECTIVITY_EXACT_THRESHOLD) {\n exactOrderC = \" + 0.0\";\n }\n }\n const vp = addC(toVectorLiteral(qvC));\n semC =\n `SELECT c.${pidQ} AS pid, c.chunk_seq, ROW_NUMBER() OVER (ORDER BY (c.embedding OPERATOR(${quoteIdent(sch)}.${op}) ${vp}::${quoteIdent(sch)}.vector)${exactOrderC}) AS r ` +\n `FROM ${quoteIdent(ck.table)} c${parentJoinC}c.embedding IS NOT NULL ORDER BY r LIMIT ${cpool}`;\n }\n let qpC = \"\";\n let qpCIdx = -1;\n if (wantTextC) {\n // FR-026: genişletme yalnız websearch BIND değerine — SQL metni değişmez.\n const qTextC =\n cfg.synonyms !== undefined ? expandSynonyms(params.query!, cfg.synonyms) : params.query;\n qpC = addC(qTextC);\n qpCIdx = bindC.length - 1;\n kwC =\n `SELECT c.${pidQ} AS pid, c.chunk_seq, ROW_NUMBER() OVER (ORDER BY ts_rank_cd(c.palbase_fts, websearch_to_tsquery('simple', ${qpC})) DESC) AS r ` +\n `FROM ${quoteIdent(ck.table)} c${parentJoinC}c.palbase_fts @@ websearch_to_tsquery('simple', ${qpC}) ORDER BY r LIMIT ${cpool}`;\n }\n const msC = params.minScore === undefined ? \"\" : addC(params.minScore);\n const colListC = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(\", \");\n const scoreC = scoreMul === \"\" ? \"g._score\" : `(g._score)${scoreMul}`;\n const assembleC = (kwIn: string, withKwn: boolean): string => {\n const kwnCol = withKwn ? `, (SELECT count(*) FROM kw)::int AS _kwn` : \"\";\n let fusedSrc: string;\n if (semC !== \"\" && kwIn !== \"\") {\n fusedSrc =\n `WITH sem AS (${semC}), kw AS (${kwIn}), fused AS (` +\n `SELECT COALESCE(sem.pid, kw.pid) AS pid, COALESCE(sem.chunk_seq, kw.chunk_seq) AS chunk_seq, ` +\n `(COALESCE(1.0/(${K2} + sem.r), 0) + COALESCE(1.0/(${K2} + kw.r), 0))::float8 AS cscore ` +\n `FROM sem FULL OUTER JOIN kw ON sem.pid = kw.pid AND sem.chunk_seq = kw.chunk_seq)`;\n } else if (semC !== \"\") {\n fusedSrc = `WITH sem AS (${semC}), fused AS (SELECT sem.pid, sem.chunk_seq, (1.0/(${K2} + sem.r))::float8 AS cscore FROM sem)`;\n } else {\n fusedSrc = `WITH kw AS (${kwIn}), fused AS (SELECT kw.pid, kw.chunk_seq, (1.0/(${K2} + kw.r))::float8 AS cscore FROM kw)`;\n }\n const inner =\n `${fusedSrc}, ranked AS (` +\n `SELECT f.pid, f.chunk_seq, f.cscore, ROW_NUMBER() OVER (PARTITION BY f.pid ORDER BY f.cscore DESC, f.chunk_seq) AS rn FROM fused f), ` +\n `grouped AS (` +\n `SELECT r.pid, MAX(r.cscore) AS _score, ` +\n `json_agg(json_build_object('content', c.content, 'score', r.cscore, 'chunkSeq', r.chunk_seq, 'charStart', c.char_start) ORDER BY r.cscore DESC, r.chunk_seq) FILTER (WHERE r.rn <= ${bpr}) AS blocks ` +\n `FROM ranked r JOIN ${quoteIdent(ck.table)} c ON c.${pidQ} = r.pid AND c.chunk_seq = r.chunk_seq ` +\n `GROUP BY r.pid) ` +\n `SELECT ${colListC}, ${scoreC}::float8 AS _score, g.blocks AS blocks${kwnCol} ` +\n `FROM grouped g JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = g.pid`;\n return msC === \"\"\n ? `SELECT * FROM (${inner}) q ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`\n : `SELECT * FROM (${inner}) q WHERE q._score >= ${msC} ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;\n };\n let rowsC = (await liveC.unsafe(assembleC(kwC, kwC !== \"\"), bindC)) as Row[];\n if (wantTextC && kwC !== \"\" && (rowsC.length === 0 || (rowsC[0] as Record<string, unknown>)._kwn === 0)) {\n // FR-002 chunk-modunda da geçerli: kelime kolu 0 adaysa trgm retry —\n // ifade chunk İÇERİĞİ üstünde (türev index'in kaynağı da o).\n const tsch = await trgmSchemaOf(liveC);\n const trgmKwC =\n `SELECT c.${pidQ} AS pid, c.chunk_seq, ROW_NUMBER() OVER (ORDER BY ${quoteIdent(tsch)}.word_similarity(${qpC}, coalesce(c.content,'')) DESC) AS r ` +\n `FROM ${quoteIdent(ck.table)} c${parentJoinC}${quoteIdent(tsch)}.word_similarity(${qpC}, coalesce(c.content,'')) > 0.3 ORDER BY r LIMIT ${cpool}`;\n // trgm kelime-benzerliği OR-sözdizimi tanımaz: retry aynı placeholder'ı\n // HAM query ile koşar (bind kopyası — kayıtlı ilk çağrı değişmez).\n const retryBindC = bindC.slice();\n if (qpCIdx >= 0) retryBindC[qpCIdx] = params.query;\n rowsC = (await liveC.unsafe(assembleC(trgmKwC, false), retryBindC)) as Row[];\n }\n for (const r of rowsC) delete (r as Record<string, unknown>)._kwn;\n const outC = asTableRows(table, rowsC).map((r) => ({ ...r, blocks: (r as { blocks?: unknown }).blocks ?? [] }));\n if (params.facets !== undefined && params.facets.length > 0) {\n Object.assign(outC, {\n _facets: await fetchFacets(liveC, table, cfg.colSet, params.facets, params.where ?? {}, validityFor),\n });\n }\n logNoResults(table, params.query, params.mode, outC.length);\n return outC;\n }\n const wantText =\n params.mode !== \"vector\" && cfg.ftsCols.length > 0 && typeof params.query === \"string\" && params.query !== \"\";\n // Vektör kolu ancak GERÇEKTEN istenecekse çözülür (FR-015, review C1):\n // çok kollu tabloda salt-text arama 'using' zorunluluğuna TAKILMAZ.\n const anyEmbed = cfg.legs.some((l) => l.embed !== undefined);\n const vectorAsked =\n params.mode !== \"text\" &&\n (Array.isArray(params.vector) || params.using !== undefined || params.mode === \"vector\" ||\n (anyEmbed && typeof params.query === \"string\" && params.query !== \"\"));\n const leg = vectorAsked ? pickLeg(table, cfg.legs, params.using) : null;\n let qv: number[] | null = Array.isArray(params.vector) ? params.vector : null;\n if (qv === null && leg?.embed !== undefined && typeof params.query === \"string\" && params.query !== \"\") {\n // FR-025: beyan edilen modelle TEK sağlayıcı çağrısı. Başarısızlıkta\n // FR-015 düşüşü: text kolu koşulabiliyorsa arama ONUNLA döner; yoksa\n // adlandırılmış hata (sessiz boş dönüş asla).\n try {\n qv = await embedQuery(leg.embed, params.query);\n } catch (e) {\n if (!wantText) throw e;\n qv = null;\n }\n }\n const wantVector = leg !== null && qv !== null;\n if (!wantText && !wantVector) {\n throw new Error(\n `search(${table}): koşulabilir kol yok — metin için 'query' (FTS beyanı gerekir), semantik için 'vector' verin (FR-015)`,\n );\n }\n const bind: unknown[] = [];\n const add = (v: unknown): string => {\n bind.push(v);\n return `$${bind.length}`;\n };\n // Probe kararı (aşağıda) kullanıcı where'ine bakar: exclude tek başına\n // neredeyse hiç seçici değildir, exact-yol probe'unu tetiklememeli.\n const userWhere = compileWhere(table, cfg.colSet, params.where ?? {}, add);\n const whereSql = userWhere + excludeSql(cfg.pk, excl, add) + validityFor(add);\n const live = await at();\n const K = 50;\n let semSql = \"\";\n let kwSql = \"\";\n if (wantVector && leg) {\n // GUC yalnız hnsw taramasını etkiler — salt-text arama onu hiç koşmaz\n // (review I4). Soğuk yolda extension-şema lookup'ı AYNI statement'a\n // biner: sıcak yol +1, soğuk yol +1 (eskiden +2) round-trip; kalan tek\n // ekstra tur NFR-002'de karar kaydıyla kabul edildi.\n const sch = await vectorSchemaWithGuc(live);\n const op = METRIC_OPERATOR[leg.metric] ?? METRIC_OPERATOR.cosine;\n // SEÇİCİ FİLTREDE EXACT YOL (NFR-005 kapanışı, ölçümle): HNSW iterative\n // scan %1 seçicilikte 100K ölçeğinde hedefe ULAŞAMIYOR — GUC gridi\n // (relaxed/strict × max_scan_tuples 200K × ef_search 200..1000) en iyi\n // 0.38 recall verdi. Filtreli küme küçükse doğru cevap index'i HİÇ\n // kullanmamak: ≤10K satırda exact mesafe taraması ms'ler sürer ve\n // recall=1.0. Seçicilik bir probe ile ölçülür (RLS aynı tx'te — sayım\n // tenant'ın görebildiği satırlarla); index'i devre dışı bırakmak için\n // sıralama ifadesine + 0.0 eklenir (planner ifade-eşleşmesini kaybeder;\n // EXPLAIN'le doğrulandı — GUC'suz, tx yan etkisiz).\n let exactOrder = \"\";\n if (userWhere !== \"\") {\n const probeRows = (await live.unsafe(\n `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,\n bind.slice(),\n )) as { n?: number }[];\n const n = probeRows?.[0]?.n;\n if (typeof n === \"number\" && n <= SELECTIVITY_EXACT_THRESHOLD) {\n exactOrder = \" + 0.0\";\n }\n }\n const vp = add(toVectorLiteral(qv!));\n semSql =\n `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY (t.${quoteIdent(leg.column)} OPERATOR(${quoteIdent(sch)}.${op}) ${vp}::${quoteIdent(sch)}.vector)${exactOrder}) AS r ` +\n `FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} ORDER BY r LIMIT ${pool}`;\n }\n let qpRef = \"\";\n let qpIdx = -1;\n if (wantText) {\n // FR-026: genişletme yalnız websearch BIND değerine — SQL metni değişmez.\n const qText =\n cfg.synonyms !== undefined ? expandSynonyms(params.query!, cfg.synonyms) : params.query;\n const qp = add(qText);\n qpIdx = bind.length - 1;\n qpRef = qp;\n kwSql =\n `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ts_rank_cd(t.palbase_fts, websearch_to_tsquery('simple', ${qp})) DESC) AS r ` +\n `FROM ${quoteTable(table)} t WHERE t.palbase_fts @@ websearch_to_tsquery('simple', ${qp})${whereSql} ORDER BY r LIMIT ${pool}`;\n }\n const colList = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(\", \");\n // minScore parametresi BİR kez bind'lenir — assemble iki kez çağrılabilir\n // (typo-fallback retry'ı) ve her çağrıda add() bind'i şişirirdi.\n const msP = params.minScore === undefined ? \"\" : add(params.minScore);\n // FR-025: vurgu yalnız satır-modu + metinli aramada; ifade typo-fallback'in\n // sorted-kolon birleşimiyle aynı. qp placeholder'ı yeniden kullanılır.\n const hlCol =\n params.highlight === true && wantText\n ? `, ts_headline('simple', ${ftsExprOf(cfg.ftsCols)}, websearch_to_tsquery('simple', ${qpRef})) AS _highlight`\n : \"\";\n // Recency çarpanı RRF-SONRASI nihai skora biner (FR-004); recency/\n // minScore yokken SQL'in tek farkı metinli aramadaki `_kwn` scalar'ıdır:\n // kelime kolunun kaç aday bulduğunu nihai SELECT taşır — typo-fallback\n // kararı (FR-002) sonuç satırından okunur, karar için ek tur yoktur.\n const assemble = (kwIn: string, withKwn: boolean): string => {\n const kwnCol = withKwn ? `, (SELECT count(*) FROM kw)::int AS _kwn` : \"\";\n let inner: string;\n let orderScore: string;\n if (semSql !== \"\" && kwIn !== \"\") {\n const score = scoreMul === \"\" ? \"fused._score\" : `(fused._score)${scoreMul}`;\n inner =\n `WITH sem AS (${semSql}), kw AS (${kwIn}), fused AS (` +\n `SELECT COALESCE(sem.id, kw.id) AS id, ` +\n `(COALESCE(1.0/(${K} + sem.r), 0) + COALESCE(1.0/(${K} + kw.r), 0))::float8 AS _score ` +\n `FROM sem FULL OUTER JOIN kw ON sem.id = kw.id) ` +\n `SELECT ${colList}, ${score} AS _score${hlCol}${kwnCol} FROM fused ` +\n `JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = fused.id`;\n orderScore = scoreMul === \"\" ? \"fused._score\" : \"_score\";\n } else {\n const single = semSql !== \"\" ? `sem AS (${semSql})` : `kw AS (${kwIn})`;\n const alias = semSql !== \"\" ? \"sem\" : \"kw\";\n const base = `(1.0/(${K} + ${alias}.r))::float8`;\n const score = scoreMul === \"\" ? base : `(${base})${scoreMul}`;\n inner =\n `WITH ${single} ` +\n `SELECT ${colList}, ${score} AS _score${hlCol}${semSql !== \"\" ? \"\" : kwnCol} FROM ${alias} ` +\n `JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = ${alias}.id`;\n orderScore = \"_score\";\n }\n // minScore süzmesi LIMIT'ten ÖNCE olmalı (FR-001): sarmalayıcı verilirse\n // sıralama+limit dışarı taşınır — süzülen satırın yeri alttakiyle dolar.\n return msP === \"\"\n ? `${inner} ORDER BY ${orderScore} DESC, t.${quoteIdent(cfg.pk)} LIMIT ${limit}`\n : `SELECT * FROM (${inner}) q WHERE q._score >= ${msP} ` +\n `ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;\n };\n let rows = (await live.unsafe(assemble(kwSql, kwSql !== \"\"), bind)) as Row[];\n if (wantText && kwSql !== \"\" && (rows.length === 0 || (rows[0] as Record<string, unknown>)._kwn === 0)) {\n // FR-002: kelime kolu HİÇ aday bulamadı — aynı sorgu pg_trgm\n // word_similarity ile BİR kez daha denenir (yalnız bu 0-sonuç yolunda\n // +1 tur, NFR-A2). Exact-önce korunur: eşleşme varken trgm hiç koşmaz.\n // İfade, Go tarafının türev trgm index'iyle BİREBİR aynı (sorted\n // kolonlar) — index'i o ifade yakalar.\n const tsch = await trgmSchemaOf(live);\n const expr = ftsExprOf(cfg.ftsCols);\n const trgmKw =\n `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) DESC) AS r ` +\n `FROM ${quoteTable(table)} t WHERE ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) > 0.3${whereSql} ORDER BY r LIMIT ${pool}`;\n // trgm kelime-benzerliği OR-sözdizimi tanımaz: retry aynı placeholder'ı\n // HAM query ile koşar (bind kopyası — kayıtlı ilk çağrı değişmez).\n const retryBind = bind.slice();\n if (qpIdx >= 0) retryBind[qpIdx] = params.query;\n rows = (await live.unsafe(assemble(trgmKw, false), retryBind)) as Row[];\n }\n for (const r of rows) delete (r as Record<string, unknown>)._kwn;\n // FR-015: dönüş tipi iki modda aynı şekildedir — satır-modunda blok\n // kavramı yoktur, tip uyumu boş diziyle sağlanır (spec kararı).\n const out = asTableRows(table, rows).map((r) => ({ ...r, blocks: [] as unknown[] }));\n if (params.facets !== undefined && params.facets.length > 0) {\n Object.assign(out, {\n _facets: await fetchFacets(live, table, cfg.colSet, params.facets, params.where ?? {}, validityFor),\n });\n }\n logNoResults(table, params.query, params.mode, out.length);\n return out;\n },\n\n /**\n * similar (T018, FR-022): \"bu satıra benzeyenler\". Hedef vektör DB'den\n * okunur — satır-modu satırın kendi kolonu, chunk-modu parent chunk'larının\n * şema-nitelikli avg'ı — ve ana arama search'ün vector yoluyla koşar;\n * kaynak satır sonuçtan düşer. İKİ tur BİLİNÇLİ (plan T018): target-CTE'li\n * tek SQL'de \"id yok\" ile \"0 komşu\" ayrılamazdı; +1 küçük turla id-yokluğu\n * adlandırılmış hataya çevrilir. Sonuç şekli search ile aynı (FR-015).\n */\n /** D-021 (FR-027 DX): sayaçlar BAĞIMSIZ op'la — search'ün dizi-üstü\n * `_facets` özelliği JSON.stringify'da kaybolur (dizi özelliği), tenant\n * yanıtına koyunca sessizce yok olurdu. Ayrı dönüş ciddi bir sözleşmedir;\n * search'teki alan geriye-uyum için DURUR. where + validity default'u\n * sayaçlara da uygulanır (sayaç, kullanıcının gördüğü kümeyi anlatır). */\n async facets(\n table: string,\n params: { facets: string[]; where?: Record<string, unknown>; validity?: \"all\" | { asOf: string } },\n ): Promise<Record<string, { value: string | null; count: number }[]>> {\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`facets(${table}): tablo aranabilir değil — search beyanı yok (FR-027)`);\n }\n for (const col of params.facets) {\n if (!cfg.colSet.has(col)) {\n throw new Error(`facets(${table}): facets kolonu \"${col}\" tabloda yok (FR-027)`);\n }\n }\n const live = await at();\n const extra = cfg.validity ? (add: (v: unknown) => string) => validitySql(params.validity, add) : () => \"\";\n return fetchFacets(live, table, cfg.colSet, params.facets, params.where ?? {}, extra);\n },\n\n async similar(\n table: string,\n id: string,\n opts: {\n where?: Record<string, unknown>;\n limit?: number;\n using?: string;\n minScore?: number;\n recency?: { field: string; halfLife: string };\n blocksPerRow?: number;\n validity?: \"all\" | { asOf: string };\n boost?: { field: string; weight: number };\n } = {},\n ): Promise<Row[]> {\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`similar(${table}): tablo aranabilir değil — ne vector kolonu ne search beyanı var (FR-013)`);\n }\n const live = await at();\n let v: unknown;\n if (cfg.chunk !== undefined) {\n const sch = await vectorSchemaWithGuc(live);\n const rows = (await live.unsafe(\n `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteIdent(cfg.chunk.table)} c ` +\n `WHERE c.${quoteIdent(`parent_${cfg.pk}`)} = $1 AND c.embedding IS NOT NULL`,\n [id],\n )) as { v?: unknown }[];\n v = rows?.[0]?.v;\n } else {\n const leg = pickLeg(table, cfg.legs, opts.using);\n if (leg === null) {\n throw new Error(`similar(${table}): tabloda vektör kolonu yok — benzerlik semantik vektör ister (FR-022)`);\n }\n const rows = (await live.unsafe(\n `SELECT t.${quoteIdent(leg.column)} AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} = $1`,\n [id],\n )) as { v?: unknown }[];\n v = rows?.[0]?.v;\n }\n // Sürücü vector'ü text literal'i olarak verir (C-9); yokluk = satır yok\n // YA DA embedding NULL — ikisi de aynı adlandırılmış hata.\n if (typeof v !== \"string\") {\n throw new Error(`similar(${table}): id \"${String(id)}\" bulunamadı ya da embedding'i yok (FR-022)`);\n }\n const p = {\n vector: JSON.parse(v) as number[],\n mode: \"vector\" as const,\n where: opts.where,\n limit: opts.limit,\n using: opts.using,\n minScore: opts.minScore,\n recency: opts.recency,\n blocksPerRow: opts.blocksPerRow,\n validity: opts.validity,\n boost: opts.boost,\n __excludeIds: [id],\n };\n return ops.search(table, p);\n },\n\n /**\n * recommend (T018, FR-023): positive/negative id kümelerinden öneri.\n * Hedef vektör DB-İÇİ CTE'lerle türer: pos = avg(embedding of positives),\n * negative varsa hedef = pos.v + (pos.v - neg.v) — pgvector avg agregası\n * ve +/- operatörleri ŞEMA-NİTELİKLİ (M-1: search_path'e güvenilmez).\n * Vektör matematiği istemciye inmez; bulunamayan positive/negative\n * adlandırılmış hatadır ve kaynak id'ler sonuçtan düşer.\n */\n async recommend(\n table: string,\n opts: {\n positive: unknown[];\n negative?: unknown[];\n where?: Record<string, unknown>;\n limit?: number;\n using?: string;\n minScore?: number;\n recency?: { field: string; halfLife: string };\n blocksPerRow?: number;\n validity?: \"all\" | { asOf: string };\n boost?: { field: string; weight: number };\n },\n ): Promise<Row[]> {\n const positive = opts?.positive;\n if (!Array.isArray(positive) || positive.length === 0) {\n throw new Error(`recommend(${table}): positive boş olamaz — en az bir kaynak id gerekir (FR-023)`);\n }\n const negative = Array.isArray(opts.negative) ? opts.negative : [];\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`recommend(${table}): tablo aranabilir değil — ne vector kolonu ne search beyanı var (FR-013)`);\n }\n let leg: SearchLeg | null = null;\n if (cfg.chunk === undefined) {\n leg = pickLeg(table, cfg.legs, opts.using);\n if (leg === null) {\n throw new Error(`recommend(${table}): tabloda vektör kolonu yok — öneri semantik vektör ister (FR-023)`);\n }\n }\n const live = await at();\n const sch = await vectorSchemaWithGuc(live);\n const bind: unknown[] = [];\n const add = (x: unknown): string => {\n bind.push(x);\n return `$${bind.length}`;\n };\n // id listesi AYRI placeholder'larla (where.in ile aynı gerekçe).\n const avgSel = (ids: unknown[]): string => {\n const inList = ids.map((x) => add(x)).join(\", \");\n return cfg.chunk !== undefined\n ? `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteIdent(cfg.chunk.table)} c ` +\n `WHERE c.${quoteIdent(`parent_${cfg.pk}`)} IN (${inList}) AND c.embedding IS NOT NULL`\n : `SELECT ${quoteIdent(sch)}.avg(t.${quoteIdent(leg!.column)}) AS v FROM ${quoteTable(table)} t ` +\n `WHERE t.${quoteIdent(cfg.pk)} IN (${inList}) AND t.${quoteIdent(leg!.column)} IS NOT NULL`;\n };\n // pos/neg yokluğu bayrak olarak AYNI sorgudan döner: aritmetik DB'de\n // kalır, hata ayrımı için ek tur gerekmez.\n const targetSql =\n negative.length === 0\n ? `WITH pos AS (${avgSel(positive)}) SELECT pos.v AS v, (pos.v IS NULL) AS pos_missing FROM pos`\n : `WITH pos AS (${avgSel(positive)}), neg AS (${avgSel(negative)}) ` +\n `SELECT (pos.v OPERATOR(${quoteIdent(sch)}.+) (pos.v OPERATOR(${quoteIdent(sch)}.-) neg.v)) AS v, ` +\n `(pos.v IS NULL) AS pos_missing, (neg.v IS NULL) AS neg_missing FROM pos, neg`;\n const rows = (await live.unsafe(targetSql, bind)) as\n { v?: unknown; pos_missing?: unknown; neg_missing?: unknown }[];\n const r0 = rows?.[0];\n if (r0 === undefined || r0.pos_missing === true) {\n throw new Error(`recommend(${table}): positive id'lerin hiçbiri bulunamadı ya da embedding'i yok (FR-023)`);\n }\n if (negative.length > 0 && r0.neg_missing === true) {\n throw new Error(`recommend(${table}): negative id'leri bulunamadı ya da embedding'i yok (FR-023)`);\n }\n if (typeof r0.v !== \"string\") {\n throw new Error(`recommend(${table}): hedef vektör hesaplanamadı (FR-023)`);\n }\n const p = {\n vector: JSON.parse(r0.v) as number[],\n mode: \"vector\" as const,\n where: opts.where,\n limit: opts.limit,\n using: opts.using,\n minScore: opts.minScore,\n recency: opts.recency,\n blocksPerRow: opts.blocksPerRow,\n validity: opts.validity,\n boost: opts.boost,\n __excludeIds: [...positive, ...negative],\n };\n return ops.search(table, p);\n },\n\n /**\n * supersede (T021, FR-029, C-9): validity'li tabloda satırın YENİ\n * versiyonunu TEK savepoint'te yazar — eski satır kapatılır\n * (valid_to = now(), superseded_by = yeni pk), yeni satır eklenir, dönüş\n * yeni satırdır. Yeni pk CLIENT'ta üretilir (row'da verilmemişse\n * randomUUID — declared şemaların uuid().defaultRandom() standardı) ki\n * kapatma UPDATE'i INSERT'ten ÖNCE koşabilsin: 0 satır = zaten superseded\n * ya da yok → INSERT hiç denenmez; INSERT hatası ise savepoint'le\n * kapatmayı da geri sarar — yarım supersede diye bir durum yoktur.\n */\n async supersede(table: string, id: string, row: Row): Promise<Row> {\n const cfg = searchConfigFor(table);\n if (cfg === null || cfg.validity !== true) {\n throw new Error(`supersede(${table}): tablo validity beyanı taşımıyor (FR-029)`);\n }\n const live = await at();\n return live.savepoint(async (sp) => {\n const newId = row[cfg.pk] ?? crypto.randomUUID();\n const closed = (await sp.unsafe(\n `UPDATE ${quoteTable(table)} SET \"valid_to\" = now(), \"superseded_by\" = $1 ` +\n `WHERE ${quoteIdent(cfg.pk)} = $2 AND \"valid_to\" IS NULL RETURNING ${quoteIdent(cfg.pk)}`,\n [newId, id],\n )) as Row[];\n if (closed.length === 0) {\n throw new Error(`supersede(${table}): id \"${String(id)}\" zaten superseded ya da yok (FR-029)`);\n }\n const data = { ...row, [cfg.pk]: newId };\n const cols = Object.keys(data);\n const placeholders = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const rows = (await sp.unsafe(\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) ` +\n `VALUES (${placeholders}) RETURNING *`,\n asBindParams(table, cols, data, \"supersede\"),\n )) as Row[];\n if (!rows[0]) {\n throw new Error(\n `supersede(${table}): INSERT satır döndürmedi — yazma reddedildi (büyük olasılıkla bir RLS policy'si)`,\n );\n }\n return asTableRow(table, rows[0]);\n });\n },\n\n /** A real SAVEPOINT inside the request's transaction. */\n async transaction<T>(cb: (t: unknown) => Promise<T>): Promise<T> {\n const live = await at();\n return live.savepoint(async (sp) => cb(withTables(createOps(sp), currentSchema)));\n },\n\n /**\n * Run `fn` against a handle bound to a SAVEPOINT, so a failure inside it\n * rolls back only what that handle wrote and the request can keep writing.\n *\n * WHY THE HANDLE IS AN ARGUMENT. The obvious shape — `attempt(async () => {\n * ... Database.insert(...) ... })`, with no parameter — would have to point\n * the ambient `Database` at the savepoint for the duration, and a request is\n * concurrent with itself: `Promise.all([Database.insert(a),\n * Database.attempt(...)])` would put `a` inside the savepoint and roll it\n * back with it. Silent data loss, and the same interleaving this file already\n * refuses for `asService()`. Passing the handle makes the boundary something\n * you can see in the code that crosses it.\n *\n * Postgres, not us: the savepoint is released on success and rolled back on\n * failure by the driver, so an aborted statement inside `fn` does not poison\n * the surrounding transaction.\n */\n async attempt<T>(fn: (tx: DBOps) => Promise<T>): Promise<T> {\n const live = await at();\n return live.savepoint(async (sp) => fn(withTables(createOps(sp), currentSchema) as DBOps));\n },\n\n /**\n * Execute a whole transaction plan — what `Database.transaction(fn)` builds.\n *\n * WHY IT RUNS HERE. The platform used to carry a complete implementation\n * of this at `/internal-api/db/tx`, for tenant code that ran in an isolate\n * with no connection of its own. Running the plan there means running it on\n * a DIFFERENT connection: a transaction would not see the uncommitted\n * writes of the request that started it, and the two would hold separate\n * RLS bindings of the same identity. In this stack the tenant's code and\n * the connection share a process, so the plan runs on the request's own\n * transaction inside one SAVEPOINT — and that surface was removed on\n * 2026-08-15, once this was the last thing that could have called it.\n *\n * Until 2026-08-15 it ran NOWHERE: `runTxPlan` called `transport.txPlan` and\n * nothing here implemented it, so a live handler answered\n * \"transport.txPlan is not a function\" while every test that covered\n * transactions passed against a mock that did implement it.\n */\n async txPlan(plan: TxPlanBody): Promise<TxPlanResponse> {\n const live = await at();\n // ONE savepoint for the whole plan: a failed expectation must undo the\n // transaction the author wrote, and nothing outside it.\n return live.savepoint(async (sp) => {\n const results: TxPlanOpResult[] = [];\n for (const op of plan.ops) {\n const rows = asTableRows(op.table, await runPlanOp(sp, op, results)) as typeof results[number][\"rows\"];\n const result: TxPlanOpResult = { rows, rows_affected: rows.length };\n results.push(result);\n assertGuard(op, result);\n }\n return { results };\n });\n },\n } satisfies DBOps & Record<string, unknown>;\n\n return ops;\n}\n\n/** The schema whose table names the typed `.tables` surface is built from —\n * and, per table, whose columns the vector transform reads. */\nlet currentSchema: {\n tables?: Record<string, { name?: string; columns?: Record<string, unknown> }>;\n} = {};\n\n/**\n * Install the project's declarations. Called once at boot.\n *\n * It takes the SET, because a project declares one schema PER FILE. The tables\n * are flattened under this system's one key convention — `public` bare,\n * anything else `schema.table` — so the key the wire carries and the key the\n * runtime looks up are the same string. A second convention here would be a\n * second answer to \"which table is this\", and the answers would diverge on the\n * day one of them learned something.\n */\nexport function setSchema(schemas: readonly unknown[]): void {\n // Yeni şema kurulumu yeni bir bağlanma demektir: vector extension'ının\n // şeması da yeniden çözülür (review I3 — iki DB'li süreçte bayat cache,\n // public↔extensions ikiliğini sessizce yanlış tarafa kilitlerdi).\n cachedVectorSchema = null;\n cachedTrgmSchema = null;\n const tables: NonNullable<typeof currentSchema.tables> = {};\n for (const entry of schemas) {\n const mod = entry as { default?: unknown } | undefined;\n const def = ((mod && \"default\" in mod ? mod.default : mod) ?? {}) as {\n name?: string;\n tables?: Record<string, { name?: string; columns?: Record<string, unknown> }>;\n };\n const schemaName = def.name ?? \"public\";\n for (const [key, table] of Object.entries(def.tables ?? {})) {\n tables[qualifiedTableKey(schemaName, table.name ?? key)] = table;\n }\n }\n currentSchema = { tables };\n}\n\n/**\n * public collapses to the bare name; every other schema is written out.\n *\n * This is the SAME rule `qualifyTableKey` states on the Go side, and it has to\n * be: the key a declaration produces, the key the wire carries and the key the\n * runtime looks up are one string, or they are three chances to disagree.\n */\nfunction qualifiedTableKey(schema: string, table: string): string {\n return schema === \"\" || schema === \"public\" ? table : `${schema}.${table}`;\n}\n\n/**\n * Merge the typed `.tables` accessor onto a raw op surface.\n *\n * Mirrors what the pod runtime does, including the recursive application to the\n * transaction callback: without it `tx.tables.rooms.insert(...)` throws\n * \"Cannot read properties of undefined\".\n */\nexport function withTables<T extends ReturnType<typeof createOps>>(\n ops: T,\n schema: { tables?: Record<string, { name?: string }> } = currentSchema,\n): T & { tables: Record<string, unknown>; schema: (name: string) => { tables: Record<string, unknown> } } {\n // THE KEY IS WHAT TRAVELS, not `def.name`. A bare name cannot say which\n // schema it lives in, and two schemas may declare the same table name —\n // `public.invoices` and `billing.invoices` are different tables.\n const bind = (key: string): Record<string, unknown> => ({\n insert: (data: Row) => ops.insert(key, data),\n update: (id: string, data: Row) => ops.update(key, id, data),\n delete: (id: string) => ops.delete(key, id),\n findById: (id: string) => ops.findById(key, id),\n findMany: (query?: Row, opts?: FindManyOptions) => ops.findMany(key, query ?? {}, opts),\n upsert: (data: Row, opts: { onConflict: readonly string[] }) => ops.upsert(key, data, opts),\n });\n\n // `Database.tables` is PUBLIC's, and only public's. One flat namespace would\n // make `tables.invoices` resolve by declaration order; the bare name is\n // always public's and everything else is asked for by schema.\n const tables: Record<string, unknown> = {};\n for (const key of Object.keys(schema.tables ?? {})) {\n if (!key.includes(\".\")) tables[key] = bind(key);\n }\n\n const schemaOf = (name: string): { tables: Record<string, unknown> } => {\n const out: Record<string, unknown> = {};\n const prefix = `${name}.`;\n for (const key of Object.keys(schema.tables ?? {})) {\n if (name === \"public\") {\n if (!key.includes(\".\")) out[key] = bind(key);\n } else if (key.startsWith(prefix)) {\n out[key.slice(prefix.length)] = bind(key);\n }\n }\n return { tables: out };\n };\n\n const base: Record<string, unknown> = Object.create(null);\n return Object.assign(base, ops, { tables, schema: schemaOf });\n}\n\n// ── the two identities one request may speak with ──────────────────────────\n\n/**\n * How long a statement on the SERVICE transaction may wait for a row lock.\n *\n * The bound exists because `asService()` runs in a SECOND transaction on a\n * SECOND connection (see {@link createRequestDatabase} for why it must). A\n * handler that writes a row through `Database.*` and then touches the same row\n * through `Database.asService()` is waiting on a lock held by a transaction\n * that cannot commit until the handler returns — a wait that can never end.\n * Unbounded, that hangs the request AND holds two pool connections for as long\n * as the process lives; a few of those and the runtime stops answering at all.\n *\n * 5s, from the two numbers around it: a healthy contended write resolves in\n * milliseconds, and the edge cuts a tenant request at 60s\n * (v2/deploy/envoy/routes.yaml, the catch-all route).\n * So the failure arrives as a legible error at the caller instead of a 504 with\n * both connections still held.\n */\nconst SERVICE_LOCK_TIMEOUT = \"5s\";\n\n/** Postgres raises 25P02 for every statement after one failed inside the same\n * transaction: `current transaction is aborted, commands ignored until end of\n * transaction block`. True, and useless on its own — it names the SYMPTOM and\n * never the write that caused it, nor the fact that a request is one\n * transaction. */\nfunction isAbortedTransaction(e: unknown): boolean {\n const message = String((e as { message?: unknown } | null)?.message ?? \"\");\n return sqlstateOf(e) === \"25P02\" || /current transaction is aborted/i.test(message);\n}\n\n/**\n * The five-character SQLSTATE, wherever this driver put it.\n *\n * MEASURED, not assumed (local stack, real Postgres, 2026-08-30): Bun's\n * `PostgresError` puts its OWN code in `.code` — the string\n * `\"ERR_POSTGRES_SERVER_ERROR\"` — and the SQLSTATE in `.errno`. node-postgres\n * puts the SQLSTATE in `.code`. Every check below was written against `.code`\n * alone, and its unit test built an object shaped like node-postgres, so the\n * tests were green and NONE of these diagnostics ever fired in production.\n *\n * The shape decides: a SQLSTATE is five characters of [0-9A-Z]. Anything else\n * in `.code` is the driver naming its own error, and the answer is in `.errno`.\n */\n/**\n * A bulk write must carry an actual predicate.\n *\n * COUNTING THE FILTER'S KEYS IS NOT ENOUGH, and the gap was measured: an\n * operator object with no operators in it — `{ created_at: {} }` — has one key\n * and compiles to NOTHING, so `WHERE true` reached Postgres and the statement\n * became a whole-table write. The shape that produces it is ordinary:\n *\n * const where = { created_at: {} };\n * if (from) where.created_at.gte = from; // neither set on this request\n * if (to) where.created_at.lte = to;\n *\n * So the check reads what the COMPILER produced, not what the caller passed.\n */\nfunction assertHasPredicate(whereSql: string, op: string, table: string): void {\n if (whereSql.trim().length > 0) return;\n throw new Error(\n `${op}(${table}): the filter compiled to no condition, so this would have ` +\n `written EVERY row. An empty filter — or an operator object with no ` +\n `operators in it, like { col: {} } — is refused. Name a condition.`,\n );\n}\n\nfunction sqlstateOf(e: unknown): string | undefined {\n const err = e as { code?: unknown; errno?: unknown } | null;\n const isState = (v: unknown): v is string => typeof v === \"string\" && /^[0-9A-Z]{5}$/.test(v);\n if (isState(err?.code)) return err.code;\n if (isState(err?.errno)) return err.errno;\n if (typeof err?.errno === \"number\") {\n const asText = String(err.errno);\n if (isState(asText)) return asText;\n }\n return undefined;\n}\n\n/** Postgres raises 23503 when a foreign key has nothing to point at. */\nfunction isForeignKeyViolation(e: unknown): boolean {\n return sqlstateOf(e) === \"23503\";\n}\n\n/** Postgres raises 23505 (unique_violation) when a write would duplicate a row. */\nfunction isUniqueViolation(e: unknown): boolean {\n return sqlstateOf(e) === \"23505\";\n}\n\n/**\n * The name of the unique constraint a 23505 names.\n *\n * The driver's own `constraint` field first — both pg and postgres.js copy it\n * straight out of the wire protocol's CONSTRAINT field, so it is the answer\n * whenever there is one. The message is the fallback, and the reason it is only\n * a fallback: it is prose, and prose is what this whole conversion exists to\n * stop anyone from matching on.\n *\n * \"\" when neither carries it. An empty name is the honest answer — the caller\n * sees it is not known — and it is still a typed 409, because whether the write\n * was a duplicate does not depend on knowing which constraint said so.\n */\nfunction constraintOf(e: unknown): string {\n const named = (e as { constraint?: unknown } | null)?.constraint;\n if (typeof named === \"string\" && named.length > 0) return named;\n const message = String((e as { message?: unknown } | null)?.message ?? \"\");\n return /violates unique constraint \"([^\"]+)\"/.exec(message)?.[1] ?? \"\";\n}\n\n/** Postgres raises 55P03 (lock_not_available) when `lock_timeout` fires. */\nfunction isLockTimeout(e: unknown): boolean {\n const message = String((e as { message?: unknown } | null)?.message ?? \"\");\n return sqlstateOf(e) === \"55P03\" || /lock timeout/i.test(message);\n}\n\n/**\n * Wrap a driver so a lock timeout says what actually happened.\n *\n * \"canceling statement due to lock timeout\" is true and useless: the author's\n * two surfaces are two transactions, which is the one thing the message cannot\n * tell them. Applied recursively through `savepoint`, so `transaction()` and\n * `txPlan` inside the service surface answer the same way.\n */\nfunction diagnosingDriver(sql: SqlDriver, surface: \"user\" | \"service\" = \"service\"): SqlDriver {\n const original = (e: unknown): string => String((e as { message?: unknown } | null)?.message ?? e);\n\n const explain = (e: unknown): unknown => {\n // A statement refused because an EARLIER one failed. The database names the\n // symptom; only this layer knows that a request is a single transaction and\n // that there is a way to keep writing.\n if (isAbortedTransaction(e)) {\n return new Error(\n \"This request cannot write any more: an earlier write in it failed, and a request runs in ONE \" +\n \"Postgres transaction, so every statement after the failure is refused. Nothing here is \" +\n \"retryable in place. Wrap a write you expect to fail in `Database.attempt(async (tx) => …)` — \" +\n \"it takes a SAVEPOINT, so only that write rolls back — or use \" +\n \"`Database.tables.<t>.upsert(data, { onConflict: [...] })` when the failure you were bracing \" +\n `for is a duplicate row. (${original(e)})`,\n );\n }\n // A duplicate row is the one database refusal an application ROUTINELY\n // expects, and until this branch existed the only way to act on it was to\n // match the driver's prose (\"duplicate key value violates unique\n // constraint …\") — a contract nobody signed, broken by a Postgres upgrade,\n // a locale, or a constraint rename, silently and in production. Typed here\n // instead: an HttpError, so an uncaught duplicate answers a generic 409\n // rather than 500 `internal_error`, and a caught one is branched on with\n // `e instanceof UniqueViolation && e.constraint === …`. The NAME rides the\n // object, not the response body — see `UniqueViolation` for whose it is.\n // Both surfaces convert: a duplicate is a duplicate whichever role wrote it.\n if (isUniqueViolation(e)) {\n return markEngineRaised(new UniqueViolation(constraintOf(e)));\n }\n // A foreign key with nothing to point at, seen from the SERVICE surface, is\n // usually not a broken key: it is the row this request already wrote through\n // `Database.*`, which has not committed and which the service transaction\n // cannot see. On the user surface the same code is an ordinary data error and\n // is left exactly as Postgres wrote it.\n if (surface === \"service\" && isForeignKeyViolation(e)) {\n return new Error(\n \"Database.asService() hit a foreign key with nothing to point at. It runs in its OWN \" +\n \"transaction on its OWN connection, so a row this request wrote through `Database.*` is not \" +\n \"visible to it until the request commits — and the request cannot commit until the handler \" +\n \"returns. If the row it needs is one this request just created, do both writes on ONE \" +\n `surface. (${original(e)})`,\n );\n }\n if (isLockTimeout(e)) {\n return new Error(\n \"Database.asService() waited too long for a row lock. It runs in its OWN transaction, so a \" +\n \"row this request already wrote through Database.* is locked against it until the request \" +\n \"commits — a wait that cannot end. Do that row's work on one surface or the other. \" +\n `(${original(e)})`,\n );\n }\n return e;\n };\n\n const wrapTx = (tx: SqlTx): SqlTx => ({\n async unsafe(text: string, params?: unknown[]) {\n try {\n return await tx.unsafe(text, params);\n } catch (e) {\n throw explain(e);\n }\n },\n savepoint<T>(cb: (sp: SqlTx) => Promise<T>) {\n return tx.savepoint((sp) => cb(wrapTx(sp)));\n },\n });\n\n return {\n unsafe: (text: string, params?: unknown[]) => sql.unsafe(text, params),\n begin: <T>(cb: (tx: SqlTx) => Promise<T>) => sql.begin((tx) => cb(wrapTx(tx))),\n };\n}\n\n/** The two transactions a request may hold, and the single `Database` over them. */\nexport interface RequestDatabase {\n /** What the engine injects as the request's `Database` singleton. */\n readonly client: DBClient;\n /** Commit whatever was opened. Called once, after the handler returns. */\n commit(): Promise<void>;\n /** Roll back whatever was opened. Called once, when the handler throws. */\n rollback(reason: unknown): Promise<void>;\n}\n\n/**\n * The `Database` one request sees: RLS-enforced by default, with the\n * service-role sibling behind `asService()`.\n *\n * # Why the sibling cannot ride the request's own transaction\n *\n * The role reaches Postgres ONCE, in the BEGIN's bind statement, and it is\n * transaction-scoped. So a sibling built on the same transaction runs as\n * `backend_authenticated` no matter what it is called — RLS still filters every\n * row and `asService()` silently means nothing. That is the failure mode worth\n * naming: it does not throw, it does not log, it simply returns the caller's own\n * rows where the author asked for everyone's, and a handler that trusts it\n * (`if (existing) throw new Conflict()`) makes the wrong decision on data it was\n * never shown.\n *\n * The obvious repair — re-issue `set_config('role', …)` around each service op\n * — is worse than the bug. Two statements are not one: `Promise.all([\n * Database.query(…), Database.asService().query(…) ])` interleaves them on the\n * single connection, and the user's query can execute between the service's\n * set-role and its own statement. That is RLS silently OFF on the DEFAULT path,\n * which is precisely the direction a security seam must never fail.\n *\n * So the service surface gets its own transaction, on its own connection, bound\n * to the service role at BEGIN. The identity separation is physical: no\n * statement of either surface can change what the other runs as.\n *\n * # What that costs, stated plainly\n *\n * - **One extra connection per request that uses it**, and only then: the second\n * transaction is lazy exactly like the first, so `asService()` called and\n * never used opens nothing.\n * - **Called twice, it is the same surface** — one transaction per REQUEST, not\n * per call — so a handler cannot leak connections by reaching for it in a\n * loop.\n * - **The two are not atomic with each other.** Both settle with the request\n * (commit when the handler returns, roll back when it throws), but they settle\n * as two transactions: if the second COMMIT fails, the first has already\n * landed. The request's own work commits first, so the failure that survives\n * is never \"the audit row exists and the thing it audits does not\".\n * - **They can wait on each other's locks.** Bounded in the service direction by\n * {@link SERVICE_LOCK_TIMEOUT}; in the other direction — a `Database.*` write\n * to a row `asService()` has already written — the wait is the request's own,\n * and the answer is not to write one row from both surfaces.\n *\n * # Claims travel unchanged\n *\n * The service transaction carries the SAME `request.jwt.claims` as the user's.\n * `asService()` changes what the caller may TOUCH, not who they are, so\n * `auth.uid()` still resolves inside a trigger or a column default. It is also\n * the fail-closed direction: a service role provisioned WITHOUT `BYPASSRLS`\n * (measured live on 2026-08-13, created by hand during a diagnosis) is not named\n * by any policy, so it reads zero rows instead of quietly reading everyone's.\n */\nexport function createRequestDatabase(\n sql: SqlDriver,\n identity: { role: string; serviceRole: string; claimsJson: string },\n): RequestDatabase {\n const tx = createLazyTransaction(diagnosingDriver(sql, \"user\"), identity.role, identity.claimsJson);\n\n // Opened on FIRST use and shared by every later `asService()` call.\n let serviceTx: LazyTransaction | null = null;\n let serviceClient: Omit<DBClient, \"asService\"> | null = null;\n\n const asService = (): Omit<DBClient, \"asService\"> => {\n if (serviceClient === null) {\n serviceTx = createLazyTransaction(\n diagnosingDriver(sql, \"service\"),\n identity.serviceRole,\n identity.claimsJson,\n { lockTimeout: SERVICE_LOCK_TIMEOUT },\n );\n // No `asService` on it: the type says `Omit<DBClient, \"asService\">` and so\n // does the object, so a second bypass is neither typeable nor callable.\n serviceClient = withTables(createOps(serviceTx));\n }\n return serviceClient;\n };\n\n return {\n client: Object.assign(withTables(createOps(tx)), { asService }),\n async commit(): Promise<void> {\n // The request's declared work first; see \"not atomic with each other\".\n await tx.commit();\n await serviceTx?.commit();\n },\n async rollback(reason: unknown): Promise<void> {\n await tx.rollback(reason);\n await serviceTx?.rollback(reason);\n },\n };\n}\n\n\n// ── the transaction plan executor ──────────────────────────────────────────\n//\n// The plan is a closed little language: five op kinds, equality-only filters,\n// and three value forms (a literal, a `$ref` to an earlier op's row, an\n// `$expr`). It is built by `TxPlanBuilder` in this same package, so the\n// executor's job is to run it faithfully rather than to defend against it —\n// with one exception that still matters: identifiers reach SQL as text, so\n// every table and column name goes through `quoteIdent`, exactly as the six\n// single-statement ops above do.\n\n/** Collects bound parameters so a value is never spliced into SQL text. */\nclass Args {\n readonly values: unknown[] = [];\n bind(value: unknown): string {\n this.values.push(value);\n return `$${this.values.length}`;\n }\n}\n\nfunction isRef(v: unknown): v is TxWireRef {\n return typeof v === \"object\" && v !== null && \"$ref\" in v;\n}\nfunction isExpr(v: unknown): v is TxWireExpr {\n return typeof v === \"object\" && v !== null && \"$expr\" in v;\n}\n\n/**\n * Render one value into SQL, binding whatever is data.\n *\n * `column` is only used by `inc`/`dec`, which read the column they write.\n */\nfunction renderValue(\n value: TxWireValue,\n column: string,\n args: Args,\n results: TxPlanOpResult[],\n vectorCols?: Set<string>,\n transforms?: ReturnType<typeof transformsOf>,\n): string {\n if (isRef(value)) {\n const source = results[value.$ref.op];\n const row = source?.rows[0];\n if (!row || !(value.$ref.field in row)) {\n throw Object.assign(new Error(`op ${value.$ref.op} has no column \"${value.$ref.field}\" to reference`), {\n error_code: \"tx_ref_unresolved\",\n });\n }\n return bindMaybeVector(args, column, vectorCols, row[value.$ref.field], transforms);\n }\n if (isExpr(value)) {\n const fn = value.$expr;\n if (fn.fn === \"now\") return \"now()\";\n const operator = fn.fn === \"inc\" ? \"+\" : \"-\";\n // The column is an identifier; the operand is BOUND. This is the one place\n // the tenant's digits could otherwise have reached SQL text.\n return `${quoteIdent(column)} ${operator} ${bindMaybeVector(args, column, vectorCols, fn.by, transforms)}`;\n }\n return bindMaybeVector(args, column, vectorCols, value, transforms);\n}\n\n/**\n * Render a WHERE clause.\n *\n * A null is compared with IS NULL, never `= NULL`: the latter is never true, so\n * a filter written that way silently matches nothing.\n */\nfunction renderWhere(\n where: Record<string, TxWireValue> | undefined,\n args: Args,\n results: TxPlanOpResult[],\n): string {\n const cols = Object.keys(where ?? {});\n if (cols.length === 0) return \"\";\n const terms = cols.map((c) => {\n const v = (where as Record<string, TxWireValue>)[c];\n if (v === null) return `${quoteIdent(c)} IS NULL`;\n return `${quoteIdent(c)} = ${renderValue(v, c, args, results)}`;\n });\n return ` WHERE ${terms.join(\" AND \")}`;\n}\n\n/** tx-plan bind'i (FR-008, review C2): vektör kolonuna giden number[] literal'e\n * çevrilir — düz op'lardaki asBindParams'ın plan-yolu ikizi. */\nfunction bindMaybeVector(\n args: { bind(v: unknown): string },\n column: string | undefined,\n vectorCols: Set<string> | undefined,\n value: unknown,\n transforms?: ReturnType<typeof transformsOf>,\n): string {\n if (column !== undefined && vectorCols?.has(column) && Array.isArray(value)) {\n return args.bind(toVectorLiteral(value as number[]));\n }\n // The column's `toDb`, exactly as `asBindParams` applies it on the direct\n // path. Without it the SAME value is stored differently depending on which\n // surface wrote it — `tables.x.insert({ amount: 12.5 })` writes \"12.5\" and\n // `tx.tables.x.insert({ amount: 12.5 })` writes 12.5 — and the caller cannot\n // tell them apart, because both take the transform's target type.\n const t = column !== undefined ? transforms?.get(column) : undefined;\n if (t?.toDb !== undefined && value !== null && value !== undefined) {\n return args.bind(t.toDb(value));\n }\n return args.bind(value);\n}\n\nasync function runPlanOp(\n sp: SqlTx,\n op: TxWireOp,\n results: TxPlanOpResult[],\n): Promise<Row[]> {\n const opVectorCols = vectorColumnsOf(currentSchema, op.table);\n const opTransforms = transformsOf(currentSchema, op.table);\n const args = new Args();\n const table = quoteIdent(op.table);\n let sql: string;\n\n switch (op.op) {\n case \"insert\": {\n const cols = Object.keys(op.values ?? {});\n const rendered = cols.map((c) => renderValue((op.values as Record<string, TxWireValue>)[c], c, args, results, opVectorCols, opTransforms));\n sql = cols.length\n ? `INSERT INTO ${table} (${cols.map(quoteIdent).join(\", \")}) VALUES (${rendered.join(\", \")}) RETURNING *`\n : `INSERT INTO ${table} DEFAULT VALUES RETURNING *`;\n break;\n }\n case \"upsert\": {\n const cols = Object.keys(op.values ?? {});\n const conflict = op.onConflict ?? [];\n if (cols.length === 0 || conflict.length === 0) {\n throw Object.assign(new Error(`upsert on ${op.table} needs columns and onConflict`), {\n error_code: \"tx_bad_upsert\",\n });\n }\n const rendered = cols.map((c) =>\n renderValue((op.values as Record<string, TxWireValue>)[c], c, args, results, opVectorCols, opTransforms),\n );\n sql =\n `INSERT INTO ${table} (${cols.map(quoteIdent).join(\", \")}) VALUES (${rendered.join(\", \")}) ` +\n `${onConflictTail(cols, conflict, \"update\")} RETURNING *`;\n break;\n }\n case \"insertMany\": {\n const rows = (op.rows ?? []) as Record<string, TxWireValue>[];\n if (rows.length === 0 || !rows[0]) return [];\n // The column list comes from the FIRST row and every row is rendered\n // against it, so a row with a stray extra key cannot shift the columns of\n // the statement it shares.\n const cols = Object.keys(rows[0]);\n const tuples = rows.map(\n (r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols, opTransforms)).join(\", \")})`,\n );\n // ON CONFLICT only when the plan asked for it: an insertMany with no\n // options must render byte-identically to what it rendered before the\n // option existed.\n //\n // DO NOTHING and RETURNING: Postgres returns only the rows it WROTE, so a\n // collided row is simply absent from the result. That is the contract the\n // caller is told about, not a rough edge.\n const conflictCols = op.onConflict ?? [];\n const tail =\n op.action !== undefined && conflictCols.length > 0\n ? ` ${onConflictTail(cols, conflictCols, op.action)}`\n : \"\";\n sql = `INSERT INTO ${table} (${cols.map(quoteIdent).join(\", \")}) VALUES ${tuples.join(\", \")}${tail} RETURNING *`;\n break;\n }\n case \"update\": {\n const cols = Object.keys(op.set ?? {});\n if (cols.length === 0) throw new Error(`update ${op.table}: nothing to set`);\n const assignments = cols.map(\n (c) => `${quoteIdent(c)} = ${renderValue((op.set as Record<string, TxWireValue>)[c], c, args, results, opVectorCols, opTransforms)}`,\n );\n sql = `UPDATE ${table} SET ${assignments.join(\", \")}${renderWhere(op.where, args, results)} RETURNING *`;\n break;\n }\n case \"delete\": {\n sql = `DELETE FROM ${table}${renderWhere(op.where, args, results)} RETURNING *`;\n break;\n }\n case \"select\": {\n const limit = op.limit !== undefined ? ` LIMIT ${Number(op.limit)}` : \"\";\n const lock = op.lock === \"update\" ? \" FOR UPDATE\" : \"\";\n sql = `SELECT * FROM ${table}${renderWhere(op.where, args, results)}${limit}${lock}`;\n break;\n }\n default:\n // Loudly, rather than rendering something for an op nobody wrote.\n throw new Error(`unknown operation \"${String((op as { op: string }).op)}\" in a transaction plan`);\n }\n\n return (await sp.unsafe(sql, args.values)) as Row[];\n}\n\n/**\n * Enforce the author's declared expectation.\n *\n * The Error the author passed never travels: the plan carries a SLOT index and\n * the SDK maps it back. So a failure here throws the shape `runTxPlan` знает —\n * `{error_code: \"tx_guard_failed\", slot}` — and the savepoint unwinds.\n */\nfunction assertGuard(op: TxWireOp, result: TxPlanOpResult): void {\n const guard = op.guard;\n if (!guard) return;\n const n = result.rows.length;\n const ok =\n guard.kind === \"one\"\n ? n === 1\n : guard.kind === \"none\"\n ? n === 0\n : guard.kind === \"atLeast\"\n ? n >= guard.n\n : n <= guard.n;\n if (ok) return;\n throw Object.assign(new Error(`transaction expectation failed: ${guard.kind} (${n} row(s))`), {\n error_code: \"tx_guard_failed\",\n slot: guard.slot,\n });\n}\n","// The decorator registry — the single plain-data store the method + parameter\n// decorators write into, and the deploy/dispatch pipeline reads back. No\n// `reflect-metadata`, no `emitDecoratorMetadata`: the registry is built from the\n// decorator arguments + the parameter INDEX that esbuild/tsc preserve for legacy\n// parameter decorators (verified — see the design spec §0/§4.1).\n//\n// A controller class carries its route metadata on a symbol-keyed static\n// property (`ROUTES`). `@Get`/`@Post`/… append a {@link RouteMeta} entry;\n// `@Body`/`@User`/… append a {@link ParamMeta} entry onto the route for the\n// method they decorate. Because parameter decorators run BEFORE the method\n// decorator for the same member (TS evaluates innermost-first, params before the\n// method), the route entry may not exist yet when a param decorator fires — so\n// param metadata is buffered per method name and merged when the method\n// decorator creates the route entry.\nimport type { AuthSpec, RateLimitConfig } from \"../endpoint.js\";\nimport type { UploadConfig } from \"./upload.js\";\nimport type { SseConfig } from \"./sse.js\";\nimport type { ZodTypeAny } from \"zod\";\n\n/** The HTTP verbs a route may declare, upper-cased (the runtime router +\n * OpenAPI lower-case on their own). */\nexport type HttpMethodUpper = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"QUERY\";\n\n/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */\nexport interface RouteOptions {\n /** OVERRIDES the controller-level default auth for this one route. */\n auth?: AuthSpec;\n /** Per-route rate limit. */\n rateLimit?: RateLimitConfig;\n /** Direct-storage upload config — present ONLY on `@Upload` routes (the\n * `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a\n * route as an upload route through the whole pipeline (registry → flatten →\n * openapi → codegen). The bytes go client→storage directly; the method body\n * runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */\n uploadConfig?: UploadConfig;\n /** Streaming config — present ONLY on `@Sse` routes (the `@Get`/`@Post`/…\n * decorators never set it). Its presence is what MARKS a route as a streaming\n * route through the whole pipeline (registry → flatten → openapi → codegen),\n * exactly as `uploadConfig` does for uploads — never a special HTTP verb. An\n * `@Sse` route registers POST like any input-bearing route, so the verb cannot\n * carry the distinction. See {@link SseConfig} (decorators/sse.ts). */\n sseConfig?: SseConfig;\n}\n\n/** The kind of value a parameter decorator injects. Drives both dispatch\n * (which request slice to inject) and codegen (which OpenAPI parameter source a\n * schema-bearing kind maps to). */\nexport type ParamKind =\n | \"body\"\n | \"query\"\n | \"param\"\n | \"headers\"\n | \"user\"\n | \"optionalUser\"\n | \"client\"\n | \"requestId\"\n | \"traceId\"\n | \"req\"\n // `@UploadedObject()` — injects the uploaded object (completion input) on an\n // `@Upload` route. No schema (the shape is the fixed UploadedObject type).\n | \"uploadedObject\"\n // `@SseOut()` — injects the frame writer on an `@Sse` route. No schema (the\n // shape is the fixed SseWriter type).\n | \"sseOut\"\n // `@Signal()` — injects the request's AbortSignal, which aborts when the\n // client disconnects. No schema. NOT derivable from `@Req()`: PBRequest\n // carries only request-scoped data and has no signal (endpoint.ts:358-363).\n | \"signal\";\n\n/** One parameter decorator's recorded metadata. `index` is the parameter\n * position esbuild/tsc preserve; `schema` is present for the schema-bearing\n * kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */\nexport interface ParamMeta {\n index: number;\n kind: ParamKind;\n /** Zod schema for `body`/`query`/`headers` (validation + codegen source). */\n schema?: ZodTypeAny;\n /** Path-param name for `@Param(\"id\")`. */\n name?: string;\n}\n\n/** One inferred throw site: the error CLASS name (e.g. \"TodoLocked\") and its\n * wire code (e.g. \"todo_locked\"). `status`, `hasData`, and the data JSON schema\n * are NOT carried here — they resolve from the error registry by `code` at\n * extract/openapi time (single source of truth). */\nexport interface ThrowDescriptor {\n name: string;\n code: string;\n}\n\n/** One route's recorded metadata: the verb + subpath + method name + options,\n * the ordered parameter metas, and the resolved return schema (injected by the\n * codegen step — see `returnSchema`). */\nexport interface RouteMeta {\n method: HttpMethodUpper;\n subpath: string;\n fnName: string;\n options: RouteOptions;\n params: ParamMeta[];\n /** Response schema for the route, if any. Derived from the method's RETURN\n * TYPE by codegen and written here via `recordReturn` (a generated top-level\n * IIFE injected per controller), not by an author-written decorator. */\n returnSchema?: ZodTypeAny;\n /** Error classes this route can throw, if inferred. Derived from the method\n * body + service call graph by the deploy stager's throw analysis and written\n * here via `recordThrows` (a generated top-level IIFE injected per controller,\n * the `recordReturn` twin), not by an author-written decorator. */\n throws?: ThrowDescriptor[];\n}\n\n/** Symbol the route metadata list is stored under on a controller class. Using\n * a symbol (not a string key) keeps it off the public structural surface and\n * avoids any chance of an authored property collision. */\nexport const ROUTES: unique symbol = Symbol.for(\"palbase.backend.routes\");\n\n/** Symbol the per-method buffered parameter metas are stored under while a class\n * is being decorated. Parameter decorators fire before the method decorator, so\n * they buffer here keyed by method name; the method decorator drains the buffer\n * into the route entry it creates. */\nconst PARAM_BUFFER: unique symbol = Symbol.for(\"palbase.backend.paramBuffer\");\n\n/** A room's own slots. Rooms are NOT routes — no verb, no path, no params — so\n * they get their own carrier slots instead of being squeezed into RouteMeta. */\nconst ROOM: unique symbol = Symbol.for(\"palbase.backend.room\");\nconst ROOM_HOOKS: unique symbol = Symbol.for(\"palbase.backend.roomHooks\");\n\n/** Symbol the per-method buffered return-type schemas are stored under while a\n * class's registry is being populated. The codegen-injected `recordReturn` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordReturn`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its return schema — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst RETURN_BUFFER: unique symbol = Symbol.for(\"palbase.backend.returnBuffer\");\n\n/** Symbol the per-method buffered throw descriptors are stored under while a\n * class's registry is being populated. The stager-injected `recordThrows` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordThrows`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its throw descriptors — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst THROWS_BUFFER: unique symbol = Symbol.for(\"palbase.backend.throwsBuffer\");\n\n/** A class constructor carrying the symbol-keyed registry slots. We type the\n * registry-bearing class as this so the decorators can read/write the slots\n * without `any` — a plain `Function` does not carry index signatures. */\ninterface RegistryCarrier {\n [ROUTES]?: RouteMeta[];\n [PARAM_BUFFER]?: Record<string, ParamMeta[]>;\n [ROOM]?: RoomMeta;\n [ROOM_HOOKS]?: RoomBuffer;\n [RETURN_BUFFER]?: Record<string, ZodTypeAny>;\n [THROWS_BUFFER]?: Record<string, ThrowDescriptor[]>;\n}\n\n/** Coerce a decorated target (class constructor or its prototype) into the\n * registry carrier that owns the slots. Method/param decorators receive the\n * PROTOTYPE as their target; the class decorator receives the constructor. We\n * always anchor the registry on the CONSTRUCTOR so `getRoutes(ctor)` finds it. */\nfunction carrierOf(target: object): RegistryCarrier {\n // For instance-member decorators, `target` is the prototype; its `.constructor`\n // is the class. For a static member or the class decorator, `target` is the\n // constructor already. Resolve to the constructor either way.\n const ctor =\n typeof target === \"function\"\n ? (target as unknown as RegistryCarrier)\n : (((target as { constructor?: unknown }).constructor ??\n target) as unknown as RegistryCarrier);\n return ctor;\n}\n\n/** Get (creating if absent) the own route list for a class constructor. Own —\n * not inherited — so a subclass does not mutate its base's routes. */\nfunction ownRoutes(carrier: RegistryCarrier): RouteMeta[] {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROUTES)) {\n carrier[ROUTES] = [];\n }\n return carrier[ROUTES] as RouteMeta[];\n}\n\n/** Get (creating if absent) the own per-method param buffer for a class. */\nfunction ownParamBuffer(carrier: RegistryCarrier): Record<string, ParamMeta[]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, PARAM_BUFFER)) {\n carrier[PARAM_BUFFER] = {};\n }\n return carrier[PARAM_BUFFER] as Record<string, ParamMeta[]>;\n}\n\n/** Record a route (called by the method decorators). Drains any parameter\n * metas already buffered for `fnName` into the new route entry, then sorts them\n * by parameter index so dispatch can inject positionally. */\nexport function recordRoute(\n target: object,\n fnName: string,\n method: HttpMethodUpper,\n subpath: string,\n options: RouteOptions,\n): void {\n const carrier = carrierOf(target);\n const routes = ownRoutes(carrier);\n const buffer = ownParamBuffer(carrier);\n const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);\n const route: RouteMeta = { method, subpath, fnName, options, params };\n // Drain a buffered return schema (the recordReturn-ran-first ordering) so the\n // route entry is complete the moment it's created — a raw-symbol consumer\n // (the runtime extractor/worker) sees the return schema without re-merging.\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer && returnBuffer[fnName] !== undefined) {\n route.returnSchema = returnBuffer[fnName];\n }\n // Same drain for buffered throw descriptors (the recordThrows-ran-first\n // ordering) — the route entry is complete the moment it's created.\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer && throwsBuffer[fnName] !== undefined) {\n route.throws = throwsBuffer[fnName];\n }\n routes.push(route);\n}\n\n/** Record one parameter decorator (called by `@Body`/`@User`/…). Buffers per\n * method name; the method decorator merges the buffer into the route entry. If\n * the route already exists (method decorator ran first — TS does evaluate the\n * method decorator AFTER its parameter decorators, but we stay order-robust),\n * the meta is also appended directly so neither ordering loses it. */\nexport function recordParam(target: object, fnName: string, meta: ParamMeta): void {\n const carrier = carrierOf(target);\n const buffer = ownParamBuffer(carrier);\n (buffer[fnName] ??= []).push(meta);\n\n // Order-robust: if the route already exists, merge in place + keep sorted.\n const routes = carrier[ROUTES];\n if (routes) {\n const route = routes.find((r) => r.fnName === fnName);\n if (route) {\n route.params.push(meta);\n route.params.sort((a, b) => a.index - b.index);\n }\n }\n}\n\n/** Attach a return schema to the route for `fnName` (called by the codegen\n * injection that reads the method's return type). If the route does not exist\n * yet, the schema is buffered (RETURN_BUFFER) and drained into the route by\n * `recordRoute` when the method decorator runs. */\nexport function recordReturn(target: object, fnName: string, schema: ZodTypeAny): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.returnSchema = schema;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, RETURN_BUFFER)) {\n carrier[RETURN_BUFFER] = {};\n }\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) returnBuffer[fnName] = schema;\n}\n\n/** Attach the inferred throw descriptors to the route for `fnName` (called by\n * the stager-injected IIFE that carries the throw analysis result — the\n * `recordReturn` twin). If the route does not exist yet, the descriptors are\n * buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the\n * method decorator runs. */\nexport function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.throws = throws;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, THROWS_BUFFER)) {\n carrier[THROWS_BUFFER] = {};\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) throwsBuffer[fnName] = throws;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas + throw descriptors (for the\n * recordReturn/recordThrows-runs-before orderings) and returns a defensive copy\n * so callers cannot mutate the registry.\n */\nexport function getRoutes(ctor: object): RouteMeta[] {\n const carrier = carrierOf(ctor);\n const routes = carrier[ROUTES] ?? [];\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) {\n for (const route of routes) {\n const buffered = returnBuffer[route.fnName];\n if (buffered && route.returnSchema === undefined) {\n route.returnSchema = buffered;\n }\n }\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) {\n for (const route of routes) {\n const buffered = throwsBuffer[route.fnName];\n if (buffered && route.throws === undefined) {\n route.throws = buffered;\n }\n }\n }\n return routes.map((r) => ({\n ...r,\n params: r.params.slice(),\n ...(r.throws !== undefined ? { throws: r.throws.slice() } : {}),\n }));\n}\n\n// ── rooms ───────────────────────────────────────────────────────────────────\n\n/** Which lifecycle hook a method is bound to. */\nexport type RoomHook = \"authorize\" | \"first\" | \"join\" | \"leave\" | \"empty\";\n\nexport interface RoomMessageMeta {\n fnName: string;\n schema: ZodTypeAny;\n}\n\nexport interface RoomMeta {\n pattern: string;\n events: Record<string, ZodTypeAny>;\n graceMs: number;\n /** hook → the method name that implements it. */\n hooks: Partial<Record<RoomHook, string>>;\n /** inbound message name → its method and payload schema. */\n messages: Record<string, RoomMessageMeta>;\n}\n\ninterface RoomBuffer {\n hooks: Partial<Record<RoomHook, string>>;\n messages: Record<string, RoomMessageMeta>;\n}\n\n/** Get (creating if absent) the own hook buffer. Own — not inherited — so a\n * subclass never mutates its base's hooks. Member decorators fill this BEFORE\n * the class decorator runs; controller.ts:203 depends on the same ordering. */\nfunction ownRoomBuffer(carrier: RegistryCarrier): RoomBuffer {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROOM_HOOKS)) {\n carrier[ROOM_HOOKS] = { hooks: {}, messages: {} };\n }\n return carrier[ROOM_HOOKS] as RoomBuffer;\n}\n\n/** Record a lifecycle hook. A second method for the same hook is refused: two\n * answers to \"who handles this\" cannot be resolved at dispatch, and silently\n * keeping one is how a hook stops running without anyone being told. */\nexport function recordRoomHook(target: object, hook: RoomHook, fnName: string): void {\n const buffer = ownRoomBuffer(carrierOf(target));\n const existing = buffer.hooks[hook];\n if (existing !== undefined && existing !== fnName) {\n const label = `On${hook.charAt(0).toUpperCase()}${hook.slice(1)}`;\n throw new Error(\n `@${label} is declared twice in one room (${existing} and ${fnName}). ` +\n `A room has one of each hook.`,\n );\n }\n buffer.hooks[hook] = fnName;\n}\n\n/** Record an inbound message handler. */\nexport function recordRoomMessage(\n target: object,\n name: string,\n fnName: string,\n schema: ZodTypeAny,\n): void {\n const buffer = ownRoomBuffer(carrierOf(target));\n const existing = buffer.messages[name];\n if (existing !== undefined && existing.fnName !== fnName) {\n throw new Error(\n `@OnMessage(\"${name}\") is declared twice in one room (${existing.fnName} and ${fnName}).`,\n );\n }\n buffer.messages[name] = { fnName, schema };\n}\n\n/** Record the room itself (called by the class decorator), draining the buffer\n * the member decorators already filled. */\nexport function recordRoom(\n ctor: object,\n meta: Omit<RoomMeta, \"hooks\" | \"messages\">,\n): void {\n const carrier = carrierOf(ctor);\n const buffer = ownRoomBuffer(carrier);\n carrier[ROOM] = { ...meta, hooks: buffer.hooks, messages: buffer.messages };\n // AND into the shared class registry, the same slot @Controller pushes to.\n //\n // Without this line a room compiles, bundles and deploys, and is never called:\n // the bundler's entry exports `SDK.getRegisteredControllers()` and the runtime\n // reads its rooms out of THAT list (server.ts's `collectRooms`). A room that\n // only marks its own constructor is a room nobody can find — measured, on the\n // fixture, at the last gate before it would have worked.\n //\n // Rooms and controllers share one list because they are one thing to the\n // loader: classes a bundle declared. What each IS is decided by the marker it\n // carries, never by which list it arrived in.\n const g = globalThis as unknown as Record<symbol, unknown[] | undefined>;\n const REGISTRY = Symbol.for(\"palbase.backend.allControllers\");\n const all = (g[REGISTRY] ??= []);\n if (!all.includes(ctor)) all.push(ctor);\n}\n\n/** The room a class declares, or undefined. A class with no `@Room` is not a\n * room — the marker is the CONFIG's presence, never a name or a base class\n * (the rule upload.ts:13-16 states for uploads). */\nexport function getRoom(ctor: object): RoomMeta | undefined {\n const carrier = carrierOf(ctor);\n if (!Object.prototype.hasOwnProperty.call(carrier, ROOM)) return undefined;\n return carrier[ROOM] as RoomMeta;\n}\n","// `@Controller(basePath, options?)` — the class decorator that marks a class as\n// a Palbase backend controller. It stamps a non-enumerable `__palbase`\n// discriminant + the resolved controller metadata onto the class so the\n// deploy/dispatch pipeline (and `isController`/`resolveController`) can detect\n// and read it without `reflect-metadata`.\nimport type { AuthSpec } from \"../endpoint.js\";\nimport { getRoutes } from \"./registry.js\";\n\n/** The controller metadata stamped onto a `@Controller`-decorated class. The\n * default export of a `controllers/*.controller.ts` file resolves to this via\n * {@link resolveController}. */\nexport interface ControllerMeta {\n /** Discriminant the runtime + tooling read. */\n readonly __palbase: \"controller\";\n /** The base path every route in this controller mounts under (e.g. \"/todos\"). */\n basePath: string;\n /** Controller-level default auth, applied to routes that don't set their own\n * (`@Get(\"/x\", { auth })` overrides this). `undefined` ⇒ the application\n * default ({@link defineDefaultAuth}), and secure-by-default below that —\n * see {@link resolveEffectiveAuth} for the whole cascade. */\n defaultAuth?: AuthSpec;\n}\n\n/** Options accepted by `@Controller`. */\nexport interface ControllerOptions {\n /** Default auth for ALL routes in this controller (route-level overrides;\n * omitting it falls through to the application default declared with\n * {@link defineDefaultAuth}). */\n auth?: AuthSpec;\n}\n\n/** Symbol the controller metadata is stamped under. Symbol-keyed (not a string\n * property) so it never collides with an authored member and stays off the\n * structural surface. */\nexport const CONTROLLER_META: unique symbol = Symbol.for(\"palbase.backend.controllerMeta\");\n\n/**\n * Every class `@Controller` has decorated, in decoration order.\n *\n * This is what lets a controller file need no export at all: importing the file\n * runs the decorator, the decorator records the class here, and the runtime\n * reads the list. Without it the only handle on a class is its export name, so\n * every controller had to be exported AND named in a generated entry — the\n * ceremony NestJS still charges (`export class` PLUS\n * `@Module({controllers:[…]})`).\n *\n * Keyed on a well-known Symbol against globalThis rather than held in a module\n * variable, because a deployed bundle inlines its own copy of this package: two\n * copies would keep two lists, and the runtime would read the empty one. The\n * same hazard `runtimeHooks` exists for, closed the same way — one shared slot.\n */\nconst REGISTRY: unique symbol = Symbol.for(\"palbase.backend.allControllers\") as never;\n\nfunction registry(): unknown[] {\n const g = globalThis as unknown as Record<symbol, unknown[] | undefined>;\n const existing = g[REGISTRY];\n if (existing) return existing;\n const fresh: unknown[] = [];\n g[REGISTRY] = fresh;\n return fresh;\n}\n\n/**\n * The controller classes this process has loaded, in decoration order.\n *\n * Decoration order is import order, which the bundler fixes by sorting the\n * files it emits imports for — so two builds of one tree produce the same\n * route table, and route precedence is not a function of module-resolution\n * accidents.\n */\nexport function getRegisteredControllers(): readonly unknown[] {\n return registry().slice();\n}\n\n/** Empty the registry. For tests, which load controllers repeatedly. */\nexport function __resetRegisteredControllers(): void {\n registry().length = 0;\n}\n\n/**\n * The APPLICATION-level default auth.\n *\n * Held on globalThis under a well-known Symbol for exactly the reason\n * {@link REGISTRY} is: a deployed bundle inlines its own copy of this package,\n * and two copies keeping two defaults is how a security setting silently\n * becomes two different settings.\n */\nconst APP_DEFAULT_AUTH: unique symbol = Symbol.for(\"palbase.backend.appDefaultAuth\") as never;\n\nfunction appAuthSlot(): Record<symbol, AuthSpec | undefined> {\n return globalThis as unknown as Record<symbol, AuthSpec | undefined>;\n}\n\n/**\n * Declare the default auth for EVERY route in the application — the ring the\n * cascade consults when neither the route nor its controller says anything.\n *\n * The measured problem it removes: `auth: { verifiedEmail: true }` repeated by\n * hand on ten `@Controller`s. A security setting that must be repeated is a\n * security setting that will be forgotten — the eleventh controller opens the\n * door and nothing says so.\n *\n * Call it at MODULE SCOPE in a file the application imports (the controllers'\n * own barrel, or a module a controller imports). The cascade reads this slot\n * when the route table is built and when the spec is emitted — both of which\n * run after module loading — so declaration order does not matter, but being\n * imported at all does.\n *\n * @example\n * defineDefaultAuth({ verifiedEmail: true }); // every route, unless it says otherwise\n */\nexport function defineDefaultAuth(auth: AuthSpec): void {\n appAuthSlot()[APP_DEFAULT_AUTH] = auth;\n}\n\n/** The declared application default, or `undefined` when none was declared. */\nexport function getDefaultAuth(): AuthSpec | undefined {\n return appAuthSlot()[APP_DEFAULT_AUTH];\n}\n\n/** Clear the application default. For tests, which declare it repeatedly. */\nexport function __resetDefaultAuth(): void {\n delete appAuthSlot()[APP_DEFAULT_AUTH];\n}\n\n/**\n * THE auth cascade: route → controller → application → `true`.\n *\n * One function, every caller — the route table (`engine/router.ts`) and the\n * spec emitter (`openapi/controllers.ts`) ASK for the answer instead of\n * spelling the chain themselves. Two hand-written copies of a cascade is how\n * the build-time answer and the runtime answer come to disagree about who may\n * call an endpoint, and the disagreement shows up as an open door.\n *\n * The terminal `true` is secure-by-default and is load-bearing: a route that\n * declared nothing, under a controller that declared nothing, in an\n * application that declared nothing, is CLOSED.\n */\nexport function resolveEffectiveAuth(\n routeAuth: AuthSpec | undefined,\n controllerAuth: AuthSpec | undefined,\n): AuthSpec {\n return routeAuth ?? controllerAuth ?? getDefaultAuth() ?? true;\n}\n\n/** A class carrying the stamped controller metadata + discriminant. */\ninterface ControllerCarrier {\n __palbase?: \"controller\";\n [CONTROLLER_META]?: ControllerMeta;\n}\n\n/** The one path segment the platform owns. The isolate matches\n * `^/webhooks/([^/]+)$` on the raw request path BEFORE controller dispatch, so\n * anything a controller resolves to under it answers `404 webhook_not_found`\n * and never runs. */\nconst RESERVED_FIRST_SEGMENT = \"webhooks\";\n\n/**\n * Throw if `path` resolves under the reserved segment. Segments are compared the\n * way the isolate compares them — `split(\"/\").filter(Boolean)` — NOT by string\n * prefix, because empty segments collapse there: `@Controller(\"/\")` +\n * `@Post(\"/webhooks/x\")` composes to `//webhooks/x`, which the isolate serves as\n * `/webhooks/x`. A prefix check reads that as safe; the segment check does not.\n * `/webhooksy` stays allowed for the same reason — it is a different segment.\n *\n * Every verb is refused, not just the POST the isolate currently intercepts: the\n * reservation is of the URL namespace, so a `@Get(\"/webhooks/x\")` that happens\n * to work today would be silently shadowed the moment the isolate's method gate\n * widens. Refusing at build is recoverable; discovering it as a 404 is not.\n */\nfunction assertNotReserved(path: string, subject: string): void {\n const [first] = path.split(\"/\").filter(Boolean);\n if (first === RESERVED_FIRST_SEGMENT) {\n throw new Error(\n `${subject} resolves under the reserved /${RESERVED_FIRST_SEGMENT} path — ` +\n \"inbound webhooks are served there and would shadow this route\",\n );\n }\n}\n\n/**\n * Mark a class as a Palbase backend controller. `basePath` is the mount path\n * for every route the class declares; `options.auth` sets the controller-level\n * default auth (a route's own `auth` overrides it; absent ⇒ secure-by-default).\n *\n * @example\n * \\@Controller(\"/todos\", { auth: false })\n * export class TodosController {\n * \\@Get(\"\") list(\\@QueryParams(ListTodosQuery) q: ListTodosQuery): TodoSchema[] { … }\n * }\n */\nexport function Controller(basePath: string, options: ControllerOptions = {}) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n // /webhooks/* belongs to the platform: the isolate matches the inbound\n // webhook route before controller dispatch, so a controller mounted here\n // would never receive a request. Silent shadowing is the failure mode this\n // whole change exists to remove, so refuse it at build.\n //\n // The COMPOSED path is what gets shadowed, not the base path. `@Controller(\"\")`\n // and `@Controller(\"/\")` both pass a base-path-only check while a\n // `@Post(\"/webhooks/stripe\")` inside them resolves to exactly the path the\n // isolate intercepts. Method decorators run BEFORE the class decorator (TS\n // evaluates members first), so every route this class declares is already in\n // the registry here — which is why the composed check can live at this one\n // seam instead of on the dispatch read path. The `@Controller(\"\") +\n // @Post(\"/webhooks/stripe\")` test is the lock on that ordering: if it ever\n // stopped holding, that test goes red.\n assertNotReserved(basePath, `@Controller(\"${basePath}\")`);\n for (const route of getRoutes(ctor)) {\n assertNotReserved(\n `${basePath}${route.subpath}`,\n `@${route.method}(\"${route.subpath}\") in @Controller(\"${basePath}\")`,\n );\n }\n\n const carrier = ctor as unknown as ControllerCarrier;\n const meta: ControllerMeta = {\n __palbase: \"controller\",\n basePath,\n ...(options.auth !== undefined ? { defaultAuth: options.auth } : {}),\n };\n // Non-enumerable so it doesn't leak onto instances / structural checks.\n Object.defineProperty(carrier, CONTROLLER_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // The bare `__palbase` discriminant is the cheap detection marker the\n // runtime/extractor checks; keep it readable but non-enumerable.\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"controller\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // Record it, so importing the file is enough and exporting is optional.\n // Guarded against a double-decoration re-entering the same class twice.\n const all = registry();\n if (!all.includes(ctor)) all.push(ctor);\n return ctor;\n };\n}\n\n/** True when `value` is a `@Controller`-decorated class (cheap discriminant\n * check). Accepts the class constructor (the default export of a controller\n * file). */\nexport function isController(value: unknown): boolean {\n if (typeof value !== \"function\" && (typeof value !== \"object\" || value === null)) {\n return false;\n }\n const carrier = value as ControllerCarrier;\n return carrier.__palbase === \"controller\" && carrier[CONTROLLER_META] !== undefined;\n}\n\n/** Read the resolved controller metadata off a `@Controller`-decorated class.\n * Throws if the class was not decorated — callers should gate with\n * {@link isController} first (the loader does). */\nexport function resolveController(ctor: unknown): ControllerMeta {\n if (typeof ctor !== \"function\" && (typeof ctor !== \"object\" || ctor === null)) {\n throw new TypeError(\"resolveController: value is not a class\");\n }\n const meta = (ctor as ControllerCarrier)[CONTROLLER_META];\n if (!meta) {\n throw new TypeError(\n \"resolveController: class is not a @Controller — every controller file must `export default` a @Controller-decorated class\",\n );\n }\n return meta;\n}\n\n/**\n * A class the runtime constructs takes NO constructor parameters.\n *\n * ONE writer, four callers (controller, hook, job, webhook) and the build's own\n * check. Four hand-written copies of this message is how the four come to\n * disagree about what is refused — and the disagreement is silent, because a\n * class that slips past one of them still ends up with `undefined` fields.\n *\n * Why it is refused rather than injected: there is no container. The parameter\n * would arrive `undefined`, the code would compile, deploy, and fail at the\n * first request that touches the field — the most expensive place to learn it.\n */\nexport function assertZeroArgConstructor(Ctrl: unknown, kind: string): void {\n const arity = (Ctrl as { length?: number }).length ?? 0;\n if (arity === 0) return;\n const name = (Ctrl as { name?: string }).name ?? \"<anonymous>\";\n throw new Error(\n `${kind} ${name} declares a constructor with ${arity} parameter(s). ` +\n `A ${kind} is constructed by the runtime with a zero-argument constructor — ` +\n `there is no injector to supply them, so every parameter would arrive as ` +\n `undefined. Hold the dependency as a module-level singleton the ${kind} ` +\n \"imports (`const repo = makeRepo()` beside the class), and construct the \" +\n \"service directly in tests (e.g. `new TodoService(fakeDatabase().db)`).\",\n );\n}\n","/**\n * engine/router.ts — the route table, built from the SDK's own registry.\n *\n * No third-party router. The table is known at boot (the decorators wrote it),\n * so matching is a segment walk over a small array rather than a compiled\n * pattern engine. Both authoring forms for a path parameter are accepted:\n * `{id}` (what the decorators are written with) and `:id`.\n */\nimport { getRoutes } from \"../decorators/registry.js\";\nimport type { RouteMeta } from \"../decorators/registry.js\";\nimport { resolveEffectiveAuth, assertZeroArgConstructor } from \"../decorators/controller.js\";\nimport type { AuthSpec } from \"../endpoint.js\";\n\nconst ROOM_META: unique symbol = Symbol.for(\"palbase.backend.room\") as never;\nconst CONTROLLER_META = Symbol.for(\"palbase.backend.controllerMeta\");\n\nexport interface RouteEntry {\n method: string;\n /** Path segments; a parameter segment is stored as `:name`. */\n segments: string[];\n meta: RouteMeta;\n /** The controller instance the method is invoked on. */\n instance: Record<string, (...args: unknown[]) => unknown>;\n /** `GET /todos/{id}` — stable, human-readable, used as the rate-limit key. */\n id: string;\n /** The auth spec that applies when the route itself declares none —\n * controller default ?? application default ?? `true`, resolved once at boot\n * by `resolveEffectiveAuth`. `engine/index.ts` reconciles the route's own\n * spec against it per request. */\n controllerAuth: AuthSpec;\n}\n\nfunction toSegments(path: string): string[] {\n return path\n .split(\"/\")\n .filter(Boolean)\n .map((s) => (s.startsWith(\"{\") && s.endsWith(\"}\") ? `:${s.slice(1, -1)}` : s));\n}\n\n/**\n * Build the table from controller classes.\n *\n * @throws when a class carries no routes — a controller that collected zero\n * endpoints is the silent failure this whole runtime is built to refuse, and\n * it must be loud at boot rather than a 404 in production.\n * @throws when a class declares constructor parameters — the same class of\n * silence one level down (FR-010): nothing here has an argument to pass, so\n * the field would simply be `undefined` in production.\n */\nexport function buildRouteTable(controllers: readonly unknown[]): RouteEntry[] {\n const table: RouteEntry[] = [];\n for (const Ctrl of controllers) {\n // A ROOM is not a routeless controller, it is a class with no HTTP surface\n // at all — server code a device reaches over the socket. It arrives here\n // because rooms and controllers share ONE registry slot (the loader's\n // `controllersOf` hands over everything a bundle declared), and the zero-route\n // refusal below is correct for a controller and wrong for a room.\n //\n // Measured on the live stack: the fixture's `@Room` reached this line and the\n // runtime refused to boot with \"controller ProbeRoom collected zero routes\" —\n // a message naming a class that was perfectly correct.\n if ((Ctrl as Record<symbol, unknown>)[ROOM_META] !== undefined) continue;\n // The `new ()` in this cast is a CLAIM — that the class is constructible with\n // no arguments — and the arity check below is what makes it true. Without it\n // the cast quietly held for `constructor(dep: Repo)` too: the call compiled,\n // deployed, and handed `this.dep` the value `undefined`.\n const ctor = Ctrl as { new (): Record<string, (...a: unknown[]) => unknown> } & Record<\n symbol,\n { basePath?: string; defaultAuth?: AuthSpec } | undefined\n >;\n const meta = ctor[CONTROLLER_META];\n const basePath = meta?.basePath ?? \"\";\n const routes = getRoutes(Ctrl as never) as RouteMeta[];\n if (routes.length === 0) {\n const name = (Ctrl as { name?: string }).name ?? \"<anonymous>\";\n throw new Error(\n `controller ${name} collected zero routes. Either it declares no @Get/@Post/… , ` +\n `or its decorator metadata was erased at build time — check that the bundle was ` +\n `compiled with experimentalDecorators enabled.`,\n );\n }\n assertZeroArgConstructor(Ctrl, \"controller\");\n const instance = new ctor();\n for (const r of routes) {\n const full = `${basePath}${r.subpath ?? \"\"}` || \"/\";\n table.push({\n method: r.method,\n segments: toSegments(full),\n meta: r,\n instance,\n id: `${r.method} ${full}`,\n // The route's OWN spec is deliberately not folded in here: this field\n // is what applies when the route is silent, and `effectiveAuth` puts\n // the route level back on top per request.\n controllerAuth: resolveEffectiveAuth(undefined, meta?.defaultAuth),\n });\n }\n }\n return table;\n}\n\nexport interface RouteMatch {\n entry: RouteEntry;\n params: Record<string, string>;\n}\n\n/** First match wins; the table is small and declaration order is the tiebreak. */\nexport function matchRoute(\n table: readonly RouteEntry[],\n method: string,\n pathname: string,\n): RouteMatch | null {\n const parts = pathname.split(\"/\").filter(Boolean);\n for (const entry of table) {\n if (entry.method !== method || entry.segments.length !== parts.length) continue;\n const params: Record<string, string> = {};\n let ok = true;\n for (let i = 0; i < entry.segments.length; i++) {\n const seg = entry.segments[i];\n const got = parts[i];\n if (seg === undefined || got === undefined) { ok = false; break; }\n if (seg.charCodeAt(0) === 58 /* ':' */) {\n params[seg.slice(1)] = decodeURIComponent(got);\n } else if (seg !== got) {\n ok = false;\n break;\n }\n }\n if (ok) return { entry, params };\n }\n return null;\n}\n","/**\n * upload.ts — the engine's half of `@Upload`.\n *\n * THE SHAPE, because it is unusual and the reason matters:\n *\n * client ──[ multipart: file + request body ]──► storage\n * storage ──[ authorize: which bucket, which path? ]──► THIS process\n * storage ── writes the bytes, renders the variants\n * storage ──[ signed: uploadedObject + request body ]──► THIS process\n * THIS process ── the handler runs, returns its typed result\n * storage ──[ that result ]──► client\n *\n * The tenant's code NEVER sees the bytes. It sees the metadata and the request\n * body, and it answers — which is what a completion handler is for. A 1 GB\n * video would otherwise stream through this process to reach the same place.\n *\n * Two calls arrive here, both from storage and neither from a browser:\n *\n * - AUTHORIZE asks which bucket and path a route writes to. Storage cannot\n * know: the answer lives in `@Upload({bucket, pathTemplate})`, which is\n * TypeScript, in the deployed bundle. Asking the process that HAS the\n * routes is what stops the client from naming its own bucket.\n * - COMPLETION runs the handler.\n *\n * Both are signed. An unsigned completion would let anyone with the route path\n * invent an upload that never happened.\n */\n\nimport type { RouteEntry } from \"./router.js\";\n\n/** What authorize answers: where this route's bytes go, and what they may be. */\nexport interface UploadGrant {\n bucket: string;\n path: string;\n maxBytes: number | null;\n mimeTypes: string[] | null;\n /**\n * Who is uploading, or null when nobody is signed in.\n *\n * Storage records this on the object row so deleting the user takes their\n * files with them. It is reported rather than DECIDED here — this process\n * already resolved the caller to render `{userId}` in a path template, and\n * storage has no identity of its own to derive one from. Authorization stays\n * exactly where it was (the route's own `auth` declaration); this is\n * attribution, which is a different question with the same answer already in\n * hand.\n *\n * null is the anonymous upload, and it stays null: a file uploaded by nobody\n * belongs to nobody, and attributing it to whoever signs in next on that\n * device would file one person's upload under another's name.\n */\n ownerUid: string | null;\n}\n\n/** The completion input storage sends after the bytes have landed. */\nexport interface CompletionEnvelope {\n uploadedObject: {\n uploadId: string;\n path: string;\n bucket: string;\n size: number;\n contentType: string;\n checksum: string;\n width?: number;\n height?: number;\n thumbhash?: string;\n variants: Record<string, string>;\n };\n /** The request body the client sent alongside the file. */\n body: unknown;\n}\n\n/** The internal path storage calls to ask where a route's bytes go. */\nexport const AUTHORIZE_PATH = \"/__palbase/upload/authorize\";\n\n/** Header carrying the shared-secret signature on both internal calls. */\nexport const SIGNATURE_HEADER = \"x-palbase-upload-signature\";\n\n/**\n * renderPath fills a `pathTemplate` on the SERVER.\n *\n * The client never chooses where its bytes land. `{filename}` is the one token\n * that comes from the caller, and it is sanitised to a single path segment:\n * without that, `../../../etc/passwd` is a filename, and a template that looks\n * like a folder structure becomes a way to write anywhere in the bucket.\n */\nexport function renderPath(template: string, tokens: {\n userId?: string | null;\n uploadId: string;\n filename?: string;\n}): string {\n return template\n .replaceAll(\"{userId}\", sanitizeSegment(tokens.userId ?? \"anonymous\"))\n .replaceAll(\"{uploadId}\", sanitizeSegment(tokens.uploadId))\n .replaceAll(\"{filename}\", sanitizeSegment(tokens.filename ?? \"file\"));\n}\n\n/**\n * sanitizeSegment reduces a value to something safe inside one path segment.\n *\n * Slashes, dots and control characters go. Keeping dots would allow `..`;\n * keeping slashes would allow a client to climb out of the prefix the template\n * put it in, which is the whole point of having a template.\n */\nexport function sanitizeSegment(raw: string): string {\n const cleaned = raw\n .replace(/[\\x00-\\x1F\\x7F]/g, \"\")\n .replace(/[/\\\\]/g, \"-\")\n .replace(/\\.{2,}/g, \".\")\n .replace(/^\\.+/, \"\")\n .trim();\n return cleaned === \"\" ? \"file\" : cleaned.slice(0, 200);\n}\n\n/**\n * grantFor resolves a route's upload configuration into a concrete grant.\n *\n * Returns null when the route is not an upload route — which is a refusal, not\n * an oversight: storage asking about a route with no `@Upload` means somebody\n * is trying to write through an endpoint that never offered to accept a file.\n */\nexport function grantFor(\n entry: RouteEntry | undefined,\n ctx: { userId: string | null; uploadId: string; filename?: string },\n bucketLimits?: { maxBytes: number | null; mimeTypes: string[] | null },\n): UploadGrant | null {\n const cfg = entry?.meta?.options?.uploadConfig;\n if (!cfg) return null;\n return {\n bucket: cfg.bucket,\n path: renderPath(cfg.pathTemplate, {\n userId: ctx.userId,\n uploadId: ctx.uploadId,\n filename: ctx.filename,\n }),\n maxBytes: bucketLimits?.maxBytes ?? null,\n mimeTypes: bucketLimits?.mimeTypes ?? null,\n ownerUid: ctx.userId ?? null,\n };\n}\n\n/**\n * CompletionLedger makes a completion run its handler EXACTLY ONCE per upload.\n *\n * The completion is a mutation — it writes the row that makes the uploaded\n * bytes mean something — and it is delivered over a network by a caller that\n * retries. A retried completion must not create a second post for one photo, so\n * the second call is answered with the FIRST call's response rather than being\n * refused: to storage, and therefore to the client waiting on it, a retry that\n * succeeds is indistinguishable from the original, which is the point.\n *\n * Bounded, and oldest-first: an upload id is interesting for as long as a retry\n * could still arrive, not forever. The cap is what keeps a long-lived process\n * from turning this into a leak — a ledger that remembered every upload would\n * be a slow way to run out of memory.\n */\nexport class CompletionLedger {\n private readonly seen = new Map<string, CompletedResponse>();\n\n constructor(private readonly capacity = 1024) {}\n\n recall(uploadId: string): CompletedResponse | undefined {\n return this.seen.get(uploadId);\n }\n\n remember(uploadId: string, response: CompletedResponse): void {\n // Delete-then-set so a repeat moves to the back: Map iterates in insertion\n // order, and the eviction below takes the front.\n this.seen.delete(uploadId);\n this.seen.set(uploadId, response);\n while (this.seen.size > this.capacity) {\n const oldest = this.seen.keys().next();\n if (oldest.done) break;\n this.seen.delete(oldest.value);\n }\n }\n\n get size(): number {\n return this.seen.size;\n }\n}\n\n/** A completion's answer, kept verbatim so a retry receives what the first call did. */\nexport interface CompletedResponse {\n status: number;\n body: string | null;\n contentType: string | null;\n}\n\n/**\n * verifySignature compares a presented signature against the expected one in\n * constant time.\n *\n * Constant time because a leaky comparison on a shared secret is recoverable\n * byte by byte, and this secret authorises running a tenant's handler with an\n * upload the caller describes.\n */\nexport function verifySignature(presented: string, expected: string): boolean {\n if (presented.length !== expected.length) return false;\n let diff = 0;\n for (let i = 0; i < presented.length; i++) {\n diff |= presented.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0;\n}\n","// engine/sse.ts — the Server-Sent Events mechanics, extracted from the request\n// pipeline so they can be tested without driving a whole request.\n//\n// This mirrors engine/upload.ts, which extracts renderPath / grantFor /\n// verifySignature and is consumed from engine/index.ts. Keeping the mechanics\n// here means the frame format, the ordering guarantee and the first-write hook\n// each have a test that names them, rather than being reachable only through a\n// full request.\n//\n// The problem being served: a provider on the server streams from a session;\n// while a client is connected its frames reach that client, and when the client\n// disconnects the provider must stop being pulled. This file owns the first\n// half — turning handler writes into wire frames, in order, without letting\n// anything escape before the request phase has been settled.\n\nimport type { SseWriter } from \"../decorators/sse.js\";\n\n/** The response content type for every `@Sse` route. */\nexport const SSE_CONTENT_TYPE = \"text/event-stream\";\n\n/**\n * Encode one value as an SSE `data:` frame.\n *\n * The payload is JSON, and that is load-bearing rather than merely convenient:\n * a raw newline inside a frame ends it and the remainder is parsed as a new\n * field, so a handler streaming user-influenced text could otherwise forge\n * events. JSON encoding escapes the newline, which makes the frame boundary\n * something only this function decides.\n */\nexport function encodeFrame(value: unknown): string {\n return `data: ${JSON.stringify(value)}\\n\\n`;\n}\n\n/**\n * Encode the terminal frame for a handler that threw AFTER it had already\n * written. The status line is long gone by then — 200 and the stream headers\n * were committed with the first frame — so the only honest way to report the\n * failure is in-band, and named, so a client can tell \"the stream ended\" from\n * \"the stream broke\".\n */\nexport function encodeErrorFrame(requestId: string): string {\n return `event: error\\ndata: ${JSON.stringify({ requestId })}\\n\\n`;\n}\n\n/** What `makeSseWriter` returns: the handler-facing writer plus the two members\n * the engine needs. `SseWriter` itself stays minimal — a handler author sees\n * only `write`. */\nexport interface EngineSseWriter extends SseWriter {\n /** Whether anything has been written yet. The engine chooses between an\n * ordinary error envelope (nothing written — the status line is still ours)\n * and a terminal error frame (already streaming) on this answer. */\n started(): boolean;\n /** Resolves when every queued frame has been enqueued. The engine awaits it\n * before closing the stream, so a handler that returns immediately after its\n * last write does not truncate it. */\n drained(): Promise<void>;\n}\n\nexport interface SseWriterOptions {\n /** Hand one encoded frame to the transport. */\n enqueue(chunk: string): void;\n /**\n * Runs ONCE, before the first frame is enqueued, and nothing is emitted until\n * it resolves. This is the seam where the request's database transaction is\n * settled: the handler runs inside that transaction, and a stream that lives\n * for minutes must not hold one open.\n */\n onFirstWrite(): Promise<void>;\n}\n\n/**\n * Build the writer handed to an `@Sse` handler.\n *\n * `write` is SYNCHRONOUS on purpose: a handler relaying a provider writes inside\n * a `for await` loop, and making every chunk awaitable would put a promise in\n * the hot path of every token for no benefit the caller can act on. The cost is\n * that the asynchronous first-write hook has to be absorbed here — so frames are\n * queued on a promise chain and emitted in exactly the order they were written.\n *\n * Values are encoded EAGERLY, inside `write`, not when the queue drains: a\n * handler that writes a mutable object and then keeps mutating it should see the\n * value as it was at the moment it wrote, which is also the only reading that\n * survives being queued.\n */\nexport function makeSseWriter(opts: SseWriterOptions): EngineSseWriter {\n let begun = false;\n let chain: Promise<void> = Promise.resolve();\n\n return {\n write(value: unknown): void {\n const frame = encodeFrame(value);\n if (!begun) {\n begun = true;\n chain = chain.then(() => opts.onFirstWrite()).then(() => opts.enqueue(frame));\n return;\n }\n chain = chain.then(() => opts.enqueue(frame));\n },\n started(): boolean {\n return begun;\n },\n drained(): Promise<void> {\n return chain;\n },\n };\n}\n","/**\n * engine/fence.ts — what the tenant's own code may reach.\n *\n * The isolate used to answer this by construction: tenant code ran in a realm\n * with no ambient network and an environment scrubbed of every secret, and each\n * privileged call hopped to a host that held the credentials. Running the\n * backend as one process removes that wall, so the two guarantees it carried\n * have to be re-made here — deliberately, and with the honest note that a\n * same-process fence is a SPEED BUMP against the tenant's own code, not a\n * sandbox. The real boundary is the machine: each tenant has its own.\n *\n * That is not a hole, it is a scope. The tenant owns this database and this\n * network namespace; the thing worth preventing is an ACCIDENT — a dependency\n * that reads `process.env` and posts it somewhere, a handler that opens its own\n * unscoped connection and quietly serves every user's rows — not a determined\n * operator attacking their own stack.\n */\n\n/** Names the engine holds and the tenant's code must not find lying around. */\nconst SECRET_ENV = [\n \"DATABASE_URL\",\n \"PALBASE_SERVICE_ROLE_KEY\",\n \"REALTIME_INGESTION_SECRET\",\n \"INTERNAL_API_SECRET\",\n \"STACK_ROOT_KEY\",\n \"PEPPER\",\n \"LOCAL_JWT_PEM\",\n] as const;\n\nexport interface ScrubResult {\n removed: string[];\n kept: string[];\n}\n\n/**\n * Delete the engine's own credentials from `process.env`.\n *\n * MUST run AFTER the config is read and BEFORE the tenant bundle is imported —\n * a bundle's module-level code runs at import, so a scrub that comes later has\n * already lost the race.\n *\n * The tenant's OWN variables (`PALBASE_VAR_*` and anything else) are untouched:\n * this removes what the platform put there, not what the operator did.\n *\n * Why RLS makes this matter: the engine binds every request to the caller with\n * `set_config('role', …)` so Postgres does the row filtering. Code that finds\n * `DATABASE_URL` can open its own connection as the owner and read every user's\n * rows — not by attacking anything, just by using a driver.\n */\nexport function scrubSecrets(env: Record<string, string | undefined>): ScrubResult {\n const removed: string[] = [];\n const kept: string[] = [];\n for (const name of SECRET_ENV) {\n if (env[name] === undefined) continue;\n delete env[name];\n removed.push(name);\n }\n for (const name of Object.keys(env)) if (name.startsWith(\"PALBASE_VAR_\")) kept.push(name);\n return { removed, kept };\n}\n\nexport interface EgressPolicy {\n /** Hostnames the tenant declared. Empty ⇒ no declaration was made. */\n allow: readonly string[];\n /** Per-call ceiling in ms. 0 ⇒ no ceiling declared. */\n timeoutMs: number;\n /** What to do when nothing was declared. */\n whenUndeclared: \"allow\" | \"deny\";\n /**\n * Hosts the BACKEND ITSELF needs: its module surface, the JWKS it verifies\n * tokens against, the artifact store it reloads from.\n *\n * These are not egress. `config/egress.ts` declares where the tenant's own\n * code may reach; a call to the platform this backend is part of is internal\n * traffic, and fencing it means the first deploy with an allowlist takes the\n * backend down — which is exactly what happened when this list did not exist:\n * every request 500'd with \"egress denied: palsvc is not in this backend's\n * declared allowlist\", and the artifact reload loop stopped with it.\n */\n alwaysAllow?: readonly string[];\n}\n\n/** `api.stripe.com` matches itself; `*.stripe.com` matches any subdomain. */\nexport function hostAllowed(host: string, allow: readonly string[]): boolean {\n const h = host.toLowerCase();\n for (const raw of allow) {\n const pattern = raw.trim().toLowerCase();\n if (!pattern) continue;\n if (pattern === h) return true;\n if (pattern.startsWith(\"*.\") && h.endsWith(pattern.slice(1)) && h.length > pattern.length - 1) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Install the tenant's declared outbound allowlist over `globalThis.fetch`.\n *\n * The engine's own traffic is exempted by HOST (`alwaysAllow`), not by holding\n * a captured reference: the module clients and the verifier resolve\n * `globalThis.fetch` at CALL time, so a captured original never reaches them.\n * That distinction is not academic — the first version of this file claimed the\n * capture worked, and every request 500'd on the first deploy that declared an\n * allowlist.\n *\n * @returns the original fetch, for the engine's own use.\n */\nexport function installEgressFence(policy: EgressPolicy): typeof fetch {\n const original = globalThis.fetch.bind(globalThis);\n const declared = policy.allow.length > 0;\n const platform = (policy.alwaysAllow ?? []).map((h) => h.toLowerCase()).filter(Boolean);\n\n if (!declared && policy.whenUndeclared === \"allow\") return original;\n\n const fenced: typeof fetch = async (input, init) => {\n const url =\n typeof input === \"string\"\n ? new URL(input)\n : input instanceof URL\n ? input\n : new URL((input as Request).url);\n\n // The backend's own platform first — internal traffic is not egress.\n if (platform.includes(url.hostname.toLowerCase())) return original(input, init);\n\n if (!declared || !hostAllowed(url.hostname, policy.allow)) {\n throw new Error(\n `egress denied: ${url.hostname} is not in this backend's declared allowlist. ` +\n `Add it to config/egress.ts and deploy.`,\n );\n }\n if (policy.timeoutMs > 0) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), policy.timeoutMs);\n try {\n return await original(input, { ...init, signal: init?.signal ?? controller.signal });\n } finally {\n clearTimeout(timer);\n }\n }\n return original(input, init);\n };\n\n globalThis.fetch = fenced;\n return original;\n}\n"],"mappings":"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","names":["resolveTx","reason","reason"]}
1
+ {"version":3,"sources":["../../src/engine/index.ts","../../src/runtime.ts","../../src/db/tx-plan.ts","../../src/errors.ts","../../src/engine/config.ts","../../src/engine/auth.ts","../../src/engine/ratelimit.ts","../../src/engine/cache.ts","../../src/db/input-guards.ts","../../src/db/schema-json.ts","../../src/engine/db.ts","../../src/decorators/registry.ts","../../src/decorators/controller.ts","../../src/engine/router.ts","../../src/engine/upload.ts","../../src/engine/sse.ts","../../src/engine/fence.ts"],"sourcesContent":["/**\n * engine/index.ts — the engine: a backend that boots itself.\n *\n * `createApp` turns a set of `@Controller` classes into a `fetch(Request)`\n * handler. No V8 isolate, no capability hop: this process owns its database\n * pool, verifies its own tokens, applies its own rate limits, and calls the\n * modules directly.\n *\n * import { createApp, loadConfig } from \"@palbase/backend/engine\";\n *\n * const app = await createApp({\n * config: loadConfig(process.env),\n * controllers: [TodosController],\n * schema,\n * });\n * Bun.serve({ port: app.config.port, fetch: app.handle });\n *\n * The Web-standard `fetch` signature is the point: the same handler runs under\n * Bun, Deno and any host that speaks Request/Response, so \"works locally\" and\n * \"works in the cloud\" are the same code path rather than two.\n */\nimport type { ZodError, ZodTypeAny } from \"zod\";\n\nimport { __runWithRuntime, __requestALS, __runStartHooks } from \"../runtime.js\";\nimport type { RuntimeServices, ShutdownRunner } from \"../runtime.js\";\nimport { isHttpError, isEngineRaised } from \"../errors.js\";\nimport type { CacheClient, ClientInfo } from \"../endpoint.js\";\n\nimport { loadConfig, BootRefused } from \"./config.js\";\nimport type { EngineConfig } from \"./config.js\";\nimport { AuthVerifier, effectiveAuth } from \"./auth.js\";\nimport type { VerifiedClaims } from \"./auth.js\";\nimport { RateLimiter } from \"./ratelimit.js\";\nimport { makeMemoryCache } from \"./cache.js\";\nimport { createRequestDatabase, setSchema, setSecretReader } from \"./db.js\";\nimport type { SqlDriver } from \"./db.js\";\nimport { buildRouteTable, matchRoute } from \"./router.js\";\nimport {\n AUTHORIZE_PATH,\n SIGNATURE_HEADER,\n grantFor,\n verifySignature,\n CompletionLedger,\n type CompletionEnvelope,\n} from \"./upload.js\";\nimport {\n SSE_CONTENT_TYPE,\n encodeErrorFrame,\n makeSseWriter,\n type EngineSseWriter,\n} from \"./sse.js\";\nimport type { RouteEntry } from \"./router.js\";\n\nexport { loadConfig, BootRefused } from \"./config.js\";\nexport type { EngineConfig } from \"./config.js\";\nexport { AuthVerifier, effectiveAuth } from \"./auth.js\";\nexport { RateLimiter } from \"./ratelimit.js\";\nexport { makeMemoryCache } from \"./cache.js\";\nexport { createLazyTransaction, createOps, withTables, createRequestDatabase, quoteIdent } from \"./db.js\";\nexport type { SqlDriver, SqlTx, RequestDatabase } from \"./db.js\";\nexport { buildRouteTable, matchRoute } from \"./router.js\";\nexport type { RouteEntry } from \"./router.js\";\nexport { scrubSecrets, installEgressFence, hostAllowed } from \"./fence.js\";\nexport type { EgressPolicy, ScrubResult } from \"./fence.js\";\n\n/** The `__`-prefixed request-scope seam, as re-exported by a deployed bundle. */\nexport interface RuntimeHooks {\n __runWithRuntime: typeof __runWithRuntime;\n __requestALS: typeof __requestALS;\n}\n\n/** The module singletons the engine injects, minus the two it owns itself. */\nexport type ModuleClients = Partial<\n Pick<\n RuntimeServices,\n \"Documents\" | \"Storage\" | \"Notifications\" | \"Flags\" | \"Realtime\" | \"Secrets\"\n >\n>;\n\nexport interface CreateAppOptions {\n /**\n * Vault'tan TEK secret okuma (FR-025): sorgu-anı embedding'in anahtarı\n * buradan akar. Verilmezse auto-embed'li search({query}) adlandırılmış\n * hatayla düşer — sessiz boş sonuç asla (FR-015).\n */\n secretReader?: (name: string) => Promise<string | null>;\n config: EngineConfig;\n /** `@Controller` classes. A class that collected zero routes is fatal. */\n controllers: readonly unknown[];\n /** The project's `defineSchema()` result, for the typed `.tables` surface. */\n schemas?: readonly unknown[];\n /** The SQL driver. Omitted ⇒ built from `Bun.sql` when running under Bun. */\n sql?: SqlDriver;\n /** Module clients. Omitted ⇒ each corresponding singleton throws when used. */\n modules?: ModuleClients;\n /** Cache. Omitted ⇒ this process's own memory. */\n cache?: CacheClient;\n /**\n * The request-scope hooks to run handlers inside.\n *\n * MUST come from the SAME `@palbase/backend` module instance the loaded\n * controllers were bundled against. A deployed bundle inlines its own copy of\n * the SDK and re-exports these two; the engine here has its own. Two copies\n * mean two AsyncLocalStorage instances, and the store this engine sets is not\n * the store the handler's `Database` proxy reads — every service would be\n * undefined at the first call, with nothing in the logs to say why. So the\n * host passes the BUNDLE's hooks and the seam closes.\n *\n * Omitted ⇒ this module's own, which is correct only when the controllers\n * were built against this same instance (tests, a single-package project).\n */\n runtimeHooks?: RuntimeHooks;\n logger?: Pick<Console, \"info\" | \"warn\" | \"error\" | \"debug\">;\n}\n\nexport interface App {\n handle: (req: Request) => Promise<Response>;\n routes: readonly RouteEntry[];\n config: EngineConfig;\n /**\n * Run work that has no request behind it — a scheduled job — inside the same\n * request scope a handler gets, with its own transaction.\n */\n runInServiceScope: <T>(fn: () => T | Promise<T>) => Promise<T>;\n /** Close the pool and release resources. */\n shutdown: () => Promise<void>;\n}\n\nconst JSON_HEADERS = { \"content-type\": \"application/json\" } as const;\n\n/** Flatten a zod failure into the `{ field, message }[]` the SDK's own\n * `BadRequest` payload declares — one shape for the engine's automatic\n * refusals and for `throw new BadRequest({ fields })` alike. */\nfunction fieldErrors(err: ZodError): Array<{ field: string; message: string }> {\n return err.issues.map((i) => ({ field: i.path.join(\".\"), message: i.message }));\n}\n\n/** Re-key the header map onto the names an `@Headers` schema declares.\n *\n * HTTP HEADER NAMES ARE CASE-INSENSITIVE (RFC 9110 §5.1); a zod key is a\n * literal. `Headers` iteration lowercases, so `Object.fromEntries(req.headers)`\n * only ever carries `x-tenant` — while the deploy gate lowercases a declared\n * name only for its RESERVED check (`extract_meta.js` validateHeadersSchema),\n * so `z.object({ \"X-Tenant\": … })` ships. That is also the spelling every HTTP\n * document uses and the one the iOS/Android generators emit into the generated\n * call's signature, so the caller really does send it.\n *\n * Comparing case-sensitively would answer 400 on a header the caller DID send,\n * on every request, forever — the schema was inert before it was enforced, so\n * the refusal would arrive with the SDK upgrade and name a header the client\n * can see itself sending. The lowercase twin stays in the map (zod strips\n * unknown keys), so the parsed value carries exactly the declared spelling.\n */\nfunction headersFor(raw: Record<string, string>, schema: ZodTypeAny): Record<string, string> {\n const shape = (schema as { shape?: Record<string, unknown> }).shape;\n if (typeof shape !== \"object\" || shape === null) return raw;\n let aliased: Record<string, string> | null = null;\n for (const declared of Object.keys(shape)) {\n const lower = declared.toLowerCase();\n if (lower === declared) continue;\n const value = raw[lower];\n if (value === undefined) continue;\n aliased ??= { ...raw };\n aliased[declared] = value;\n }\n return aliased ?? raw;\n}\n\nfunction envelope(\n error: string,\n description: string,\n status: number,\n requestId: string,\n extra?: Record<string, unknown>,\n): Response {\n return new Response(\n JSON.stringify({ error, error_description: description, status, request_id: requestId, ...extra }),\n { status, headers: JSON_HEADERS },\n );\n}\n\n/** A module that was never configured must say so by name on first use, not\n * fail with \"Cannot read properties of undefined\". */\n/**\n * A module singleton nobody injected.\n *\n * The message names TWO causes because there are two, and pointing at only one\n * sends an operator to check a setting that is already correct. Measured on\n * 2026-08-15: a handler reaching for `Purchases` was told to set\n * MODULE_BASE_URL — which was set. Purchases is simply not part of this\n * backend, and an error that hides that costs the reader the afternoon.\n */\nfunction unavailable(name: string): never {\n throw new Error(\n `${name} is unavailable. Either this backend was started without module clients ` +\n `(set MODULE_BASE_URL and the API keys so the engine can reach the module surface), ` +\n `or ${name} is not one of the modules this backend provides.`,\n );\n}\n\nfunction stubModule(name: string): unknown {\n return new Proxy(\n {},\n {\n get: () => unavailable(name),\n apply: () => unavailable(name),\n },\n );\n}\n\nasync function defaultSqlDriver(config: EngineConfig): Promise<SqlDriver> {\n const g = globalThis as { Bun?: { SQL: new (o: { url: string; max: number }) => SqlDriver } };\n if (!g.Bun?.SQL) {\n throw new BootRefused(\n [],\n \"boot refused: no SQL driver. Running outside Bun means the driver must be supplied — \" +\n \"pass `sql` to createApp().\",\n );\n }\n return new g.Bun.SQL({ url: config.databaseUrl, max: config.poolMax });\n}\n\n/** The statuses an author THROWS to answer a request. Everything else that\n * reaches the catch is unplanned and gets logged — see the branch that reads\n * this. Kept beside nothing else so there is one list, not a condition spread\n * across two files.\n *\n * 409 IS IN THIS LIST, and the reason is the whole shape of the check. The\n * scaffold teaches `throw new Conflict(\"title already taken\")` as the way to\n * answer with a 409 (template/AGENTS.md), and the engine raises\n * `UniqueViolation` — also a 409 — from a duplicate write. The status cannot\n * tell them apart, so intent is read from ORIGIN instead: the engine MARKS what\n * it built (`markEngineRaised`), and the branch below logs on that mark\n * regardless of status. Splitting on the status alone wrote an \"unhandled\" line\n * every time an author took the documented path — measured. */\nconst AUTHOR_ANSWERED: ReadonlySet<number> = new Set([400, 401, 403, 404, 409, 429]);\n\n/**\n * Build the app. Fails fast: the database is reached here, at boot, rather than\n * on the first request that needs it.\n */\n\nexport async function createApp(opts: CreateAppOptions): Promise<App> {\n const { config, controllers } = opts;\n setSchema(opts.schemas ?? []);\n setSecretReader(opts.secretReader ?? null);\n\n const routes = buildRouteTable(controllers);\n if (routes.length === 0) {\n throw new BootRefused([], \"boot refused: zero endpoints collected — nothing would answer.\");\n }\n\n const sql = opts.sql ?? (await defaultSqlDriver(config));\n await sql.unsafe(\"select 1\");\n\n const auth = new AuthVerifier({ jwksUrl: config.authJwksUrl, issuer: config.authIssuer });\n const limiter = new RateLimiter();\n const cache = opts.cache ?? makeMemoryCache();\n const log = opts.logger ?? console;\n const modules = opts.modules ?? {};\n const runWithRuntime = opts.runtimeHooks?.__runWithRuntime ?? __runWithRuntime;\n const requestALS = opts.runtimeHooks?.__requestALS ?? __requestALS;\n\n // The secret storage signs its internal calls with. Absent means uploads are\n // not wired, and authorize REFUSES rather than answering with a grant anybody\n // could have asked for.\n const uploadSecret = config.uploadSecret ?? \"\";\n\n /**\n * Answer \"which bucket and path does this route write to?\".\n *\n * Storage cannot know: the answer is `@Upload({bucket, pathTemplate})`, which\n * lives in the deployed bundle. Asking the process that HAS the routes is\n * what keeps the client from naming its own bucket — the request carries the\n * route it wants to use, and this decides what that means.\n */\n // One ledger per app: a completion retried against this process must find\n // its own first answer, and a process restart legitimately forgets — the\n // window a retry lives in is far shorter than an uptime.\n const completions = new CompletionLedger();\n\n /**\n * The service bundle a scope binds, built around ONE request-scoped database.\n *\n * Extracted so the request path and the job path cannot drift: a second copy\n * of this object is a second definition of what a handler can reach, and the\n * one that goes stale is always the one nobody is looking at.\n */\n /** `db === null` is the BOOT scope: everything else is available, and\n * `Database` refuses by name because a start hook runs before any request and\n * there is no transaction for a query to belong to. One writer, so the boot\n * scope cannot drift from the request one. */\n function buildServices(db: ReturnType<typeof createRequestDatabase> | null): RuntimeServices {\n return {\n Database:\n db?.client ??\n stubModule(\"Database (a start hook runs before any request — open your own connection here)\"),\n Cache: cache,\n Log: log,\n Documents: modules.Documents ?? stubModule(\"Documents\"),\n Storage: modules.Storage ?? stubModule(\"Storage\"),\n Notifications: modules.Notifications ?? stubModule(\"Notifications\"),\n Flags: modules.Flags ?? stubModule(\"Flags\"),\n Realtime: modules.Realtime ?? stubModule(\"Realtime\"),\n // Named, never undefined. A backend started without a secrets client\n // that returned `undefined` here would fail inside the handler as\n // \"Cannot read properties of undefined\", which says nothing about what\n // to configure — the stub says the name and the variable.\n Secrets: modules.Secrets ?? stubModule(\"Secrets\"),\n } as unknown as RuntimeServices;\n }\n\n /**\n * Run `fn` as the system, with no request behind it.\n *\n * Scheduled jobs need exactly what a handler needs — Database, Log,\n * Notifications, resolved out of the request scope — but there is no request\n * to take an identity from. So the claims are EMPTY: a job is nobody, and\n * `Database` here satisfies no owner-scoped RLS policy. That is why a job\n * reaches for `Database.asService()`, and why this does not quietly hand it\n * service_role by default.\n *\n * The transaction settles the same way a request's does: commit on return,\n * rollback on throw. A job that fails halfway leaves nothing behind that the\n * next run has to reason about.\n */\n async function runInServiceScope<T>(fn: () => T | Promise<T>): Promise<T> {\n const db = createRequestDatabase(sql, {\n role: config.dbRole,\n serviceRole: config.dbServiceRole,\n claimsJson: \"{}\",\n });\n try {\n const out = await runWithRuntime(buildServices(db), fn as () => Promise<T>);\n await db.commit();\n return out;\n } catch (err) {\n await db.rollback(err);\n throw err;\n }\n }\n\n async function handleAuthorize(req: Request, requestId: string): Promise<Response> {\n if (uploadSecret === \"\" ||\n !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? \"\", uploadSecret)) {\n return envelope(\"unauthorized\", \"This endpoint is not callable directly\", 401, requestId);\n }\n const body = (await req.json().catch(() => null)) as {\n method?: string;\n path?: string;\n userId?: string | null;\n uploadId?: string;\n filename?: string;\n } | null;\n if (!body?.path || !body.uploadId) {\n return envelope(\"bad_request\", \"authorize needs a path and an uploadId\", 400, requestId);\n }\n const target = matchRoute(routes, body.method ?? \"POST\", body.path);\n\n // THE AUTH DECISION HAPPENS HERE, BEFORE A SINGLE BYTE IS ACCEPTED.\n //\n // Storage asks this question precisely so it can refuse early: without it,\n // an anonymous caller could push a file at a route that requires a user,\n // have it written and its variants rendered, and only then be turned away\n // by the completion — the bytes were still accepted, and the work still\n // done, once per attempt.\n //\n // The credential is the caller's own, forwarded by storage, and it is\n // verified HERE rather than trusted: the userId that ends up in the path\n // template comes from these claims and from nothing else, so neither the\n // client nor storage can name a folder that belongs to somebody else.\n const spec = effectiveAuth(target?.entry.meta.options?.auth, target?.entry.controllerAuth);\n const callerClaims = await auth.verify(req.headers.get(\"authorization\"));\n if (spec.required && !callerClaims) {\n return envelope(\"unauthorized\", \"A valid access token is required\", 401, requestId);\n }\n if (callerClaims && spec.role && callerClaims.role !== spec.role) {\n return envelope(\"forbidden\", `This endpoint requires the \"${spec.role}\" role`, 403, requestId);\n }\n\n const grant = grantFor(target?.entry, {\n userId: typeof callerClaims?.sub === \"string\" ? callerClaims.sub : null,\n uploadId: body.uploadId,\n filename: body.filename,\n });\n if (!grant) {\n // A route with no @Upload never offered to accept a file. Refusing by\n // NAME rather than 404 so an operator reading storage's log learns which\n // route was asked for.\n return envelope(\"not_an_upload_route\",\n `${body.method ?? \"POST\"} ${body.path} does not declare @Upload`, 400, requestId);\n }\n return new Response(JSON.stringify(grant), { status: 200, headers: JSON_HEADERS });\n }\n\n async function handle(req: Request): Promise<Response> {\n const requestId = `req_${crypto.randomUUID()}`;\n const url = new URL(req.url);\n\n // ── storage's two internal calls, before ordinary routing ───────────────\n //\n // They are not the tenant's routes and must not be reachable as one: an\n // app that declared `POST /__palbase/upload/authorize` would otherwise\n // shadow the mechanism that decides where uploads land.\n if (url.pathname === AUTHORIZE_PATH) {\n return handleAuthorize(req, requestId);\n }\n\n const hit = matchRoute(routes, req.method, url.pathname);\n if (!hit) return envelope(\"not_found\", \"No route matches this method and path\", 404, requestId);\n const { meta } = hit.entry;\n\n // ── auth ────────────────────────────────────────────────────────────────\n const spec = effectiveAuth(meta.options?.auth, hit.entry.controllerAuth);\n const claims: VerifiedClaims | null = await auth.verify(req.headers.get(\"authorization\"));\n if (spec.required && !claims) {\n return envelope(\"unauthorized\", \"A valid access token is required\", 401, requestId);\n }\n const userId = typeof claims?.sub === \"string\" ? claims.sub : undefined;\n if (claims && spec.role && claims.role !== spec.role) {\n return envelope(\"forbidden\", `This endpoint requires the \"${spec.role}\" role`, 403, requestId);\n }\n if (claims && spec.verifiedEmail && claims.email_verified !== true) {\n return envelope(\"email_not_verified\", \"A verified email address is required\", 403, requestId);\n }\n\n // ── rate limit ──────────────────────────────────────────────────────────\n const retryAfter = limiter.check(\n meta.options?.rateLimit,\n RateLimiter.key(hit.entry.id, userId, req.headers),\n Date.now(),\n );\n if (retryAfter !== null) {\n // THE HINT GOES IN THE BODY TOO, under the name this SDK already\n // publishes for it. `error-registry.ts` declares\n // `too_many_requests: { retryAfter: number }`, so codegen types\n // `error.data.retryAfter` on every generated client and a thrown\n // `new TooManyRequests({ retryAfter })` already answers in that shape.\n // This limiter answered with the header ALONE, so the one 429 the engine\n // itself produces was the one shape no generated client could read — and\n // a browser behind a CORS gateway cannot see `Retry-After` at all unless\n // it is explicitly exposed. The header stays: it is the HTTP-correct\n // signal, and `@palbase/core`'s retry loop reads it.\n return new Response(\n JSON.stringify({\n error: \"too_many_requests\",\n error_description: \"Rate limit exceeded for this endpoint\",\n status: 429,\n request_id: requestId,\n data: { retryAfter },\n }),\n { status: 429, headers: { ...JSON_HEADERS, \"retry-after\": String(retryAfter) } },\n );\n }\n\n // ── arguments ───────────────────────────────────────────────────────────\n // Set when this request IS a completion, so its answer can be remembered.\n let completionUploadId: string | null = null;\n\n const args: unknown[] = [];\n let parsedBody: unknown;\n let bodyRead = false;\n\n // The SSE writer has to exist BEFORE the parameter loop (that is where it is\n // injected) but its two collaborators only exist later: the transport queue\n // is created when the ReadableStream starts, and the transaction it settles\n // is opened further down. So both are reached through holders the SSE branch\n // fills in — the writer itself stays ignorant of either.\n let sseEnqueue: ((chunk: string) => void) | null = null;\n let sseSettle: () => Promise<void> = async () => {};\n const sseWriter: EngineSseWriter = makeSseWriter({\n enqueue: (chunk) => sseEnqueue?.(chunk),\n onFirstWrite: () => sseSettle(),\n });\n for (const p of meta.params ?? []) {\n switch (p.kind) {\n case \"body\": {\n if (!bodyRead) {\n parsedBody = await req.json().catch(() => ({}));\n bodyRead = true;\n }\n const r = p.schema!.safeParse(parsedBody);\n if (!r.success) {\n return envelope(\"bad_request\", \"Request body failed validation\", 400, requestId, {\n data: { fields: fieldErrors(r.error) },\n });\n }\n args[p.index] = r.data;\n break;\n }\n case \"query\": {\n const r = p.schema!.safeParse(Object.fromEntries(url.searchParams));\n if (!r.success) {\n return envelope(\"bad_request\", \"Query parameters failed validation\", 400, requestId, {\n data: { fields: fieldErrors(r.error) },\n });\n }\n args[p.index] = r.data;\n break;\n }\n case \"param\":\n args[p.index] = hit.params[p.name!];\n break;\n case \"headers\": {\n // A DECLARED HEADER SCHEMA IS A CONTRACT, and three other systems\n // already treat it as one: the deploy gate REFUSES a build whose\n // schema names a reserved or non-string header\n // (cli/internal/backend/devjs/extract_meta.js), the OpenAPI document\n // lists it as an `in: header` parameter, and the iOS/Android\n // generators put it in the generated call's signature. The runtime\n // was the only one that read the schema and did nothing with it, so a\n // request with the header missing or malformed answered 200 and the\n // handler read `undefined` off a value whose type says `string`.\n //\n // Keys arrive LOWERCASE — `Headers` iteration lowercases them — so\n // the declared names are matched case-insensitively (`headersFor`)\n // and `x-tenant` and `X-Tenant` both work, as HTTP says they must.\n const raw = Object.fromEntries(req.headers);\n if (!p.schema) {\n args[p.index] = raw;\n break;\n }\n const r = p.schema.safeParse(headersFor(raw, p.schema));\n if (!r.success) {\n return envelope(\"bad_request\", \"Request headers failed validation\", 400, requestId, {\n data: { fields: fieldErrors(r.error) },\n });\n }\n // The PARSED value, matching @Body/@QueryParams: the parameter's type\n // is `z.infer<Schema>`, and injecting the whole header map made the\n // value wider than its own declared type. An author who wants every\n // header still writes `@Headers()` with no schema.\n args[p.index] = r.data;\n break;\n }\n case \"user\":\n case \"optionalUser\":\n args[p.index] = claims\n ? {\n id: userId,\n email: claims.email,\n role: claims.role,\n emailVerified: claims.email_verified === true,\n metadata: (claims.metadata as Record<string, unknown>) ?? {},\n }\n : null;\n break;\n case \"uploadedObject\": {\n // An @Upload route runs as a COMPLETION handler: the bytes went to\n // storage, and what arrives here is what storage recorded about them.\n // The call must be signed, or anyone who knows the route path could\n // invent an upload that never happened and make the handler write a\n // row for it.\n if (uploadSecret === \"\" ||\n !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? \"\", uploadSecret)) {\n return envelope(\"unauthorized\",\n \"This endpoint accepts uploads through storage, not directly\", 401, requestId);\n }\n if (!bodyRead) {\n parsedBody = await req.json().catch(() => ({}));\n bodyRead = true;\n }\n const envelopeIn = parsedBody as CompletionEnvelope | null;\n if (!envelopeIn?.uploadedObject) {\n return envelope(\"bad_request\", \"the completion call carried no uploaded object\", 400, requestId);\n }\n // A RETRY MUST NOT RUN THE HANDLER AGAIN.\n //\n // Storage retries a completion it did not hear back from, and the\n // handler is a mutation: run twice, one uploaded photo becomes two\n // posts. The first answer is replayed instead, which is what makes\n // the retry invisible to the client waiting on the other end.\n const uploadId = envelopeIn.uploadedObject.uploadId;\n if (typeof uploadId === \"string\" && uploadId !== \"\") {\n const already = completions.recall(uploadId);\n if (already) {\n return new Response(already.body, {\n status: already.status,\n headers: already.contentType ? { \"content-type\": already.contentType } : undefined,\n });\n }\n completionUploadId = uploadId;\n }\n args[p.index] = envelopeIn.uploadedObject;\n // The author's @Body sees THEIR payload, not the envelope around it.\n parsedBody = envelopeIn.body ?? {};\n break;\n }\n case \"requestId\":\n args[p.index] = requestId;\n break;\n case \"traceId\":\n args[p.index] = requestId;\n break;\n case \"client\":\n // The data was always on the wire; nothing read it. Every shipped\n // client SDK stamps these four on every request (iOS\n // Palbe/Core/ClientInfo.swift, web core/src/http.ts), and the\n // platform already reads the same names in Go\n // (user-flags/internal/middleware/clientcontext.go). Header names are\n // canonical here, not invented: the deploy gate REFUSES an\n // `@Headers` schema that names an `x-palbase-*` key, which makes\n // `@Client()` the only sanctioned reader of them.\n //\n // `Headers.get()` answers `string | null`, which is exactly what\n // `ClientInfo` declares — a non-SDK caller (curl, server-to-server)\n // sends none of these and gets four nulls rather than a throw.\n args[p.index] = {\n sdkVersion: req.headers.get(\"x-palbase-sdk-version\"),\n appVersion: req.headers.get(\"x-palbase-client-version\"),\n platform: req.headers.get(\"x-platform\"),\n osVersion: req.headers.get(\"x-os-version\"),\n } satisfies ClientInfo;\n break;\n case \"req\":\n args[p.index] = req;\n break;\n // `@Signal()` — the raw request's AbortSignal, which enters the aborted\n // state when the client disconnects. Measured on Bun: an infinite\n // producer guarded by it stops within a few frames of the client dying.\n // It is deliberately NOT reachable through `@Req()`: PBRequest carries\n // request-scoped data and no signal.\n case \"signal\":\n args[p.index] = req.signal;\n break;\n // `@SseOut()` — the frame writer. Meaningful only on an `@Sse` route;\n // on any other route it is an inert writer whose frames go nowhere,\n // which is the same shape `@UploadedObject()` has off an `@Upload`\n // route.\n case \"sseOut\":\n args[p.index] = sseWriter;\n break;\n default:\n args[p.index] = undefined;\n }\n }\n\n // ── dispatch, inside the request's transaction(s) ───────────────────────\n //\n // One for the caller's identity, and — only if the handler asks for it —\n // one more for `Database.asService()`. Both settle here, together.\n const db = createRequestDatabase(sql, {\n role: config.dbRole,\n serviceRole: config.dbServiceRole,\n claimsJson: JSON.stringify(claims ?? {}),\n });\n try {\n const services = buildServices(db);\n\n // ── the streaming branch ────────────────────────────────────────────────\n //\n // An `@Sse` route answers with `text/event-stream` and a body that stays\n // open; its return value is discarded. What makes this more than \"return a\n // stream\" is the moment of commitment: once ONE frame has gone out, the\n // 200 and the headers are spent, so a later throw can only be reported\n // in-band (FR-011). Before that first frame the status line is still ours\n // and an ordinary error envelope is both possible and much more useful\n // (FR-010). So the handler is started, and the decision waits for whichever\n // comes first — its first write, or its own completion.\n if (meta.options?.sseConfig !== undefined) {\n // The transport is built BEFORE the handler starts, so there is never a\n // window in which a written frame has nowhere to go. An unused stream\n // costs nothing: if the handler turns out never to write, the response\n // below is an ordinary envelope and this object is simply dropped.\n // (An earlier version created the stream only after the first frame and\n // held frames in a buffer meanwhile. That buffer's correctness depended\n // on microtask timing, so no test could pin it — mutation-checked: the\n // flush could be deleted with the suite still green. Untestable\n // defensive code is worse than no window at all.)\n let sseController!: ReadableStreamDefaultController<Uint8Array>;\n const sseEncoder = new TextEncoder();\n const stream = new ReadableStream<Uint8Array>({\n start(c) {\n sseController = c;\n },\n });\n sseEnqueue = (chunk) => {\n // Same exposure as the close below: a frame written after the client\n // left has nowhere to go, and saying so by throwing would kill the\n // process rather than the request.\n try {\n sseController.enqueue(sseEncoder.encode(chunk));\n } catch {\n // The reader is gone. The handler's own signal is what stops it.\n }\n };\n\n let sawFirstFrame!: () => void;\n const firstFrame = new Promise<void>((r) => (sawFirstFrame = r));\n\n // THE FIRST FRAME ENDS THE REQUEST PHASE.\n //\n // The handler runs inside the request's transaction, and a stream may\n // live for minutes. Holding a transaction that long exhausts the\n // connection pool — a failure no unit test sees, that appears only under\n // load, and that looks like \"the database is slow\" when it arrives. So\n // the transaction settles HERE, in the hook the writer awaits before it\n // emits anything: the ordering is structural, not a happy accident of\n // microtask scheduling.\n sseSettle = async () => {\n await db.commit();\n sawFirstFrame();\n };\n\n // …and afterwards the database is refused BY NAME. The alternative is a\n // settled transaction quietly answering a query, which is a correctness\n // bug the author would never find. The message says what happened and\n // what to do instead.\n const guarded: RuntimeServices = {\n ...services,\n Database: new Proxy(services.Database as object, {\n get(target, prop, recv) {\n // `started()` flips SYNCHRONOUSLY inside `write()`, which is the\n // only reading that works: `write` returns immediately, so a\n // handler's next line runs before the commit has finished. The\n // author's own call is the boundary, not the commit's completion.\n if (sseWriter.started()) {\n throw new Error(\n `sse_db_after_write: ${hit.entry.id} touched the database after its ` +\n `first write(). A streaming response settles its transaction with the ` +\n `first frame — do the database work before the first write.`,\n );\n }\n return Reflect.get(target, prop, recv);\n },\n }) as RuntimeServices[\"Database\"],\n };\n\n let thrown: unknown = null;\n const ran = Promise.resolve(runWithRuntime(guarded, () => {\n const box = requestALS.getStore();\n if (box) {\n box.userId = userId ?? null;\n box.requestId = requestId;\n box.idempotencyKey = req.headers.get(\"idempotency-key\");\n }\n const method = hit.entry.instance[meta.fnName];\n if (typeof method !== \"function\") {\n throw new Error(\n `route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`,\n );\n }\n return method.apply(hit.entry.instance, args);\n })).then(\n () => undefined,\n (err: unknown) => {\n thrown = err;\n },\n );\n\n await Promise.race([firstFrame, ran]);\n\n if (!sseWriter.started()) {\n // Nothing was ever written. The handler either finished silently or\n // threw before its first frame — either way the response shape is\n // still a free choice, so it gets the ordinary one.\n await ran;\n await db.commit();\n if (thrown !== null) throw thrown;\n return new Response(null, { status: 204 });\n }\n\n void (async () => {\n await ran;\n await sseWriter.drained();\n // THE CLIENT LEAVING IS A NORMAL ENDING, NOT AN ERROR.\n //\n // When the client disconnects the runtime closes this controller\n // itself, so the terminal write and close below arrive at a stream\n // that is already gone. Left unguarded they throw\n // `ERR_INVALID_STATE: Controller is already closed` from inside a\n // detached async task — which is an unhandled rejection, and under Bun\n // that KILLS THE SERVER PROCESS. One user closing a tab would take the\n // backend down with them.\n //\n // Measured 2026-08-29 against real OpenAI: curl was killed mid-stream\n // and the process exited with code 1 at this line. No unit test could\n // have caught it — in a test the client never disconnects at the\n // transport layer, so the controller is always still open here.\n try {\n if (thrown !== null) {\n log.error(`[engine] ${hit.entry.id} threw mid-stream`, thrown);\n sseController.enqueue(sseEncoder.encode(encodeErrorFrame(requestId)));\n }\n sseController.close();\n } catch {\n // Already closed: the client is gone and there is nobody to tell.\n }\n })();\n return new Response(stream, {\n status: 200,\n headers: { \"content-type\": SSE_CONTENT_TYPE, \"cache-control\": \"no-cache\" },\n });\n }\n\n const result = await runWithRuntime(services, () => {\n // The ALS box carries the caller's identity beside the services; Flags'\n // auto-bind reads it, and so does anything else that needs a\n // server-owned user id rather than one the caller supplied.\n const box = requestALS.getStore();\n if (box) {\n box.userId = userId ?? null;\n box.requestId = requestId;\n box.idempotencyKey = req.headers.get(\"idempotency-key\");\n }\n const method = hit.entry.instance[meta.fnName];\n if (typeof method !== \"function\") {\n throw new Error(\n `route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`,\n );\n }\n return method.apply(hit.entry.instance, args);\n });\n await db.commit();\n\n if (meta.returnSchema) {\n const v = meta.returnSchema.safeParse(result);\n if (!v.success) {\n log.error(`[engine] ${hit.entry.id} returned a value its declared type rejects`, v.error.issues);\n return envelope(\n \"output_invalid\",\n \"The handler returned a value its declared return type rejects\",\n 500,\n requestId,\n );\n }\n }\n if (result === undefined || result === null) {\n if (completionUploadId) {\n completions.remember(completionUploadId, { status: 204, body: null, contentType: null });\n }\n return new Response(null, { status: 204 });\n }\n const payload = JSON.stringify(result);\n if (completionUploadId) {\n completions.remember(completionUploadId, {\n status: 200,\n body: payload,\n contentType: JSON_HEADERS[\"content-type\"] ?? \"application/json\",\n });\n }\n return new Response(payload, { status: 200, headers: JSON_HEADERS });\n } catch (err) {\n // The handler threw after writing: nothing it wrote may survive.\n await db.rollback(err);\n // Branded, not `instanceof`: the tenant's bundle carries its own copy of\n // this SDK, so class identity does not survive the hop from the handler\n // to this catch. See HTTP_ERROR_BRAND.\n if (isHttpError(err)) {\n // AN UNCAUGHT HttpError LEFT NO TRACE. A `NotFound` is the handler\n // ANSWERING — logging every one of those is noise nobody reads. But an\n // error the handler did not mean to answer with — the `UniqueViolation`\n // the engine raised from a duplicate write, say — became an HTTP\n // response and vanished server-side, which is BLINDER than the bare 500\n // it replaced: that one at least logged.\n //\n // The split is on INTENT, and intent has TWO readings because one is\n // not enough: the engine MARKS the errors it built out of driver\n // failures (those always log, whatever their status), and beyond that\n // the codes an author throws to answer a request stay quiet. 409 needs\n // both — see AUTHOR_ANSWERED.\n if (isEngineRaised(err) || !AUTHOR_ANSWERED.has(err.status)) {\n log.error(`[engine] unhandled ${err.error} in ${hit.entry.id}`, err);\n }\n return envelope(\n err.error,\n err.errorDescription,\n err.status,\n requestId,\n err.data !== undefined ? { data: err.data } : undefined,\n );\n }\n log.error(`[engine] unhandled error in ${hit.entry.id}`, err);\n return envelope(\"internal_error\", \"The request could not be completed\", 500, requestId);\n }\n }\n\n // The author's own long-lived resources come up HERE: after the pool has been\n // proven (`select 1` above) and before anything can be served. A hook that\n // throws REFUSES THE BOOT — an app that answers with a half-open resource\n // behind it is the silence `onStart` exists to replace — and the pool this\n // function opened is closed on the way out, because nobody will ever get the\n // `shutdown` below to close it.\n // START HOOKS RUN IN A SCOPE — a BOOT one, not a request one.\n //\n // A start hook is where a long-lived resource comes up, and the credential\n // that resource needs lives in the vault. `Secrets.get()` threw \"outside a\n // request scope\" here, so the one place an author is TOLD to open a pool could\n // not read the password for it (D-19).\n //\n // Everything that is genuinely boot-level — Secrets, Cache, Log, the module\n // clients — is handed over. `Database` is NOT, and refuses BY NAME: a start\n // hook runs before anything is served, so there is no request and no\n // transaction for a query to belong to. Handing out a real one would open a\n // transaction on the boot path that nobody closes; saying so is the honest\n // answer and the one an author can act on.\n const bootServices = buildServices(null);\n\n let runShutdownHooks: ShutdownRunner;\n try {\n runShutdownHooks = await runWithRuntime(bootServices, () => __runStartHooks());\n } catch (err) {\n await closeDriver(sql);\n throw err;\n }\n\n return {\n handle,\n routes,\n config,\n runInServiceScope,\n async shutdown() {\n // The author's resource is released BEFORE the pool: a driver standing on\n // this pool cannot close after the pool is gone.\n await runShutdownHooks();\n await closeDriver(sql);\n },\n };\n}\n\n/** Let go of the driver — `close` or `end`, whichever it carries. */\nasync function closeDriver(sql: SqlDriver): Promise<void> {\n const closable = sql as { close?: () => Promise<void> | void; end?: () => Promise<void> | void };\n await closable.close?.();\n await closable.end?.();\n}\n","/**\n * runtime.ts — request-scoped service singletons.\n *\n * The backend SDK no longer threads a `ctx` god-object through every handler.\n * Instead, controller methods import PascalCase service singletons directly:\n *\n * import { Controller, Post, Body, Database } from \"@palbase/backend\";\n *\n * \\@Controller(\"/todos\")\n * export default class TodosController {\n * \\@Post(\"\") create(\\@Body(CreateTodoBody) body: CreateTodoBody): unknown {\n * return Database.insert(\"todos\", { title: body.title });\n * }\n * }\n *\n * The singletons are thin Proxies. Every property access forwards to the live\n * client for the CURRENT request scope, resolved through {@link __getRuntime}.\n *\n * # Request-scope resolution (persistent app-server)\n *\n * The runtime is a long-running Node process that serves many concurrent\n * requests on one event loop (NOT a fresh subprocess per request). A single\n * module-global slot would let one in-flight request's services bleed into\n * another's. So the services are carried in an {@link AsyncLocalStorage} store\n * ({@link __requestALS}) that the runtime sets per request with\n * {@link __runWithRuntime}; every async continuation of that request reads its\n * own store. `__getRuntime` reads the ALS store first; the module-global slot\n * (set by {@link __setRuntime}) is only a fallback for callers that run OUTSIDE\n * an ALS scope (dev-server, unit tests, the legacy single-shot path). Because\n * each `br-<ref>` pod is single-tenant, there is no cross-tenant leakage; the\n * ALS store is what prevents cross-REQUEST leakage within the shared process.\n *\n * The seam that makes `import { Database } from \"@palbase/backend\"` resolve to\n * the runtime-injected client: `@palbase/backend` is marked esbuild-EXTERNAL\n * when the tenant bundle is built, and the package is installed globally in the\n * pod (NODE_PATH=/usr/local/lib/node_modules). So worker.js's\n * `require('@palbase/backend')` and the bundle's `import` resolve to ONE shared\n * module instance — the ALS store and `__setRuntime` slot on that instance are\n * visible to the singletons the bundle imported.\n */\n\nimport type { PalbaseFlagKey } from \"./stack.js\";\nimport type { Buckets, BucketTypes, Schemas } from \"./db/env.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type {\n DBClient,\n DBOps,\n CacheClient,\n Logger,\n PalbaseDocsClient,\n SecretsService,\n} from \"./endpoint.js\";\nimport type {\n PalbaseStorageClient,\n PalbaseBucketClient,\n PalbaseNotificationsClient,\n PalbaseFlagsClient,\n PalbaseFlagsServiceClient,\n PalbaseFlagContext,\n PalbaseFlagVariant,\n PalbaseFlag,\n PalbaseFlagValue,\n PalbaseSetOverrideResult,\n PalbaseRealtimeClient,\n} from \"./clients.js\";\nimport type { PalbaseResult } from \"./endpoint.js\";\nimport type {\n EnvTypedDatabase,\n EnvServiceDatabase,\n EnvSchemas,\n EnvTables,\n TxPlan,\n TxTables,\n} from \"./db/typed-db.js\";\nimport type { Materialized } from \"./db/tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./db/tx-plan.js\";\n\n/** The set of live clients the runtime injects per request scope.\n *\n * Realtime is BROADCAST-ONLY here (a stateless handler can push an event but\n * cannot hold a subscription socket — `subscribe()` lives on the client SDK).\n *\n * EXCLUDED on purpose: Functions, Links, Analytics, Auth. They are not\n * exposed as backend handler singletons (auth lives on the client SDK; the rest\n * are out of scope for backend endpoints). */\nexport interface RuntimeServices {\n Database: DBClient;\n Secrets: SecretsService;\n Documents: PalbaseDocsClient;\n Storage: PalbaseStorageClient;\n Cache: CacheClient;\n Log: Logger;\n Notifications: PalbaseNotificationsClient;\n Flags: PalbaseFlagsClient;\n Realtime: PalbaseRealtimeClient;\n}\n\n/**\n * The per-request ALS box.\n *\n * `runtime` is the service bundle. `userId` is the request's authenticated user\n * id, written by the runtime immediately after it assembles the request object\n * (worker.js: `requestALS.getStore().userId = pbReq.user?.id || null`) and\n * `null` on an anonymous request. It was already being written there for the\n * Flags client's auto-bind; declaring it here makes the existing contract typed\n * instead of implicit, which is what lets `currentSubjectId()` read a\n * server-owned identity rather than trusting anything the caller sent.\n */\nexport interface RequestStore {\n runtime: RuntimeServices;\n userId?: string | null;\n /** This request's id (`req_…`), written by the runtime. Used as the spend\n * idempotency scope when the caller supplied no `Idempotency-Key`. */\n requestId?: string;\n /** The caller's `Idempotency-Key` header, or `null` when absent. What makes a\n * client's retry replay its first result instead of charging twice. */\n idempotencyKey?: string | null;\n}\n\n/**\n * Per-request store. The persistent runtime runs each request inside\n * {@link __runWithRuntime}, so every async continuation of that request reads\n * its OWN `runtime` (and any other request-scoped fields the runtime adds).\n *\n * Exported with a `__` prefix so the runtime (worker.js) shares the SAME ALS\n * instance across the one module instance — two ALS instances would silently\n * not see each other's stores. NOT part of the public author-facing API.\n */\nexport const __requestALS = new AsyncLocalStorage<RequestStore>();\n\n/** Process-global fallback slot. Used only OUTSIDE an ALS scope (dev-server,\n * unit tests, legacy single-shot worker). Inside the persistent server every\n * request runs in {@link __requestALS}, which takes precedence. */\nlet runtime: RuntimeServices | null = null;\n\n/** Install the live clients in the process-global fallback slot.\n *\n * Persistent-server requests should use {@link __runWithRuntime} instead; this\n * remains for dev-server / tests / the legacy single-shot path that run without\n * an ALS scope. NOT part of the public author-facing API. */\nexport function __setRuntime(services: RuntimeServices): void {\n runtime = services;\n}\n\n/** Run `fn` with `services` bound as the request-scoped runtime.\n *\n * The persistent worker calls this once per request so concurrent requests\n * never share a services slot. NOT part of the public author-facing API. */\nexport function __runWithRuntime<T>(services: RuntimeServices, fn: () => T): T {\n return __requestALS.run({ runtime: services }, fn);\n}\n\n/** Read the live clients, throwing if accessed outside a request scope.\n *\n * Resolves the ALS store first (persistent server, per-request), then the\n * process-global fallback (dev-server / tests). NOT part of the public\n * author-facing API — used by the runtime and the singleton Proxies. */\nexport function __getRuntime(): RuntimeServices {\n const scoped = __requestALS.getStore();\n if (scoped) return scoped.runtime;\n if (runtime === null) {\n throw new Error(\n \"Palbase services accessed outside a request scope. The Database/Documents/… \" +\n \"singletons are only available inside an endpoint handler (or after the \" +\n \"runtime has called __runWithRuntime / __setRuntime).\",\n );\n }\n return runtime;\n}\n\n// ─── lifecycle: where a long-lived resource lives (FR-013) ─────────────────\n//\n// `Resource` was removed in 23.0.0 and nothing replaced the LIFECYCLE half of\n// it. What that left behind is measurable: a connection pool (the driver in\n// `docs/resources.md`'s own example was Neo4j) had no documented place to be\n// opened and NO WAY AT ALL to be closed, so every deploy left the pool it\n// opened behind. These two hooks are that half — and only that half. The\n// secret-distribution half does not come back: a handler reads `Secrets.get`,\n// and a start hook, which runs before any request scope exists, reads the\n// `process.env` the runtime mirrors the vault into at boot.\n\n/** A lifecycle hook. Sync or async; the runtime awaits what it returns. */\nexport type LifecycleHook = () => void | Promise<void>;\n\n/** Runs one release's shutdown hooks. Handed back by {@link __runStartHooks}\n * and called by the engine's `app.shutdown()`. Idempotent. */\nexport type ShutdownRunner = () => Promise<void>;\n\ninterface DeclaredHook {\n name: string;\n run: LifecycleHook;\n}\n\ninterface DeclaredLifecycle {\n start: DeclaredHook[];\n shutdown: DeclaredHook[];\n}\n\n/**\n * What has been DECLARED and not yet claimed by an app.\n *\n * On globalThis under a well-known Symbol for the reason the controller\n * registry is (`decorators/controller.ts`): a deployed bundle inlines its own\n * copy of this package, and the engine that has to RUN these hooks holds the\n * other copy. Two module-local arrays would mean the engine reads the empty one\n * and every declared hook is silently never run — which is exactly how\n * `Resource`'s `init(env)` died.\n */\nconst LIFECYCLE: unique symbol = Symbol.for(\"palbase.backend.lifecycleHooks\") as never;\n\nfunction declaredLifecycle(): DeclaredLifecycle {\n const g = globalThis as unknown as Record<symbol, DeclaredLifecycle | undefined>;\n return (g[LIFECYCLE] ??= { start: [], shutdown: [] });\n}\n\n/**\n * Run `hook` ONCE while the application comes up, before it serves anything.\n *\n * Call it at MODULE SCOPE in a file the application imports — the same rule\n * `defineDefaultAuth` and `@Controller` follow, and for the same reason: the\n * declaration is claimed when the app boots, which is after module loading and\n * before the first request. `name` is not decoration: a hook that throws is\n * reported by that name and the boot is REFUSED, so it is what tells an\n * operator which resource did not come up.\n *\n * There is no request scope yet, so the `Database`/`Secrets`/… singletons are\n * NOT available inside a start hook. A secret is read from `process.env` here\n * (the runtime mirrors the vault into it at boot).\n *\n * @example\n * // resources/graph.ts\n * import neo4j from \"neo4j-driver\";\n * import { onStart, onShutdown } from \"@palbase/backend\";\n *\n * export let graph: Driver;\n * onStart(\"graph\", () => {\n * graph = neo4j.driver(process.env.NEO4J_URL!, neo4j.auth.basic(\"neo4j\", process.env.NEO4J_PASSWORD!));\n * });\n * onShutdown(\"graph\", () => graph.close());\n */\nexport function onStart(name: string, hook: LifecycleHook): void {\n declaredLifecycle().start.push({ name, run: hook });\n}\n\n/**\n * Run `hook` while the application shuts down — the place a pool opened in\n * {@link onStart} is closed.\n *\n * Shutdown is BEST-EFFORT by design: a hook that throws is reported by name and\n * the rest still run. A drain that abandoned the remaining hooks on the first\n * failure would leak exactly what this exists to release, and the process is\n * leaving anyway.\n *\n * Hooks run in REVERSE declaration order, so a resource is released before what\n * it was built on.\n */\nexport function onShutdown(name: string, hook: LifecycleHook): void {\n declaredLifecycle().shutdown.push({ name, run: hook });\n}\n\nfunction reason(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Best-effort drain: every hook runs, a failure is reported, none is silent. */\nasync function drain(hooks: DeclaredHook[]): Promise<void> {\n for (const h of [...hooks].reverse()) {\n try {\n await h.run();\n } catch (err) {\n console.error(`[palbase] shutdown hook \"${h.name}\" failed: ${reason(err)}`, err);\n }\n }\n}\n\n/**\n * CLAIM what has been declared, run the start hooks, and hand back the runner\n * for this release's shutdown hooks. Called by the engine's `createApp`; the\n * `App.shutdown()` it builds calls what comes back. NOT part of the public\n * author-facing API.\n *\n * IT CLAIMS RATHER THAN READS, which is what makes it correct in this runtime:\n * a candidate release is loaded BESIDE the live one in one process\n * (`v2/runtime/src/registry-scope.ts`), and both bundles append to the one\n * shared slot above. If each app read the whole list, the live app's shutdown\n * would close the candidate's pool and the candidate's would close the live\n * app's. Taking the declarations leaves each app holding exactly its own.\n *\n * A start hook that throws REFUSES THE BOOT — with the hook's name in the\n * message — after releasing whatever the earlier hooks already opened. Serving\n * from a half-initialised app is the silence this whole surface replaces, and a\n * boot that dies holding an open pool is the leak it replaces.\n */\nexport async function __runStartHooks(): Promise<ShutdownRunner> {\n const slot = declaredLifecycle();\n const start = slot.start.splice(0);\n const shutdown = slot.shutdown.splice(0);\n\n for (const h of start) {\n try {\n await h.run();\n } catch (err) {\n await drain(shutdown);\n throw new Error(`[palbase] start hook \"${h.name}\" failed: ${reason(err)}`, { cause: err });\n }\n }\n\n let drained = false;\n return async () => {\n // SIGTERM racing a redeploy asks twice; a pool is closed once.\n if (drained) return;\n drained = true;\n await drain(shutdown);\n };\n}\n\n/** Drop every declaration. For tests, which declare repeatedly in one process.\n * NOT part of the public author-facing API. */\nexport function __resetLifecycleHooks(): void {\n const g = globalThis as unknown as Record<symbol, DeclaredLifecycle | undefined>;\n delete g[LIFECYCLE];\n}\n\n/**\n * Build a Proxy singleton that forwards every property access to the live\n * client named `key` on the current runtime.\n *\n * The single `as RuntimeServices[K]` is the only contained cast in the surface:\n * `Reflect.get` on a typed object returns `unknown` for a `string | symbol`\n * key, but `prop` is constrained to keys of the client interface at the call\n * sites (the exported singletons are typed below), so the forward is sound.\n */\nfunction makeServiceProxy<K extends keyof RuntimeServices>(key: K): RuntimeServices[K] {\n const handler: ProxyHandler<RuntimeServices[K]> = {\n get(_target, prop, receiver) {\n const client = __getRuntime()[key];\n const value = Reflect.get(client as object, prop, receiver) as unknown;\n // Bind methods to their owning client so `this` stays correct when the\n // author destructures or calls `Database.query(...)`.\n return typeof value === \"function\" ? value.bind(client) : value;\n },\n };\n // The Proxy target is irrelevant (all access goes through `get`); the cast\n // names the surface type the singleton presents to authors.\n return new Proxy({} as RuntimeServices[K], handler);\n}\n\n/**\n * Build the `.tables` accessor for the top-level `Database`. Each\n * `tables.<name>` access returns a small object that forwards the five CRUD ops\n * to the underlying client using `name` as the string table identifier. The\n * shapes are typed against the generated `palbase-env.d.ts` (`EnvTables`); at\n * runtime they are plain string-keyed calls, so no schema value is needed here.\n *\n * Returns `EnvTables` — TS cannot infer the mapped type through the Proxy, so\n * a single structural narrowing names the surface (the proxy returns a\n * correctly-shaped accessor for whatever string member is read).\n */\n/** T018 (C-8): similar/recommend'in string-keyed yüzü. DBOps'a (endpoint.ts)\n * BİLEREK eklenmedi — search-param imza üçlüsü (engine/db + typed-db +\n * endpoint) büyümesin: proxy dispatch runtime'da engine ops'una zaten ulaşır,\n * derleme güvenliğini typed yüzey (EnvTypedTable) verir. */\ninterface RecoOps {\n similar(table: string, id: string, params?: Record<string, unknown>): Promise<Record<string, unknown>[]>;\n recommend(table: string, params: Record<string, unknown>): Promise<Record<string, unknown>[]>;\n}\n\n/**\n * The Proxy behind EVERY `.tables` map — public's and every other schema's.\n *\n * `prefix` is what the wire name is built from: `\"\"` for `public`, so its tables\n * stay BARE, and `\"<schema>.\"` for any other, so `schema(\"billing\").tables\n * .invoices` reaches the broker as `billing.invoices` (D-10 — the same\n * schema-qualified key `toSchemaJSON` and the generated `relations` use).\n *\n * One trap for both surfaces: two copies would be two op lists that can drift,\n * and the one that forgets an op does not complain — it answers `undefined`.\n */\nfunction makeTableProxy(ops: () => DBOps & RecoOps, prefix: string): object {\n return new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n const name = `${prefix}${prop}`;\n return {\n insert: (data: Record<string, unknown>) => ops().insert(name, data),\n update: (id: string, data: Record<string, unknown>) => ops().update(name, id, data),\n delete: (id: string) => ops().delete(name, id),\n findById: (id: string) => ops().findById(name, id),\n findMany: (query?: Record<string, unknown>, opts?: Parameters<DBOps[\"findMany\"]>[2]) =>\n ops().findMany(name, query, opts),\n upsert: (data: Record<string, unknown>, opts: { onConflict: readonly string[] }) =>\n ops().upsert(name, data, opts),\n // THREE VERBS THE TYPE PROMISED AND THIS PROXY DID NOT EMIT.\n //\n // `EnvTypedTableBase` declares `updateMany`, `deleteMany` and `count`\n // (typed-db.ts) and the ops layer implements all three — only this\n // proxy, which is what a handler actually touches, left them out. So\n // the type said the verb exists, autocomplete offered it, and the call\n // answered `undefined is not a function`.\n //\n // Older than this run, but the run rewrote this proxy for\n // `Database.schema(name).tables.*` and would have carried the gap onto\n // the new surface too.\n updateMany: (where: Record<string, unknown>, set: Record<string, unknown>) =>\n ops().updateMany(name, where, set),\n deleteMany: (where: Record<string, unknown>) => ops().deleteMany(name, where),\n count: (where?: Record<string, unknown>) => ops().count(name, where),\n search: (params?: Record<string, unknown>) => ops().search(name, params),\n similar: (id: string, params?: Record<string, unknown>) => ops().similar(name, id, params),\n recommend: (params: Record<string, unknown>) => ops().recommend(name, params),\n facets: (params: { facets: string[] } & Record<string, unknown>) => ops().facets(name, params),\n supersede: (id: string, row: Record<string, unknown>) => ops().supersede(name, id, row),\n };\n },\n },\n );\n}\n\nfunction makeTablesAccessor(ops: () => DBOps & RecoOps): EnvTables {\n return makeTableProxy(ops, \"\") as EnvTables;\n}\n\n/**\n * The `.tables` map of ONE schema other than `public`, as\n * `Database.schema(\"billing\")` returns it.\n *\n * Same accessor, one difference: the wire name is schema-qualified. Nothing here\n * decides whether the schema is reachable — `exposed` is the schema's own\n * declaration and the broker checks it.\n */\nfunction makeSchemaAccessor<S extends keyof Schemas>(\n ops: () => DBOps & RecoOps,\n schema: S,\n): EnvSchemas[S] {\n return { tables: makeTableProxy(ops, `${String(schema)}.`) } as EnvSchemas[S];\n}\n\n/** The raw string-keyed `DBClient` for the current request scope. */\nconst rawDatabase: DBClient = makeServiceProxy(\"Database\");\n\n/**\n * Wrap a raw `DBClient` into the typed `{ ...ops, tables, transaction }`\n * surface. The five string ops forward straight through; `tables` is the\n * env-typed accessor; `transaction` yields typed tables. Reused for both the\n * default (RLS-enforced) `Database` and the `asService()` sibling — each is\n * fed its own raw client (the default proxy vs `rawDatabase.asService()`).\n *\n * The `satisfies` pins the op surface so a missing/renamed op is a compile\n * error; the assembled object carries `tables`/`transaction` alongside.\n */\nfunction makeTypedSurface(raw: Omit<DBClient, \"asService\">): EnvServiceDatabase {\n // Proxy dispatch her üyeyi taşır; RecoOps tipi DBClient'a eklenmediğinden\n // (yukarıdaki karar) similar/recommend erişimi bu daraltmadan geçer.\n const reco = raw as Omit<DBClient, \"asService\"> & RecoOps;\n const ops = {\n query: (sql: string, params?: unknown[]) => raw.query(sql, params),\n insert: (table: string, data: Record<string, unknown>) => raw.insert(table, data),\n update: (table: string, id: string, data: Record<string, unknown>) =>\n raw.update(table, id, data),\n delete: (table: string, id: string) => raw.delete(table, id),\n findById: (table: string, id: string) => raw.findById(table, id),\n findMany: (table: string, query?: Record<string, unknown>, opts?: Parameters<DBOps[\"findMany\"]>[2]) =>\n raw.findMany(table, query, opts),\n upsert: (table: string, data: Record<string, unknown>, opts: { onConflict: readonly string[] }) =>\n raw.upsert(table, data, opts),\n updateMany: (table: string, where: Record<string, unknown>, set: Record<string, unknown>) =>\n raw.updateMany(table, where, set),\n deleteMany: (table: string, where: Record<string, unknown>) => raw.deleteMany(table, where),\n count: (table: string, where?: Record<string, unknown>) => raw.count(table, where),\n search: (table: string, params?: Record<string, unknown>) => raw.search(table, params),\n similar: (table: string, id: string, params?: Record<string, unknown>) =>\n reco.similar(table, id, params),\n recommend: (table: string, params: Record<string, unknown>) => reco.recommend(table, params),\n facets: (table: string, params: { facets: string[] } & Record<string, unknown>) => reco.facets(table, params),\n supersede: (table: string, id: string, row: Record<string, unknown>) =>\n raw.supersede(table, id, row),\n } satisfies DBOps & RecoOps;\n return Object.assign(ops, {\n // Both surfaces get it: a savepoint on the service transaction is as useful\n // as one on the request's, and each is bound to its own connection.\n attempt: <T,>(fn: (tx: DBOps) => Promise<T>) => raw.attempt(fn),\n tables: makeTablesAccessor(() => reco),\n schema: <S extends keyof Schemas>(name: S): EnvSchemas[S] =>\n makeSchemaAccessor(() => reco, name),\n transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n // A FRESH builder per call: it holds this transaction's ops and its error\n // slot table, and the runtime serves concurrent requests on one event loop.\n // A shared builder would splice one request's writes into another's plan.\n const builder = new TxPlanBuilder();\n return runTxPlan(raw, makeTxTablesAccessor(builder), builder, fn) as Promise<\n Materialized<T>\n >;\n },\n });\n}\n\n/**\n * The transaction twin of {@link makeTablesAccessor}: `tables.<name>` yields the\n * table's PLAN operations, recorded into `builder` instead of sent one by one.\n *\n * Same Proxy shape and same reason for the single narrowing — TS cannot infer a\n * mapped type through a Proxy, so the cast names what the trap returns.\n */\nfunction makeTxTablesAccessor(builder: TxPlanBuilder): TxTables {\n const tablesProxy = new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n return builder.table(prop);\n },\n },\n );\n return tablesProxy as TxTables;\n}\n\n/**\n * The project's own Postgres (pgx, schema `env_<envId>`).\n *\n * Typed by default: `Database.tables.<name>.insert({...})` is typed against\n * the project's generated `palbase-env.d.ts` with NO import and NO generic.\n * The raw string ops (`query`/`insert`/`update`/`delete`/`findById`/`findMany`)\n * are also available for dynamic table names and read-only SQL.\n *\n * RLS is enforced by default (the runtime runs each op as `authenticated` with\n * the verified user's claims). To bypass RLS, call `Database.asService()` —\n * explicit and greppable — which runs as the `service_role` (BYPASSRLS).\n *\n * @example\n * import { Database } from \"@palbase/backend\";\n *\n * const todo = await Database.tables.todos.insert({ title: req.input.title });\n * todo.id; // string ✓\n * const rows = await Database.query(\"SELECT id FROM todos WHERE done = $1\", [false]);\n * const all = await Database.asService().tables.todos.findMany({}); // RLS bypass\n */\nexport const Database: EnvTypedDatabase = Object.assign(makeTypedSurface(rawDatabase), {\n /**\n * Lazily resolve the runtime's service-role sibling on each call. We do NOT\n * cache it: `rawDatabase.asService()` reads the CURRENT request scope through\n * the runtime proxy, and the per-request runtime injects a service client\n * bound to that request's identity headers — caching would leak one request's\n * sibling into another concurrent request.\n */\n asService(): EnvServiceDatabase {\n return makeTypedSurface(rawDatabase.asService());\n },\n});\n\n/** Firestore-like document client (PalDocs). */\nexport const Documents: PalbaseDocsClient = makeServiceProxy(\"Documents\");\n\n/**\n * `buckets.<name>` — the storage twin of `Database.tables.<name>`, and the same\n * mechanism: `config/storage.ts` generates a `Buckets` augmentation into\n * `palbase-env.d.ts`, so a bucket name is a property with no import and no\n * generic, and a typo is a compile error.\n *\n * The intermediate `.buckets` is there for the reason `.tables` is: bucket\n * names must not share a namespace with the client's own methods, or the day\n * somebody declares a bucket called `bucket` the surface breaks.\n */\nexport type EnvBuckets = {\n [K in keyof Buckets]: TypedBucketClient<Buckets[K] extends BucketTypes ? Buckets[K] : BucketTypes>;\n};\n\n/** One bucket, with its declared variant names in the type. */\nexport interface TypedBucketClient<B extends BucketTypes> extends Omit<PalbaseBucketClient, \"getPublicUrl\"> {\n /** The public URL for the object, or for one of THIS bucket's declared\n * renditions. A name the bucket does not declare is a compile error. */\n getPublicUrl(path: string, options?: { variant?: B[\"variants\"] }): string;\n}\n\nfunction makeBucketsAccessor(storage: () => PalbaseStorageClient): EnvBuckets {\n return new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n return storage().bucket(prop);\n },\n },\n ) as EnvBuckets;\n}\n\nconst rawStorage: PalbaseStorageClient = makeServiceProxy(\"Storage\");\n\n/**\n * Object storage: buckets, objects, renditions and signed URLs.\n *\n * `Storage.buckets.posts.upload(...)` is the typed path. `Storage.bucket(name)`\n * remains for a name computed at runtime — rare, and it gives up the typing,\n * which is the honest trade rather than a second blessed way to do it.\n */\nexport const Storage: PalbaseStorageClient & { buckets: EnvBuckets } = Object.assign(\n {\n // FORWARDED explicitly, not assigned onto the service proxy.\n //\n // `Object.assign(rawStorage, {buckets})` writes onto the proxy's TARGET, and\n // the proxy's only trap is `get`, which forwards every read to the module\n // client — so the property landed somewhere nothing reads and\n // `Storage.buckets.docs` was `undefined` in a deployed handler. It\n // typechecked, every test passed, and the live call answered\n // \"TypeError: undefined is not an object\". `Database` never had the bug\n // because it builds a plain surface the same way this now does.\n bucket: (name: string) => rawStorage.bucket(name),\n },\n { buckets: makeBucketsAccessor(() => rawStorage) },\n);\n\n/** JSON-typed cache (get/set/incr/getOrSet). */\nexport const Cache: CacheClient = makeServiceProxy(\"Cache\");\n\n\n/**\n * This tenant's secrets — API keys, provider credentials, signing material the\n * BACKEND owns.\n *\n * `await Secrets.get(\"STRIPE_KEY\")` in a handler. There is no `.env` to read\n * and no file to mount: a secret is written through the vault's authenticated\n * API (or the CLI/MCP that calls it), and this is how the deployed code reads\n * it back. A name this tenant has not set answers null — as does every name\n * the STACK holds, because no route returns a platform secret's value at all.\n */\nexport const Secrets: SecretsService = makeServiceProxy(\"Secrets\");\n\n/** Structured logger. */\nexport const Log: Logger = makeServiceProxy(\"Log\");\n\n/** Push / email / SMS / in-app notifications. */\nexport const Notifications: PalbaseNotificationsClient = makeServiceProxy(\"Notifications\");\n\n\n/**\n * The raw runtime Flags client for the current request scope. Carries the\n * default-surface reads + `setOverride` AND the runtime's `asService()` sibling\n * (the br-pod's `buildFlagsClient` returns both). The default `Flags` singleton\n * below forwards reads + `setOverride` through here; `Flags.asService()`\n * forwards to this client's own `asService()`.\n */\nconst rawFlags: PalbaseFlagsClient = makeServiceProxy(\"Flags\");\n\n/**\n * Feature flags.\n *\n * Mirrors the `Database` / `Database.asService()` model. The default surface is\n * RLS-equivalent for flags: reads resolve against the CURRENT request user and\n * `Flags.setOverride(key, value)` writes an override for that same signed-in\n * user (no userId argument, no admin power). Cross-user admin writes\n * (`setOverrideForUser`, …) live behind `Flags.asService()` — explicit and\n * greppable, just like `Database.asService()`.\n *\n * @example\n * import { Flags } from \"@palbase/backend\";\n *\n * if (await Flags.isEnabled(\"new_checkout\")) { ... } // current user\n * await Flags.setOverride(\"new_checkout\", true); // current user\n * await Flags.asService().setOverrideForUser(\"u_9\", \"x\", true); // cross-user\n */\nexport const Flags: PalbaseFlagsClient = Object.assign(\n {\n isEnabled(\n flagName: PalbaseFlagKey,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<boolean>> {\n return rawFlags.isEnabled(flagName, context);\n },\n getVariant(\n flagName: PalbaseFlagKey,\n context?: PalbaseFlagContext,\n ): Promise<PalbaseResult<PalbaseFlagVariant>> {\n return rawFlags.getVariant(flagName, context);\n },\n getAll(context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlag[]>> {\n return rawFlags.getAll(context);\n },\n /**\n * Resolve a flag's value, with an optional fallback.\n *\n * FORWARDED as of 2026-08-15. This surface is written out by hand, method\n * by method, and `get` was missing from it — so the client implemented it,\n * thirty assertions covered it, and `Flags.get(\"x\")` was `undefined` in a\n * deployed handler. Exactly the shape of the `Storage.buckets` defect found\n * the same day: a hand-maintained forwarding list is a list somebody has to\n * remember to update.\n */\n get(\n flagName: PalbaseFlagKey,\n defaultOrContext?: PalbaseFlagValue | PalbaseFlagContext,\n maybeContext?: PalbaseFlagContext,\n ): Promise<PalbaseResult<PalbaseFlagValue>> {\n return rawFlags.get(flagName, defaultOrContext, maybeContext);\n },\n setOverride(\n key: PalbaseFlagKey,\n value: PalbaseFlagValue,\n ): Promise<PalbaseResult<PalbaseSetOverrideResult>> {\n return rawFlags.setOverride(key, value);\n },\n },\n {\n /**\n * Lazily resolve the runtime's cross-user sibling on each call. We do NOT\n * cache it: `rawFlags.asService()` reads the CURRENT request scope through\n * the runtime proxy, so caching would leak one request's sibling into\n * another concurrent request. Mirrors `Database.asService()`.\n */\n asService(): PalbaseFlagsServiceClient {\n return rawFlags.asService();\n },\n },\n);\n\n/**\n * The Realtime broadcast singleton for the current request scope. Backend-side\n * Realtime is BROADCAST-ONLY (a stateless handler can push but not subscribe —\n * `subscribe()` lives on the client SDK's `pb.realtime`). Fire-and-forget:\n * `broadcast` resolves once accepted (or with an `error`), never blocking the\n * handler on subscribers.\n *\n * @example\n * import { Realtime } from \"@palbase/backend\";\n *\n * await Realtime.broadcast(\"room:42\", \"message\", { text, from: user.id });\n */\nexport const Realtime: PalbaseRealtimeClient = makeServiceProxy(\"Realtime\");\n","/**\n * tx-plan.ts — `Database.transaction()` as a PLAN, not a pinned session.\n *\n * A transaction used to be a conversation: BEGIN, then one network round trip\n * per operation, then COMMIT. Each of those round trips cost ~4 ms and, because\n * the pooler runs in transaction mode, an open transaction pinned a Postgres\n * backend for the whole conversation. A 121-operation statement upload pinned\n * one backend for ~490 ms.\n *\n * So the callback no longer TALKS to the database. It DESCRIBES what should\n * happen; the description is serialised and sent once; the broker runs the whole\n * thing inside one transaction and answers once. Committing on return and\n * rolling back on throw is unchanged — that is the only property tenant code\n * actually asked for.\n *\n * The consequences, stated plainly, because they are the whole design:\n *\n * - The callback is SYNCHRONOUS. There is nothing to await: no statement has\n * run yet when it returns. `async` on the callback and `await` inside it are\n * both compile errors (see {@link TxPlan} and {@link NotAwaitable}).\n * - `insert()` does not hand back a row, it hands back {@link TxRows}. Reading\n * a field requires `.expectOne(err)` first, which makes \"what if the row\n * isn't there\" a question you cannot route around: it is the argument.\n * - A field read from a row is a {@link Ref} — a PROMISE OF A VALUE THE SERVER\n * WILL PRODUCE, not the value. It can be written into a later operation and\n * it can be returned from the callback (it is substituted for the real value\n * before `transaction()` resolves). It cannot be branched on. See the\n * \"Truthiness\" note below — this is the sharp edge of the whole design.\n * - Control flow that needs a real value must move OUT of the callback: read\n * before the transaction, or express the condition as a guard\n * (`updateWhere({ id, accepted_at: null }, …).expectOne(new Conflict(…))`)\n * which the server evaluates and which rolls the whole plan back.\n *\n * # Truthiness — the hole this file CANNOT close\n *\n * JavaScript does not let a Proxy trap truthiness. `if (ref)` takes the true\n * branch, always, for every Ref, and no `get` handler ever runs. `tsc` is silent\n * because a Ref is a perfectly good object. So:\n *\n * const pot = tx.tables.pots.select({ id }, { limit: 1 }).expectOne(e);\n * if (!pot.balance) { … } // ← ALWAYS false. Silently wrong data.\n *\n * What this file does close: coercion (`Symbol.toPrimitive`/`valueOf`/\n * `toString`), awaiting (`then` is a callable member with a non-thenable\n * signature, which is a *compile* error), serialisation (`toJSON`), and nesting\n * a Ref inside a literal value where the server would store it as data. What it\n * cannot close is a bare truthiness test. The real defence is the build-time\n * static analysis (`tx_analysis.js`, phase P4); until that ships, this hole is\n * open and this comment is the only warning.\n *\n * # Wire contract\n *\n * The JSON this file emits is consumed by\n * the plan executor in `engine/db.ts`. That executor rejects\n * unknown fields at every level, so an op carries EXACTLY the fields its kind\n * takes. Everything here that looks like a needless restriction is one of the\n * server's rules made visible early:\n *\n * - `$ref` only points BACKWARDS, and only at an op statically known to yield\n * at most one row (insert, or a `one`/`atMost 1` guard, or `select limit 1`).\n * `.expectOne()` is what this file uses to satisfy that, always.\n * - `$expr` is a closed set: `inc`/`dec` (update only — they read the column's\n * current value) and `now()`.\n * - `update`/`delete` require a `where`; `insert` refuses one.\n * - `insertMany` rows must all set the same columns.\n * - ≤1000 ops, ≤5000 rows per insertMany, ≤8 MiB of JSON.\n *\n * Column keys are emitted SORTED, so the same callback always produces byte-\n * identical JSON. That is what lets the Go decoder be locked to golden files\n * this SDK emits (`testdata/tx_plan_golden/`).\n */\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * A plan handle was used as if it were a value: awaited, coerced to a string or\n * number, serialised, or nested inside another value.\n *\n * Thrown while the callback is still BUILDING the plan, so nothing has been sent\n * and nothing has been written.\n */\nexport class TxRefError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxRefError\";\n }\n}\n\n/**\n * The plan the callback described cannot be sent: it breaks a rule the server\n * would reject, and rejecting it here names the line that wrote it instead of\n * returning a 400 about an op index.\n */\nexport class TxPlanError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TxPlanError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wire types — mirror the plan executor in `engine/db.ts` exactly.\n// ---------------------------------------------------------------------------\n\n/** A backwards reference to an earlier op's single-row result. */\nexport interface TxWireRef {\n $ref: { op: number; field: string };\n}\n\n/** A call from the server's closed function set. */\nexport interface TxWireExpr {\n $expr: { fn: \"inc\" | \"dec\"; by: number } | { fn: \"now\" };\n}\n\n/** One value in a `values`/`set`/`where` map: a literal, a `$ref` or a `$expr`. */\nexport type TxWireValue = TxWireRef | TxWireExpr | unknown;\n\n/** The tenant's declared expectation about an op's row count. `slot` indexes the\n * client-side error table — the error OBJECT never travels. */\nexport interface TxWireGuard {\n kind: \"one\" | \"none\" | \"atLeast\" | \"atMost\";\n n: number;\n slot: number;\n}\n\n/** One operation in the wire plan. Fields are omitted, never null: the decoder\n * rejects a field that does not belong to the op's kind. */\nexport interface TxWireOp {\n /** upsert and insertMany: the columns Postgres matches on. */\n onConflict?: readonly string[];\n /** insertMany only: what a collision does. Absent means no ON CONFLICT clause\n * at all, which is what every insertMany did before this option existed. */\n action?: \"ignore\" | \"update\";\n op: \"insert\" | \"insertMany\" | \"upsert\" | \"update\" | \"delete\" | \"select\";\n table: string;\n values?: Record<string, TxWireValue>;\n rows?: Record<string, TxWireValue>[];\n set?: Record<string, TxWireValue>;\n where?: Record<string, TxWireValue>;\n limit?: number;\n lock?: \"update\";\n guard?: TxWireGuard;\n}\n\n/** The plan the engine executes on the request's own transaction. */\nexport interface TxPlanBody {\n ops: TxWireOp[];\n}\n\n/** One op's outcome, positionally matched to the plan's ops. */\nexport interface TxPlanOpResult {\n rows: Record<string, unknown>[];\n rows_affected: number;\n}\n\n/** One result per op, in plan order. */\nexport interface TxPlanResponse {\n results: TxPlanOpResult[];\n}\n\n/**\n * The fields the runtime must copy from the broker's error envelope onto the\n * rejection it throws out of {@link DBClient.txPlan}.\n *\n * `slot` is the whole point: on a guard failure the server answers with the\n * INDEX of the expectation that did not hold, never with an error message of its\n * own, and this SDK maps that index back to the `Error` the callback handed to\n * `.expectOne(…)`. Without `slot` a guard failure degrades to a generic 409.\n */\nexport interface TxPlanRejection {\n status?: number;\n /** `tx_plan_invalid` | `tx_guard_failed` | `tx_ref_unresolved` | a pg class. */\n error_code?: string;\n /** Present only for `tx_guard_failed`: the client-side error table index. */\n slot?: number;\n /** Present on a database error: which op failed. */\n op?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Handle types\n// ---------------------------------------------------------------------------\n\ndeclare const refBrand: unique symbol;\ndeclare const rowBrand: unique symbol;\ndeclare const rowsBrand: unique symbol;\n\n/**\n * Makes a handle a compile error to `await`.\n *\n * `then` is declared as a CALLABLE member whose signature is not `PromiseLike`,\n * which is precisely the shape TypeScript rejects: `await handle` is TS1320 and\n * `async () => handle` is TS1058. A non-callable `then` would not do it — the\n * compiler simply ignores those.\n */\nexport interface NotAwaitable {\n /** Not a promise. Nothing here has run yet; there is nothing to await. */\n then(doNotAwaitAPlanHandle: \"a transaction plan is built synchronously\"): never;\n}\n\n/**\n * A value the SERVER will produce, standing in for a column of a row this plan\n * writes or reads.\n *\n * Legal uses: write it into a later operation's `values`/`set`/`where`, or\n * return it from the callback (it is replaced by the real value before\n * `transaction()` resolves).\n *\n * Illegal, and caught: `await`, `String(ref)`, `` `${ref}` ``, `ref + 1`,\n * `JSON.stringify(ref)`, burying it inside a jsonb object.\n *\n * Illegal, and NOT caught: `if (ref)`. See the truthiness note at the top.\n */\nexport interface Ref<T> extends NotAwaitable {\n readonly [refBrand]: T;\n}\n\n/** The brand carried by a single-row handle, and the seam `Materialized` reads\n * to turn `return st` into the whole row. */\nexport interface TxRowHandle<Row> extends NotAwaitable {\n readonly [rowBrand]: Row;\n}\n\n/**\n * A row this plan is known to produce exactly one of. Every property is a\n * {@link Ref}; returning the handle itself yields the whole row.\n *\n * Only `.expectOne(err)` produces one — which is the design: a row you can read\n * fields from is a row whose absence you have already answered for.\n */\nexport type TxRow<Row> = { readonly [K in keyof Row]: Ref<Row[K]> } & TxRowHandle<Row>;\n\n/**\n * The result of one operation, before any expectation is declared about it.\n *\n * Deliberately not a row and not a list: an operation's row count is not known\n * until the server runs it, so the only thing that can be said about it here is\n * an EXPECTATION. Declaring one is also the only way to get a readable row.\n *\n * At most one expectation per operation — the wire carries one guard per op, and\n * a second call throws rather than silently dropping the first.\n */\nexport interface TxRows<Row> extends NotAwaitable {\n readonly [rowsBrand]: Row;\n /**\n * Require exactly one row, and read it. On any other count the server rolls\n * the whole transaction back and this `error` is thrown to the caller.\n *\n * This is the only way to reach a row's fields, and the only shape a `$ref`\n * may point at.\n */\n expectOne(error: Error): TxRow<Row>;\n /** Require zero rows (e.g. \"this membership must not already exist\"). */\n expectNone(error: Error): void;\n /** Require at least `n` rows. */\n expectAtLeast(n: number, error: Error): void;\n /** Require at most `n` rows. */\n expectAtMost(n: number, error: Error): void;\n}\n\n/** `now()` — the server's clock, usable wherever a value is. */\nexport interface TxNow extends NotAwaitable {\n readonly $expr: { fn: \"now\" };\n}\n\n/** `inc(n)` / `dec(n)` — read the column's CURRENT value and write it back\n * changed. Only meaningful in an update's `set`, which is where the types allow\n * it and where the server allows it. */\nexport interface TxColumnExpr extends NotAwaitable {\n readonly $expr: { fn: \"inc\" | \"dec\"; by: number };\n}\n\n/**\n * Resolve a callback's return type against what actually comes back: every\n * {@link Ref} becomes its value, every {@link TxRow} becomes its row, and\n * anything else keeps its shape.\n *\n * A {@link TxRows} resolves to an explanatory string type rather than a row\n * list: it has no single answer to give, and saying so in the type is louder\n * than a runtime throw.\n */\nexport type Materialized<T> = T extends Ref<infer U>\n ? U\n : T extends TxRowHandle<infer R>\n ? R\n : T extends TxRows<unknown>\n ? \"a TxRows cannot leave the transaction callback — read a row with .expectOne(err) first\"\n : T extends Date\n ? T\n : T extends object\n ? { [K in keyof T]: Materialized<T[K]> }\n : T;\n\n// ---------------------------------------------------------------------------\n// Author-facing value types\n// ---------------------------------------------------------------------------\n\n/** A value written by an INSERT: a literal, an earlier row's field, or `now()`.\n * `inc`/`dec` are absent on purpose — they read a current value, and an inserted\n * row has none. */\nexport type TxInsertValue<V> = V | Ref<V> | TxNow;\n\n/** A value written by an UPDATE's `set`: everything an insert takes, plus the\n * read-modify-write expressions. */\nexport type TxSetValue<V> = V | Ref<V> | TxNow | TxColumnExpr;\n\n/** An insert payload: the table's insert shape, with refs and `now()` allowed. */\nexport type TxInsertShape<Insert> = { [K in keyof Insert]: TxInsertValue<Insert[K]> };\n\n/** An update's `set`: any subset of the insert shape, with expressions allowed. */\nexport type TxSetShape<Insert> = { [K in keyof Insert]?: TxSetValue<Insert[K]> };\n\n/**\n * A filter. Every entry is an equality test and they are AND-ed; a `null`\n * becomes `IS NULL`, which is what makes `{ accepted_at: null }` a usable\n * \"not yet accepted\" guard rather than a clause that matches nothing.\n */\nexport type TxWhere<Row> = { [K in keyof Row]?: Row[K] | Ref<Row[K]> };\n\n/** Options for a plan `select`. */\nexport interface TxSelectOptions {\n /** Cap the rows read. */\n limit?: number;\n /** Take a real `FOR UPDATE` row lock for the rest of the transaction. */\n lock?: \"update\";\n}\n\n/** One table, as the plan sees it. */\nexport interface TxTable<Row, Insert> {\n /** Insert one row. Returns a handle — call `.expectOne(err)` to read fields. */\n insert(values: TxInsertShape<Insert>): TxRows<Row>;\n /**\n * Insert many rows in ONE statement. Every row must set the same columns\n * (a row that omits one would silently take the column's default).\n *\n * An empty list writes nothing and sends nothing.\n */\n /**\n * Insert many rows in ONE statement, optionally choosing what a collision does.\n *\n * Without `opts` this is a plain multi-row INSERT and a collision aborts the\n * transaction — the behaviour every call had before the option existed.\n *\n * `action: \"ignore\"` emits `ON CONFLICT DO NOTHING`, which is how \"insert the\n * ones that are new\" becomes one round-trip instead of one per row with a\n * 23505 caught around each. **The returned rows are the ones actually\n * INSERTED**: a row that collided is skipped, so it is absent from the result\n * — Postgres does not return what it did not write.\n *\n * `action: \"update\"` emits `ON CONFLICT DO UPDATE`, setting every non-conflict\n * column from the incoming row, and every row comes back.\n */\n insertMany(\n rows: readonly TxInsertShape<Insert>[],\n opts?: {\n onConflict: readonly Extract<keyof Row, string>[];\n action?: \"ignore\" | \"update\";\n },\n ): TxRows<Row>;\n /**\n * Insert the row, or update it when it collides on `onConflict` — inside the\n * plan's savepoint, with the same meaning `tables.<t>.upsert()` has outside it.\n *\n * It is an operation because the alternative is not writable here: a failed\n * insert aborts the whole transaction, so \"try, then fall back\" cannot be two\n * plan steps.\n */\n upsert(\n values: TxInsertShape<Insert>,\n options: { onConflict: readonly Extract<keyof Row, string>[] },\n ): TxRows<Row>;\n /**\n * Update every row matching `where`. The filter comes first because it is the\n * dangerous half: an update whose `where` you got wrong rewrites rows you\n * never looked at. The server refuses an update with no `where` at all.\n */\n updateWhere(where: TxWhere<Row>, set: TxSetShape<Insert>): TxRows<Row>;\n /** Delete every row matching `where`. The server refuses an unfiltered delete. */\n deleteWhere(where: TxWhere<Row>): TxRows<Row>;\n /** Read rows, optionally locking them for the rest of the transaction. */\n select(where?: TxWhere<Row>, options?: TxSelectOptions): TxRows<Row>;\n}\n\n/**\n * The handle a transaction callback receives.\n *\n * It carries tables and nothing else: no `query`, no `findById`, no `asService`.\n * A read whose value the plan does not write belongs OUTSIDE the transaction,\n * where it costs one round trip and can be branched on like an ordinary value.\n */\nexport interface TxPlanHandle<TTables> {\n tables: TTables;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — expressions\n// ---------------------------------------------------------------------------\n\n/** Internal marker read by the serialiser. */\nconst EXPR = Symbol.for(\"palbase.tx.expr\");\nconst REF = Symbol.for(\"palbase.tx.ref\");\nconst ROW = Symbol.for(\"palbase.tx.row\");\nconst ROWS = Symbol.for(\"palbase.tx.rows\");\n\ninterface RefDescriptor {\n op: number;\n field: string;\n}\n\n/** Property reads that must not silently produce a value on a plan handle.\n * `then` is the one that matters for correctness (it makes `await` a compile\n * error AND stops a handle from being adopted by a promise); the rest turn a\n * silent wrong answer — `\"[object Object]\"`, `NaN`, `{}` — into a thrown one. */\nconst TRAPPED_PROPS: readonly (string | symbol)[] = [\n \"then\",\n \"valueOf\",\n \"toString\",\n \"toJSON\",\n Symbol.toPrimitive,\n];\n\nfunction trap(prop: string | symbol, what: string, hint: string): never {\n const name = typeof prop === \"symbol\" ? prop.description ?? String(prop) : prop;\n throw new TxRefError(\n `${what} was used as a value (via \\`${name}\\`). Nothing in a transaction ` +\n `callback has run yet, so there is no value to read. ${hint}`,\n );\n}\n\n/** The server's `now()`. */\nexport function now(): TxNow {\n return makeExpr({ fn: \"now\" }) as TxNow;\n}\n\n/** Add `by` to the column's current value. Only valid in an update's `set`. */\nexport function inc(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"inc\");\n return makeExpr({ fn: \"inc\", by }) as TxColumnExpr;\n}\n\n/** Subtract `by` from the column's current value. Only valid in an update's `set`. */\nexport function dec(by: number): TxColumnExpr {\n assertFiniteNumber(by, \"dec\");\n return makeExpr({ fn: \"dec\", by }) as TxColumnExpr;\n}\n\nfunction assertFiniteNumber(by: number, fn: string): void {\n if (typeof by !== \"number\" || !Number.isFinite(by)) {\n // JSON has no NaN/Infinity: they would serialise to `null` and the server\n // would reject the plan with an unhelpful decode error.\n throw new TxPlanError(`${fn}() needs a finite number, got ${String(by)}`);\n }\n}\n\nfunction makeExpr(expr: TxWireExpr[\"$expr\"]): unknown {\n return new Proxy(\n { [EXPR]: expr } as Record<string | symbol, unknown>,\n {\n get(target, prop) {\n if (prop === EXPR) return target[EXPR];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(prop, \"A plan expression\", \"Write it into an operation instead.\");\n }\n return undefined;\n },\n },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — refs and row handles\n// ---------------------------------------------------------------------------\n\nfunction makeRef(op: number, field: string): unknown {\n const target: Record<string | symbol, unknown> = { [REF]: { op, field } satisfies RefDescriptor };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === REF) return t[REF];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n `\\`${field}\\` of a row this transaction has not written yet`,\n \"Pass it to another operation in the same plan, or return it from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n return undefined;\n },\n });\n}\n\nfunction makeRowHandle(op: number): unknown {\n const target: Record<string | symbol, unknown> = { [ROW]: op };\n return new Proxy(target, {\n get(t, prop) {\n if (prop === ROW) return t[ROW];\n if (TRAPPED_PROPS.includes(prop)) {\n trap(\n prop,\n \"A row this transaction has not written yet\",\n \"Read one of its columns to reference it, or return the row from the \" +\n \"callback and read it after `transaction()` resolves.\",\n );\n }\n if (typeof prop === \"symbol\") return undefined;\n return makeRef(op, prop);\n },\n });\n}\n\nfunction refDescriptor(v: unknown): RefDescriptor | null {\n if (typeof v !== \"object\" || v === null) return null;\n const d = (v as Record<symbol, unknown>)[REF];\n return isRefDescriptor(d) ? d : null;\n}\n\nfunction isRefDescriptor(d: unknown): d is RefDescriptor {\n return (\n typeof d === \"object\" &&\n d !== null &&\n typeof (d as RefDescriptor).op === \"number\" &&\n typeof (d as RefDescriptor).field === \"string\"\n );\n}\n\nfunction rowOpIndex(v: unknown): number | null {\n if (typeof v !== \"object\" || v === null) return null;\n const op = (v as Record<symbol, unknown>)[ROW];\n return typeof op === \"number\" ? op : null;\n}\n\nfunction exprOf(v: unknown): TxWireExpr[\"$expr\"] | null {\n if (typeof v !== \"object\" || v === null) return null;\n const e = (v as Record<symbol, unknown>)[EXPR];\n return typeof e === \"object\" && e !== null ? (e as TxWireExpr[\"$expr\"]) : null;\n}\n\nfunction isRowsHandle(v: unknown): boolean {\n return typeof v === \"object\" && v !== null && (v as Record<symbol, unknown>)[ROWS] !== undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — value encoding\n// ---------------------------------------------------------------------------\n\n/**\n * Encode one value of a `values`/`set`/`where` map.\n *\n * The nesting check is not defensive tidiness. The server treats `$ref` as a\n * tagged value only at the TOP of a column's value; a ref buried inside a jsonb\n * payload is just data, and would be stored as the literal object\n * `{\"$ref\":{...}}` — a write that succeeds, commits, and is wrong. So a nested\n * handle is a hard error here, where the line that wrote it is still on the\n * stack.\n */\nfunction encodeValue(value: unknown, column: string, allowColumnExpr: boolean): TxWireValue {\n const ref = refDescriptor(value);\n if (ref) return { $ref: { op: ref.op, field: ref.field } } satisfies TxWireRef;\n\n const expr = exprOf(value);\n if (expr) {\n if (expr.fn !== \"now\" && !allowColumnExpr) {\n throw new TxPlanError(\n `\\`${column}\\`: ${expr.fn}() reads the column's current value, so it is ` +\n `only valid in updateWhere(where, set).`,\n );\n }\n return { $expr: expr } satisfies TxWireExpr;\n }\n\n if (rowOpIndex(value) !== null) {\n throw new TxPlanError(\n `\\`${column}\\`: a row handle is not a value. Read the column you meant ` +\n `(e.g. \\`row.id\\`).`,\n );\n }\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: an operation result is not a value. Declare an expectation ` +\n `first (\\`.expectOne(err)\\`) and read a column from the row.`,\n );\n }\n\n assertNoNestedHandles(value, column);\n return value;\n}\n\nfunction assertNoNestedHandles(value: unknown, column: string): void {\n if (typeof value !== \"object\" || value === null) return;\n if (value instanceof Date) return;\n if (refDescriptor(value) || exprOf(value) || rowOpIndex(value) !== null || isRowsHandle(value)) {\n throw new TxPlanError(\n `\\`${column}\\`: a plan handle is nested inside a value. The server would ` +\n `store it as literal JSON, not resolve it. Put the reference directly in ` +\n `the column.`,\n );\n }\n if (Array.isArray(value)) {\n for (const item of value) assertNoNestedHandles(item, column);\n return;\n }\n for (const item of Object.values(value as Record<string, unknown>)) {\n assertNoNestedHandles(item, column);\n }\n}\n\n/**\n * Encode a column map, dropping `undefined` and emitting keys SORTED.\n *\n * Sorting is what makes the same callback produce byte-identical JSON every\n * time, which is what lets the Go decoder be locked to goldens this SDK emits.\n * Dropping `undefined` mirrors what `JSON.stringify` would do anyway, but does\n * it where the resulting column list is still checkable.\n */\nfunction encodeMap(\n map: Record<string, unknown>,\n allowColumnExpr: boolean,\n): Record<string, TxWireValue> {\n const out: Record<string, TxWireValue> = {};\n for (const key of Object.keys(map).sort()) {\n const value = map[key];\n if (value === undefined) continue;\n out[key] = encodeValue(value, key, allowColumnExpr);\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the builder\n// ---------------------------------------------------------------------------\n\n/** How many rows an op can produce, as far as the CLIENT can tell before it\n * runs. Only the empty `insertMany` is knowable, and knowing it is what lets a\n * doomed expectation fail on the line that declared it. */\nconst SKIPPED_OP = -1;\n\nclass TxRowsImpl<Row> implements TxRows<Row> {\n // Present so `isRowsHandle` recognises the object; never read for its value.\n readonly [ROWS] = true;\n // Phantom: the type brand that stops a bare object passing as a TxRows. Never\n // present at run time, which is what `declare` says.\n declare readonly [rowsBrand]: Row;\n private guarded = false;\n\n constructor(\n private readonly builder: TxPlanBuilder,\n private readonly opIndex: number,\n private readonly what: string,\n ) {}\n\n // The type-level `await` guard made real: TS rejects `await rows` at compile\n // time, and reaching this means someone called `.then(...)` by hand.\n then(): never {\n throw new TxRefError(\n `${this.what} cannot be awaited: a transaction callback builds a plan, it ` +\n `does not run statements. Remove the \\`await\\`.`,\n );\n }\n\n expectOne(error: Error): TxRow<Row> {\n this.declareGuard(\"one\", 1, error);\n if (this.opIndex === SKIPPED_OP) throw error;\n return makeRowHandle(this.opIndex) as TxRow<Row>;\n }\n\n expectNone(error: Error): void {\n this.declareGuard(\"none\", 0, error);\n }\n\n expectAtLeast(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtLeast\");\n this.declareGuard(\"atLeast\", n, error);\n if (this.opIndex === SKIPPED_OP && n > 0) throw error;\n }\n\n expectAtMost(n: number, error: Error): void {\n assertGuardCount(n, \"expectAtMost\");\n this.declareGuard(\"atMost\", n, error);\n }\n\n private declareGuard(kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n if (!(error instanceof Error)) {\n // The error object is the ONLY thing that describes this failure to the\n // caller — the server sends back an index, never a message.\n throw new TxPlanError(\n `${this.what}: an expectation needs the Error to throw when it does not ` +\n `hold (e.g. \\`.expect…(new Conflict(\"already accepted\"))\\`).`,\n );\n }\n if (this.guarded) {\n throw new TxPlanError(\n `${this.what} already has an expectation. One operation carries one ` +\n `expectation; declare the second one on its own operation.`,\n );\n }\n this.guarded = true;\n if (this.opIndex === SKIPPED_OP) return;\n this.builder.attachGuard(this.opIndex, kind, n, error);\n }\n}\n\nfunction assertGuardCount(n: number, fn: string): void {\n if (!Number.isInteger(n) || n < 0) {\n throw new TxPlanError(`${fn}(n) needs a non-negative integer, got ${String(n)}`);\n }\n}\n\n/** Bounds mirrored from the plan executor so an over-sized plan is named here rather\n * than rejected as an opaque 400 after it has crossed the network. */\nconst MAX_OPS = 1000;\nconst MAX_ROWS = 5000;\n\n/**\n * Accumulates ops and the client-side error table while the callback runs.\n *\n * Exported for the runtime and for tests that need the serialised plan without\n * a server; author code never sees it.\n */\nexport class TxPlanBuilder {\n private readonly ops: TxWireOp[] = [];\n /** Errors handed to expectations, indexed by the `slot` the server echoes. */\n private readonly slots: Error[] = [];\n\n /** The table surface handed to the callback. Untyped here; the public\n * `transaction()` signatures put the schema types on top. */\n table(name: string): TxTable<Record<string, unknown>, Record<string, unknown>> {\n return {\n insert: (values) => {\n const encoded = encodeMap(values as Record<string, unknown>, false);\n if (Object.keys(encoded).length === 0) {\n throw new TxPlanError(`${name}.insert() needs at least one column`);\n }\n return this.push({ op: \"insert\", table: name, values: encoded }, `${name}.insert()`);\n },\n\n upsert: (values, options) => {\n const encoded = encodeMap(values as Record<string, unknown>, false);\n if (Object.keys(encoded).length === 0) {\n throw new TxPlanError(`${name}.upsert() needs at least one column`);\n }\n if (options.onConflict.length === 0) {\n throw new TxPlanError(`${name}.upsert() needs at least one onConflict column`);\n }\n return this.push(\n { op: \"upsert\", table: name, values: encoded, onConflict: options.onConflict },\n `${name}.upsert()`,\n );\n },\n\n insertMany: (rows, opts) => {\n if (rows.length === 0) {\n // Nothing to write. Emitting an op would be a guaranteed 400 (the\n // server requires rows), and refusing outright would punish the\n // ordinary \"filtered every candidate out\" case.\n return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);\n }\n if (rows.length > MAX_ROWS) {\n throw new TxPlanError(\n `${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. ` +\n `Split the write across requests.`,\n );\n }\n const encoded = rows.map((row) => encodeMap(row as Record<string, unknown>, false));\n assertUniformRows(encoded, name);\n if (opts !== undefined && opts.onConflict.length === 0) {\n throw new TxPlanError(\n `${name}.insertMany() was given a conflict action with no onConflict ` +\n `columns. Postgres matches a collision on columns, so name them.`,\n );\n }\n return this.push(\n {\n op: \"insertMany\",\n table: name,\n rows: encoded,\n // Omitted entirely when no options were given, so the op a plain\n // insertMany produces is byte-identical to the one it produced\n // before this option existed.\n ...(opts !== undefined\n ? { onConflict: opts.onConflict, action: opts.action ?? \"ignore\" }\n : {}),\n },\n `${name}.insertMany()`,\n );\n },\n\n updateWhere: (where, set) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n const encodedSet = encodeMap(set as Record<string, unknown>, true);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.updateWhere() needs a filter. An update with no filter ` +\n `rewrites the whole table.`,\n );\n }\n if (Object.keys(encodedSet).length === 0) {\n throw new TxPlanError(`${name}.updateWhere() needs at least one column to set`);\n }\n return this.push(\n { op: \"update\", table: name, set: encodedSet, where: encodedWhere },\n `${name}.updateWhere()`,\n );\n },\n\n deleteWhere: (where) => {\n const encodedWhere = encodeMap(where as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length === 0) {\n throw new TxPlanError(\n `${name}.deleteWhere() needs a filter. A delete with no filter empties ` +\n `the table.`,\n );\n }\n return this.push(\n { op: \"delete\", table: name, where: encodedWhere },\n `${name}.deleteWhere()`,\n );\n },\n\n select: (where, options) => {\n const op: TxWireOp = { op: \"select\", table: name };\n const encodedWhere = encodeMap((where ?? {}) as Record<string, unknown>, false);\n if (Object.keys(encodedWhere).length > 0) op.where = encodedWhere;\n if (options?.limit !== undefined) {\n if (!Number.isInteger(options.limit) || options.limit < 0) {\n throw new TxPlanError(\n `${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`,\n );\n }\n op.limit = options.limit;\n }\n if (options?.lock !== undefined) op.lock = options.lock;\n return this.push(op, `${name}.select()`);\n },\n };\n }\n\n private push(op: TxWireOp, what: string): TxRows<Record<string, unknown>> {\n if (this.ops.length >= MAX_OPS) {\n throw new TxPlanError(\n `this transaction has ${MAX_OPS} operations, which is the limit. Use ` +\n `insertMany() for bulk writes, or split the work across requests.`,\n );\n }\n const index = this.ops.length;\n this.ops.push(op);\n return new TxRowsImpl(this, index, what);\n }\n\n /** Attach an expectation to an op and record its error in the slot table. */\n attachGuard(opIndex: number, kind: TxWireGuard[\"kind\"], n: number, error: Error): void {\n const op = this.ops[opIndex];\n // Unreachable: the index came from `push`. A loud failure beats a silently\n // unguarded write if that ever stops being true.\n if (!op) throw new TxPlanError(`internal: expectation on unknown operation ${opIndex}`);\n const slot = this.slots.length;\n this.slots.push(error);\n op.guard = { kind, n, slot };\n }\n\n /** The serialisable plan. Empty when the callback described no writes. */\n body(): TxPlanBody {\n return { ops: this.ops };\n }\n\n /** The error the server's `slot` selects, or `null` when it names one this\n * plan never declared (a server/client disagreement, not a tenant error). */\n errorForSlot(slot: number): Error | null {\n return this.slots[slot] ?? null;\n }\n}\n\nfunction assertUniformRows(rows: Record<string, TxWireValue>[], table: string): void {\n const first = rows[0];\n if (!first) return;\n const want = Object.keys(first);\n const wantKey = want.join(\",\");\n for (let i = 1; i < rows.length; i++) {\n const got = Object.keys(rows[i] as Record<string, TxWireValue>);\n if (got.join(\",\") !== wantKey) {\n // One statement, one column list. A ragged row would take the DB default\n // for the column it omitted — a write that succeeds and is wrong.\n throw new TxPlanError(\n `${table}.insertMany(): every row must set the same columns. Row 0 sets ` +\n `[${want.join(\", \")}] but row ${i} sets [${got.join(\", \")}]. ` +\n `(A property set to \\`undefined\\` counts as absent — use \\`null\\`.)`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — materialisation\n// ---------------------------------------------------------------------------\n\n/**\n * Replace every handle in the callback's return value with what the server\n * actually produced.\n *\n * Walks arrays and PLAIN objects only. Class instances (a Date, a Zod schema, a\n * domain object) are returned untouched — recursing into them would rebuild them\n * as bare objects, and nothing inside one can be a handle that this SDK created.\n */\nexport function materializeResult(value: unknown, results: TxPlanOpResult[]): unknown {\n const ref = refDescriptor(value);\n if (ref) {\n const row = rowOf(results, ref.op, `\\`${ref.field}\\``);\n if (!(ref.field in row)) {\n throw new TxPlanError(\n `the transaction's operation ${ref.op} returned no column \\`${ref.field}\\`.`,\n );\n }\n return row[ref.field];\n }\n\n const rowOp = rowOpIndex(value);\n if (rowOp !== null) return rowOf(results, rowOp, \"a row\");\n\n if (isRowsHandle(value)) {\n throw new TxPlanError(\n \"an operation result cannot be returned from a transaction callback: its \" +\n \"row count is not known until the plan runs. Declare an expectation \" +\n \"(`.expectOne(err)`) and return the row, or a column of it.\",\n );\n }\n\n if (Array.isArray(value)) return value.map((item) => materializeResult(item, results));\n\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) out[key] = materializeResult(item, results);\n return out;\n }\n\n return value;\n}\n\nfunction rowOf(results: TxPlanOpResult[], opIndex: number, what: string): Record<string, unknown> {\n const result = results[opIndex];\n if (!result) {\n throw new TxPlanError(\n `the transaction returned no result for operation ${opIndex}, so ${what} ` +\n `cannot be read.`,\n );\n }\n const row = result.rows[0];\n if (!row) {\n // Unreachable through the public API: a handle only exists behind an\n // `expectOne`, and the server rolls back rather than answering 200 with a\n // guard unmet. Loud, because the alternative is `undefined` in tenant data.\n throw new TxPlanError(\n `the transaction's operation ${opIndex} returned no row, so ${what} cannot ` +\n `be read.`,\n );\n }\n return row;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n// ---------------------------------------------------------------------------\n// Runtime — the driver\n// ---------------------------------------------------------------------------\n\n/** What {@link runTxPlan} needs from the runtime: one call, one transaction. */\nexport interface TxPlanTransport {\n txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;\n}\n\n/**\n * Build the plan, send it, and resolve the callback's return value.\n *\n * A callback that throws never reaches the network: there is nothing to roll\n * back because nothing was sent. A callback that describes no writes also skips\n * the round trip entirely.\n *\n * The RETURN type is `unknown` here on purpose. `Materialized<T>` is a compile-\n * time rewrite of the callback's return type, and it belongs on the public\n * `transaction()` signatures where `T` is inferred from the author's callback;\n * threading it through this driver as well would mean inferring `T` twice, from\n * two different positions, and reconciling them. The public wrappers narrow\n * once, at the seam where the value types were erased anyway.\n */\nexport async function runTxPlan<TTables>(\n transport: TxPlanTransport,\n tables: TTables,\n builder: TxPlanBuilder,\n fn: (tx: TxPlanHandle<TTables>) => unknown,\n): Promise<unknown> {\n const returned = fn({ tables });\n const body = builder.body();\n if (body.ops.length === 0) {\n return materializeResult(returned, []);\n }\n\n let response: TxPlanResponse;\n try {\n response = await transport.txPlan(body);\n } catch (err) {\n throw translateRejection(err, builder);\n }\n return materializeResult(returned, response.results);\n}\n\n/**\n * Turn the broker's rejection back into the tenant's own error.\n *\n * The server never sees the `Error` an expectation was given — only its slot\n * index — so this is the only place the intended error can be produced. A\n * rejection this SDK does not recognise passes through untouched: inventing an\n * error for it would hide the real failure.\n */\nfunction translateRejection(err: unknown, builder: TxPlanBuilder): unknown {\n if (typeof err !== \"object\" || err === null) return err;\n const rejection = err as TxPlanRejection;\n if (rejection.error_code !== \"tx_guard_failed\" || typeof rejection.slot !== \"number\") {\n return err;\n }\n return builder.errorForSlot(rejection.slot) ?? err;\n}\n","/**\n * The brand that identifies an HttpError ACROSS SDK instances.\n *\n * A process legitimately holds more than one copy of this SDK — the runtime\n * loads the engine from its own node_modules while the tenant's bundle carries\n * an inlined copy, which is why the controller registry and the error registry\n * are both anchored on `Symbol.for`. The one place that did not follow the\n * pattern was the engine's catch: `err instanceof HttpError` compares CLASS\n * IDENTITY, so a `throw new NotFound()` from the bundle's copy did not match\n * the engine's copy and every typed error in every deployed backend degraded to\n * `500 internal_error`. Measured through the edge on a real deploy: a route\n * throwing `NotFound` answered 500 while the runtime's own log printed the\n * error object with `status: 404` right beside it.\n *\n * `Symbol.for` puts this in the cross-realm registry, so every copy of the SDK\n * agrees on it by VALUE rather than by identity.\n */\nexport const HTTP_ERROR_BRAND: unique symbol = Symbol.for(\"palbase.backend.httpError\");\n\n/**\n * Set on an `HttpError` the ENGINE built out of a driver failure, as opposed to\n * one the author constructed to ANSWER a request.\n *\n * The distinction cannot be read off the status, and 409 is why. The scaffold\n * teaches `throw new Conflict(\"title already taken\")` as the way to answer\n * (template/AGENTS.md), and the engine raises `UniqueViolation` — also a 409 —\n * when a write hits a unique index. Logging by status therefore either loses the\n * engine's event or writes an \"unhandled\" line every time an author takes the\n * documented path. Measured: it did the second.\n *\n * `Symbol.for` so the mark survives the bundle/runtime SDK split, the same way\n * {@link HTTP_ERROR_BRAND} does.\n */\nexport const ENGINE_RAISED: unique symbol = Symbol.for(\"palbase.backend.engineRaised\") as never;\n\n/** Mark `e` as engine-raised and return it, so a conversion site reads as one expression. */\nexport function markEngineRaised<E extends object>(e: E): E {\n (e as Record<symbol, unknown>)[ENGINE_RAISED] = true;\n return e;\n}\n\n/** Whether the engine built this error, rather than the author throwing it to answer. */\nexport function isEngineRaised(e: unknown): boolean {\n return typeof e === \"object\" && e !== null && (e as Record<symbol, unknown>)[ENGINE_RAISED] === true;\n}\n\n/**\n * Whether a thrown value is an HttpError from ANY copy of this SDK.\n *\n * The shape is checked as well as the brand: the brand says \"this claims to be\n * one of ours\", the fields say the envelope can actually be built from it, and\n * a half-formed object must fall through to the 500 path rather than produce a\n * malformed response.\n */\nexport function isHttpError(err: unknown): err is HttpError {\n if (typeof err !== \"object\" || err === null) return false;\n const e = err as Record<PropertyKey, unknown>;\n return (\n e[HTTP_ERROR_BRAND] === true &&\n typeof e.status === \"number\" &&\n typeof e.error === \"string\" &&\n typeof e.errorDescription === \"string\"\n );\n}\n\n/** HTTP error with structured error response format.\n *\n * The base class for the throwable error classes (`PalError`, `Conflict`,\n * `NotFound`, …). Construct one directly with `throw new HttpError(404,\n * \"todo_not_found\", \"No such todo\")`, or throw a named subclass\n * (`throw new NotFound(\"todo not found\")`). The runtime catches any `HttpError`\n * and emits the standard envelope; on the wire (and to iOS) it surfaces as\n * `BackendError.server(code, status, message, requestId)`.\n *\n * The optional `data` field carries a structured payload alongside the\n * standard envelope — for errors that need to ship extra context\n * (e.g. `new Conflict(\"locked\", \"title_locked\", { retryAfter: 30 })`). It rides\n * through to the iOS typed enum's associated value.\n */\nexport class HttpError extends Error {\n public readonly status: number;\n public readonly error: string;\n public readonly errorDescription: string;\n public readonly data?: unknown;\n /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */\n public readonly [HTTP_ERROR_BRAND] = true;\n\n constructor(status: number, error: string, errorDescription: string, data?: unknown) {\n super(errorDescription);\n this.name = \"HttpError\";\n this.status = status;\n this.error = error;\n this.errorDescription = errorDescription;\n if (data !== undefined) {\n this.data = data;\n }\n }\n\n /**\n * Serialize to the standard Palbase error response format.\n * The `requestId` is injected by the runtime layer from the request context.\n * When called without arguments (e.g. JSON.stringify), request_id is omitted.\n * When `data` is set, it is appended as a strict-superset field.\n */\n toJSON(requestId?: string): {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } {\n const result: {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } = {\n error: this.error,\n error_description: this.errorDescription,\n status: this.status,\n };\n if (requestId) {\n result.request_id = requestId;\n }\n if (this.data !== undefined) {\n result.data = this.data;\n }\n return result;\n }\n}\n\n/**\n * Throw with a custom HTTP status + wire code. The general-purpose escape hatch\n * when none of the named classes (`Conflict`/`NotFound`/…) fits.\n *\n * @example\n * throw new PalError(418, \"teapot\", \"I'm a teapot\");\n */\nexport class PalError extends HttpError {\n constructor(status: number, code: string, description: string, data?: unknown) {\n super(status, code, description, data);\n this.name = \"PalError\";\n }\n}\n\n/** Base for the named status classes. Each subclass fixes its HTTP status; the\n * `code` defaults to the class's canonical wire code (overridable), and the\n * `message` defaults to a human-readable label (overridable). */\nabstract class NamedHttpError extends HttpError {\n protected constructor(\n status: number,\n defaultCode: string,\n name: string,\n message?: string,\n code?: string,\n data?: unknown,\n ) {\n super(status, code ?? defaultCode, message ?? defaultMessage(name), data);\n this.name = name;\n }\n}\n\n/** Derive a default human-readable message from a class name\n * (\"NotFound\" → \"Not found\", \"TooManyRequests\" → \"Too many requests\"). */\nfunction defaultMessage(name: string): string {\n const spaced = name.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\");\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\n/**\n * 400 — the request was malformed or failed validation. Carries a fixed typed\n * payload: `new BadRequest({ fields: [{ field: \"email\", message: \"invalid\" }] })`.\n * The shape is declared once in the SDK so codegen surfaces `error.data.fields`\n * typed on the client.\n */\nexport class BadRequest extends NamedHttpError {\n public declare readonly data: BadRequestData;\n constructor(data: BadRequestData, message?: string) {\n super(400, \"bad_request\", \"BadRequest\", message, undefined, data);\n }\n}\n\n/** 401 — the caller is not authenticated. */\nexport class Unauthorized extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(401, \"unauthorized\", \"Unauthorized\", message, code, data);\n }\n}\n\n/** 403 — the caller is authenticated but not allowed. */\nexport class Forbidden extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(403, \"forbidden\", \"Forbidden\", message, code, data);\n }\n}\n\n/** 404 — the requested resource does not exist. */\nexport class NotFound extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(404, \"not_found\", \"NotFound\", message, code, data);\n }\n}\n\n/** 409 — the request conflicts with the current state. */\nexport class Conflict extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(409, \"conflict\", \"Conflict\", message, code, data);\n }\n}\n\n/**\n * 409 — a write was refused because it would duplicate an existing row.\n * Carries the NAME of the unique constraint Postgres named (`users_email_key`).\n *\n * The engine produces it: a statement rejected with SQLSTATE `23505` is\n * converted here rather than surfacing as an opaque driver error (see\n * `engine/db.ts`, `diagnosingDriver`). What that removes is the string match —\n * before this, the only way to act on a duplicate was to test the driver\n * message for \"duplicate key value violates unique constraint\", a contract\n * nobody signed that breaks on a Postgres upgrade, a locale, or a constraint\n * rename, silently and in production.\n *\n * THE NAME IS A FIELD AND STAYS OUT OF THE DEFAULT MESSAGE. The two are not\n * the same audience. `constraint` is read by the code that catches this — the\n * developer, who already knows the schema. `errorDescription` is the HTTP\n * response body, and an UNCAUGHT duplicate puts it in front of the\n * application's end user: `users_email_key` there discloses how the schema is\n * built to whoever sent the request. The platform's own data API took the same\n * decision one surface over and wrote down why —\n * `v2/internal/modules/database/internal/handler/pgerror.go:83-87` collapses\n * every 23xxx to a generic conflict, \"never disclose the constraint/column\n * name\". A thrower who WANTS the name on the wire passes it deliberately\n * (`new UniqueViolation(c, \\`\\${c} already exists\\`)`, or through `data`).\n *\n * @example\n * try {\n * await Database.tables.users.insert({ email });\n * } catch (e) {\n * if (UniqueViolation.is(e) && e.constraint === \"users_email_key\") {\n * throw new Conflict(\"That email is taken\", \"email_taken\");\n * }\n * throw e;\n * }\n */\nexport class UniqueViolation extends Conflict {\n /**\n * Whether `e` is a unique violation — REGARDLESS of which copy of this SDK\n * constructed it.\n *\n * Use this instead of `instanceof`. Measured on a live stack: a controller\n * bundle INLINES its own copy of `@palbase/backend`, and the engine that\n * raises this error is the runtime's copy. Two copies, two class identities,\n * and `e instanceof UniqueViolation` is false in the one place a caller\n * writes it — a check that reads as correct and silently never matches.\n */\n static is(e: unknown): e is UniqueViolation {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as { name?: unknown }).name === \"UniqueViolation\" &&\n typeof (e as { constraint?: unknown }).constraint === \"string\"\n );\n }\n\n /** The unique constraint the statement violated, as Postgres named it.\n * `\"\"` when the driver did not say which — see `engine/db.ts`. */\n public readonly constraint: string;\n\n constructor(constraint: string, message?: string, code?: string, data?: unknown) {\n super(message ?? \"Unique constraint violated\", code ?? \"unique_violation\", data);\n this.name = \"UniqueViolation\";\n this.constraint = constraint;\n }\n}\n\n/** A single field-level validation failure carried by {@link BadRequest}. */\nexport interface FieldError {\n /** The offending field's name (dotted path for nested fields). */\n field: string;\n /** Human-readable reason the field failed. */\n message: string;\n}\n\n/** The fixed, typed payload {@link BadRequest} ships. */\nexport interface BadRequestData {\n /** The fields that failed validation. */\n fields: FieldError[];\n}\n\n/** The fixed, typed payload {@link TooManyRequests} ships. */\nexport interface TooManyRequestsData {\n /** Seconds the caller should wait before retrying. */\n retryAfter: number;\n}\n\n/**\n * 429 — the caller has exceeded the rate limit. Carries a fixed typed payload:\n * `new TooManyRequests({ retryAfter: 30 })`. The shape is declared once in the\n * SDK (error-registry pre-seed) so codegen surfaces `error.data.retryAfter`\n * typed on the client — no per-project definition needed.\n */\nexport class TooManyRequests extends NamedHttpError {\n public declare readonly data: TooManyRequestsData;\n constructor(data: TooManyRequestsData, message?: string) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, undefined, data);\n }\n}\n","/**\n * engine/config.ts — settings from the environment, and the gate that refuses\n * to boot without them.\n *\n * A mandatory module that is not configured must stop the process, by name.\n * The failure this prevents is the expensive one: a stack that boots, passes\n * its probes, and answers 500 on first contact — where the missing value is\n * discovered by a customer rather than by the operator who could fix it.\n *\n * Database and Auth are mandatory. That is a product decision (2026-08-14), not\n * a technical necessity: a backend whose data layer or whose notion of \"who is\n * calling\" is undefined has nothing safe to do with a request.\n */\n\n/** Everything the engine needs to serve. Built once, at boot, never re-read. */\nexport interface EngineConfig {\n /** Postgres connection string. MANDATORY. */\n databaseUrl: string;\n /** Where this stack publishes its token signing keys. MANDATORY. */\n authJwksUrl: string;\n /** When set, a token whose `iss` differs is rejected. */\n authIssuer?: string;\n /** Base URL of the module surface (`/v1/*`, `/auth/*`). Empty ⇒ module\n * singletons throw a named error on first use rather than silently no-op. */\n moduleBaseUrl: string;\n /**\n * The address CLIENTS reach this stack at — `https://<ref>.palbase.studio` in\n * the cloud, whatever domain the certificate is for when self-hosted.\n *\n * NOT `moduleBaseUrl`, and the distinction is the whole point: that one is\n * this process's internal route to palsvc (`http://127.0.0.1:8080`), which\n * resolves nowhere outside the pod. A public object URL has to survive\n * leaving the response body, so it cannot be built from the internal one.\n *\n * Only the operator knows this value, so only the operator sets it\n * (`PALBASE_PUBLIC_ORIGIN`). Empty ⇒ `Storage…getPublicUrl()` throws a named\n * error, the same way an unconfigured module does.\n */\n publicOrigin: string;\n /** Shared secret storage signs its internal upload calls with. Empty means\n * uploads are not wired, and those calls are refused. */\n uploadSecret: string;\n /** Publishable key, sent as `apikey` on module calls. */\n anonKey: string;\n /** Secret key. Used for privileged module calls. */\n serviceRoleKey: string;\n /** HMAC the realtime broadcast token is signed with. Empty ⇒ broadcast\n * returns a clear `realtime_unconfigured` error instead of failing silently. */\n realtimeSecret: string;\n port: number;\n /** The Postgres role each request is bound to. RLS policies are written\n * against it, so changing it changes who the database thinks is asking. */\n dbRole: string;\n /**\n * The Postgres role `Database.asService()` is bound to. It is the one that\n * carries BYPASSRLS, which is the whole of what \"as service\" means — a name\n * pointing at a role without it does not fail, it returns fewer rows.\n *\n * Configurable for the same reason `dbRole` is, and beside it on purpose: a\n * stack that renames one of the pair must rename both, or the request and its\n * service sibling stop being two identities of the same installation.\n */\n dbServiceRole: string;\n poolMax: number;\n}\n\n/** Thrown when a mandatory module is unconfigured. Carries the missing names. */\nexport class BootRefused extends Error {\n readonly missing: readonly string[];\n constructor(missing: readonly string[], message: string) {\n super(message);\n this.name = \"BootRefused\";\n this.missing = missing;\n }\n}\n\nconst MANDATORY: ReadonlyArray<{ key: string; what: string }> = [\n { key: \"DATABASE_URL\", what: \"the stack's Postgres (Database module)\" },\n { key: \"AUTH_JWKS_URL\", what: \"where this stack publishes its token signing keys (Auth module)\" },\n];\n\n/**\n * Read the engine's settings, or refuse.\n *\n * @throws {BootRefused} naming every missing mandatory value at once — one\n * restart per missing variable is a bad way to learn what a stack needs.\n */\nexport function loadConfig(env: Record<string, string | undefined>): EngineConfig {\n const missing = MANDATORY.filter((m) => !env[m.key]?.trim()).map((m) => m.key);\n if (missing.length > 0) {\n const detail = MANDATORY.filter((m) => missing.includes(m.key))\n .map((m) => ` ${m.key.padEnd(16)}${m.what}`)\n .join(\"\\n\");\n throw new BootRefused(\n missing,\n `boot refused: mandatory module not configured — missing ${missing.join(\", \")}.\\n${detail}`,\n );\n }\n\n const port = Number(env.PORT ?? 3000);\n if (!Number.isInteger(port) || port < 0 || port > 65535) {\n throw new BootRefused([], `boot refused: PORT is not a valid port number (got ${env.PORT}).`);\n }\n const poolMax = Number(env.DB_POOL_MAX ?? 10);\n if (!Number.isInteger(poolMax) || poolMax < 1) {\n throw new BootRefused([], `boot refused: DB_POOL_MAX must be a positive integer (got ${env.DB_POOL_MAX}).`);\n }\n\n return {\n databaseUrl: env.DATABASE_URL!.trim(),\n authJwksUrl: env.AUTH_JWKS_URL!.trim(),\n authIssuer: env.AUTH_ISSUER?.trim() || undefined,\n moduleBaseUrl: (env.MODULE_BASE_URL ?? \"\").replace(/\\/+$/, \"\"),\n publicOrigin: (env.PALBASE_PUBLIC_ORIGIN ?? \"\").trim().replace(/\\/+$/, \"\"),\n // The secret storage signs its two internal calls with (authorize, and the\n // completion that runs an @Upload handler). Empty means uploads are not\n // wired, and both calls REFUSE — an unsigned completion would let anyone\n // who knows a route path invent an upload that never happened.\n uploadSecret: env.PALBASE_UPLOAD_SECRET ?? \"\",\n anonKey: env.PALBASE_ANON_KEY ?? \"\",\n serviceRoleKey: env.PALBASE_SERVICE_ROLE_KEY ?? \"\",\n realtimeSecret: env.REALTIME_INGESTION_SECRET ?? \"\",\n port,\n dbRole: env.DB_ROLE ?? \"backend_authenticated\",\n // Verified against the stack that provisions them, not from memory: the six\n // roles and their attributes are declared in v2/internal/migrate/provision.go\n // (`roleBackendServiceRole = \"backend_service_role\"`, NOLOGIN BYPASSRLS),\n // and the live database agrees (pg_roles.rolbypassrls = true).\n dbServiceRole: env.DB_SERVICE_ROLE ?? \"backend_service_role\",\n poolMax,\n };\n}\n","/**\n * engine/auth.ts — verifying the stack's own access tokens.\n *\n * The engine does this itself rather than trusting a header stamped upstream.\n * In the isolate architecture a gateway verified the token and the runtime read\n * the result; a backend that boots on its own has no such upstream, so the\n * verification lives here — against the keys the stack publishes.\n *\n * Deliberately narrow: ES256 over P-256, which is what palauth mints. An\n * unrecognised `alg` is refused rather than accommodated, because the classic\n * JWT break is a verifier that is helpful about algorithms.\n */\n\n/** A JSON Web Key, narrowed to the EC keys this verifier accepts. */\ninterface EcJwk {\n kid: string;\n kty: string;\n crv: string;\n x: string;\n y: string;\n}\n\n/** The claims the engine reads. Everything else rides along untyped. */\nexport interface VerifiedClaims extends Record<string, unknown> {\n sub?: string;\n role?: string;\n email?: string;\n email_verified?: boolean;\n exp?: number;\n iss?: string;\n}\n\nfunction b64urlToBytes(s: string): Uint8Array<ArrayBuffer> {\n const pad = s.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const full = pad.padEnd(Math.ceil(pad.length / 4) * 4, \"=\");\n const bin = atob(full);\n // Backed by a plain ArrayBuffer so the result satisfies BufferSource — a\n // Uint8Array over ArrayBufferLike could be shared memory, which the WebCrypto\n // signatures reject.\n const out = new Uint8Array(new ArrayBuffer(bin.length));\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\nexport interface AuthVerifierOptions {\n jwksUrl: string;\n issuer?: string;\n /** Injectable for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** How long a fetched keyset is trusted before it is fetched again. A key\n * rotation must become visible without a restart, and an unknown `kid` must\n * not be able to force a fetch per request (that is a free DoS lever). */\n keysetTtlMs?: number;\n}\n\nexport class AuthVerifier {\n private keys = new Map<string, CryptoKey>();\n private fetchedAt = 0;\n private inflight: Promise<void> | null = null;\n private readonly jwksUrl: string;\n private readonly issuer?: string;\n private readonly fetchImpl: typeof fetch;\n private readonly ttl: number;\n\n constructor(opts: AuthVerifierOptions) {\n this.jwksUrl = opts.jwksUrl;\n this.issuer = opts.issuer;\n this.fetchImpl = opts.fetchImpl ?? ((...a: Parameters<typeof fetch>) => fetch(...a));\n this.ttl = opts.keysetTtlMs ?? 5 * 60_000;\n }\n\n /** Fetch the keyset at most once per TTL, and at most once concurrently. */\n private async refresh(): Promise<void> {\n if (this.inflight) return this.inflight;\n this.inflight = (async () => {\n try {\n const res = await this.fetchImpl(this.jwksUrl);\n if (!res.ok) return;\n const body = (await res.json()) as { keys?: EcJwk[] };\n const next = new Map<string, CryptoKey>();\n for (const jwk of body.keys ?? []) {\n if (jwk.kty !== \"EC\" || jwk.crv !== \"P-256\") continue;\n try {\n next.set(\n jwk.kid,\n await crypto.subtle.importKey(\n \"jwk\",\n { kty: \"EC\", crv: jwk.crv, x: jwk.x, y: jwk.y, ext: true },\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"verify\"],\n ),\n );\n } catch {\n // A single malformed key must not blind the verifier to the rest.\n }\n }\n if (next.size > 0) {\n this.keys = next;\n this.fetchedAt = Date.now();\n }\n } finally {\n this.inflight = null;\n }\n })();\n return this.inflight;\n }\n\n private async key(kid: string): Promise<CryptoKey | null> {\n const stale = Date.now() - this.fetchedAt > this.ttl;\n if (!this.keys.has(kid) || stale) await this.refresh();\n return this.keys.get(kid) ?? null;\n }\n\n /**\n * Verify an `Authorization` header value.\n *\n * @returns the verified claims, or `null` for absent / malformed / expired /\n * wrong-issuer / bad-signature. One `null` for every failure on purpose:\n * the caller answers 401 either way, and a detailed reason is an oracle.\n */\n async verify(authorization: string | null | undefined): Promise<VerifiedClaims | null> {\n if (!authorization || !authorization.startsWith(\"Bearer \")) return null;\n const parts = authorization.slice(7).trim().split(\".\");\n if (parts.length !== 3) return null;\n const h = parts[0];\n const p = parts[1];\n const sig = parts[2];\n if (h === undefined || p === undefined || sig === undefined) return null;\n\n let header: { alg?: string; kid?: string };\n let claims: VerifiedClaims;\n try {\n header = JSON.parse(new TextDecoder().decode(b64urlToBytes(h)));\n claims = JSON.parse(new TextDecoder().decode(b64urlToBytes(p)));\n } catch {\n return null;\n }\n // `none`, `HS256`-with-the-public-key, and friends all die here.\n if (header.alg !== \"ES256\" || !header.kid) return null;\n\n const key = await this.key(header.kid);\n if (!key) return null;\n\n let ok = false;\n try {\n ok = await crypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n key,\n b64urlToBytes(sig),\n new TextEncoder().encode(`${h}.${p}`),\n );\n } catch {\n return null;\n }\n if (!ok) return null;\n if (typeof claims.exp === \"number\" && claims.exp * 1000 <= Date.now()) return null;\n if (this.issuer && claims.iss !== this.issuer) return null;\n return claims;\n }\n}\n\n/** What a route demands, after the route's own spec and the controller's\n * default have been reconciled. */\nexport interface EffectiveAuth {\n required: boolean;\n role?: string;\n verifiedEmail: boolean;\n}\n\n/**\n * Reconcile route-level and controller-level auth.\n *\n * The route's own spec wins when it says anything at all; otherwise the\n * controller's default applies; when NEITHER speaks, the answer is `required`.\n * That last clause is the whole point — a route that forgot to declare must be\n * closed, not open. (Measured: an engine that only read the route level served\n * a controller marked `auth: false` as 401, and would have served the reverse\n * mistake as an open endpoint.)\n */\nexport function effectiveAuth(routeAuth: unknown, controllerAuth: unknown): EffectiveAuth {\n const spec = routeAuth !== undefined ? routeAuth : controllerAuth;\n if (spec === false) return { required: false, verifiedEmail: false };\n if (spec === true || spec === undefined || spec === null) return { required: true, verifiedEmail: false };\n if (typeof spec !== \"object\") return { required: true, verifiedEmail: false };\n\n const o = spec as { required?: unknown; role?: unknown; verifiedEmail?: unknown };\n const role = typeof o.role === \"string\" && o.role.trim() !== \"\" ? o.role.trim() : undefined;\n return {\n required: o.required !== false,\n role,\n verifiedEmail: o.verifiedEmail === true,\n };\n}\n","/**\n * engine/ratelimit.ts — the customer's own per-route limit, enforced here.\n *\n * This is the PRODUCT feature (`@Get(\"/x\", { rateLimit: { max, window } })`),\n * not a quota the platform imposes. It runs in this process, on this pod,\n * because the route table lives here: the edge proxies by path and has never\n * seen a route's options, so teaching it would mean shipping the table twice\n * and keeping the copies in step.\n *\n * Fixed window, in memory. A single-tenant backend is the whole stack rather\n * than a shard of it, so \"in process\" is not an approximation. A restart\n * forgets the window, which for an endpoint guard fails in the right\n * direction: it forgives, it never invents a refusal.\n */\n\nexport interface RateLimitRule {\n max: number;\n /** Seconds. */\n window: number;\n}\n\ninterface Bucket {\n count: number;\n resetAt: number;\n}\n\nexport class RateLimiter {\n private buckets = new Map<string, Bucket>();\n /** Bound on distinct keys held, so an attacker cycling identities cannot\n * grow this map without limit. On overflow the oldest windows are dropped —\n * forgiving, consistent with the restart behaviour above. */\n constructor(private readonly maxKeys = 100_000) {}\n\n /**\n * Identify the caller: the signed-in user when the route resolved one,\n * otherwise the address the edge forwarded. Callers the edge did not\n * identify share one bucket — deliberately conservative, since the\n * alternative is a limit anyone resets by omitting a header.\n */\n static key(routeId: string, userId: string | undefined, headers: Headers): string {\n if (userId) return `${routeId}\\x00u:${userId}`;\n const fwd = headers.get(\"x-forwarded-for\");\n const addr = (fwd ? (fwd.split(\",\")[0] ?? \"\") : (headers.get(\"x-real-ip\") ?? \"\")).trim();\n return `${routeId}\\x00a:${addr || \"anonymous\"}`;\n }\n\n /**\n * @returns `null` when the request may proceed, or the number of seconds to\n * wait (never 0 — a caller told to wait 0 comes straight back to the same\n * refusal).\n */\n check(rule: RateLimitRule | undefined, key: string, now: number): number | null {\n if (!rule || !(rule.max > 0) || !(rule.window > 0)) return null;\n\n const bucket = this.buckets.get(key);\n if (!bucket || now >= bucket.resetAt) {\n if (this.buckets.size >= this.maxKeys) this.evict(now);\n this.buckets.set(key, { count: 1, resetAt: now + rule.window * 1000 });\n return null;\n }\n if (bucket.count < rule.max) {\n bucket.count++;\n return null;\n }\n return Math.max(1, Math.ceil((bucket.resetAt - now) / 1000));\n }\n\n /** Drop expired windows; if none are expired, drop the earliest-resetting\n * quarter so the map cannot wedge at the ceiling. */\n private evict(now: number): void {\n let dropped = 0;\n for (const [k, b] of this.buckets) {\n if (now >= b.resetAt) {\n this.buckets.delete(k);\n dropped++;\n }\n }\n if (dropped > 0) return;\n const byReset = [...this.buckets.entries()].sort((a, b) => a[1].resetAt - b[1].resetAt);\n for (let i = 0; i < Math.ceil(byReset.length / 4); i++) {\n const victim = byReset[i];\n if (victim) this.buckets.delete(victim[0]);\n }\n }\n\n /** Test seam. */\n get size(): number {\n return this.buckets.size;\n }\n}\n","/**\n * engine/cache.ts — the cache, in this process's own memory.\n *\n * A stack that serves one tenant has nobody to share a cache with; palsvc drew\n * exactly this conclusion for itself when it dropped Redis, and a backend that\n * reaches over a network for a hash map is paying a round trip for nothing.\n *\n * JSON-typed, matching `CacheClient`: values round-trip as whatever was stored.\n */\nimport type { CacheClient } from \"../endpoint.js\";\n\ninterface Entry {\n value: unknown;\n /** Epoch ms, or 0 for \"no expiry\". */\n expiresAt: number;\n}\n\nexport interface MemoryCacheOptions {\n /** Bound on entries held. On overflow the soonest-to-expire are dropped. */\n maxEntries?: number;\n /** Injectable clock, for tests. */\n now?: () => number;\n}\n\n/**\n * Build an in-process cache.\n *\n * `getOrSet` is single-flight: concurrent misses on one key share one fill, so\n * a cold key under load does not become N identical expensive calls.\n */\nexport function makeMemoryCache(opts: MemoryCacheOptions = {}): CacheClient {\n const maxEntries = opts.maxEntries ?? 50_000;\n const now = opts.now ?? (() => Date.now());\n const store = new Map<string, Entry>();\n const inflight = new Map<string, Promise<unknown>>();\n\n const live = (key: string): Entry | undefined => {\n const e = store.get(key);\n if (!e) return undefined;\n if (e.expiresAt !== 0 && e.expiresAt <= now()) {\n store.delete(key);\n return undefined;\n }\n return e;\n };\n\n const evict = () => {\n const t = now();\n let dropped = 0;\n for (const [k, e] of store) {\n if (e.expiresAt !== 0 && e.expiresAt <= t) {\n store.delete(k);\n dropped++;\n }\n }\n if (dropped > 0) return;\n // Nothing expired: drop the soonest-to-expire quarter (entries with no\n // expiry sort last, so an unbounded writer sheds its own oldest first).\n const order = [...store.entries()].sort(\n (a, b) => (a[1].expiresAt || Infinity) - (b[1].expiresAt || Infinity),\n );\n for (let i = 0; i < Math.ceil(order.length / 4); i++) {\n const victim = order[i];\n if (victim) store.delete(victim[0]);\n }\n };\n\n const set = async (key: string, value: unknown, ttl?: number): Promise<void> => {\n if (store.size >= maxEntries && !store.has(key)) evict();\n store.set(key, { value, expiresAt: ttl && ttl > 0 ? now() + ttl * 1000 : 0 });\n };\n\n return {\n async get<T = unknown>(key: string): Promise<T | null> {\n const e = live(key);\n return e ? (e.value as T) : null;\n },\n set,\n async del(key: string): Promise<void> {\n store.delete(key);\n },\n async incr(key: string): Promise<number> {\n const e = live(key);\n const next = (typeof e?.value === \"number\" ? e.value : 0) + 1;\n store.set(key, { value: next, expiresAt: e?.expiresAt ?? 0 });\n return next;\n },\n async getOrSet<T>(key: string, ttl: number, fn: () => Promise<T> | T): Promise<T> {\n const hit = live(key);\n if (hit) return hit.value as T;\n\n const running = inflight.get(key);\n if (running) return running as Promise<T>;\n\n const fill = (async () => {\n try {\n const value = await fn();\n await set(key, value, ttl);\n return value;\n } finally {\n inflight.delete(key);\n }\n })();\n inflight.set(key, fill);\n return fill as Promise<T>;\n },\n };\n}\n","/**\n * The refusals a Database call gets BEFORE any SQL exists — written once, so the\n * engine and the test double cannot disagree about them.\n *\n * WHY THIS FILE EXISTS. `fakeDatabase()` is a second implementation of the same\n * surface (`__tests__/helpers/mock-db.ts`), and it never touched `compileWhere`\n * or `asBindParams`. Measured against the published 24.1.0: all four of the\n * calls that release had just started refusing went through the fake SILENTLY —\n * `update{title:undefined}`, `insert{title:undefined}`, `findMany{done:{}}`,\n * `deleteMany{owner,created_at:{}}`.\n *\n * The scaffold tells authors to test the service layer against exactly that\n * fake. So a test went green on a call production would throw on, and the\n * author found out in production instead — the same \"the surface does not match\n * the engine\" shape these refusals exist to end, arriving through the door the\n * SDK hands people for testing.\n *\n * These are pure and SQL-free on purpose: an in-memory store can run them as\n * easily as the driver path can.\n */\n\n/** The comparison operators a filter value may carry. Kept here because the\n * guard has to tell an operator object from a plain value. */\nconst KNOWN_OPS = new Set([\"gt\", \"gte\", \"lt\", \"lte\", \"neq\", \"eq\", \"in\"]);\n\n/**\n * Refuse a filter that would compile to something other than what it reads like.\n *\n * Three shapes, each measured in production before it was closed:\n *\n * `{ col: undefined }` binds NULL; `= NULL` matches no row, so the query\n * answered \"no records\" and said nothing.\n * `{ col: {} }` produces no term at all — every row on the read\n * path, a dropped condition on the write path.\n * `{ col: { gte: undefined } }` and an `undefined` inside `in`: the same NULL,\n * one level down.\n */\nexport function assertUsableFilter(\n caller: string,\n table: string,\n where: Record<string, unknown> | undefined,\n): void {\n if (!where) return;\n for (const [col, cond] of Object.entries(where)) {\n if (cond === undefined) {\n throw new Error(\n `${caller}(${table}): where.${col} değeri undefined — bu bir filtre değeri değil. ` +\n `Bağlanınca NULL olur ve '= NULL' hiçbir satıra uymaz, yani sorgu sessizce ` +\n `boş sonuç dönerdi. Değer yoksa anahtarı filtreye hiç koymayın.`,\n );\n }\n if (cond === null || typeof cond !== \"object\" || Array.isArray(cond)) continue;\n\n const entries = Object.entries(cond as Record<string, unknown>);\n if (entries.length === 0) {\n throw new Error(\n `${caller}(${table}): where.${col} boş bir operatör nesnesi ({}) — hiçbir koşul ` +\n `üretmez, yani bu alan filtreden sessizce DÜŞERDİ. Koşul kurulmayacaksa ` +\n `anahtarı filtreye hiç koymayın (D-21).`,\n );\n }\n for (const [op, v] of entries) {\n if (op === \"in\") {\n if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmalı`);\n if (v.some((x) => x === undefined)) {\n throw new Error(\n `${caller}(${table}): where.${col}.in listesinde undefined var — sessizce NULL'a ` +\n `bağlanır ve o eleman hiçbir satırla eşleşmez. Listeyi kurarken eleyin.`,\n );\n }\n continue;\n }\n if (!KNOWN_OPS.has(op)) {\n throw new Error(\n `${caller}(${table}): where.${col} bilinmeyen operatör \"${op}\" (gt/gte/lt/lte/neq/in)`,\n );\n }\n if (v === undefined) {\n throw new Error(\n `${caller}(${table}): where.${col}.${op} değeri undefined — karşılaştırmanın ` +\n `sağ tarafı NULL olur ve sonuç hiçbir satıra uymaz. Koşulu kurmayın.`,\n );\n }\n }\n }\n}\n\n/**\n * Refuse a write whose value never arrived.\n *\n * `{ title: req.body.title }` with no `title` in the body bound NULL and\n * answered 200 — the column was ERASED. `null` is untouched, and the difference\n * is the whole point: null is an author SAYING \"empty this column\"; undefined is\n * nobody saying anything.\n */\nexport function assertUsableWriteValues(\n caller: string,\n table: string,\n cols: readonly string[],\n data: Record<string, unknown>,\n): void {\n for (const c of cols) {\n if (data[c] === undefined) {\n throw new Error(\n `${caller}(${table}): \"${c}\" değeri undefined — bu bir yazma değeri değil. ` +\n `Kolonu boşaltmak istiyorsan null yaz; kolonu değiştirmek istemiyorsan nesneye hiç koyma ` +\n `(bir eksik istek alanı sessizce NULL yazıyordu — FR-016).`,\n );\n }\n }\n}\n","// The wire shape of a declared schema — what the deploy reads.\n//\n// `defineSchema(...)` produces a value full of builders and phantom types, which\n// is the right shape for authoring and the wrong shape for anything outside this\n// process. The deploy is Go: it introspects the live database, diffs it against\n// the declaration, and applies the difference. So the declaration has to leave\n// TypeScript as data, and this file is where that happens.\n//\n// It lives in the SDK because the SDK owns the DSL. The alternative — a script\n// beside the deploy that reaches into `._def` — is a second reading of a private\n// shape, and it drifts the moment a column gains a property: the DSL keeps\n// working, the emitter silently omits it, and the database is missing something\n// nobody can see in the source.\n//\n// The field names below are a CONTRACT with Go's `schema.SchemaJSON`. Renaming\n// one here without renaming it there produces a declaration that parses to\n// something emptier than it was — the failure mode being a column, a policy, or\n// a whole table that quietly never gets created.\nimport type { ColumnBuilder, ColumnDef } from \"./columns.js\";\nimport type { PolicyDef } from \"./policy.js\";\nimport type { MemoryDecl, SchemaDef, SearchDecl, TableDef } from \"./schema.js\";\n\n/** One column, flattened. Mirrors Go's `schema.ColumnJSON`. */\nexport interface ColumnJSON {\n type: string;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n renamedFrom?: string;\n /** See Go's `schema.ColumnJSON.Ignored` — the contraction gate's only signal. */\n ignored?: boolean;\n owns?: boolean;\n references?: { table: string; column: string };\n onDeleteAction?: string;\n enumName?: string;\n enumValues?: string[];\n unique?: boolean;\n dimensions?: number;\n}\n\n/** One RLS policy. Mirrors Go's `schema.PolicyJSON`. */\nexport interface PolicyJSON {\n name: string;\n command: string;\n roles: string[];\n using: string | null;\n withCheck: string | null;\n permissive: boolean;\n}\n\n/** One table. Mirrors Go's `schema.TableJSON`. */\nexport interface TableJSON {\n /**\n * The schema this table lives in. `public` unless declared otherwise.\n *\n * The table carries it because the diff iterates over KEYS but passes the\n * VALUE around: a bare name inside a qualified key space writes the migration\n * into the wrong schema, silently.\n */\n schema: string;\n name: string;\n columns: Record<string, ColumnJSON>;\n rls: boolean;\n policies: PolicyJSON[];\n primaryKey?: string[];\n uniqueConstraints?: { name: string; columns: string[] }[];\n rawConstraints?: { name: string; up: string; down: string | null }[];\n checks?: { name: string; expr: string }[];\n indexes?: { name: string; columns: string[] }[];\n search?: SearchJSON;\n memory?: MemoryJSON;\n}\n\n/** C-11 wire şekli — Go'nun MemoryJSON'ıyla alan-adı sözleşmesi (D-019).\n * Beyansız tablolarda alan OMIT — eski şemalar bayt-aynı (NFR-B1). */\nexport interface MemoryJSON {\n from: string[];\n into: string;\n subject?: string;\n extract: { provider: string; model: string };\n}\n\n/** A whole declaration. Mirrors Go's `schema.SchemaJSON`. */\nexport interface SchemaJSON {\n tables: Record<string, TableJSON>;\n extensions: string[];\n /**\n * Every declared schema, with its HTTP reachability.\n *\n * The flag has nowhere else to live: `/v1/db` must know which schemas are\n * reachable, and introspection must know which schemas the project DECLARED —\n * a live database also contains internal module schemas that are none of the\n * diff's business.\n */\n schemas: SchemaMetaJSON[];\n}\n\nexport interface SchemaMetaJSON {\n name: string;\n exposed: boolean;\n}\n\n/** The definition behind a column, whichever side of the builder it arrives on. */\nfunction defOf(column: ColumnBuilder | ColumnDef): ColumnDef {\n return \"_def\" in column ? column._def : column;\n}\n\nfunction columnToJSON(column: ColumnBuilder | ColumnDef): ColumnJSON {\n const def = defOf(column);\n const out: ColumnJSON = {\n type: def.type,\n nullable: def.nullable,\n primaryKey: def.primaryKey,\n };\n // Every optional field is omitted rather than emitted as undefined: Go\n // distinguishes \"absent\" from \"present and empty\" on several of these, and a\n // `defaultValue: null` is a real default that says NULL.\n if (def.defaultValue !== undefined) out.defaultValue = def.defaultValue;\n if (def.defaultRandom === true) out.defaultRandom = true;\n if (def.defaultNow === true) out.defaultNow = true;\n if (def.renamedFrom !== undefined) out.renamedFrom = def.renamedFrom;\n // Go'daki schema.ColumnJSON'un aynası. `omitempty` karşılığı: yalnız TRUE ise yazılır,\n // böylece işaretsiz bir şemanın JSON'u bu alandan önceki hâliyle byte-eş kalır.\n if (def.ignored === true) out.ignored = true;\n // OWNERSHIP HAS TO CROSS THE WIRE, because the gate that enforces it is on the\n // other side. `ownedByUser()` sets `owns` on the column, and Go's\n // `validateOwnership` reads `ColumnJSON.Owns` to refuse a table that declares\n // two owners — but nothing was carrying the flag between them.\n //\n // Measured on the live cluster: a table with TWO `ownedByUser()` columns\n // pushed clean and both foreign keys landed on `auth.users` ON DELETE CASCADE.\n // The rule existed in the DSL and in the generator; the wire in between said\n // nothing, so the generator saw ZERO ownership columns and had nothing to\n // refuse. A flag with a reader and no writer is a dead wire.\n if (def.owns === true) out.owns = true;\n if (def.references !== undefined) {\n out.references = { table: def.references.table, column: def.references.column };\n }\n if (def.onDeleteAction !== undefined) out.onDeleteAction = def.onDeleteAction;\n if (def.enumName !== undefined) out.enumName = def.enumName;\n if (def.enumValues !== undefined) out.enumValues = [...def.enumValues];\n if (def.unique === true) out.unique = true;\n if (def.dimensions !== undefined) out.dimensions = def.dimensions;\n return out;\n}\n\nfunction policyToJSON(policy: PolicyDef): PolicyJSON {\n return {\n name: policy.name,\n command: policy.command ?? \"all\",\n roles: policy.roles ? [...policy.roles] : [],\n // null rather than omitted: a policy with no USING clause is a different\n // thing from one whose clause the emitter forgot, and Go reads the\n // difference.\n using: policy.using ?? null,\n withCheck: policy.withCheck ?? null,\n permissive: policy.permissive !== false,\n };\n}\n\n/** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).\n * `mode`/`chunks` yalnız yeni-biçim chunk-modunda emit edilir (D-010);\n * satır-modu ve eski biçim bayt-aynı kalır (NFR-B1). */\nexport interface SearchJSON {\n text?: { columns: string[] };\n vector?: {\n column?: string;\n metric: string;\n embed?: { provider: string; model: string; from: string[]; apiKeyName?: string; dimensions?: number; baseURL?: string };\n staleness?: \"null\" | \"keep\";\n mode?: \"row\" | \"chunks\";\n chunks?: { sizeChars?: number; overlapChars?: number };\n }[];\n /** FR-026: sorgu-yeniden-yazımı haritası — beyan yoksa OMIT (NFR-B1). */\n synonyms?: Record<string, string[]>;\n /** C-1: sonuç yeniden-sıralama beyanı — beyan yoksa OMIT. */\n /** FR-029: geçerlilik türevleri — beyan yoksa OMIT. */\n validity?: boolean;\n}\n\n/** T020 (C-1): iki biçimin de üst-düzey ortak alanları — beyan yoksa OMIT,\n * boş synonyms haritası da OMIT (NFR-B1 baytları kımıldamaz). */\nfunction commonSearchFields(search: SearchDecl, out: SearchJSON): void {\n if (search.synonyms !== undefined && Object.keys(search.synonyms).length > 0) {\n out.synonyms = Object.fromEntries(\n Object.entries(search.synonyms).map(([word, alts]) => [word, [...alts]]),\n );\n }\n if (search.validity === true) out.validity = true;\n}\n\n/** Beyanı normalize eder: vector her zaman DİZİ, metric her zaman dolu (vars. cosine),\n * authoring'deki `from`/`model` wire'da `embed` altında toplanır. Alan yoksa OMIT —\n * search'süz şema bayt-aynı kalır (NFR-006). */\nfunction searchToJSON(search: SearchDecl, vectorColumn: string | undefined): SearchJSON {\n if (search.from !== undefined && search.model !== undefined) {\n // YENİ biçim (D-007): from tek listedir — FTS'i de embed'i de besler.\n // Mod ŞEMADAN türer (D-010): tabloda vector kolonu varsa satır-modu\n // (column yazılır, mode OMIT — eski davranışla aynı wire), yoksa\n // chunk-modu (mode:\"chunks\", column yok — vektörler türev tabloda).\n const out: SearchJSON = {};\n const textCols =\n search.text === false ? undefined : Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from;\n if (textCols !== undefined) out.text = { columns: [...textCols] };\n const v: NonNullable<SearchJSON[\"vector\"]>[number] = { metric: search.metric ?? \"cosine\" };\n if (vectorColumn !== undefined) v.column = vectorColumn;\n v.embed = {\n provider: search.model.provider,\n model: search.model.model,\n from: [...search.from],\n ...(search.model.apiKeyName !== undefined ? { apiKeyName: search.model.apiKeyName } : {}),\n ...(search.model.dimensions !== undefined ? { dimensions: search.model.dimensions } : {}),\n ...(search.model.baseURL !== undefined ? { baseURL: search.model.baseURL } : {}),\n };\n if (search.staleness !== undefined) v.staleness = search.staleness;\n if (vectorColumn === undefined) {\n v.mode = \"chunks\";\n if (search.chunks !== undefined) {\n const c: NonNullable<typeof v.chunks> = {};\n if (search.chunks.size !== undefined && search.chunks.size > 0) c.sizeChars = search.chunks.size;\n if (search.chunks.overlap !== undefined && search.chunks.overlap > 0) c.overlapChars = search.chunks.overlap;\n if (Object.keys(c).length > 0) v.chunks = c;\n }\n }\n out.vector = [v];\n commonSearchFields(search, out);\n return out;\n }\n const out: SearchJSON = {};\n // Eski biçimde text yalnız dizi olabilir (boolean'ı defineSchema zaten\n // reddediyor); Array.isArray hem tipi daraltır hem o sözleşmeyi belgeler.\n if (Array.isArray(search.text) && search.text.length > 0) out.text = { columns: [...search.text] };\n const legs = search.vector === undefined ? []\n : Array.isArray(search.vector) ? search.vector : [search.vector];\n if (legs.length > 0) {\n out.vector = legs.map((leg) => {\n const v: NonNullable<SearchJSON[\"vector\"]>[number] = { metric: leg.metric ?? \"cosine\" };\n if (leg.column !== undefined) v.column = leg.column;\n if (leg.staleness !== undefined) v.staleness = leg.staleness;\n if (leg.model !== undefined) {\n v.embed = {\n provider: leg.model.provider,\n model: leg.model.model,\n from: [...(leg.from ?? [])],\n ...(leg.model.apiKeyName !== undefined ? { apiKeyName: leg.model.apiKeyName } : {}),\n ...(leg.model.dimensions !== undefined ? { dimensions: leg.model.dimensions } : {}),\n ...(leg.model.baseURL !== undefined ? { baseURL: leg.model.baseURL } : {}),\n };\n }\n return v;\n });\n }\n commonSearchFields(search, out);\n return out;\n}\n\nfunction memoryToJSON(m: MemoryDecl): MemoryJSON {\n return {\n from: [...m.from],\n into: m.into,\n ...(m.subject !== undefined ? { subject: m.subject } : {}),\n extract: { provider: m.extract.provider, model: m.extract.model },\n };\n}\n\nfunction tableToJSON(table: TableDef, schemaName: string): TableJSON {\n const columns: Record<string, ColumnJSON> = {};\n for (const [name, column] of Object.entries(table.columns)) {\n columns[name] = columnToJSON(column);\n }\n\n const out: TableJSON = {\n name: table.name,\n schema: schemaName,\n columns,\n // Read, not re-derived. `defineSchema` already resolves the fail-closed\n // default (RLS on unless the author wrote `rls: false`, and forced on by any\n // policy), and a second copy of a SECURITY default is exactly the thing that\n // drifts — the direction it drifted last time was \"expose everything\", and\n // the live proof was one user reading another's rows.\n rls: table.rls,\n policies: (table.policies ?? []).map(policyToJSON),\n };\n\n if (table.primaryKey !== undefined && table.primaryKey.length > 0) {\n out.primaryKey = [...table.primaryKey];\n }\n if (table.unique !== undefined && table.unique.length > 0) {\n out.uniqueConstraints = table.unique.map((u) => ({ name: u.name, columns: [...u.columns] }));\n }\n if (table.raw !== undefined && table.raw.length > 0) {\n out.rawConstraints = table.raw.map((r) => ({\n name: r.name,\n up: r.up,\n down: r.down ?? null,\n }));\n }\n if (table.checks !== undefined && table.checks.length > 0) {\n out.checks = table.checks.map((c) => ({ name: c.name, expr: c.expr }));\n }\n if (table.indexes !== undefined && table.indexes.length > 0) {\n out.indexes = table.indexes.map((i) => ({ name: i.name, columns: [...i.columns] }));\n }\n if (table.search !== undefined) {\n // D-010 mod kararının tek girdisi: tabloda dimensions'lı (vector) kolon\n // adı. Birden çoksa ilkini yazmak YANLIŞ olurdu — o durum eski biçimin\n // işidir ve yeni biçim + çoklu vector kolonu apply'da reddedilir.\n const vectorColumn = Object.entries(columns).find(([, c]) => c.dimensions !== undefined)?.[0];\n const sj = searchToJSON(table.search, vectorColumn);\n if (sj.text !== undefined || sj.vector !== undefined) out.search = sj;\n }\n if (table.memory !== undefined) {\n out.memory = memoryToJSON(table.memory);\n }\n return out;\n}\n\n/**\n * The key a table answers to in `SchemaJSON.tables`.\n *\n * A public table is BARE, anything else is schema-qualified. This is not a new\n * convention: `RefJSON.Table` already carries `auth.users`, and introspection\n * already returns a public referent bare and a non-public one qualified. Adding\n * a second key space would make two interpreters of the same database.\n */\nexport function qualifiedTableKey(schemaName: string, tableName: string): string {\n // An ABSENT schema means public, exactly as Go's `isPublicSchema` says. This\n // branch used to be missing here and present in the engine's private copy, so\n // the two writers of one rule answered DIFFERENTLY for `\"\"`: one qualified it\n // into a schema literally named the empty string, the other left it bare.\n return schemaName === \"\" || schemaName === \"public\" ? tableName : `${schemaName}.${tableName}`;\n}\n\n/**\n * Serialize declared schemas into the JSON the deploy applies.\n *\n * Takes every schema the project declares — one file per schema — because a\n * cross-schema foreign key can only be checked when both ends are in hand.\n */\nexport function toSchemaJSON(schemas: readonly SchemaDef[]): SchemaJSON {\n const tables: Record<string, TableJSON> = {};\n const extensions: string[] = [];\n const meta: SchemaMetaJSON[] = [];\n const seen = new Set<string>();\n for (const schema of schemas) {\n if (seen.has(schema.name)) {\n throw new Error(`two schemas declare the name \"${schema.name}\" — schema names must be unique`);\n }\n seen.add(schema.name);\n for (const table of Object.values(schema.tables)) {\n const json = tableToJSON(table, schema.name);\n tables[qualifiedTableKey(schema.name, json.name)] = json;\n }\n extensions.push(...(schema.extensions ?? []));\n // The schema list travels because the flag has nowhere else to live: without\n // it /v1/db cannot know which schemas are reachable over HTTP, and nothing\n // downstream can read the DECLARED schema set that introspection needs.\n meta.push({ name: schema.name, exposed: schema.exposed });\n }\n return { tables, extensions: [...new Set(extensions)], schemas: meta };\n}\n","/**\n * engine/db.ts — a real pooled connection, and the identity every request is\n * bound to inside it.\n *\n * # Why one transaction per request\n *\n * In the isolate architecture every `Database.*` call was its own HTTP hop to a\n * capability surface, so two writes in one handler could not be atomic — a\n * handler that wrote and then threw left the first write behind. Here the whole\n * request runs inside one transaction: it commits when the handler returns and\n * rolls back when it throws. Atomicity stops being something the author has to\n * ask for.\n *\n * # Why it opens lazily\n *\n * A handler that touches no table must cost no round trip. Opening eagerly cost\n * four (BEGIN + bind + … + COMMIT) on endpoints that never query — measured at\n * 1,243 rps against 31,579 for the same endpoint once the open became lazy.\n *\n * # How the caller's identity reaches RLS\n *\n * One statement, not three:\n *\n * select set_config('role',$1,true),\n * set_config('search_path','public',true),\n * set_config('request.jwt.claims',$2,true)\n *\n * `set_config(..., is_local => true)` is transaction-scoped exactly like\n * `SET LOCAL`, but takes BOUND PARAMETERS, which `SET LOCAL` cannot. So the\n * role and the caller's claims travel as parameters — user identity is never\n * spliced into SQL text — and `auth.uid()` resolves inside RLS policies, which\n * means the row filter is enforced by Postgres rather than by our code.\n */\nimport type { DBClient, DBOps } from \"../endpoint.js\";\n// A VALUE import, not a type: the engine constructs one (23505 → 409).\nimport { UniqueViolation, markEngineRaised,\n} from \"../errors.js\";\nimport { assertUsableFilter, assertUsableWriteValues } from \"../db/input-guards.js\";\nimport { qualifiedTableKey } from \"../db/schema-json.js\";\nimport type {\n TxPlanBody,\n TxPlanOpResult,\n TxPlanResponse,\n TxWireExpr,\n TxWireOp,\n TxWireRef,\n TxWireValue,\n} from \"../db/tx-plan.js\";\n\n/** The slice of a SQL driver the engine uses. `Bun.sql` satisfies it. */\nexport interface SqlDriver {\n /** Run a parameterised statement. */\n unsafe(sql: string, params?: unknown[]): Promise<unknown>;\n /** Open a transaction; the driver commits when `cb` resolves and rolls back\n * when it rejects. */\n begin<T>(cb: (tx: SqlTx) => Promise<T>): Promise<T>;\n}\n\nexport interface SqlTx {\n unsafe(sql: string, params?: unknown[]): Promise<unknown>;\n savepoint<T>(cb: (sp: SqlTx) => Promise<T>): Promise<T>;\n}\n\ntype Row = Record<string, unknown>;\n\n/** Quote an identifier. Table and column names reach here from the schema and\n * from handler arguments; neither is allowed to become syntax. */\nexport function quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Quote a TABLE KEY, which is one identifier or two — never one that contains\n * a dot.\n *\n * A table travels under this system's one key convention: `public` bare,\n * anything else `schema.table` (the same rule `qualifiedTableKey` writes on the\n * Go side). Handing that key to `quoteIdent` produces `\"billing.invoices\"`,\n * which Postgres reads as a PUBLIC table whose NAME contains a dot — so every\n * call through `Database.schema(\"billing\").tables.*` named a table that does\n * not exist, or, worse, a different one that does.\n *\n * The public half stays BYTE-IDENTICAL to the single-schema world, because\n * every existing query and golden asserts the bare form.\n */\nexport function quoteTable(key: string): string {\n const dot = key.indexOf(\".\");\n if (dot === -1) return quoteIdent(key);\n return `${quoteIdent(key.slice(0, dot))}.${quoteIdent(key.slice(dot + 1))}`;\n}\n\n/**\n * Render a JavaScript array as a Postgres array literal, so `= ANY($n::uuid[])`\n * works from `Database.query`.\n *\n * WHY THIS EXISTS. `Bun.SQL`'s `unsafe(text, params)` does NOT bind a JS array as\n * a Postgres array — it applies `Array.prototype.toString()`. `[\"a\",\"b\"]` arrives\n * as the text `a,b`, with no braces, and `$1::uuid[]` fails with \"malformed array\n * literal\" (measured 2026-08-29 against pgvector/pg16 + bun 1.3.9). Every fan-in\n * query a tenant writes therefore had to hand-build the literal; one of them did,\n * and reported it. node-postgres converts arrays for exactly this reason.\n *\n * Bun's own escape hatch, `sql.array()`, cannot be used here: it is a tagged-\n * template FRAGMENT that renders inline `ARRAY[...]` TEXT, and nothing that\n * travels in the `params` array can carry it.\n *\n * There is deliberately NO vector branch, and there cannot be one: this sees raw\n * SQL, so which column a parameter is destined for is unknowable. The single\n * uniform encoding is what makes a vector parameter writable at all —\n * `$n::float8[]::vector` round-trips (measured), where today nothing does.\n */\nexport function encodePgArray(value: readonly unknown[]): string {\n const element = (x: unknown): string => {\n // Unquoted NULL is the only spelling Postgres reads as the null element;\n // `\"NULL\"` would be the four-character string.\n if (x === null || x === undefined) return \"NULL\";\n if (Array.isArray(x)) return encodePgArray(x);\n return `\"${String(x).replace(/([\"\\\\])/g, \"\\\\$1\")}\"`;\n };\n return `{${value.map(element).join(\",\")}}`;\n}\n\nconst BIND_SQL =\n \"select set_config('role',$1,true), set_config('search_path','public',true), set_config('request.jwt.claims',$2,true)\";\n\n/**\n * A transaction that does not exist until somebody reads or writes.\n *\n * `begin(cb)` is callback-scoped, so to hold one open across a whole request\n * the callback parks on a promise this object controls: `commit()` resolves it\n * (the driver commits), `rollback()` rejects it (the driver rolls back). A\n * request that never touches the database never enters the callback at all.\n */\nexport function createLazyTransaction(\n sql: SqlDriver,\n role: string,\n claimsJson: string,\n options: { lockTimeout?: string } = {},\n) {\n const { lockTimeout } = options;\n // `lock_timeout` travels as a BOUND parameter like the other two, so a value\n // from configuration can never become SQL text.\n const bindSql = lockTimeout ? `${BIND_SQL}, set_config('lock_timeout',$3,true)` : BIND_SQL;\n const bindParams = lockTimeout ? [role, claimsJson, lockTimeout] : [role, claimsJson];\n\n let opening: Promise<SqlTx> | null = null;\n let release: (() => void) | null = null;\n let fail: ((e: unknown) => void) | null = null;\n let settled: Promise<unknown> | null = null;\n\n const ensure = (): Promise<SqlTx> => {\n if (opening) return opening;\n opening = new Promise<SqlTx>((resolveTx, rejectTx) => {\n const parked = new Promise<void>((res, rej) => {\n release = res;\n fail = rej;\n });\n settled = sql\n .begin(async (tx) => {\n await tx.unsafe(bindSql, bindParams);\n resolveTx(tx);\n await parked;\n })\n .catch((e: unknown) => {\n // Both paths matter: a caller awaiting `ensure()` must see the\n // failure, and `commit()` must not hang waiting for a dead driver.\n rejectTx(e);\n throw e;\n });\n });\n return opening;\n };\n\n return {\n ensure,\n get opened(): boolean {\n return opening !== null;\n },\n async commit(): Promise<void> {\n if (!opening) return;\n release!();\n await settled;\n },\n async rollback(reason: unknown): Promise<void> {\n if (!opening) return;\n fail!(reason);\n // The rejection is the mechanism, not an error to report twice.\n await settled?.catch(() => undefined);\n },\n };\n}\n\nexport type LazyTransaction = ReturnType<typeof createLazyTransaction>;\n\n/** Either a live driver transaction or the lazy holder above. */\ntype TxLike = SqlTx | LazyTransaction;\n\nconst resolveTx = async (tx: TxLike): Promise<SqlTx> =>\n typeof (tx as LazyTransaction).ensure === \"function\"\n ? await (tx as LazyTransaction).ensure()\n : (tx as SqlTx);\n\n/**\n * What a row LOOKS like to the code that reads it.\n *\n * The driver hands back a `Date` for every timestamp column, while the typed\n * surface this SDK generates for the same table says `string` — and so does the\n * response schema derived from a handler's return type, and so does the JSON on\n * the wire. So a handler that returned a row straight from `Database.tables.x`\n * failed its OWN declared type: measured on 2026-08-16, `POST /todos` answered\n * 500 `output_invalid` with \"expected string, received date\" for `created_at`,\n * from code that had done nothing wrong.\n *\n * ISO-8601, because that is what the schema, the generated client and every\n * JSON reader already agree on.\n */\nfunction asWireValue(value: unknown): unknown {\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map(asWireValue);\n return value;\n}\n\n/** Every row a caller receives passes through here. */\nfunction asWireRow<T>(row: T): T {\n if (row === null || typeof row !== \"object\") return row;\n const out: Row = {};\n for (const [key, value] of Object.entries(row as Row)) out[key] = asWireValue(value);\n return out as T;\n}\n\nfunction asWireRows(rows: Row[]): Row[] {\n return rows.map((row) => asWireRow(row));\n}\n\n/** pgvector text literal: '[v1,v2,...]' — the driver would otherwise bind a\n * Postgres ARRAY, which vector's input function refuses. (FR-008) */\nfunction toVectorLiteral(v: number[]): string {\n return `[${v.join(\",\")}]`;\n}\n\n/**\n * The vector-typed column names of one table, read from the installed schema.\n *\n * Ops receive the PHYSICAL table name (`withTables` maps key → `def.name`), so\n * the lookup matches `def.name ?? key`. A column arrives either as a\n * ColumnBuilder (with `_def`) or as the plain def — the same double reading\n * schema-json does, for the same reason: both shapes exist in the wild.\n */\nfunction vectorColumnsOf(schema: typeof currentSchema, table: string): Set<string> {\n const out = new Set<string>();\n const def = tableDefOf(table, schema);\n if (def) {\n for (const [col, c] of Object.entries(def.columns ?? {})) {\n const d = (c !== null && typeof c === \"object\" && \"_def\" in c\n ? (c as { _def: unknown })._def\n : c) as { type?: unknown } | null;\n if (d !== null && typeof d === \"object\" && d.type === \"vector\") out.add(col);\n }\n }\n return out;\n}\n\n/**\n * The one place that answers \"which declared table is this?\".\n *\n * Ops receive the table's WIRE KEY — public bare, anything else qualified —\n * and the installed schema is flattened under exactly those keys. There used to\n * be four separate scans here, each matching `def.name ?? key` against the\n * name, and every one of them missed a table outside public: the column\n * metadata (vectors, transforms, search config) came back EMPTY and the ops\n * fell through to their \"no schema to check against\" path without saying so.\n */\nfunction tableDefOf(\n key: string,\n schema: typeof currentSchema = currentSchema,\n): { name?: string; columns?: Record<string, unknown> } | null {\n return schema.tables?.[key] ?? null;\n}\n\n/** The driver hands a vector back as its text literal; JSON.parse restores the\n * number[] the typed surface declares — the literal is valid JSON (C-9). A null\n * (row without an embedding yet) passes through untouched. */\nfunction reviveVectors<T>(row: T, vectorCols: Set<string>): T {\n if (row === null || typeof row !== \"object\" || vectorCols.size === 0) return row;\n const out = row as Row;\n for (const col of vectorCols) {\n const v = out[col];\n if (typeof v === \"string\") out[col] = JSON.parse(v);\n }\n return row;\n}\n\n/** The declared `{ fromDb, toDb }` per column of `table`, empty when none.\n *\n * Read the same way vector columns are: a column is either a ColumnBuilder\n * (with `_def`) or the flat generated shape, and both are accepted.\n *\n * WITHOUT THIS the hook is a type-level promise the runtime does not keep — the\n * declaration would say `number` and the driver would still hand over the\n * string, which is the defect class this whole surface exists to remove. */\nfunction transformsOf(\n schema: typeof currentSchema,\n table: string,\n): Map<string, { fromDb?: (v: unknown) => unknown; toDb?: (v: unknown) => unknown }> {\n const out = new Map<string, { fromDb?: (v: unknown) => unknown; toDb?: (v: unknown) => unknown }>();\n const def = tableDefOf(table, schema);\n if (def) {\n for (const [col, c] of Object.entries(def.columns ?? {})) {\n const d = (c !== null && typeof c === \"object\" && \"_def\" in c\n ? (c as { _def: unknown })._def\n : c) as { transform?: unknown } | null;\n const t = d?.transform;\n if (t !== null && typeof t === \"object\") {\n out.set(col, t as { fromDb?: (v: unknown) => unknown; toDb?: (v: unknown) => unknown });\n }\n }\n }\n return out;\n}\n\n/** Apply every declared `fromDb` to one row. NULL is passed through untouched:\n * \"no value\" is not a value to convert, and a `fromDb` written for a string\n * would answer `0` for it. */\nfunction applyFromDb(row: Row, transforms: ReturnType<typeof transformsOf>): Row {\n if (transforms.size === 0) return row;\n for (const [col, t] of transforms) {\n if (t.fromDb === undefined) continue;\n const v = row[col];\n if (v === null || v === undefined) continue;\n row[col] = t.fromDb(v);\n }\n return row;\n}\n\n/** `asWireRow`, made table-aware: what the table's schema calls a vector comes\n * back as number[]. Rows from tables the schema does not know pass unchanged. */\nfunction asTableRow<T>(table: string, row: T): T {\n const revived = reviveVectors(asWireRow(row), vectorColumnsOf(currentSchema, table));\n return applyFromDb(revived as Row, transformsOf(currentSchema, table)) as T;\n}\n\nfunction asTableRows(table: string, rows: Row[]): Row[] {\n const vectorCols = vectorColumnsOf(currentSchema, table);\n const transforms = transformsOf(currentSchema, table);\n return rows.map((row) => applyFromDb(reviveVectors(asWireRow(row), vectorCols), transforms));\n}\n\n/** Bind parameters for one write: a value headed for a vector column becomes\n * the pgvector text literal; everything else binds as-is. (FR-008) */\nfunction asBindParams(table: string, cols: string[], data: Row, caller: string): unknown[] {\n // AN `undefined` VALUE IS NOT A WRITE — it is a value that never arrived.\n //\n // The read path already refuses one (see compileWhere): a filter nobody filled\n // in returned an empty list and said nothing. The WRITE half is the same shape\n // and a far more expensive result: `{ title: req.body.title }` with no `title`\n // in the body bound NULL and answered 200 — the column was ERASED, silently.\n // Measured on the 24.0.x line across insert, update, updateMany, upsert and\n // supersede, all of which bind through here.\n //\n // `null` is untouched, and the difference is the whole point: null is an author\n // SAYING \"empty this column\". undefined is nobody saying anything.\n assertUsableWriteValues(caller, table, cols, data);\n const vectorCols = vectorColumnsOf(currentSchema, table);\n const transforms = transformsOf(currentSchema, table);\n return cols.map((c) => {\n const v = data[c];\n if (Array.isArray(v) && vectorCols.has(c)) return toVectorLiteral(v);\n // `toDb` before the bind, and NULL straight through for the same reason\n // `fromDb` skips it.\n const t = transforms.get(c);\n if (t?.toDb !== undefined && v !== null && v !== undefined) return t.toDb(v);\n return v;\n });\n}\n\n// ---------------------------------------------------------------------------\n// search (T017, FR-013..016) — tek-SQL hibrit RRF.\n// ---------------------------------------------------------------------------\n\n/** Metrik → operatör. Tek kelimeden türetilir; opclass/operatör asla yüzeye\n * çıkmaz, uyumsuzluk yapısal olarak imkânsız (D-5, prod arıza #2). */\n// ≤ bu kadar satır eşleşiyorsa vektör kolu EXACT taranır (10K×1536d ≈ 10-20ms;\n// HNSW'nin seçici filtrede recall çöküşüne karşı — ölçüm: engine/db.ts NFR-005 yorumu).\nconst SELECTIVITY_EXACT_THRESHOLD = 10000;\n\nconst METRIC_OPERATOR: Record<string, string> = {\n cosine: \"<=>\",\n euclidean: \"<->\",\n inner_product: \"<#>\",\n};\n\ninterface SearchLeg {\n column: string;\n metric: string;\n /** Auto-embed beyanı (authoring EmbeddingModelRef — runtime şeması defineSchema çıktısıdır). */\n embed?: { model: string; apiKeyName: string; baseURL?: string; dimensions?: number };\n}\n\n/** Chunk-modu hedefi (D-010): arama bu türev tabloda koşar. */\ninterface ChunkTarget {\n table: string;\n metric: string;\n embed?: SearchLeg[\"embed\"];\n fts: boolean;\n}\n\ninterface SearchConfig {\n chunk?: ChunkTarget;\n pk: string;\n cols: string[];\n colSet: Set<string>;\n ftsCols: string[];\n legs: SearchLeg[];\n /** FR-026: beyandan gelen eş anlamlı haritası — websearch girdisi bununla genişler. */\n synonyms?: Record<string, string[]>;\n /** FR-029: beyanda validity:true — arama varsayılan yalnız günceli tarar,\n * supersede bu tabloda çalışır (T019 türev kolonları: valid_from/valid_to/superseded_by). */\n validity?: boolean;\n}\n\n/** Tablonun arama konfigürasyonu, runtime'ın kurduğu şemadan (setSchema — C-9).\n * `search` bloğu yoksa vector kolonlarının VARLIĞI yeter (D-3/FR-013): her\n * vector kolonu cosine metrikli bir leg olur. Tablo şemada yoksa null. */\nfunction searchConfigFor(table: string): SearchConfig | null {\n const t = tableDefOf(table);\n if (!t) return null;\n const columns = t.columns ?? {};\n const defOf = (c: unknown): { type?: string } =>\n c !== null && typeof c === \"object\" && \"_def\" in (c as Record<string, unknown>)\n ? ((c as { _def: { type?: string } })._def)\n : ((c ?? {}) as { type?: string });\n const cols = Object.keys(columns);\n const vectorCols = cols.filter((c) => defOf((columns as Record<string, unknown>)[c]).type === \"vector\");\n // PK adı ŞEMADAN (review I3): Go tarafı tek-kolon PK'nın adını bilinçli\n // serbest bırakır (FR-020 \"adı serbesttir\") — SQL'e 'id' gömmek, pk'sı\n // başka adla declare edilmiş searchable tabloyu runtime 500'üne çevirirdi.\n const defOfFull = (c: unknown): { type?: string; primaryKey?: boolean } =>\n c !== null && typeof c === \"object\" && \"_def\" in (c as Record<string, unknown>)\n ? ((c as { _def: { type?: string; primaryKey?: boolean } })._def)\n : ((c ?? {}) as { type?: string; primaryKey?: boolean });\n const pkCols = cols.filter((c) => defOfFull((columns as Record<string, unknown>)[c]).primaryKey === true);\n const pk = pkCols.length === 1 ? pkCols[0]! : cols.includes(\"id\") ? \"id\" : null;\n if (pk === null) {\n throw new Error(\n `search(${table}): tek-kolon primary key bulunamadı — arama sıralaması ve satır birleşimi PK ister (FR-020)`,\n );\n }\n const search = (t as {\n search?: { text?: string[] | boolean; vector?: unknown; from?: string[]; metric?: string;\n model?: { model: string; apiKeyName?: string; baseURL?: string; dimensions?: number };\n synonyms?: Record<string, string[]>; validity?: boolean };\n }).search;\n const synonyms =\n search?.synonyms !== undefined && Object.keys(search.synonyms).length > 0\n ? { synonyms: search.synonyms }\n : {};\n // T019 notu: validity beyanı wire'da SEARCH bloğunda yaşar (SearchJSON.Validity).\n const validity = search?.validity === true ? { validity: true } : {};\n // YENİ biçim (D-007/D-010): `from`+`model`. Vector kolonu varsa satır-modu\n // (tek leg, kolon o); yoksa CHUNK-modu — arama türev __palbase_chunks\n // tablosunda koşar, sonuç parent'a gruplanır (FR-015).\n if (search?.from !== undefined && search.model !== undefined) {\n const m = search.model;\n const embed = {\n model: m.model, apiKeyName: m.apiKeyName ?? \"OPENAI_API_KEY\",\n ...(m.baseURL !== undefined ? { baseURL: m.baseURL } : {}),\n ...(m.dimensions !== undefined ? { dimensions: m.dimensions } : {}),\n };\n const metric = search.metric ?? \"cosine\";\n const ftsOn = search.text !== false;\n const ftsColsNew = ftsOn\n ? (Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from)\n : [];\n if (vectorCols.length > 0) {\n return { pk, cols, colSet: new Set(cols), ftsCols: ftsColsNew,\n legs: [{ column: vectorCols[0]!, metric, embed }], ...synonyms, ...validity };\n }\n return { pk, cols, colSet: new Set(cols), ftsCols: ftsColsNew, legs: [],\n chunk: { table: `${table}__palbase_chunks`, metric, embed, fts: ftsOn }, ...synonyms, ...validity };\n }\n const ftsCols = (Array.isArray(search?.text) ? search.text : undefined) ?? [];\n const rawLegs = search?.vector === undefined ? [] : Array.isArray(search.vector) ? search.vector : [search.vector];\n let legs: SearchLeg[];\n if (rawLegs.length > 0) {\n legs = rawLegs.map((leg) => {\n const l = leg as { column?: string; metric?: string };\n const column = l.column ?? (vectorCols.length === 1 ? vectorCols[0]! : undefined);\n if (column === undefined) {\n throw new Error(`search(${table}): birden çok vector kolonu var — beyanda 'column' zorunlu (FR-010)`);\n }\n const model = (l as { model?: { model: string; apiKeyName?: string; baseURL?: string; dimensions?: number } }).model;\n return {\n column,\n metric: l.metric ?? \"cosine\",\n ...(model !== undefined\n ? { embed: { model: model.model, apiKeyName: model.apiKeyName ?? \"OPENAI_API_KEY\",\n ...(model.baseURL !== undefined ? { baseURL: model.baseURL } : {}),\n ...(model.dimensions !== undefined ? { dimensions: model.dimensions } : {}) } }\n : {}),\n };\n });\n } else {\n legs = vectorCols.map((column) => ({ column, metric: \"cosine\" }));\n }\n if (ftsCols.length === 0 && legs.length === 0) return null;\n return { pk, cols, colSet: new Set(cols), ftsCols, legs, ...synonyms, ...validity };\n}\n\n/** using → hedef leg. using yok + tek leg → o; using yok + çok leg → adlandırılmış\n * hata (model geçişinde seçim bilinçli olmalı); using yanlış → adlandırılmış hata. */\nfunction pickLeg(table: string, legs: SearchLeg[], using: string | undefined): SearchLeg | null {\n if (legs.length === 0) return null;\n if (using !== undefined) {\n const hit = legs.find((l) => l.column === using);\n if (!hit) {\n throw new Error(\n `search(${table}): using \"${using}\" bir vektör kolunu adlamıyor — mevcut: ${legs.map((l) => l.column).join(\", \")}`,\n );\n }\n return hit;\n }\n if (legs.length === 1) return legs[0]!;\n throw new Error(`search(${table}): birden çok vektör kolu var — 'using' ile seçin (FR-013) — salt metin arıyorsan mode:\\\"text\\\" kullan`);\n}\n\nconst HALF_LIFE_UNIT_SECONDS: Record<string, number> = { s: 1, m: 60, h: 3600, d: 86400 };\n\n/** \"30d\" gibi bir yarı ömrü saniyeye çevirir (FR-004). Biçim <sayı>(s|m|h|d);\n * çözülemeyen YA DA sıfır süre adıyla reddedilir — SQL'e sıfır bölen gitmez. */\nfunction parseHalfLife(s: string): number {\n const m = /^(\\d+)(s|m|h|d)$/.exec(s);\n const sec = m === null ? 0 : Number(m[1]) * HALF_LIFE_UNIT_SECONDS[m[2]!]!;\n if (!Number.isFinite(sec) || sec <= 0) {\n throw new Error(`recency.halfLife \"${s}\" çözümlenemedi — beklenen: pozitif <sayı>+(s|m|h|d), örn. \"30d\" (FR-004)`);\n }\n return sec;\n}\n\nconst WHERE_OPS: Record<string, string> = { gt: \">\", gte: \">=\", lt: \"<\", lte: \"<=\", neq: \"<>\" };\n\n/** FTS kolonlarının sorted coalesce birleşimi — typo-fallback trgm ifadesi ve\n * ts_headline kaynağı (FR-028) AYNI ifadeyi kullanır (Go türev index'iyle birebir). */\nfunction ftsExprOf(ftsCols: string[]): string {\n return [...ftsCols]\n .sort()\n .map((c) => `coalesce(t.${quoteIdent(c)},'')`)\n .join(\" || ' ' || \");\n}\n\n/**\n * expandSynonyms (T020, FR-026): websearch girdisinde tek yönlü eş anlamlı\n * genişletmesi — haritadaki kelime `(kelime OR eş1 OR eş2)` olur\n * (websearch_to_tsquery OR'u tanır). Çift tırnaklı kesimler AYNEN korunur\n * (yazar tam-ifade istedi); eşleşme küçük-harf üzerinden, orijinal token\n * çıktıda kalır. Saf fonksiyon — SQL'e değil bind DEĞERİNE uygulanır.\n */\nexport function expandSynonyms(query: string, map: Record<string, string[]>): string {\n const lower: Record<string, string[]> = {};\n for (const [word, alts] of Object.entries(map)) lower[word.toLowerCase()] = alts;\n return query\n .split(/(\"[^\"]*\")/)\n .map((seg) => {\n if (seg.startsWith('\"')) return seg;\n return seg\n .split(/(\\s+)/)\n .map((tok) => {\n if (tok === \"\" || /^\\s+$/.test(tok)) return tok;\n const alts = lower[tok.toLowerCase()];\n return alts !== undefined && alts.length > 0 ? `(${tok} OR ${alts.join(\" OR \")})` : tok;\n })\n .join(\"\");\n })\n .join(\"\");\n}\n\ntype SearchLogFn = (event: string, fields: Record<string, unknown>) => void;\n// Varsayılan console'a düşer: dikiş kurulmamış runtime'da bile no-results\n// sinyali kaybolmasın (FR-025; bölüm 25-f canlıda sessiz kalmıştı).\nlet searchLogger: SearchLogFn | null = (evt, fields) => {\n console.log(evt, JSON.stringify(fields));\n};\n/** Runtime boot'ta bağlanır (setSecretReader ile aynı kanal deseni): yapısal\n * arama telemetrisi. Varsayılan console.log'tur (a8d5a03: 0-sonuç görünür kalsın); null ile susturulur\n * (FR-025; db.ts'de başka log yolu yok, grep 2026-08-29 boş döndü). */\nexport function setSearchLogger(fn: SearchLogFn | null): void {\n searchLogger = fn;\n}\n\n/** FR-025: nihai dönüş boşsa (typo-fallback DAHİL denendikten sonra) yapısal\n * satır — query HAM haliyle ve 200'e kırpılıp yazılır, sinonim genişletmesi\n * telemetriyi kirletmez. Anahtar/vektör değeri asla loglanmaz. */\nfunction logNoResults(table: string, query: string | undefined, mode: string | undefined, n: number): void {\n if (n === 0) {\n searchLogger?.(\"palbase.search.no_results\", {\n table,\n query: (query ?? \"\").slice(0, 200),\n mode: mode ?? \"hybrid\",\n });\n }\n}\n\n/**\n * fetchFacets (T020, FR-027): filtrelenmiş küme üzerinde kolon başına değer\n * sayaçları — kolon başına top-20, tek UNION ALL sorgusu (parçalar LIMIT/ORDER\n * taşıdığından parantezli). Kolon adları çağıran tarafından şemadan doğrulanmış\n * gelir; where filtreleri sayaçlara da uygulanır (sayaç, kullanıcının gördüğü\n * kümeyi anlatır). Kendi bind listesiyle koşar — ana sorgunun parametreleriyle\n * karışmaz (kullanılmayan bind Postgres'te hatadır).\n */\nasync function fetchFacets(\n live: { unsafe(sql: string, params?: unknown[]): Promise<unknown> },\n table: string,\n colSet: Set<string>,\n facets: string[],\n where: Record<string, unknown>,\n extraWhere: (add: (v: unknown) => string) => string = () => \"\",\n): Promise<Record<string, { value: string | null; count: number }[]>> {\n const bind: unknown[] = [];\n const add = (v: unknown): string => {\n bind.push(v);\n return `$${bind.length}`;\n };\n const whereSql = compileWhere(table, colSet, where, add) + extraWhere(add);\n const parts = facets.map(\n (col) =>\n `(SELECT '${col.replace(/'/g, \"''\")}' AS f, t.${quoteIdent(col)}::text AS v, count(*) AS n ` +\n `FROM ${quoteTable(table)} t WHERE true${whereSql} GROUP BY 2 ORDER BY 3 DESC LIMIT 20)`,\n );\n const rows = (await live.unsafe(parts.join(\" UNION ALL \"), bind)) as\n { f?: string; v?: string | null; n?: unknown }[];\n const out: Record<string, { value: string | null; count: number }[]> = {};\n for (const col of facets) out[col] = [];\n for (const r of rows) {\n if (typeof r.f === \"string\" && out[r.f] !== undefined) {\n out[r.f]!.push({ value: r.v ?? null, count: Number(r.n) });\n }\n }\n return out;\n}\n\n/** C-8 iç kanalı (T018): similar/recommend kaynak id'lerini sonuçtan düşürür.\n * Public search imzasında BİLEREK yok — search-param imza üçlüsü (engine/db +\n * typed-db + endpoint) büyümesin; yalnız bu dosyadaki similar/recommend yazar. */\ninterface InternalSearchParams {\n __excludeIds?: unknown[];\n}\n\n/** FR-029: validity'li tabloda zaman filtresi (T019 türev kolonları sabit:\n * valid_from/valid_to). Varsayılan yalnız güncel satır; \"all\" filtreyi\n * kaldırır; {asOf} o anda geçerli olan versiyonu seçer (tek bind, iki kullanım).\n * Çağıran yalnız cfg.validity === true iken çağırır. */\nfunction validitySql(\n v: \"all\" | { asOf: string } | undefined,\n add: (x: unknown) => string,\n): string {\n if (v === \"all\") return \"\";\n if (v !== undefined) {\n const p = add(v.asOf);\n return ` AND t.\"valid_from\" <= ${p} AND (t.\"valid_to\" IS NULL OR t.\"valid_to\" > ${p})`;\n }\n return ` AND t.\"valid_to\" IS NULL`;\n}\n\n/** Kaynak satır(lar)ı eleyen SQL parçası. Tek id düz `<>`; çoklu\n * `<> ALL(ARRAY[...])` — elemanlar AYRI placeholder: dizi bind'i sürücüde\n * Postgres array literal'ine çevrilmiyor (verify 19-3b dersi, where.in ile aynı). */\nfunction excludeSql(pk: string, ids: unknown[], add: (v: unknown) => string): string {\n if (ids.length === 0) return \"\";\n if (ids.length === 1) return ` AND t.${quoteIdent(pk)} <> ${add(ids[0])}`;\n // ::text — pk uuid'yken text bind'lerle karşılaştırma \"operator does not\n // exist: uuid <> text\" veriyordu (bölüm 25-b canlı ölçümü).\n return ` AND t.${quoteIdent(pk)}::text <> ALL(ARRAY[${ids.map((x) => add(x)).join(\", \")}])`;\n}\n\n/** What `findMany` accepts beside its filter: an ordering, a row ceiling and a\n * page offset. All three used to require dropping to raw SQL, and the docs said\n * so — which is how a tenant's controllers filled up with hand-written SELECTs. */\nexport interface FindManyOptions {\n orderBy?: { column: string; direction?: \"asc\" | \"desc\" };\n limit?: number;\n /** Rows to skip before the page starts. Only meaningful with `limit`, and\n * refused without it — see `offsetClause`. */\n offset?: number;\n}\n\n/** The table's columns as the installed schema knows them, or null when this\n * process has no schema for it (unit tests, a table addressed by name alone).\n * Null means \"cannot validate\", never \"allow anything into SQL\": every\n * identifier still goes through quoteIdent. */\nfunction schemaColumns(table: string): Set<string> | null {\n const t = tableDefOf(table);\n const cols = t?.columns ? Object.keys(t.columns) : [];\n return cols.length > 0 ? new Set(cols) : null;\n}\n\n/** ORDER BY, with the column checked BEFORE it can reach SQL. Against a known\n * schema the check is membership; without one it is a conservative identifier\n * shape. Either way an ordering column is never interpolated on trust. */\nfunction orderClause(\n table: string,\n known: Set<string> | null,\n orderBy: FindManyOptions[\"orderBy\"],\n): string {\n if (!orderBy) return \"\";\n const col = orderBy.column;\n const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);\n if (known !== null ? !known.has(col) : !shapeOK) {\n throw new Error(`findMany(${table}): orderBy kolonu \"${col}\" tabloda yok`);\n }\n const dir = orderBy.direction === \"desc\" ? \"DESC\" : \"ASC\";\n return ` ORDER BY ${quoteIdent(col)} ${dir}`;\n}\n\n/** LIMIT, as a literal because it is a number this code produced — a bound must\n * not be bindable to something that is not one. */\nfunction limitClause(limit: number | undefined): string {\n if (limit === undefined) return \"\";\n if (!Number.isInteger(limit) || limit < 0) {\n throw new Error(`findMany: limit bir negatif olmayan tam sayı olmalı (geldi: ${String(limit)})`);\n }\n return ` LIMIT ${limit}`;\n}\n\n/** OFFSET, a literal for the same reason LIMIT is one.\n *\n * A bare `offset` — no `limit` — is refused BY NAME. Postgres accepts it, but\n * \"skip 10 rows of an unbounded result\" is not a page, and every caller that\n * writes `offset` means a page; letting it through would hand back the whole\n * tail and look like it worked. */\nfunction offsetClause(offset: number | undefined, limit: number | undefined): string {\n if (offset === undefined) return \"\";\n if (!Number.isInteger(offset) || offset < 0) {\n throw new Error(\n `findMany: offset bir negatif olmayan tam sayı olmalı (geldi: ${String(offset)})`,\n );\n }\n if (limit === undefined) {\n throw new Error(\n \"findMany: offset yalnız limit ile birlikte verilir — limitsiz offset bir sayfa değil, sınırsız bir kuyruğun kaydırılmışıdır\",\n );\n }\n return ` OFFSET ${offset}`;\n}\n\n/** where → SQL (FR-016): eşitlik + gt/gte/lt/lte/neq/in, AND'li. Kolon adı\n * şemadan doğrulanır — bilinmeyen ad SQL'e ulaşmadan, adıyla reddedilir. */\nfunction compileWhere(\n table: string,\n colSet: Set<string> | null,\n where: Record<string, unknown>,\n add: (v: unknown) => string,\n caller = \"search\",\n): string {\n const parts: string[] = [];\n // A column's `toDb` applies on the WHERE path too. Without it a transform is\n // half-wired: `insert` writes the converted value and `findMany({ at: date })`\n // binds the client-side shape, so the row that was just written does not come\n // back. The bind goes through `bind` below, never `add` directly.\n const transforms = transformsOf(currentSchema, table);\n const bindFor = (col: string) => {\n const t = transforms.get(col);\n return t?.toDb === undefined\n ? add\n : (v: unknown) => add(v === null || v === undefined ? v : t.toDb!(v));\n };\n // The refusals live in ONE place (db/input-guards.ts) because `fakeDatabase()`\n // is a second implementation of this surface and has to answer identically —\n // measured on 24.1.0: every call this function had just started refusing went\n // through the fake silently, so an author's test went green on code that\n // throws in production.\n assertUsableFilter(caller, table, where);\n for (const [col, cond] of Object.entries(where)) {\n // A null colSet means \"no schema to check against\" — the case `findMany`\n // reaches when a table is addressed by name alone. Identifiers still go\n // through quoteIdent, so an unknown name is a Postgres error, never syntax.\n if (colSet !== null && !colSet.has(col)) {\n throw new Error(`${caller}(${table}): where kolonu \"${col}\" tabloda yok (FR-016)`);\n }\n const q = `t.${quoteIdent(col)}`;\n const bind = bindFor(col);\n if (cond !== null && typeof cond === \"object\" && !Array.isArray(cond)) {\n for (const [op, v] of Object.entries(cond as Record<string, unknown>)) {\n if (op === \"in\") {\n if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmalı`);\n if (v.length === 0) {\n // Boş in-listesi \"hiçbir satır\" demektir — sessiz tam-tarama yerine\n // anlamı SQL'e açıkça yaz (review I5).\n parts.push(\"false\");\n continue;\n }\n // Placeholder genişletmesi: her eleman AYRI parametre. `= ANY($n)`\n // dizi bind'i sürücüde Postgres array literal'ine çevrilmiyor ve\n // canlıda `malformed array literal: \"ops,general\"` 500'ü veriyordu\n // (verify 19-3b, 2026-08-28). IN listesi tip-agnostik ve sürücüden\n // bağımsız; boş liste yukarıda açık `false`.\n parts.push(`${q} IN (${v.map((x) => bind(x)).join(\", \")})`);\n } else if (op in WHERE_OPS) {\n // NULL'a eşitlik SQL'de hiçbir zaman doğru değildir — `= NULL` ve\n // `<> NULL` ikisi de UNKNOWN, yani hiçbir satır. Yazarın YAZDIĞI bir\n // null'ı sessizce boş sonuca çevirmek, undefined'ın az önce kapatılan\n // hatasının aynısı. Soru IS NULL / IS NOT NULL ile sorulur.\n if (v === null && (op === \"neq\" || op === \"eq\")) {\n parts.push(`${q} IS ${op === \"neq\" ? \"NOT \" : \"\"}NULL`);\n continue;\n }\n parts.push(`${q} ${WHERE_OPS[op]} ${bind(v)}`);\n } else {\n throw new Error(`${caller}(${table}): where.${col} bilinmeyen operatör \"${op}\" (gt/gte/lt/lte/neq/in)`);\n }\n }\n } else if (cond === null) {\n // Aynı gerekçe, kısa yazılış: `{ deleted_at: null }` — \"silinmemiş\n // satırlar\" demenin en doğal yolu — `= $1` derlenip hiçbir satır\n // döndürüyordu.\n parts.push(`${q} IS NULL`);\n } else {\n parts.push(`${q} = ${bind(cond)}`);\n }\n }\n return parts.length === 0 ? \"\" : ` AND ${parts.join(\" AND \")}`;\n}\n\n/** The `ON CONFLICT …` tail shared by `upsert` and `insertMany`.\n *\n * ONE writer, deliberately: two hand-written ON CONFLICT clauses is how the\n * single-row and the many-row spellings come to disagree about what a collision\n * does — and a disagreement there is silent, because both statements succeed.\n *\n * `DO UPDATE` sets every column that is NOT part of the conflict key; those are\n * what matched, so assigning them to themselves is the no-op Postgres needs when\n * there is nothing else to set. */\nfunction onConflictTail(\n cols: string[],\n conflict: readonly string[],\n action: \"ignore\" | \"update\",\n): string {\n const target = `ON CONFLICT (${conflict.map(quoteIdent).join(\", \")})`;\n if (action === \"ignore\") return `${target} DO NOTHING`;\n const conflictSet = new Set(conflict);\n const sets = cols\n .filter((c) => !conflictSet.has(c))\n .map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);\n return sets.length\n ? `${target} DO UPDATE SET ${sets.join(\", \")}`\n : `${target} DO UPDATE SET ${quoteIdent(conflict[0]!)} = EXCLUDED.${quoteIdent(conflict[0]!)}`;\n}\n\n/** vector extension'ının yaşadığı şema (C-10): canlı stack'te public, taze\n * stack'te extensions — operatör bununla nitelenir, search_path'e GÜVENİLMEZ\n * (M-1 ölçümü; veri düzlemi search_path=public kurar, handler.go:101). */\nlet cachedVectorSchema: string | null = null;\n\n/** pg_trgm'in kurulu olduğu şema — typo-fallback operatörü bununla nitelenir\n * (search_path'e GÜVENİLMEZ, M-1 ile aynı gerekçe). Bağlanma başına bir kez. */\nlet cachedTrgmSchema: string | null = null;\nasync function trgmSchemaOf(live: { unsafe: (sql: string, params?: unknown[]) => Promise<unknown> }): Promise<string> {\n if (cachedTrgmSchema !== null) return cachedTrgmSchema;\n const rows = (await live.unsafe(\n \"select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'pg_trgm'\",\n )) as { nspname?: string }[];\n cachedTrgmSchema = rows?.[0]?.nspname ?? \"public\";\n return cachedTrgmSchema;\n}\n/** GUC + (soğukken) extension-şema çözümü TEK statement'ta (review I4). */\nasync function vectorSchemaWithGuc(runner: { unsafe(sql: string, params?: unknown[]): Promise<unknown> }): Promise<string> {\n if (cachedVectorSchema !== null) {\n // NFR-005 kapanışı, ÖLÇÜMLE (40K×384, %1 filtre, exact referans):\n // relaxed (vars. 20K tavan) → recall@20 0.62\n // relaxed + max_scan_tuples=200K → 0.64 (tavan tek başına YETMEZ:\n // iterative scan LIMIT dolunca durur, bulduğu ilk N \"en yakın N\" değil)\n // relaxed + 200K + ef_search=200 → 0.95 (asıl düğme aday genişliği)\n // ef_search=200 normal sorguya ms-mertebesi maliyet ekler; karşılığı\n // seçici filtrede doğru sonuç. strict_order ölçümde ek kazanç vermedi.\n await runner.unsafe(\n \"select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true)\",\n );\n return cachedVectorSchema;\n }\n const rows = (await runner.unsafe(\n \"select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true), \" +\n \"(select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'vector') as nspname\",\n )) as { nspname?: string }[];\n const name = rows?.[0]?.nspname;\n if (typeof name !== \"string\" || name === \"\") {\n throw new Error(\"pgvector extension kurulu değil — vector araması çalışamaz (extensions beyanı deploy'dan geçti mi?)\");\n }\n cachedVectorSchema = name;\n return name;\n}\n\n/** Test edilebilirlik: setSchema gibi, cache'i sıfırlar. */\nexport function resetVectorSchemaCache(): void {\n cachedVectorSchema = null;\n}\n\n// ---------------------------------------------------------------------------\n// Sorgu-anı embed (T024, FR-025) — CLAIM-N1: POST /v1/embeddings.\n// ---------------------------------------------------------------------------\n\ntype SecretReader = (name: string) => Promise<string | null>;\nlet secretReader: SecretReader | null = null;\n/** Runtime boot'ta bağlanır (setSchema ile AYNI kanal deseni): vault'tan\n * secret okuma. Engine anahtarın yalnız ADINI bilir, değeri buradan akar. */\nexport function setSecretReader(fn: SecretReader | null): void {\n secretReader = fn;\n}\n\ntype EmbedFetch = (url: string, init?: RequestInit) => Promise<Response>;\nlet embedFetch: EmbedFetch = (url, init) => fetch(url, init);\n/** Test dikişi: sağlayıcı çağrısının fetch'i. Üretimde global fetch. */\nexport function setEmbedFetch(fn: EmbedFetch | null): void {\n embedFetch = fn ?? ((url, init) => fetch(url, init));\n}\n\n/** Sorgu metnini beyan edilen modelle vektörler (CLAIM-N1). Tek deneme, 10s\n * timeout — retry worker'ın işidir, sorgu yolunun değil. Hata apiKeyName'i\n * ADLANDIRIR; anahtar yoksa sağlayıcı hiç aranmaz. */\nasync function embedQuery(\n embed: NonNullable<SearchLeg[\"embed\"]>,\n text: string,\n): Promise<number[]> {\n if (secretReader === null) {\n throw new Error(`query embed: secret reader bağlanmamış — ${embed.apiKeyName} okunamıyor`);\n }\n const key = await secretReader(embed.apiKeyName);\n if (key === null || key === \"\") {\n throw new Error(`query embed: vault'ta ${embed.apiKeyName} yok (FR-021/FR-025)`);\n }\n const url = (embed.baseURL ?? \"https://api.openai.com/v1\").replace(/\\/$/, \"\") + \"/embeddings\";\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10_000);\n try {\n const res = await embedFetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${key}` },\n body: JSON.stringify({\n model: embed.model,\n input: [text],\n ...(embed.dimensions !== undefined ? { dimensions: embed.dimensions } : {}),\n }),\n signal: controller.signal,\n });\n if (!res.ok) {\n throw new Error(`query embed: sağlayıcı ${res.status} döndü (${embed.apiKeyName} ile) — anahtar/model doğru mu?`);\n }\n const data = (await res.json()) as { data?: { embedding?: number[] }[] };\n const vec = data.data?.[0]?.embedding;\n if (!Array.isArray(vec)) {\n throw new Error(\"query embed: sağlayıcı yanıtında data[0].embedding yok (CLAIM-N1 şekli)\");\n }\n return vec;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** The six string-keyed operations, plus an interactive `transaction`. */\nexport function createOps(tx: TxLike) {\n const at = () => resolveTx(tx);\n\n const ops = {\n async query(sql: string, params: unknown[] = []): Promise<Row[]> {\n // Arrays become Postgres array literals; everything else is bound as-is.\n // See encodePgArray for what the driver does without this.\n const bound = params.map((p) => (Array.isArray(p) ? encodePgArray(p) : p));\n return asWireRows((await (await at()).unsafe(sql, bound)) as Row[]);\n },\n\n async insert(table: string, data: Row): Promise<Row> {\n const cols = Object.keys(data);\n if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);\n const placeholders = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const sql =\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) ` +\n `VALUES (${placeholders}) RETURNING *`;\n const rows = (await (await at()).unsafe(sql, asBindParams(table, cols, data, \"insert\"))) as Row[];\n const inserted = rows[0];\n if (!inserted) {\n // RETURNING * with no row back means the write was filtered away — an\n // RLS WITH CHECK that rejected it, most often. Silence here would hand\n // the author `undefined` and a 500 three lines later.\n throw new Error(\n `insert into ${table} returned no row — the write was rejected (an RLS policy, most likely).`,\n );\n }\n return asTableRow(table, inserted);\n },\n\n /**\n * INSERT the row, or UPDATE it when it collides on `onConflict`.\n *\n * WHY IT IS AN OPERATION rather than a recipe. \"Try the insert, catch the\n * unique violation, update instead\" does not work here: a request runs in ONE\n * Postgres transaction, so the failed insert aborts it and every later\n * statement answers `current transaction is aborted`. A tenant measured that\n * as 7 of 8 concurrent requests returning 500, gave up on upsert, and had a\n * trigger create the row instead — a workaround that needs a new trigger for\n * every table with a unique row.\n *\n * The conflict columns are excluded from the SET list: they are what MATCHED,\n * so writing them back is at best a no-op and at worst a surprise.\n */\n async upsert(table: string, data: Row, opts: { onConflict: readonly string[] }): Promise<Row> {\n const conflict = opts.onConflict;\n if (conflict.length === 0) {\n // A silent fall-through to a plain INSERT would be an upsert that is not\n // one: it would work until two callers raced, which is the only time it\n // matters.\n throw new Error(`upsert into ${table}: onConflict en az bir kolon adı ister`);\n }\n const cols = Object.keys(data);\n if (cols.length === 0) throw new Error(`upsert into ${table}: no columns given`);\n // D-020 eki (FR-020): validity'li tabloda \"aynı anahtarın yeni değeri\"\n // EZME değil SUPERSEDE'dir — geçmiş silinmez. Düz DO UPDATE burada iki\n // kez yanlıştır: geçerli satırı ezer VE partial arbiter'la (UNIQUE ...\n // WHERE valid_to IS NULL) düz ON CONFLICT eşleşmez (42P10). Desen:\n // partial-arbiter'lı DO NOTHING insert (abort'suz), çakışmada\n // kapat→ekle→bağla (worker writeMemoryFacts ile aynı sıra).\n if (searchConfigFor(table)?.validity) {\n const ph = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const insertSql =\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) VALUES (${ph}) ` +\n `ON CONFLICT (${conflict.map(quoteIdent).join(\", \")}) WHERE \"valid_to\" IS NULL DO NOTHING RETURNING *`;\n const live = await at();\n const bindData = asBindParams(table, cols, data, \"upsert\");\n const first = (await live.unsafe(insertSql, bindData)) as Row[];\n if (first[0]) return asTableRow(table, first[0]);\n const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(\" AND \");\n const condBind = conflict.map((c) => (data as Record<string, unknown>)[c]);\n const cur = (await live.unsafe(\n `SELECT * FROM ${quoteTable(table)} WHERE ${condSql} AND \"valid_to\" IS NULL`, condBind)) as Row[];\n const old = cur[0] as Record<string, unknown> | undefined;\n if (old === undefined) {\n throw new Error(`upsert into ${table}: eşzamanlı supersede yarışı — geçerli satır bulunamadı, isteği yineleyin (D-020)`);\n }\n const pk = Object.keys(old).includes(\"id\") ? \"id\" : Object.keys(old)[0]!;\n await live.unsafe(\n `UPDATE ${quoteTable(table)} SET \"valid_to\" = now() WHERE ${quoteIdent(pk)} = $1 AND \"valid_to\" IS NULL`,\n [old[pk]]);\n const second = (await live.unsafe(insertSql, bindData)) as Row[];\n if (!second[0]) {\n throw new Error(`upsert into ${table}: eşzamanlı supersede yarışı — yeni satır açılamadı, isteği yineleyin (D-020)`);\n }\n const fresh = second[0] as Record<string, unknown>;\n await live.unsafe(\n `UPDATE ${quoteTable(table)} SET \"superseded_by\" = $2 WHERE ${quoteIdent(pk)} = $1`,\n [old[pk], fresh[pk]]);\n return asTableRow(table, second[0]);\n }\n const placeholders = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const conflictSet = new Set(conflict);\n const assignments = cols\n .filter((c) => !conflictSet.has(c))\n .map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);\n // Nothing to update means the row's identity IS the row: keep it and hand\n // the existing one back rather than answering zero rows.\n const action = assignments.length\n ? `DO UPDATE SET ${assignments.join(\", \")}`\n : `DO UPDATE SET ${quoteIdent(conflict[0]!)} = EXCLUDED.${quoteIdent(conflict[0]!)}`;\n const sql =\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) ` +\n `VALUES (${placeholders}) ` +\n `ON CONFLICT (${conflict.map(quoteIdent).join(\", \")}) ${action} RETURNING *`;\n const rows = (await (await at()).unsafe(sql, asBindParams(table, cols, data, \"upsert\"))) as Row[];\n const row = rows[0];\n if (!row) {\n throw new Error(\n `upsert into ${table} returned no row — the write was rejected (an RLS policy, most likely).`,\n );\n }\n return asTableRow(table, row);\n },\n\n async update(table: string, id: string, data: Row): Promise<Row | null> {\n const cols = Object.keys(data);\n if (cols.length === 0) return ops.findById(table, id);\n const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(\", \");\n const sql = `UPDATE ${quoteTable(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;\n const rows = (await (await at()).unsafe(sql, [...asBindParams(table, cols, data, \"update\"), id])) as Row[];\n return rows[0] ? asTableRow(table, rows[0]) : null;\n },\n\n async delete(table: string, id: string): Promise<void> {\n await (await at()).unsafe(`DELETE FROM ${quoteTable(table)} WHERE id = $1`, [id]);\n },\n\n /**\n * Update every row the filter matches, in ONE statement.\n *\n * The capability was already here and only reachable from inside a\n * transaction plan (`tx.tables.x.updateWhere`, since 11.0.0). Outside it the\n * only door was `update(id, …)`, so \"mark every unapproved row in this\n * household\" was an N+1 loop or hand-written SQL — and hand-written SQL is\n * where the typed surface and RLS both stop helping.\n *\n * The filter language is `findMany`'s, compiled by the same `compileWhere`:\n * one filter language, or the two spellings drift.\n *\n * AN EMPTY FILTER IS REFUSED. `UPDATE … WHERE true` is a whole-table write,\n * and the shape that produces it by accident — a filter object built from\n * request input that happened to come back empty — is exactly the shape that\n * should not silently succeed. Callers who mean every row say so with a\n * predicate that is true for every row.\n */\n async updateMany(table: string, where: Row, set: Row): Promise<Row[]> {\n const cols = Object.keys(set);\n if (cols.length === 0) {\n // A silent `[]` here is indistinguishable from \"nothing matched\", and a\n // caller that turns an empty result into a 404 answers the wrong thing.\n throw new Error(\n `updateMany(${table}): nothing to set. An update with no columns is ` +\n `not a no-op worth pretending happened — pass the columns to write.`,\n );\n }\n // SET kolonları da WHERE kolonları gibi şemadan doğrulanır. Doğrulanmayan\n // yarı, bir yazım hatasını Postgres'e kadar taşıyordu: çağıran ham\n // `column \"dome\" of relation \"todos\" does not exist` görüyordu, SDK'nın\n // kendi diliyle değil. Null şema \"kontrol edemem\" demektir, \"serbest\"\n // değil — identifier yine quoteIdent'ten geçer (D-21).\n const known = schemaColumns(table);\n if (known !== null) {\n for (const c of cols) {\n if (!known.has(c)) {\n throw new Error(`updateMany(${table}): set kolonu \"${c}\" tabloda yok (FR-016)`);\n }\n }\n }\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n const assignments = cols\n .map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set, \"updateMany\")[0])}`)\n .join(\", \");\n const whereSql = compileWhere(table, known, where, add, \"updateMany\");\n assertHasPredicate(whereSql, \"updateMany\", table);\n // `AS t`, because compileWhere qualifies every column with the `t.` alias —\n // the same compiler findMany uses, and it must stay the same one. Without\n // the alias the predicate names a relation this statement never declared.\n const sql = `UPDATE ${quoteTable(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;\n return asTableRows(table, (await (await at()).unsafe(sql, params)) as Row[]);\n },\n\n /**\n * Delete every row the filter matches, in ONE statement; resolves to how\n * many went. Same filter language, same empty-filter refusal as\n * {@link updateMany} — and here the accident is worse.\n */\n async deleteMany(table: string, where: Row): Promise<number> {\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n const known = schemaColumns(table);\n const whereSql = compileWhere(table, known, where, add, \"deleteMany\");\n assertHasPredicate(whereSql, \"deleteMany\", table);\n const sql = `DELETE FROM ${quoteTable(table)} AS t WHERE true${whereSql} RETURNING 1`;\n const rows = (await (await at()).unsafe(sql, params)) as Row[];\n return rows.length;\n },\n\n /**\n * How many rows match — the half of pagination `limit`/`offset` cannot\n * supply. Without it a page count is either a guess or \"fetch everything and\n * read .length\", and the second one is the scale risk this surface exists to\n * remove.\n *\n * An empty filter is legitimate HERE: counting a whole table is a read, and\n * reads do not destroy anything.\n */\n async count(table: string, where: Row = {}): Promise<number> {\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n const known = schemaColumns(table);\n const whereSql = compileWhere(table, known, where, add, \"count\");\n const sql = `SELECT count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql}`;\n const rows = (await (await at()).unsafe(sql, params)) as Row[];\n // Postgres answers count() as bigint, which the driver hands over as a\n // STRING. Returning it unconverted would put the report's own A4 defect\n // into a brand-new surface: a \"number\" the caller cannot add to.\n return Number((rows[0] as Record<string, unknown> | undefined)?.n ?? 0);\n },\n\n async findById(table: string, id: string): Promise<Row | null> {\n const rows = (await (await at()).unsafe(\n `SELECT * FROM ${quoteTable(table)} WHERE id = $1`,\n [id],\n )) as Row[];\n return rows[0] ? asTableRow(table, rows[0]) : null;\n },\n\n async findMany(table: string, query: Row = {}, opts: FindManyOptions = {}): Promise<Row[]> {\n const params: unknown[] = [];\n const add = (v: unknown): string => {\n params.push(v);\n return `$${params.length}`;\n };\n // The SAME compiler `search` uses. Two builders for one filter language is\n // how the two spellings drift; the operator set (gt/gte/lt/lte/neq/in) was\n // already written and already tested, it was just never reachable from here.\n const known = schemaColumns(table);\n const whereSql = compileWhere(table, known, query, add, \"findMany\");\n const order = orderClause(table, known, opts.orderBy);\n const limit = limitClause(opts.limit);\n const offset = offsetClause(opts.offset, opts.limit);\n const sql =\n `SELECT * FROM ${quoteTable(table)} t WHERE true${whereSql}${order}${limit}${offset}`;\n return asTableRows(table, (await (await at()).unsafe(sql, params)) as Row[]);\n },\n\n /**\n * Tek-SQL hibrit arama (FR-014): iki kol CTE + FULL OUTER JOIN + RRF\n * (1/(50+rank), CLAIM-N4). Operatör şema-nitelikli (C-10, M-1); GUC\n * hnsw.iterative_scan=relaxed_order aynı tx'te set_config ile (CLAIM-N3 —\n * RLS/filtre altında LIMIT-altı dönüş açığını kapatır). Sorgu-anı embed\n * T024'te gelir; o zamana dek vector kolu yalnız params.vector ile koşar.\n */\n async search(\n table: string,\n params: {\n query?: string;\n vector?: number[];\n where?: Record<string, unknown>;\n limit?: number;\n using?: string;\n mode?: \"hybrid\" | \"text\" | \"vector\";\n /** Nihai (RRF-sonrası) skor alt eşiği — süzme LIMIT'ten ÖNCE (FR-001). */\n minScore?: number;\n /** RRF-sonrası üstel tazelik çürümesi: _score * exp(-ln(2)*yaş/halfLife) (FR-004). */\n recency?: { field: string; halfLife: string };\n /** Chunk-modunda satır başına dönen en iyi blok sayısı (1..10, vars. 3; FR-015). */\n blocksPerRow?: number;\n /** Filtrelenmiş küme üzerinde kolon başına top-20 değer sayacı —\n * dönüş dizisinin `_facets` özelliği (FR-027). */\n facets?: string[];\n /** Satır-modunda FTS eşleşme vurgusu: ts_headline ile `_highlight`\n * alanı; chunk-modda no-op — bloklar zaten eşleşen kesittir (FR-025). */\n highlight?: boolean;\n /** Validity'li tabloda zaman penceresi: varsayılan yalnız güncel;\n * \"all\" tüm versiyonlar; {asOf} o andaki geçerli versiyon (FR-029). */\n validity?: \"all\" | { asOf: string };\n /** Alan-boost (FR-030): skor * (1 + w·x/(1+x)) — sınırlı, dış servissiz. */\n boost?: { field: string; weight: number };\n } = {},\n ): Promise<Row[]> {\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`search(${table}): tablo aranabilir değil — ne vector kolonu ne search beyanı var (FR-013)`);\n }\n const excl = (params as InternalSearchParams).__excludeIds ?? [];\n // facets kolonları sorgu atılmadan doğrulanır (compileWhere deseni).\n if (params.facets !== undefined) {\n for (const col of params.facets) {\n if (!cfg.colSet.has(col)) {\n throw new Error(`search(${table}): facets kolonu \"${col}\" tabloda yok (FR-027)`);\n }\n }\n }\n if (params.validity !== undefined && cfg.validity !== true) {\n throw new Error(\n `search(${table}): validity parametresi verildi ama tablo validity beyanı taşımıyor (FR-029)`,\n );\n }\n // FR-029: validity filtresi where'lerle aynı bileşime girer — sem/kw/probe\n // ve chunk parent'ı; facets sayaçları da aynı pencereyi görür.\n const validityFor = (adder: (x: unknown) => string): string =>\n cfg.validity === true ? validitySql(params.validity, adder) : \"\";\n const rawLimit = params.limit ?? 20;\n if (typeof rawLimit !== \"number\" || !Number.isFinite(rawLimit)) {\n throw new Error(`search(${table}): limit sonlu bir sayı olmalı, ${String(rawLimit)} verildi (FR-013)`);\n }\n const limit = Math.min(Math.max(1, Math.trunc(rawLimit)), 100);\n const pool = Math.max(limit * 3, 30);\n if (params.minScore !== undefined && (typeof params.minScore !== \"number\" || !Number.isFinite(params.minScore))) {\n throw new Error(`search(${table}): minScore sonlu bir sayı olmalı, ${String(params.minScore)} verildi (FR-001)`);\n }\n // recency.field yalnız kolon-üyeliğiyle doğrulanır — cfg kolon TİPİ\n // taşımaz; timestamp olmayan kolon SQL'de kendi adıyla düşer (C-6).\n let recencyMul = \"\";\n if (params.recency !== undefined) {\n const { field, halfLife } = params.recency;\n if (!cfg.colSet.has(field)) {\n throw new Error(`search(${table}): recency.field \"${field}\" tabloda yok (FR-004)`);\n }\n recencyMul = ` * exp(-ln(2) * extract(epoch from (now() - t.${quoteIdent(field)})) / ${parseHalfLife(halfLife)})`;\n }\n // FR-030/D-017: alan-boost dış servissiz SINIRLI çarpandır — x/(1+x)\n // 0..1'e doyar, 1 + w·(...) hiçbir satırı sıfırlamaz; weight doğrulanmış\n // SONLU sayı olarak SQL'e literal iner (recency'nin halfLife'ı gibi).\n // Bileşim sırası FR-030: RRF → boost → recency → minScore.\n let boostMul = \"\";\n if (params.boost !== undefined) {\n const { field, weight } = params.boost;\n if (!cfg.colSet.has(field)) {\n throw new Error(`search(${table}): boost.field \"${field}\" tabloda yok (FR-030)`);\n }\n if (typeof weight !== \"number\" || !Number.isFinite(weight)) {\n throw new Error(`search(${table}): boost.weight sonlu bir sayı olmalı, ${String(weight)} verildi (FR-030)`);\n }\n const g = `greatest(t.${quoteIdent(field)},0)`;\n boostMul = ` * (1 + ${weight} * ${g}/(1+${g}))`;\n }\n const scoreMul = boostMul + recencyMul;\n if (cfg.chunk !== undefined) {\n // CHUNK-MODU (FR-015, D-010): arama türev tabloda koşar; RRF chunk\n // düzeyinde, sonra parent'a MAX-skor toplaması + en iyi blokların\n // json_agg'ı. minScore/recency GRUPLAMA-SONRASI parent skoruna\n // uygulanır (FR-018). `where` filtreleri parent satırına uygulanır;\n // RLS'i chunk tablosunun parent-mirror policy'si zaten süzer.\n const ck = cfg.chunk;\n const pidQ = quoteIdent(`parent_${cfg.pk}`);\n const bpr = Math.min(Math.max(1, Math.trunc(params.blocksPerRow ?? 3)), 10);\n const wantTextC =\n params.mode !== \"vector\" && ck.fts && typeof params.query === \"string\" && params.query !== \"\";\n let qvC: number[] | null = Array.isArray(params.vector) ? params.vector : null;\n if (qvC === null && ck.embed !== undefined && params.mode !== \"text\" &&\n typeof params.query === \"string\" && params.query !== \"\") {\n try {\n qvC = await embedQuery(ck.embed, params.query);\n } catch (e) {\n if (!wantTextC) throw e;\n qvC = null;\n }\n }\n if (!wantTextC && qvC === null) {\n throw new Error(\n `search(${table}): koşulabilir kol yok — metin için 'query' (FTS beyanı gerekir), semantik için 'vector' verin (FR-015)`,\n );\n }\n const bindC: unknown[] = [];\n const addC = (v: unknown): string => { bindC.push(v); return `$${bindC.length}`; };\n // where/validity/exclude ADAY ÜRETİMİNE gömülür (final-review C1):\n // küresel top-K chunk havuzu filtreli kümeden seçilmezse seçici bir\n // where'de eşleşen sayfa havuza hiç giremez ve arama sessizce boş\n // döner. Satır-modunun kanıtlı deseniyle simetri: filtrenin tek\n // yazarı aday CTE'leridir (sem/kw/trgm-retry); dış katman tekrarlamaz.\n const userWhereC = compileWhere(table, cfg.colSet, params.where ?? {}, addC);\n const whereC = userWhereC + excludeSql(cfg.pk, excl, addC) + validityFor(addC);\n const parentJoinC = ` JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = c.${pidQ} WHERE true${whereC} AND `;\n const liveC = await at();\n const K2 = 50;\n const cpool = Math.max(limit * 9, 90); // blok başına aday: parent-limit × blocksPerRow payı\n let semC = \"\";\n let kwC = \"\";\n if (qvC !== null) {\n const sch = await vectorSchemaWithGuc(liveC);\n const op = METRIC_OPERATOR[ck.metric] ?? METRIC_OPERATOR.cosine;\n // NFR-B4 kapanışı: satır-modu probe'unun chunk ikizi — filtreli chunk\n // kümesi ≤ eşikse HNSW yerine exact tarama (+ 0.0 sıralama ifadesini\n // index-eşleşmesinden düşürür); recall=1.0, ms'ler. Probe RLS'li aynı\n // tx'te, C1'in parent-JOIN'li filtresiyle aynı kümeyi sayar.\n let exactOrderC = \"\";\n if (userWhereC !== \"\") {\n const probeRows = (await liveC.unsafe(\n `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(ck.table)} c${parentJoinC}c.embedding IS NOT NULL LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,\n bindC.slice(),\n )) as { n?: number }[];\n const n = probeRows?.[0]?.n;\n if (typeof n === \"number\" && n <= SELECTIVITY_EXACT_THRESHOLD) {\n exactOrderC = \" + 0.0\";\n }\n }\n const vp = addC(toVectorLiteral(qvC));\n semC =\n `SELECT c.${pidQ} AS pid, c.chunk_seq, ROW_NUMBER() OVER (ORDER BY (c.embedding OPERATOR(${quoteIdent(sch)}.${op}) ${vp}::${quoteIdent(sch)}.vector)${exactOrderC}) AS r ` +\n `FROM ${quoteTable(ck.table)} c${parentJoinC}c.embedding IS NOT NULL ORDER BY r LIMIT ${cpool}`;\n }\n let qpC = \"\";\n let qpCIdx = -1;\n if (wantTextC) {\n // FR-026: genişletme yalnız websearch BIND değerine — SQL metni değişmez.\n const qTextC =\n cfg.synonyms !== undefined ? expandSynonyms(params.query!, cfg.synonyms) : params.query;\n qpC = addC(qTextC);\n qpCIdx = bindC.length - 1;\n kwC =\n `SELECT c.${pidQ} AS pid, c.chunk_seq, ROW_NUMBER() OVER (ORDER BY ts_rank_cd(c.palbase_fts, websearch_to_tsquery('simple', ${qpC})) DESC) AS r ` +\n `FROM ${quoteTable(ck.table)} c${parentJoinC}c.palbase_fts @@ websearch_to_tsquery('simple', ${qpC}) ORDER BY r LIMIT ${cpool}`;\n }\n const msC = params.minScore === undefined ? \"\" : addC(params.minScore);\n const colListC = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(\", \");\n const scoreC = scoreMul === \"\" ? \"g._score\" : `(g._score)${scoreMul}`;\n const assembleC = (kwIn: string, withKwn: boolean): string => {\n const kwnCol = withKwn ? `, (SELECT count(*) FROM kw)::int AS _kwn` : \"\";\n let fusedSrc: string;\n if (semC !== \"\" && kwIn !== \"\") {\n fusedSrc =\n `WITH sem AS (${semC}), kw AS (${kwIn}), fused AS (` +\n `SELECT COALESCE(sem.pid, kw.pid) AS pid, COALESCE(sem.chunk_seq, kw.chunk_seq) AS chunk_seq, ` +\n `(COALESCE(1.0/(${K2} + sem.r), 0) + COALESCE(1.0/(${K2} + kw.r), 0))::float8 AS cscore ` +\n `FROM sem FULL OUTER JOIN kw ON sem.pid = kw.pid AND sem.chunk_seq = kw.chunk_seq)`;\n } else if (semC !== \"\") {\n fusedSrc = `WITH sem AS (${semC}), fused AS (SELECT sem.pid, sem.chunk_seq, (1.0/(${K2} + sem.r))::float8 AS cscore FROM sem)`;\n } else {\n fusedSrc = `WITH kw AS (${kwIn}), fused AS (SELECT kw.pid, kw.chunk_seq, (1.0/(${K2} + kw.r))::float8 AS cscore FROM kw)`;\n }\n const inner =\n `${fusedSrc}, ranked AS (` +\n `SELECT f.pid, f.chunk_seq, f.cscore, ROW_NUMBER() OVER (PARTITION BY f.pid ORDER BY f.cscore DESC, f.chunk_seq) AS rn FROM fused f), ` +\n `grouped AS (` +\n `SELECT r.pid, MAX(r.cscore) AS _score, ` +\n `json_agg(json_build_object('content', c.content, 'score', r.cscore, 'chunkSeq', r.chunk_seq, 'charStart', c.char_start) ORDER BY r.cscore DESC, r.chunk_seq) FILTER (WHERE r.rn <= ${bpr}) AS blocks ` +\n `FROM ranked r JOIN ${quoteTable(ck.table)} c ON c.${pidQ} = r.pid AND c.chunk_seq = r.chunk_seq ` +\n `GROUP BY r.pid) ` +\n `SELECT ${colListC}, ${scoreC}::float8 AS _score, g.blocks AS blocks${kwnCol} ` +\n `FROM grouped g JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = g.pid`;\n return msC === \"\"\n ? `SELECT * FROM (${inner}) q ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`\n : `SELECT * FROM (${inner}) q WHERE q._score >= ${msC} ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;\n };\n let rowsC = (await liveC.unsafe(assembleC(kwC, kwC !== \"\"), bindC)) as Row[];\n if (wantTextC && kwC !== \"\" && (rowsC.length === 0 || (rowsC[0] as Record<string, unknown>)._kwn === 0)) {\n // FR-002 chunk-modunda da geçerli: kelime kolu 0 adaysa trgm retry —\n // ifade chunk İÇERİĞİ üstünde (türev index'in kaynağı da o).\n const tsch = await trgmSchemaOf(liveC);\n const trgmKwC =\n `SELECT c.${pidQ} AS pid, c.chunk_seq, ROW_NUMBER() OVER (ORDER BY ${quoteIdent(tsch)}.word_similarity(${qpC}, coalesce(c.content,'')) DESC) AS r ` +\n `FROM ${quoteTable(ck.table)} c${parentJoinC}${quoteIdent(tsch)}.word_similarity(${qpC}, coalesce(c.content,'')) > 0.3 ORDER BY r LIMIT ${cpool}`;\n // trgm kelime-benzerliği OR-sözdizimi tanımaz: retry aynı placeholder'ı\n // HAM query ile koşar (bind kopyası — kayıtlı ilk çağrı değişmez).\n const retryBindC = bindC.slice();\n if (qpCIdx >= 0) retryBindC[qpCIdx] = params.query;\n rowsC = (await liveC.unsafe(assembleC(trgmKwC, false), retryBindC)) as Row[];\n }\n for (const r of rowsC) delete (r as Record<string, unknown>)._kwn;\n const outC = asTableRows(table, rowsC).map((r) => ({ ...r, blocks: (r as { blocks?: unknown }).blocks ?? [] }));\n if (params.facets !== undefined && params.facets.length > 0) {\n Object.assign(outC, {\n _facets: await fetchFacets(liveC, table, cfg.colSet, params.facets, params.where ?? {}, validityFor),\n });\n }\n logNoResults(table, params.query, params.mode, outC.length);\n return outC;\n }\n const wantText =\n params.mode !== \"vector\" && cfg.ftsCols.length > 0 && typeof params.query === \"string\" && params.query !== \"\";\n // Vektör kolu ancak GERÇEKTEN istenecekse çözülür (FR-015, review C1):\n // çok kollu tabloda salt-text arama 'using' zorunluluğuna TAKILMAZ.\n const anyEmbed = cfg.legs.some((l) => l.embed !== undefined);\n const vectorAsked =\n params.mode !== \"text\" &&\n (Array.isArray(params.vector) || params.using !== undefined || params.mode === \"vector\" ||\n (anyEmbed && typeof params.query === \"string\" && params.query !== \"\"));\n const leg = vectorAsked ? pickLeg(table, cfg.legs, params.using) : null;\n let qv: number[] | null = Array.isArray(params.vector) ? params.vector : null;\n if (qv === null && leg?.embed !== undefined && typeof params.query === \"string\" && params.query !== \"\") {\n // FR-025: beyan edilen modelle TEK sağlayıcı çağrısı. Başarısızlıkta\n // FR-015 düşüşü: text kolu koşulabiliyorsa arama ONUNLA döner; yoksa\n // adlandırılmış hata (sessiz boş dönüş asla).\n try {\n qv = await embedQuery(leg.embed, params.query);\n } catch (e) {\n if (!wantText) throw e;\n qv = null;\n }\n }\n const wantVector = leg !== null && qv !== null;\n if (!wantText && !wantVector) {\n throw new Error(\n `search(${table}): koşulabilir kol yok — metin için 'query' (FTS beyanı gerekir), semantik için 'vector' verin (FR-015)`,\n );\n }\n const bind: unknown[] = [];\n const add = (v: unknown): string => {\n bind.push(v);\n return `$${bind.length}`;\n };\n // Probe kararı (aşağıda) kullanıcı where'ine bakar: exclude tek başına\n // neredeyse hiç seçici değildir, exact-yol probe'unu tetiklememeli.\n const userWhere = compileWhere(table, cfg.colSet, params.where ?? {}, add);\n const whereSql = userWhere + excludeSql(cfg.pk, excl, add) + validityFor(add);\n const live = await at();\n const K = 50;\n let semSql = \"\";\n let kwSql = \"\";\n if (wantVector && leg) {\n // GUC yalnız hnsw taramasını etkiler — salt-text arama onu hiç koşmaz\n // (review I4). Soğuk yolda extension-şema lookup'ı AYNI statement'a\n // biner: sıcak yol +1, soğuk yol +1 (eskiden +2) round-trip; kalan tek\n // ekstra tur NFR-002'de karar kaydıyla kabul edildi.\n const sch = await vectorSchemaWithGuc(live);\n const op = METRIC_OPERATOR[leg.metric] ?? METRIC_OPERATOR.cosine;\n // SEÇİCİ FİLTREDE EXACT YOL (NFR-005 kapanışı, ölçümle): HNSW iterative\n // scan %1 seçicilikte 100K ölçeğinde hedefe ULAŞAMIYOR — GUC gridi\n // (relaxed/strict × max_scan_tuples 200K × ef_search 200..1000) en iyi\n // 0.38 recall verdi. Filtreli küme küçükse doğru cevap index'i HİÇ\n // kullanmamak: ≤10K satırda exact mesafe taraması ms'ler sürer ve\n // recall=1.0. Seçicilik bir probe ile ölçülür (RLS aynı tx'te — sayım\n // tenant'ın görebildiği satırlarla); index'i devre dışı bırakmak için\n // sıralama ifadesine + 0.0 eklenir (planner ifade-eşleşmesini kaybeder;\n // EXPLAIN'le doğrulandı — GUC'suz, tx yan etkisiz).\n let exactOrder = \"\";\n if (userWhere !== \"\") {\n const probeRows = (await live.unsafe(\n `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,\n bind.slice(),\n )) as { n?: number }[];\n const n = probeRows?.[0]?.n;\n if (typeof n === \"number\" && n <= SELECTIVITY_EXACT_THRESHOLD) {\n exactOrder = \" + 0.0\";\n }\n }\n const vp = add(toVectorLiteral(qv!));\n semSql =\n `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY (t.${quoteIdent(leg.column)} OPERATOR(${quoteIdent(sch)}.${op}) ${vp}::${quoteIdent(sch)}.vector)${exactOrder}) AS r ` +\n `FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} ORDER BY r LIMIT ${pool}`;\n }\n let qpRef = \"\";\n let qpIdx = -1;\n if (wantText) {\n // FR-026: genişletme yalnız websearch BIND değerine — SQL metni değişmez.\n const qText =\n cfg.synonyms !== undefined ? expandSynonyms(params.query!, cfg.synonyms) : params.query;\n const qp = add(qText);\n qpIdx = bind.length - 1;\n qpRef = qp;\n kwSql =\n `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ts_rank_cd(t.palbase_fts, websearch_to_tsquery('simple', ${qp})) DESC) AS r ` +\n `FROM ${quoteTable(table)} t WHERE t.palbase_fts @@ websearch_to_tsquery('simple', ${qp})${whereSql} ORDER BY r LIMIT ${pool}`;\n }\n const colList = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(\", \");\n // minScore parametresi BİR kez bind'lenir — assemble iki kez çağrılabilir\n // (typo-fallback retry'ı) ve her çağrıda add() bind'i şişirirdi.\n const msP = params.minScore === undefined ? \"\" : add(params.minScore);\n // FR-025: vurgu yalnız satır-modu + metinli aramada; ifade typo-fallback'in\n // sorted-kolon birleşimiyle aynı. qp placeholder'ı yeniden kullanılır.\n const hlCol =\n params.highlight === true && wantText\n ? `, ts_headline('simple', ${ftsExprOf(cfg.ftsCols)}, websearch_to_tsquery('simple', ${qpRef})) AS _highlight`\n : \"\";\n // Recency çarpanı RRF-SONRASI nihai skora biner (FR-004); recency/\n // minScore yokken SQL'in tek farkı metinli aramadaki `_kwn` scalar'ıdır:\n // kelime kolunun kaç aday bulduğunu nihai SELECT taşır — typo-fallback\n // kararı (FR-002) sonuç satırından okunur, karar için ek tur yoktur.\n const assemble = (kwIn: string, withKwn: boolean): string => {\n const kwnCol = withKwn ? `, (SELECT count(*) FROM kw)::int AS _kwn` : \"\";\n let inner: string;\n let orderScore: string;\n if (semSql !== \"\" && kwIn !== \"\") {\n const score = scoreMul === \"\" ? \"fused._score\" : `(fused._score)${scoreMul}`;\n inner =\n `WITH sem AS (${semSql}), kw AS (${kwIn}), fused AS (` +\n `SELECT COALESCE(sem.id, kw.id) AS id, ` +\n `(COALESCE(1.0/(${K} + sem.r), 0) + COALESCE(1.0/(${K} + kw.r), 0))::float8 AS _score ` +\n `FROM sem FULL OUTER JOIN kw ON sem.id = kw.id) ` +\n `SELECT ${colList}, ${score} AS _score${hlCol}${kwnCol} FROM fused ` +\n `JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = fused.id`;\n orderScore = scoreMul === \"\" ? \"fused._score\" : \"_score\";\n } else {\n const single = semSql !== \"\" ? `sem AS (${semSql})` : `kw AS (${kwIn})`;\n const alias = semSql !== \"\" ? \"sem\" : \"kw\";\n const base = `(1.0/(${K} + ${alias}.r))::float8`;\n const score = scoreMul === \"\" ? base : `(${base})${scoreMul}`;\n inner =\n `WITH ${single} ` +\n `SELECT ${colList}, ${score} AS _score${hlCol}${semSql !== \"\" ? \"\" : kwnCol} FROM ${alias} ` +\n `JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = ${alias}.id`;\n orderScore = \"_score\";\n }\n // minScore süzmesi LIMIT'ten ÖNCE olmalı (FR-001): sarmalayıcı verilirse\n // sıralama+limit dışarı taşınır — süzülen satırın yeri alttakiyle dolar.\n return msP === \"\"\n ? `${inner} ORDER BY ${orderScore} DESC, t.${quoteIdent(cfg.pk)} LIMIT ${limit}`\n : `SELECT * FROM (${inner}) q WHERE q._score >= ${msP} ` +\n `ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;\n };\n let rows = (await live.unsafe(assemble(kwSql, kwSql !== \"\"), bind)) as Row[];\n if (wantText && kwSql !== \"\" && (rows.length === 0 || (rows[0] as Record<string, unknown>)._kwn === 0)) {\n // FR-002: kelime kolu HİÇ aday bulamadı — aynı sorgu pg_trgm\n // word_similarity ile BİR kez daha denenir (yalnız bu 0-sonuç yolunda\n // +1 tur, NFR-A2). Exact-önce korunur: eşleşme varken trgm hiç koşmaz.\n // İfade, Go tarafının türev trgm index'iyle BİREBİR aynı (sorted\n // kolonlar) — index'i o ifade yakalar.\n const tsch = await trgmSchemaOf(live);\n const expr = ftsExprOf(cfg.ftsCols);\n const trgmKw =\n `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) DESC) AS r ` +\n `FROM ${quoteTable(table)} t WHERE ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) > 0.3${whereSql} ORDER BY r LIMIT ${pool}`;\n // trgm kelime-benzerliği OR-sözdizimi tanımaz: retry aynı placeholder'ı\n // HAM query ile koşar (bind kopyası — kayıtlı ilk çağrı değişmez).\n const retryBind = bind.slice();\n if (qpIdx >= 0) retryBind[qpIdx] = params.query;\n rows = (await live.unsafe(assemble(trgmKw, false), retryBind)) as Row[];\n }\n for (const r of rows) delete (r as Record<string, unknown>)._kwn;\n // FR-015: dönüş tipi iki modda aynı şekildedir — satır-modunda blok\n // kavramı yoktur, tip uyumu boş diziyle sağlanır (spec kararı).\n const out = asTableRows(table, rows).map((r) => ({ ...r, blocks: [] as unknown[] }));\n if (params.facets !== undefined && params.facets.length > 0) {\n Object.assign(out, {\n _facets: await fetchFacets(live, table, cfg.colSet, params.facets, params.where ?? {}, validityFor),\n });\n }\n logNoResults(table, params.query, params.mode, out.length);\n return out;\n },\n\n /**\n * similar (T018, FR-022): \"bu satıra benzeyenler\". Hedef vektör DB'den\n * okunur — satır-modu satırın kendi kolonu, chunk-modu parent chunk'larının\n * şema-nitelikli avg'ı — ve ana arama search'ün vector yoluyla koşar;\n * kaynak satır sonuçtan düşer. İKİ tur BİLİNÇLİ (plan T018): target-CTE'li\n * tek SQL'de \"id yok\" ile \"0 komşu\" ayrılamazdı; +1 küçük turla id-yokluğu\n * adlandırılmış hataya çevrilir. Sonuç şekli search ile aynı (FR-015).\n */\n /** D-021 (FR-027 DX): sayaçlar BAĞIMSIZ op'la — search'ün dizi-üstü\n * `_facets` özelliği JSON.stringify'da kaybolur (dizi özelliği), tenant\n * yanıtına koyunca sessizce yok olurdu. Ayrı dönüş ciddi bir sözleşmedir;\n * search'teki alan geriye-uyum için DURUR. where + validity default'u\n * sayaçlara da uygulanır (sayaç, kullanıcının gördüğü kümeyi anlatır). */\n async facets(\n table: string,\n params: { facets: string[]; where?: Record<string, unknown>; validity?: \"all\" | { asOf: string } },\n ): Promise<Record<string, { value: string | null; count: number }[]>> {\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`facets(${table}): tablo aranabilir değil — search beyanı yok (FR-027)`);\n }\n for (const col of params.facets) {\n if (!cfg.colSet.has(col)) {\n throw new Error(`facets(${table}): facets kolonu \"${col}\" tabloda yok (FR-027)`);\n }\n }\n const live = await at();\n const extra = cfg.validity ? (add: (v: unknown) => string) => validitySql(params.validity, add) : () => \"\";\n return fetchFacets(live, table, cfg.colSet, params.facets, params.where ?? {}, extra);\n },\n\n async similar(\n table: string,\n id: string,\n opts: {\n where?: Record<string, unknown>;\n limit?: number;\n using?: string;\n minScore?: number;\n recency?: { field: string; halfLife: string };\n blocksPerRow?: number;\n validity?: \"all\" | { asOf: string };\n boost?: { field: string; weight: number };\n } = {},\n ): Promise<Row[]> {\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`similar(${table}): tablo aranabilir değil — ne vector kolonu ne search beyanı var (FR-013)`);\n }\n const live = await at();\n let v: unknown;\n if (cfg.chunk !== undefined) {\n const sch = await vectorSchemaWithGuc(live);\n const rows = (await live.unsafe(\n `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteTable(cfg.chunk.table)} c ` +\n `WHERE c.${quoteIdent(`parent_${cfg.pk}`)} = $1 AND c.embedding IS NOT NULL`,\n [id],\n )) as { v?: unknown }[];\n v = rows?.[0]?.v;\n } else {\n const leg = pickLeg(table, cfg.legs, opts.using);\n if (leg === null) {\n throw new Error(`similar(${table}): tabloda vektör kolonu yok — benzerlik semantik vektör ister (FR-022)`);\n }\n const rows = (await live.unsafe(\n `SELECT t.${quoteIdent(leg.column)} AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} = $1`,\n [id],\n )) as { v?: unknown }[];\n v = rows?.[0]?.v;\n }\n // Sürücü vector'ü text literal'i olarak verir (C-9); yokluk = satır yok\n // YA DA embedding NULL — ikisi de aynı adlandırılmış hata.\n if (typeof v !== \"string\") {\n throw new Error(`similar(${table}): id \"${String(id)}\" bulunamadı ya da embedding'i yok (FR-022)`);\n }\n const p = {\n vector: JSON.parse(v) as number[],\n mode: \"vector\" as const,\n where: opts.where,\n limit: opts.limit,\n using: opts.using,\n minScore: opts.minScore,\n recency: opts.recency,\n blocksPerRow: opts.blocksPerRow,\n validity: opts.validity,\n boost: opts.boost,\n __excludeIds: [id],\n };\n return ops.search(table, p);\n },\n\n /**\n * recommend (T018, FR-023): positive/negative id kümelerinden öneri.\n * Hedef vektör DB-İÇİ CTE'lerle türer: pos = avg(embedding of positives),\n * negative varsa hedef = pos.v + (pos.v - neg.v) — pgvector avg agregası\n * ve +/- operatörleri ŞEMA-NİTELİKLİ (M-1: search_path'e güvenilmez).\n * Vektör matematiği istemciye inmez; bulunamayan positive/negative\n * adlandırılmış hatadır ve kaynak id'ler sonuçtan düşer.\n */\n async recommend(\n table: string,\n opts: {\n positive: unknown[];\n negative?: unknown[];\n where?: Record<string, unknown>;\n limit?: number;\n using?: string;\n minScore?: number;\n recency?: { field: string; halfLife: string };\n blocksPerRow?: number;\n validity?: \"all\" | { asOf: string };\n boost?: { field: string; weight: number };\n },\n ): Promise<Row[]> {\n const positive = opts?.positive;\n if (!Array.isArray(positive) || positive.length === 0) {\n throw new Error(`recommend(${table}): positive boş olamaz — en az bir kaynak id gerekir (FR-023)`);\n }\n const negative = Array.isArray(opts.negative) ? opts.negative : [];\n const cfg = searchConfigFor(table);\n if (!cfg) {\n throw new Error(`recommend(${table}): tablo aranabilir değil — ne vector kolonu ne search beyanı var (FR-013)`);\n }\n let leg: SearchLeg | null = null;\n if (cfg.chunk === undefined) {\n leg = pickLeg(table, cfg.legs, opts.using);\n if (leg === null) {\n throw new Error(`recommend(${table}): tabloda vektör kolonu yok — öneri semantik vektör ister (FR-023)`);\n }\n }\n const live = await at();\n const sch = await vectorSchemaWithGuc(live);\n const bind: unknown[] = [];\n const add = (x: unknown): string => {\n bind.push(x);\n return `$${bind.length}`;\n };\n // id listesi AYRI placeholder'larla (where.in ile aynı gerekçe).\n const avgSel = (ids: unknown[]): string => {\n const inList = ids.map((x) => add(x)).join(\", \");\n return cfg.chunk !== undefined\n ? `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteTable(cfg.chunk.table)} c ` +\n `WHERE c.${quoteIdent(`parent_${cfg.pk}`)} IN (${inList}) AND c.embedding IS NOT NULL`\n : `SELECT ${quoteIdent(sch)}.avg(t.${quoteIdent(leg!.column)}) AS v FROM ${quoteTable(table)} t ` +\n `WHERE t.${quoteIdent(cfg.pk)} IN (${inList}) AND t.${quoteIdent(leg!.column)} IS NOT NULL`;\n };\n // pos/neg yokluğu bayrak olarak AYNI sorgudan döner: aritmetik DB'de\n // kalır, hata ayrımı için ek tur gerekmez.\n const targetSql =\n negative.length === 0\n ? `WITH pos AS (${avgSel(positive)}) SELECT pos.v AS v, (pos.v IS NULL) AS pos_missing FROM pos`\n : `WITH pos AS (${avgSel(positive)}), neg AS (${avgSel(negative)}) ` +\n `SELECT (pos.v OPERATOR(${quoteIdent(sch)}.+) (pos.v OPERATOR(${quoteIdent(sch)}.-) neg.v)) AS v, ` +\n `(pos.v IS NULL) AS pos_missing, (neg.v IS NULL) AS neg_missing FROM pos, neg`;\n const rows = (await live.unsafe(targetSql, bind)) as\n { v?: unknown; pos_missing?: unknown; neg_missing?: unknown }[];\n const r0 = rows?.[0];\n if (r0 === undefined || r0.pos_missing === true) {\n throw new Error(`recommend(${table}): positive id'lerin hiçbiri bulunamadı ya da embedding'i yok (FR-023)`);\n }\n if (negative.length > 0 && r0.neg_missing === true) {\n throw new Error(`recommend(${table}): negative id'leri bulunamadı ya da embedding'i yok (FR-023)`);\n }\n if (typeof r0.v !== \"string\") {\n throw new Error(`recommend(${table}): hedef vektör hesaplanamadı (FR-023)`);\n }\n const p = {\n vector: JSON.parse(r0.v) as number[],\n mode: \"vector\" as const,\n where: opts.where,\n limit: opts.limit,\n using: opts.using,\n minScore: opts.minScore,\n recency: opts.recency,\n blocksPerRow: opts.blocksPerRow,\n validity: opts.validity,\n boost: opts.boost,\n __excludeIds: [...positive, ...negative],\n };\n return ops.search(table, p);\n },\n\n /**\n * supersede (T021, FR-029, C-9): validity'li tabloda satırın YENİ\n * versiyonunu TEK savepoint'te yazar — eski satır kapatılır\n * (valid_to = now(), superseded_by = yeni pk), yeni satır eklenir, dönüş\n * yeni satırdır. Yeni pk CLIENT'ta üretilir (row'da verilmemişse\n * randomUUID — declared şemaların uuid().defaultRandom() standardı) ki\n * kapatma UPDATE'i INSERT'ten ÖNCE koşabilsin: 0 satır = zaten superseded\n * ya da yok → INSERT hiç denenmez; INSERT hatası ise savepoint'le\n * kapatmayı da geri sarar — yarım supersede diye bir durum yoktur.\n */\n async supersede(table: string, id: string, row: Row): Promise<Row> {\n const cfg = searchConfigFor(table);\n if (cfg === null || cfg.validity !== true) {\n throw new Error(`supersede(${table}): tablo validity beyanı taşımıyor (FR-029)`);\n }\n const live = await at();\n return live.savepoint(async (sp) => {\n const newId = row[cfg.pk] ?? crypto.randomUUID();\n const closed = (await sp.unsafe(\n `UPDATE ${quoteTable(table)} SET \"valid_to\" = now(), \"superseded_by\" = $1 ` +\n `WHERE ${quoteIdent(cfg.pk)} = $2 AND \"valid_to\" IS NULL RETURNING ${quoteIdent(cfg.pk)}`,\n [newId, id],\n )) as Row[];\n if (closed.length === 0) {\n throw new Error(`supersede(${table}): id \"${String(id)}\" zaten superseded ya da yok (FR-029)`);\n }\n const data = { ...row, [cfg.pk]: newId };\n const cols = Object.keys(data);\n const placeholders = cols.map((_, i) => `$${i + 1}`).join(\", \");\n const rows = (await sp.unsafe(\n `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(\", \")}) ` +\n `VALUES (${placeholders}) RETURNING *`,\n asBindParams(table, cols, data, \"supersede\"),\n )) as Row[];\n if (!rows[0]) {\n throw new Error(\n `supersede(${table}): INSERT satır döndürmedi — yazma reddedildi (büyük olasılıkla bir RLS policy'si)`,\n );\n }\n return asTableRow(table, rows[0]);\n });\n },\n\n /** A real SAVEPOINT inside the request's transaction. */\n async transaction<T>(cb: (t: unknown) => Promise<T>): Promise<T> {\n const live = await at();\n return live.savepoint(async (sp) => cb(withTables(createOps(sp), currentSchema)));\n },\n\n /**\n * Run `fn` against a handle bound to a SAVEPOINT, so a failure inside it\n * rolls back only what that handle wrote and the request can keep writing.\n *\n * WHY THE HANDLE IS AN ARGUMENT. The obvious shape — `attempt(async () => {\n * ... Database.insert(...) ... })`, with no parameter — would have to point\n * the ambient `Database` at the savepoint for the duration, and a request is\n * concurrent with itself: `Promise.all([Database.insert(a),\n * Database.attempt(...)])` would put `a` inside the savepoint and roll it\n * back with it. Silent data loss, and the same interleaving this file already\n * refuses for `asService()`. Passing the handle makes the boundary something\n * you can see in the code that crosses it.\n *\n * Postgres, not us: the savepoint is released on success and rolled back on\n * failure by the driver, so an aborted statement inside `fn` does not poison\n * the surrounding transaction.\n */\n async attempt<T>(fn: (tx: DBOps) => Promise<T>): Promise<T> {\n const live = await at();\n return live.savepoint(async (sp) => fn(withTables(createOps(sp), currentSchema) as DBOps));\n },\n\n /**\n * Execute a whole transaction plan — what `Database.transaction(fn)` builds.\n *\n * WHY IT RUNS HERE. The platform used to carry a complete implementation\n * of this at `/internal-api/db/tx`, for tenant code that ran in an isolate\n * with no connection of its own. Running the plan there means running it on\n * a DIFFERENT connection: a transaction would not see the uncommitted\n * writes of the request that started it, and the two would hold separate\n * RLS bindings of the same identity. In this stack the tenant's code and\n * the connection share a process, so the plan runs on the request's own\n * transaction inside one SAVEPOINT — and that surface was removed on\n * 2026-08-15, once this was the last thing that could have called it.\n *\n * Until 2026-08-15 it ran NOWHERE: `runTxPlan` called `transport.txPlan` and\n * nothing here implemented it, so a live handler answered\n * \"transport.txPlan is not a function\" while every test that covered\n * transactions passed against a mock that did implement it.\n */\n async txPlan(plan: TxPlanBody): Promise<TxPlanResponse> {\n const live = await at();\n // ONE savepoint for the whole plan: a failed expectation must undo the\n // transaction the author wrote, and nothing outside it.\n return live.savepoint(async (sp) => {\n const results: TxPlanOpResult[] = [];\n for (const op of plan.ops) {\n const rows = asTableRows(op.table, await runPlanOp(sp, op, results)) as typeof results[number][\"rows\"];\n const result: TxPlanOpResult = { rows, rows_affected: rows.length };\n results.push(result);\n assertGuard(op, result);\n }\n return { results };\n });\n },\n } satisfies DBOps & Record<string, unknown>;\n\n return ops;\n}\n\n/** The schema whose table names the typed `.tables` surface is built from —\n * and, per table, whose columns the vector transform reads. */\nlet currentSchema: {\n tables?: Record<string, { name?: string; columns?: Record<string, unknown> }>;\n} = {};\n\n/**\n * Install the project's declarations. Called once at boot.\n *\n * It takes the SET, because a project declares one schema PER FILE. The tables\n * are flattened under this system's one key convention — `public` bare,\n * anything else `schema.table` — so the key the wire carries and the key the\n * runtime looks up are the same string. A second convention here would be a\n * second answer to \"which table is this\", and the answers would diverge on the\n * day one of them learned something.\n */\nexport function setSchema(schemas: readonly unknown[]): void {\n // Yeni şema kurulumu yeni bir bağlanma demektir: vector extension'ının\n // şeması da yeniden çözülür (review I3 — iki DB'li süreçte bayat cache,\n // public↔extensions ikiliğini sessizce yanlış tarafa kilitlerdi).\n cachedVectorSchema = null;\n cachedTrgmSchema = null;\n const tables: NonNullable<typeof currentSchema.tables> = {};\n for (const entry of schemas) {\n const mod = entry as { default?: unknown } | undefined;\n const def = ((mod && \"default\" in mod ? mod.default : mod) ?? {}) as {\n name?: string;\n tables?: Record<string, { name?: string; columns?: Record<string, unknown> }>;\n };\n const schemaName = def.name ?? \"public\";\n for (const [key, table] of Object.entries(def.tables ?? {})) {\n tables[qualifiedTableKey(schemaName, table.name ?? key)] = table;\n }\n }\n currentSchema = { tables };\n}\n\n\n\n/**\n * Merge the typed `.tables` accessor onto a raw op surface.\n *\n * Mirrors what the pod runtime does, including the recursive application to the\n * transaction callback: without it `tx.tables.rooms.insert(...)` throws\n * \"Cannot read properties of undefined\".\n */\nexport function withTables<T extends ReturnType<typeof createOps>>(\n ops: T,\n schema: { tables?: Record<string, { name?: string }> } = currentSchema,\n): T & { tables: Record<string, unknown>; schema: (name: string) => { tables: Record<string, unknown> } } {\n // THE KEY IS WHAT TRAVELS, not `def.name`. A bare name cannot say which\n // schema it lives in, and two schemas may declare the same table name —\n // `public.invoices` and `billing.invoices` are different tables.\n const bind = (key: string): Record<string, unknown> => ({\n insert: (data: Row) => ops.insert(key, data),\n update: (id: string, data: Row) => ops.update(key, id, data),\n delete: (id: string) => ops.delete(key, id),\n findById: (id: string) => ops.findById(key, id),\n findMany: (query?: Row, opts?: FindManyOptions) => ops.findMany(key, query ?? {}, opts),\n upsert: (data: Row, opts: { onConflict: readonly string[] }) => ops.upsert(key, data, opts),\n });\n\n // `Database.tables` is PUBLIC's, and only public's. One flat namespace would\n // make `tables.invoices` resolve by declaration order; the bare name is\n // always public's and everything else is asked for by schema.\n const tables: Record<string, unknown> = {};\n for (const key of Object.keys(schema.tables ?? {})) {\n if (!key.includes(\".\")) tables[key] = bind(key);\n }\n\n const schemaOf = (name: string): { tables: Record<string, unknown> } => {\n const out: Record<string, unknown> = {};\n const prefix = `${name}.`;\n for (const key of Object.keys(schema.tables ?? {})) {\n if (name === \"public\") {\n if (!key.includes(\".\")) out[key] = bind(key);\n } else if (key.startsWith(prefix)) {\n out[key.slice(prefix.length)] = bind(key);\n }\n }\n return { tables: out };\n };\n\n const base: Record<string, unknown> = Object.create(null);\n return Object.assign(base, ops, { tables, schema: schemaOf });\n}\n\n// ── the two identities one request may speak with ──────────────────────────\n\n/**\n * How long a statement on the SERVICE transaction may wait for a row lock.\n *\n * The bound exists because `asService()` runs in a SECOND transaction on a\n * SECOND connection (see {@link createRequestDatabase} for why it must). A\n * handler that writes a row through `Database.*` and then touches the same row\n * through `Database.asService()` is waiting on a lock held by a transaction\n * that cannot commit until the handler returns — a wait that can never end.\n * Unbounded, that hangs the request AND holds two pool connections for as long\n * as the process lives; a few of those and the runtime stops answering at all.\n *\n * 5s, from the two numbers around it: a healthy contended write resolves in\n * milliseconds, and the edge cuts a tenant request at 60s\n * (v2/deploy/envoy/routes.yaml, the catch-all route).\n * So the failure arrives as a legible error at the caller instead of a 504 with\n * both connections still held.\n */\nconst SERVICE_LOCK_TIMEOUT = \"5s\";\n\n/** Postgres raises 25P02 for every statement after one failed inside the same\n * transaction: `current transaction is aborted, commands ignored until end of\n * transaction block`. True, and useless on its own — it names the SYMPTOM and\n * never the write that caused it, nor the fact that a request is one\n * transaction. */\nfunction isAbortedTransaction(e: unknown): boolean {\n const message = String((e as { message?: unknown } | null)?.message ?? \"\");\n return sqlstateOf(e) === \"25P02\" || /current transaction is aborted/i.test(message);\n}\n\n/**\n * The five-character SQLSTATE, wherever this driver put it.\n *\n * MEASURED, not assumed (local stack, real Postgres, 2026-08-30): Bun's\n * `PostgresError` puts its OWN code in `.code` — the string\n * `\"ERR_POSTGRES_SERVER_ERROR\"` — and the SQLSTATE in `.errno`. node-postgres\n * puts the SQLSTATE in `.code`. Every check below was written against `.code`\n * alone, and its unit test built an object shaped like node-postgres, so the\n * tests were green and NONE of these diagnostics ever fired in production.\n *\n * The shape decides: a SQLSTATE is five characters of [0-9A-Z]. Anything else\n * in `.code` is the driver naming its own error, and the answer is in `.errno`.\n */\n/**\n * A bulk write must carry an actual predicate.\n *\n * COUNTING THE FILTER'S KEYS IS NOT ENOUGH, and the gap was measured: an\n * operator object with no operators in it — `{ created_at: {} }` — has one key\n * and compiles to NOTHING, so `WHERE true` reached Postgres and the statement\n * became a whole-table write. The shape that produces it is ordinary:\n *\n * const where = { created_at: {} };\n * if (from) where.created_at.gte = from; // neither set on this request\n * if (to) where.created_at.lte = to;\n *\n * So the check reads what the COMPILER produced, not what the caller passed.\n */\nfunction assertHasPredicate(whereSql: string, op: string, table: string): void {\n if (whereSql.trim().length > 0) return;\n throw new Error(\n `${op}(${table}): the filter compiled to no condition, so this would have ` +\n `written EVERY row. An empty filter — or an operator object with no ` +\n `operators in it, like { col: {} } — is refused. Name a condition.`,\n );\n}\n\nfunction sqlstateOf(e: unknown): string | undefined {\n const err = e as { code?: unknown; errno?: unknown } | null;\n const isState = (v: unknown): v is string => typeof v === \"string\" && /^[0-9A-Z]{5}$/.test(v);\n if (isState(err?.code)) return err.code;\n if (isState(err?.errno)) return err.errno;\n if (typeof err?.errno === \"number\") {\n const asText = String(err.errno);\n if (isState(asText)) return asText;\n }\n return undefined;\n}\n\n/** Postgres raises 23503 when a foreign key has nothing to point at. */\nfunction isForeignKeyViolation(e: unknown): boolean {\n return sqlstateOf(e) === \"23503\";\n}\n\n/** Postgres raises 23505 (unique_violation) when a write would duplicate a row. */\nfunction isUniqueViolation(e: unknown): boolean {\n return sqlstateOf(e) === \"23505\";\n}\n\n/**\n * The name of the unique constraint a 23505 names.\n *\n * The driver's own `constraint` field first — both pg and postgres.js copy it\n * straight out of the wire protocol's CONSTRAINT field, so it is the answer\n * whenever there is one. The message is the fallback, and the reason it is only\n * a fallback: it is prose, and prose is what this whole conversion exists to\n * stop anyone from matching on.\n *\n * \"\" when neither carries it. An empty name is the honest answer — the caller\n * sees it is not known — and it is still a typed 409, because whether the write\n * was a duplicate does not depend on knowing which constraint said so.\n */\nfunction constraintOf(e: unknown): string {\n const named = (e as { constraint?: unknown } | null)?.constraint;\n if (typeof named === \"string\" && named.length > 0) return named;\n const message = String((e as { message?: unknown } | null)?.message ?? \"\");\n return /violates unique constraint \"([^\"]+)\"/.exec(message)?.[1] ?? \"\";\n}\n\n/** Postgres raises 55P03 (lock_not_available) when `lock_timeout` fires. */\nfunction isLockTimeout(e: unknown): boolean {\n const message = String((e as { message?: unknown } | null)?.message ?? \"\");\n return sqlstateOf(e) === \"55P03\" || /lock timeout/i.test(message);\n}\n\n/**\n * Wrap a driver so a lock timeout says what actually happened.\n *\n * \"canceling statement due to lock timeout\" is true and useless: the author's\n * two surfaces are two transactions, which is the one thing the message cannot\n * tell them. Applied recursively through `savepoint`, so `transaction()` and\n * `txPlan` inside the service surface answer the same way.\n */\nfunction diagnosingDriver(sql: SqlDriver, surface: \"user\" | \"service\" = \"service\"): SqlDriver {\n const original = (e: unknown): string => String((e as { message?: unknown } | null)?.message ?? e);\n\n const explain = (e: unknown): unknown => {\n // A statement refused because an EARLIER one failed. The database names the\n // symptom; only this layer knows that a request is a single transaction and\n // that there is a way to keep writing.\n if (isAbortedTransaction(e)) {\n return new Error(\n \"This request cannot write any more: an earlier write in it failed, and a request runs in ONE \" +\n \"Postgres transaction, so every statement after the failure is refused. Nothing here is \" +\n \"retryable in place. Wrap a write you expect to fail in `Database.attempt(async (tx) => …)` — \" +\n \"it takes a SAVEPOINT, so only that write rolls back — or use \" +\n \"`Database.tables.<t>.upsert(data, { onConflict: [...] })` when the failure you were bracing \" +\n `for is a duplicate row. (${original(e)})`,\n );\n }\n // A duplicate row is the one database refusal an application ROUTINELY\n // expects, and until this branch existed the only way to act on it was to\n // match the driver's prose (\"duplicate key value violates unique\n // constraint …\") — a contract nobody signed, broken by a Postgres upgrade,\n // a locale, or a constraint rename, silently and in production. Typed here\n // instead: an HttpError, so an uncaught duplicate answers a generic 409\n // rather than 500 `internal_error`, and a caught one is branched on with\n // `e instanceof UniqueViolation && e.constraint === …`. The NAME rides the\n // object, not the response body — see `UniqueViolation` for whose it is.\n // Both surfaces convert: a duplicate is a duplicate whichever role wrote it.\n if (isUniqueViolation(e)) {\n return markEngineRaised(new UniqueViolation(constraintOf(e)));\n }\n // A foreign key with nothing to point at, seen from the SERVICE surface, is\n // usually not a broken key: it is the row this request already wrote through\n // `Database.*`, which has not committed and which the service transaction\n // cannot see. On the user surface the same code is an ordinary data error and\n // is left exactly as Postgres wrote it.\n if (surface === \"service\" && isForeignKeyViolation(e)) {\n return new Error(\n \"Database.asService() hit a foreign key with nothing to point at. It runs in its OWN \" +\n \"transaction on its OWN connection, so a row this request wrote through `Database.*` is not \" +\n \"visible to it until the request commits — and the request cannot commit until the handler \" +\n \"returns. If the row it needs is one this request just created, do both writes on ONE \" +\n `surface. (${original(e)})`,\n );\n }\n if (isLockTimeout(e)) {\n return new Error(\n \"Database.asService() waited too long for a row lock. It runs in its OWN transaction, so a \" +\n \"row this request already wrote through Database.* is locked against it until the request \" +\n \"commits — a wait that cannot end. Do that row's work on one surface or the other. \" +\n `(${original(e)})`,\n );\n }\n return e;\n };\n\n const wrapTx = (tx: SqlTx): SqlTx => ({\n async unsafe(text: string, params?: unknown[]) {\n try {\n return await tx.unsafe(text, params);\n } catch (e) {\n throw explain(e);\n }\n },\n savepoint<T>(cb: (sp: SqlTx) => Promise<T>) {\n return tx.savepoint((sp) => cb(wrapTx(sp)));\n },\n });\n\n return {\n unsafe: (text: string, params?: unknown[]) => sql.unsafe(text, params),\n begin: <T>(cb: (tx: SqlTx) => Promise<T>) => sql.begin((tx) => cb(wrapTx(tx))),\n };\n}\n\n/** The two transactions a request may hold, and the single `Database` over them. */\nexport interface RequestDatabase {\n /** What the engine injects as the request's `Database` singleton. */\n readonly client: DBClient;\n /** Commit whatever was opened. Called once, after the handler returns. */\n commit(): Promise<void>;\n /** Roll back whatever was opened. Called once, when the handler throws. */\n rollback(reason: unknown): Promise<void>;\n}\n\n/**\n * The `Database` one request sees: RLS-enforced by default, with the\n * service-role sibling behind `asService()`.\n *\n * # Why the sibling cannot ride the request's own transaction\n *\n * The role reaches Postgres ONCE, in the BEGIN's bind statement, and it is\n * transaction-scoped. So a sibling built on the same transaction runs as\n * `backend_authenticated` no matter what it is called — RLS still filters every\n * row and `asService()` silently means nothing. That is the failure mode worth\n * naming: it does not throw, it does not log, it simply returns the caller's own\n * rows where the author asked for everyone's, and a handler that trusts it\n * (`if (existing) throw new Conflict()`) makes the wrong decision on data it was\n * never shown.\n *\n * The obvious repair — re-issue `set_config('role', …)` around each service op\n * — is worse than the bug. Two statements are not one: `Promise.all([\n * Database.query(…), Database.asService().query(…) ])` interleaves them on the\n * single connection, and the user's query can execute between the service's\n * set-role and its own statement. That is RLS silently OFF on the DEFAULT path,\n * which is precisely the direction a security seam must never fail.\n *\n * So the service surface gets its own transaction, on its own connection, bound\n * to the service role at BEGIN. The identity separation is physical: no\n * statement of either surface can change what the other runs as.\n *\n * # What that costs, stated plainly\n *\n * - **One extra connection per request that uses it**, and only then: the second\n * transaction is lazy exactly like the first, so `asService()` called and\n * never used opens nothing.\n * - **Called twice, it is the same surface** — one transaction per REQUEST, not\n * per call — so a handler cannot leak connections by reaching for it in a\n * loop.\n * - **The two are not atomic with each other.** Both settle with the request\n * (commit when the handler returns, roll back when it throws), but they settle\n * as two transactions: if the second COMMIT fails, the first has already\n * landed. The request's own work commits first, so the failure that survives\n * is never \"the audit row exists and the thing it audits does not\".\n * - **They can wait on each other's locks.** Bounded in the service direction by\n * {@link SERVICE_LOCK_TIMEOUT}; in the other direction — a `Database.*` write\n * to a row `asService()` has already written — the wait is the request's own,\n * and the answer is not to write one row from both surfaces.\n *\n * # Claims travel unchanged\n *\n * The service transaction carries the SAME `request.jwt.claims` as the user's.\n * `asService()` changes what the caller may TOUCH, not who they are, so\n * `auth.uid()` still resolves inside a trigger or a column default. It is also\n * the fail-closed direction: a service role provisioned WITHOUT `BYPASSRLS`\n * (measured live on 2026-08-13, created by hand during a diagnosis) is not named\n * by any policy, so it reads zero rows instead of quietly reading everyone's.\n */\nexport function createRequestDatabase(\n sql: SqlDriver,\n identity: { role: string; serviceRole: string; claimsJson: string },\n): RequestDatabase {\n const tx = createLazyTransaction(diagnosingDriver(sql, \"user\"), identity.role, identity.claimsJson);\n\n // Opened on FIRST use and shared by every later `asService()` call.\n let serviceTx: LazyTransaction | null = null;\n let serviceClient: Omit<DBClient, \"asService\"> | null = null;\n\n const asService = (): Omit<DBClient, \"asService\"> => {\n if (serviceClient === null) {\n serviceTx = createLazyTransaction(\n diagnosingDriver(sql, \"service\"),\n identity.serviceRole,\n identity.claimsJson,\n { lockTimeout: SERVICE_LOCK_TIMEOUT },\n );\n // No `asService` on it: the type says `Omit<DBClient, \"asService\">` and so\n // does the object, so a second bypass is neither typeable nor callable.\n serviceClient = withTables(createOps(serviceTx));\n }\n return serviceClient;\n };\n\n return {\n client: Object.assign(withTables(createOps(tx)), { asService }),\n async commit(): Promise<void> {\n // The request's declared work first; see \"not atomic with each other\".\n await tx.commit();\n await serviceTx?.commit();\n },\n async rollback(reason: unknown): Promise<void> {\n await tx.rollback(reason);\n await serviceTx?.rollback(reason);\n },\n };\n}\n\n\n// ── the transaction plan executor ──────────────────────────────────────────\n//\n// The plan is a closed little language: five op kinds, equality-only filters,\n// and three value forms (a literal, a `$ref` to an earlier op's row, an\n// `$expr`). It is built by `TxPlanBuilder` in this same package, so the\n// executor's job is to run it faithfully rather than to defend against it —\n// with one exception that still matters: identifiers reach SQL as text, so\n// every table and column name goes through `quoteIdent`, exactly as the six\n// single-statement ops above do.\n\n/** Collects bound parameters so a value is never spliced into SQL text. */\nclass Args {\n readonly values: unknown[] = [];\n bind(value: unknown): string {\n this.values.push(value);\n return `$${this.values.length}`;\n }\n}\n\nfunction isRef(v: unknown): v is TxWireRef {\n return typeof v === \"object\" && v !== null && \"$ref\" in v;\n}\nfunction isExpr(v: unknown): v is TxWireExpr {\n return typeof v === \"object\" && v !== null && \"$expr\" in v;\n}\n\n/**\n * Render one value into SQL, binding whatever is data.\n *\n * `column` is only used by `inc`/`dec`, which read the column they write.\n */\nfunction renderValue(\n value: TxWireValue,\n column: string,\n args: Args,\n results: TxPlanOpResult[],\n vectorCols?: Set<string>,\n transforms?: ReturnType<typeof transformsOf>,\n): string {\n if (isRef(value)) {\n const source = results[value.$ref.op];\n const row = source?.rows[0];\n if (!row || !(value.$ref.field in row)) {\n throw Object.assign(new Error(`op ${value.$ref.op} has no column \"${value.$ref.field}\" to reference`), {\n error_code: \"tx_ref_unresolved\",\n });\n }\n return bindMaybeVector(args, column, vectorCols, row[value.$ref.field], transforms);\n }\n if (isExpr(value)) {\n const fn = value.$expr;\n if (fn.fn === \"now\") return \"now()\";\n const operator = fn.fn === \"inc\" ? \"+\" : \"-\";\n // The column is an identifier; the operand is BOUND. This is the one place\n // the tenant's digits could otherwise have reached SQL text.\n return `${quoteIdent(column)} ${operator} ${bindMaybeVector(args, column, vectorCols, fn.by, transforms)}`;\n }\n return bindMaybeVector(args, column, vectorCols, value, transforms);\n}\n\n/**\n * Render a WHERE clause.\n *\n * A null is compared with IS NULL, never `= NULL`: the latter is never true, so\n * a filter written that way silently matches nothing.\n */\nfunction renderWhere(\n where: Record<string, TxWireValue> | undefined,\n args: Args,\n results: TxPlanOpResult[],\n): string {\n const cols = Object.keys(where ?? {});\n if (cols.length === 0) return \"\";\n const terms = cols.map((c) => {\n const v = (where as Record<string, TxWireValue>)[c];\n if (v === null) return `${quoteIdent(c)} IS NULL`;\n return `${quoteIdent(c)} = ${renderValue(v, c, args, results)}`;\n });\n return ` WHERE ${terms.join(\" AND \")}`;\n}\n\n/** tx-plan bind'i (FR-008, review C2): vektör kolonuna giden number[] literal'e\n * çevrilir — düz op'lardaki asBindParams'ın plan-yolu ikizi. */\nfunction bindMaybeVector(\n args: { bind(v: unknown): string },\n column: string | undefined,\n vectorCols: Set<string> | undefined,\n value: unknown,\n transforms?: ReturnType<typeof transformsOf>,\n): string {\n if (column !== undefined && vectorCols?.has(column) && Array.isArray(value)) {\n return args.bind(toVectorLiteral(value as number[]));\n }\n // The column's `toDb`, exactly as `asBindParams` applies it on the direct\n // path. Without it the SAME value is stored differently depending on which\n // surface wrote it — `tables.x.insert({ amount: 12.5 })` writes \"12.5\" and\n // `tx.tables.x.insert({ amount: 12.5 })` writes 12.5 — and the caller cannot\n // tell them apart, because both take the transform's target type.\n const t = column !== undefined ? transforms?.get(column) : undefined;\n if (t?.toDb !== undefined && value !== null && value !== undefined) {\n return args.bind(t.toDb(value));\n }\n return args.bind(value);\n}\n\nasync function runPlanOp(\n sp: SqlTx,\n op: TxWireOp,\n results: TxPlanOpResult[],\n): Promise<Row[]> {\n const opVectorCols = vectorColumnsOf(currentSchema, op.table);\n const opTransforms = transformsOf(currentSchema, op.table);\n const args = new Args();\n const table = quoteIdent(op.table);\n let sql: string;\n\n switch (op.op) {\n case \"insert\": {\n const cols = Object.keys(op.values ?? {});\n const rendered = cols.map((c) => renderValue((op.values as Record<string, TxWireValue>)[c], c, args, results, opVectorCols, opTransforms));\n sql = cols.length\n ? `INSERT INTO ${table} (${cols.map(quoteIdent).join(\", \")}) VALUES (${rendered.join(\", \")}) RETURNING *`\n : `INSERT INTO ${table} DEFAULT VALUES RETURNING *`;\n break;\n }\n case \"upsert\": {\n const cols = Object.keys(op.values ?? {});\n const conflict = op.onConflict ?? [];\n if (cols.length === 0 || conflict.length === 0) {\n throw Object.assign(new Error(`upsert on ${op.table} needs columns and onConflict`), {\n error_code: \"tx_bad_upsert\",\n });\n }\n const rendered = cols.map((c) =>\n renderValue((op.values as Record<string, TxWireValue>)[c], c, args, results, opVectorCols, opTransforms),\n );\n sql =\n `INSERT INTO ${table} (${cols.map(quoteIdent).join(\", \")}) VALUES (${rendered.join(\", \")}) ` +\n `${onConflictTail(cols, conflict, \"update\")} RETURNING *`;\n break;\n }\n case \"insertMany\": {\n const rows = (op.rows ?? []) as Record<string, TxWireValue>[];\n if (rows.length === 0 || !rows[0]) return [];\n // The column list comes from the FIRST row and every row is rendered\n // against it, so a row with a stray extra key cannot shift the columns of\n // the statement it shares.\n const cols = Object.keys(rows[0]);\n const tuples = rows.map(\n (r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols, opTransforms)).join(\", \")})`,\n );\n // ON CONFLICT only when the plan asked for it: an insertMany with no\n // options must render byte-identically to what it rendered before the\n // option existed.\n //\n // DO NOTHING and RETURNING: Postgres returns only the rows it WROTE, so a\n // collided row is simply absent from the result. That is the contract the\n // caller is told about, not a rough edge.\n const conflictCols = op.onConflict ?? [];\n const tail =\n op.action !== undefined && conflictCols.length > 0\n ? ` ${onConflictTail(cols, conflictCols, op.action)}`\n : \"\";\n sql = `INSERT INTO ${table} (${cols.map(quoteIdent).join(\", \")}) VALUES ${tuples.join(\", \")}${tail} RETURNING *`;\n break;\n }\n case \"update\": {\n const cols = Object.keys(op.set ?? {});\n if (cols.length === 0) throw new Error(`update ${op.table}: nothing to set`);\n const assignments = cols.map(\n (c) => `${quoteIdent(c)} = ${renderValue((op.set as Record<string, TxWireValue>)[c], c, args, results, opVectorCols, opTransforms)}`,\n );\n sql = `UPDATE ${table} SET ${assignments.join(\", \")}${renderWhere(op.where, args, results)} RETURNING *`;\n break;\n }\n case \"delete\": {\n sql = `DELETE FROM ${table}${renderWhere(op.where, args, results)} RETURNING *`;\n break;\n }\n case \"select\": {\n const limit = op.limit !== undefined ? ` LIMIT ${Number(op.limit)}` : \"\";\n const lock = op.lock === \"update\" ? \" FOR UPDATE\" : \"\";\n sql = `SELECT * FROM ${table}${renderWhere(op.where, args, results)}${limit}${lock}`;\n break;\n }\n default:\n // Loudly, rather than rendering something for an op nobody wrote.\n throw new Error(`unknown operation \"${String((op as { op: string }).op)}\" in a transaction plan`);\n }\n\n return (await sp.unsafe(sql, args.values)) as Row[];\n}\n\n/**\n * Enforce the author's declared expectation.\n *\n * The Error the author passed never travels: the plan carries a SLOT index and\n * the SDK maps it back. So a failure here throws the shape `runTxPlan` знает —\n * `{error_code: \"tx_guard_failed\", slot}` — and the savepoint unwinds.\n */\nfunction assertGuard(op: TxWireOp, result: TxPlanOpResult): void {\n const guard = op.guard;\n if (!guard) return;\n const n = result.rows.length;\n const ok =\n guard.kind === \"one\"\n ? n === 1\n : guard.kind === \"none\"\n ? n === 0\n : guard.kind === \"atLeast\"\n ? n >= guard.n\n : n <= guard.n;\n if (ok) return;\n throw Object.assign(new Error(`transaction expectation failed: ${guard.kind} (${n} row(s))`), {\n error_code: \"tx_guard_failed\",\n slot: guard.slot,\n });\n}\n","// The decorator registry — the single plain-data store the method + parameter\n// decorators write into, and the deploy/dispatch pipeline reads back. No\n// `reflect-metadata`, no `emitDecoratorMetadata`: the registry is built from the\n// decorator arguments + the parameter INDEX that esbuild/tsc preserve for legacy\n// parameter decorators (verified — see the design spec §0/§4.1).\n//\n// A controller class carries its route metadata on a symbol-keyed static\n// property (`ROUTES`). `@Get`/`@Post`/… append a {@link RouteMeta} entry;\n// `@Body`/`@User`/… append a {@link ParamMeta} entry onto the route for the\n// method they decorate. Because parameter decorators run BEFORE the method\n// decorator for the same member (TS evaluates innermost-first, params before the\n// method), the route entry may not exist yet when a param decorator fires — so\n// param metadata is buffered per method name and merged when the method\n// decorator creates the route entry.\nimport type { AuthSpec, RateLimitConfig } from \"../endpoint.js\";\nimport type { UploadConfig } from \"./upload.js\";\nimport type { SseConfig } from \"./sse.js\";\nimport type { ZodTypeAny } from \"zod\";\n\n/** The HTTP verbs a route may declare, upper-cased (the runtime router +\n * OpenAPI lower-case on their own). */\nexport type HttpMethodUpper = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"QUERY\";\n\n/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */\nexport interface RouteOptions {\n /** OVERRIDES the controller-level default auth for this one route. */\n auth?: AuthSpec;\n /** Per-route rate limit. */\n rateLimit?: RateLimitConfig;\n /** Direct-storage upload config — present ONLY on `@Upload` routes (the\n * `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a\n * route as an upload route through the whole pipeline (registry → flatten →\n * openapi → codegen). The bytes go client→storage directly; the method body\n * runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */\n uploadConfig?: UploadConfig;\n /** Streaming config — present ONLY on `@Sse` routes (the `@Get`/`@Post`/…\n * decorators never set it). Its presence is what MARKS a route as a streaming\n * route through the whole pipeline (registry → flatten → openapi → codegen),\n * exactly as `uploadConfig` does for uploads — never a special HTTP verb. An\n * `@Sse` route registers POST like any input-bearing route, so the verb cannot\n * carry the distinction. See {@link SseConfig} (decorators/sse.ts). */\n sseConfig?: SseConfig;\n}\n\n/** The kind of value a parameter decorator injects. Drives both dispatch\n * (which request slice to inject) and codegen (which OpenAPI parameter source a\n * schema-bearing kind maps to). */\nexport type ParamKind =\n | \"body\"\n | \"query\"\n | \"param\"\n | \"headers\"\n | \"user\"\n | \"optionalUser\"\n | \"client\"\n | \"requestId\"\n | \"traceId\"\n | \"req\"\n // `@UploadedObject()` — injects the uploaded object (completion input) on an\n // `@Upload` route. No schema (the shape is the fixed UploadedObject type).\n | \"uploadedObject\"\n // `@SseOut()` — injects the frame writer on an `@Sse` route. No schema (the\n // shape is the fixed SseWriter type).\n | \"sseOut\"\n // `@Signal()` — injects the request's AbortSignal, which aborts when the\n // client disconnects. No schema. NOT derivable from `@Req()`: PBRequest\n // carries only request-scoped data and has no signal (endpoint.ts:358-363).\n | \"signal\";\n\n/** One parameter decorator's recorded metadata. `index` is the parameter\n * position esbuild/tsc preserve; `schema` is present for the schema-bearing\n * kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */\nexport interface ParamMeta {\n index: number;\n kind: ParamKind;\n /** Zod schema for `body`/`query`/`headers` (validation + codegen source). */\n schema?: ZodTypeAny;\n /** Path-param name for `@Param(\"id\")`. */\n name?: string;\n}\n\n/** One inferred throw site: the error CLASS name (e.g. \"TodoLocked\") and its\n * wire code (e.g. \"todo_locked\"). `status`, `hasData`, and the data JSON schema\n * are NOT carried here — they resolve from the error registry by `code` at\n * extract/openapi time (single source of truth). */\nexport interface ThrowDescriptor {\n name: string;\n code: string;\n}\n\n/** One route's recorded metadata: the verb + subpath + method name + options,\n * the ordered parameter metas, and the resolved return schema (injected by the\n * codegen step — see `returnSchema`). */\nexport interface RouteMeta {\n method: HttpMethodUpper;\n subpath: string;\n fnName: string;\n options: RouteOptions;\n params: ParamMeta[];\n /** Response schema for the route, if any. Derived from the method's RETURN\n * TYPE by codegen and written here via `recordReturn` (a generated top-level\n * IIFE injected per controller), not by an author-written decorator. */\n returnSchema?: ZodTypeAny;\n /** Error classes this route can throw, if inferred. Derived from the method\n * body + service call graph by the deploy stager's throw analysis and written\n * here via `recordThrows` (a generated top-level IIFE injected per controller,\n * the `recordReturn` twin), not by an author-written decorator. */\n throws?: ThrowDescriptor[];\n}\n\n/** Symbol the route metadata list is stored under on a controller class. Using\n * a symbol (not a string key) keeps it off the public structural surface and\n * avoids any chance of an authored property collision. */\nexport const ROUTES: unique symbol = Symbol.for(\"palbase.backend.routes\");\n\n/** Symbol the per-method buffered parameter metas are stored under while a class\n * is being decorated. Parameter decorators fire before the method decorator, so\n * they buffer here keyed by method name; the method decorator drains the buffer\n * into the route entry it creates. */\nconst PARAM_BUFFER: unique symbol = Symbol.for(\"palbase.backend.paramBuffer\");\n\n/** A room's own slots. Rooms are NOT routes — no verb, no path, no params — so\n * they get their own carrier slots instead of being squeezed into RouteMeta. */\nconst ROOM: unique symbol = Symbol.for(\"palbase.backend.room\");\nconst ROOM_HOOKS: unique symbol = Symbol.for(\"palbase.backend.roomHooks\");\n\n/** Symbol the per-method buffered return-type schemas are stored under while a\n * class's registry is being populated. The codegen-injected `recordReturn` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordReturn`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its return schema — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst RETURN_BUFFER: unique symbol = Symbol.for(\"palbase.backend.returnBuffer\");\n\n/** Symbol the per-method buffered throw descriptors are stored under while a\n * class's registry is being populated. The stager-injected `recordThrows` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordThrows`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its throw descriptors — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst THROWS_BUFFER: unique symbol = Symbol.for(\"palbase.backend.throwsBuffer\");\n\n/** A class constructor carrying the symbol-keyed registry slots. We type the\n * registry-bearing class as this so the decorators can read/write the slots\n * without `any` — a plain `Function` does not carry index signatures. */\ninterface RegistryCarrier {\n [ROUTES]?: RouteMeta[];\n [PARAM_BUFFER]?: Record<string, ParamMeta[]>;\n [ROOM]?: RoomMeta;\n [ROOM_HOOKS]?: RoomBuffer;\n [RETURN_BUFFER]?: Record<string, ZodTypeAny>;\n [THROWS_BUFFER]?: Record<string, ThrowDescriptor[]>;\n}\n\n/** Coerce a decorated target (class constructor or its prototype) into the\n * registry carrier that owns the slots. Method/param decorators receive the\n * PROTOTYPE as their target; the class decorator receives the constructor. We\n * always anchor the registry on the CONSTRUCTOR so `getRoutes(ctor)` finds it. */\nfunction carrierOf(target: object): RegistryCarrier {\n // For instance-member decorators, `target` is the prototype; its `.constructor`\n // is the class. For a static member or the class decorator, `target` is the\n // constructor already. Resolve to the constructor either way.\n const ctor =\n typeof target === \"function\"\n ? (target as unknown as RegistryCarrier)\n : (((target as { constructor?: unknown }).constructor ??\n target) as unknown as RegistryCarrier);\n return ctor;\n}\n\n/** Get (creating if absent) the own route list for a class constructor. Own —\n * not inherited — so a subclass does not mutate its base's routes. */\nfunction ownRoutes(carrier: RegistryCarrier): RouteMeta[] {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROUTES)) {\n carrier[ROUTES] = [];\n }\n return carrier[ROUTES] as RouteMeta[];\n}\n\n/** Get (creating if absent) the own per-method param buffer for a class. */\nfunction ownParamBuffer(carrier: RegistryCarrier): Record<string, ParamMeta[]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, PARAM_BUFFER)) {\n carrier[PARAM_BUFFER] = {};\n }\n return carrier[PARAM_BUFFER] as Record<string, ParamMeta[]>;\n}\n\n/** Record a route (called by the method decorators). Drains any parameter\n * metas already buffered for `fnName` into the new route entry, then sorts them\n * by parameter index so dispatch can inject positionally. */\nexport function recordRoute(\n target: object,\n fnName: string,\n method: HttpMethodUpper,\n subpath: string,\n options: RouteOptions,\n): void {\n const carrier = carrierOf(target);\n const routes = ownRoutes(carrier);\n const buffer = ownParamBuffer(carrier);\n const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);\n const route: RouteMeta = { method, subpath, fnName, options, params };\n // Drain a buffered return schema (the recordReturn-ran-first ordering) so the\n // route entry is complete the moment it's created — a raw-symbol consumer\n // (the runtime extractor/worker) sees the return schema without re-merging.\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer && returnBuffer[fnName] !== undefined) {\n route.returnSchema = returnBuffer[fnName];\n }\n // Same drain for buffered throw descriptors (the recordThrows-ran-first\n // ordering) — the route entry is complete the moment it's created.\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer && throwsBuffer[fnName] !== undefined) {\n route.throws = throwsBuffer[fnName];\n }\n routes.push(route);\n}\n\n/** Record one parameter decorator (called by `@Body`/`@User`/…). Buffers per\n * method name; the method decorator merges the buffer into the route entry. If\n * the route already exists (method decorator ran first — TS does evaluate the\n * method decorator AFTER its parameter decorators, but we stay order-robust),\n * the meta is also appended directly so neither ordering loses it. */\nexport function recordParam(target: object, fnName: string, meta: ParamMeta): void {\n const carrier = carrierOf(target);\n const buffer = ownParamBuffer(carrier);\n (buffer[fnName] ??= []).push(meta);\n\n // Order-robust: if the route already exists, merge in place + keep sorted.\n const routes = carrier[ROUTES];\n if (routes) {\n const route = routes.find((r) => r.fnName === fnName);\n if (route) {\n route.params.push(meta);\n route.params.sort((a, b) => a.index - b.index);\n }\n }\n}\n\n/** Attach a return schema to the route for `fnName` (called by the codegen\n * injection that reads the method's return type). If the route does not exist\n * yet, the schema is buffered (RETURN_BUFFER) and drained into the route by\n * `recordRoute` when the method decorator runs. */\nexport function recordReturn(target: object, fnName: string, schema: ZodTypeAny): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.returnSchema = schema;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, RETURN_BUFFER)) {\n carrier[RETURN_BUFFER] = {};\n }\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) returnBuffer[fnName] = schema;\n}\n\n/** Attach the inferred throw descriptors to the route for `fnName` (called by\n * the stager-injected IIFE that carries the throw analysis result — the\n * `recordReturn` twin). If the route does not exist yet, the descriptors are\n * buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the\n * method decorator runs. */\nexport function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.throws = throws;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, THROWS_BUFFER)) {\n carrier[THROWS_BUFFER] = {};\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) throwsBuffer[fnName] = throws;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas + throw descriptors (for the\n * recordReturn/recordThrows-runs-before orderings) and returns a defensive copy\n * so callers cannot mutate the registry.\n */\nexport function getRoutes(ctor: object): RouteMeta[] {\n const carrier = carrierOf(ctor);\n const routes = carrier[ROUTES] ?? [];\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) {\n for (const route of routes) {\n const buffered = returnBuffer[route.fnName];\n if (buffered && route.returnSchema === undefined) {\n route.returnSchema = buffered;\n }\n }\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) {\n for (const route of routes) {\n const buffered = throwsBuffer[route.fnName];\n if (buffered && route.throws === undefined) {\n route.throws = buffered;\n }\n }\n }\n return routes.map((r) => ({\n ...r,\n params: r.params.slice(),\n ...(r.throws !== undefined ? { throws: r.throws.slice() } : {}),\n }));\n}\n\n// ── rooms ───────────────────────────────────────────────────────────────────\n\n/** Which lifecycle hook a method is bound to. */\nexport type RoomHook = \"authorize\" | \"first\" | \"join\" | \"leave\" | \"empty\";\n\nexport interface RoomMessageMeta {\n fnName: string;\n schema: ZodTypeAny;\n}\n\nexport interface RoomMeta {\n pattern: string;\n events: Record<string, ZodTypeAny>;\n graceMs: number;\n /** hook → the method name that implements it. */\n hooks: Partial<Record<RoomHook, string>>;\n /** inbound message name → its method and payload schema. */\n messages: Record<string, RoomMessageMeta>;\n}\n\ninterface RoomBuffer {\n hooks: Partial<Record<RoomHook, string>>;\n messages: Record<string, RoomMessageMeta>;\n}\n\n/** Get (creating if absent) the own hook buffer. Own — not inherited — so a\n * subclass never mutates its base's hooks. Member decorators fill this BEFORE\n * the class decorator runs; controller.ts:203 depends on the same ordering. */\nfunction ownRoomBuffer(carrier: RegistryCarrier): RoomBuffer {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROOM_HOOKS)) {\n carrier[ROOM_HOOKS] = { hooks: {}, messages: {} };\n }\n return carrier[ROOM_HOOKS] as RoomBuffer;\n}\n\n/** Record a lifecycle hook. A second method for the same hook is refused: two\n * answers to \"who handles this\" cannot be resolved at dispatch, and silently\n * keeping one is how a hook stops running without anyone being told. */\nexport function recordRoomHook(target: object, hook: RoomHook, fnName: string): void {\n const buffer = ownRoomBuffer(carrierOf(target));\n const existing = buffer.hooks[hook];\n if (existing !== undefined && existing !== fnName) {\n const label = `On${hook.charAt(0).toUpperCase()}${hook.slice(1)}`;\n throw new Error(\n `@${label} is declared twice in one room (${existing} and ${fnName}). ` +\n `A room has one of each hook.`,\n );\n }\n buffer.hooks[hook] = fnName;\n}\n\n/** Record an inbound message handler. */\nexport function recordRoomMessage(\n target: object,\n name: string,\n fnName: string,\n schema: ZodTypeAny,\n): void {\n const buffer = ownRoomBuffer(carrierOf(target));\n const existing = buffer.messages[name];\n if (existing !== undefined && existing.fnName !== fnName) {\n throw new Error(\n `@OnMessage(\"${name}\") is declared twice in one room (${existing.fnName} and ${fnName}).`,\n );\n }\n buffer.messages[name] = { fnName, schema };\n}\n\n/** Record the room itself (called by the class decorator), draining the buffer\n * the member decorators already filled. */\nexport function recordRoom(\n ctor: object,\n meta: Omit<RoomMeta, \"hooks\" | \"messages\">,\n): void {\n const carrier = carrierOf(ctor);\n const buffer = ownRoomBuffer(carrier);\n carrier[ROOM] = { ...meta, hooks: buffer.hooks, messages: buffer.messages };\n // AND into the shared class registry, the same slot @Controller pushes to.\n //\n // Without this line a room compiles, bundles and deploys, and is never called:\n // the bundler's entry exports `SDK.getRegisteredControllers()` and the runtime\n // reads its rooms out of THAT list (server.ts's `collectRooms`). A room that\n // only marks its own constructor is a room nobody can find — measured, on the\n // fixture, at the last gate before it would have worked.\n //\n // Rooms and controllers share one list because they are one thing to the\n // loader: classes a bundle declared. What each IS is decided by the marker it\n // carries, never by which list it arrived in.\n const g = globalThis as unknown as Record<symbol, unknown[] | undefined>;\n const REGISTRY = Symbol.for(\"palbase.backend.allControllers\");\n const all = (g[REGISTRY] ??= []);\n if (!all.includes(ctor)) all.push(ctor);\n}\n\n/** The room a class declares, or undefined. A class with no `@Room` is not a\n * room — the marker is the CONFIG's presence, never a name or a base class\n * (the rule upload.ts:13-16 states for uploads). */\nexport function getRoom(ctor: object): RoomMeta | undefined {\n const carrier = carrierOf(ctor);\n if (!Object.prototype.hasOwnProperty.call(carrier, ROOM)) return undefined;\n return carrier[ROOM] as RoomMeta;\n}\n","// `@Controller(basePath, options?)` — the class decorator that marks a class as\n// a Palbase backend controller. It stamps a non-enumerable `__palbase`\n// discriminant + the resolved controller metadata onto the class so the\n// deploy/dispatch pipeline (and `isController`/`resolveController`) can detect\n// and read it without `reflect-metadata`.\nimport type { AuthSpec } from \"../endpoint.js\";\nimport { getRoutes } from \"./registry.js\";\n\n/** The controller metadata stamped onto a `@Controller`-decorated class. The\n * default export of a `controllers/*.controller.ts` file resolves to this via\n * {@link resolveController}. */\nexport interface ControllerMeta {\n /** Discriminant the runtime + tooling read. */\n readonly __palbase: \"controller\";\n /** The base path every route in this controller mounts under (e.g. \"/todos\"). */\n basePath: string;\n /** Controller-level default auth, applied to routes that don't set their own\n * (`@Get(\"/x\", { auth })` overrides this). `undefined` ⇒ the application\n * default ({@link defineDefaultAuth}), and secure-by-default below that —\n * see {@link resolveEffectiveAuth} for the whole cascade. */\n defaultAuth?: AuthSpec;\n}\n\n/** Options accepted by `@Controller`. */\nexport interface ControllerOptions {\n /** Default auth for ALL routes in this controller (route-level overrides;\n * omitting it falls through to the application default declared with\n * {@link defineDefaultAuth}). */\n auth?: AuthSpec;\n}\n\n/** Symbol the controller metadata is stamped under. Symbol-keyed (not a string\n * property) so it never collides with an authored member and stays off the\n * structural surface. */\nexport const CONTROLLER_META: unique symbol = Symbol.for(\"palbase.backend.controllerMeta\");\n\n/**\n * Every class `@Controller` has decorated, in decoration order.\n *\n * This is what lets a controller file need no export at all: importing the file\n * runs the decorator, the decorator records the class here, and the runtime\n * reads the list. Without it the only handle on a class is its export name, so\n * every controller had to be exported AND named in a generated entry — the\n * ceremony NestJS still charges (`export class` PLUS\n * `@Module({controllers:[…]})`).\n *\n * Keyed on a well-known Symbol against globalThis rather than held in a module\n * variable, because a deployed bundle inlines its own copy of this package: two\n * copies would keep two lists, and the runtime would read the empty one. The\n * same hazard `runtimeHooks` exists for, closed the same way — one shared slot.\n */\nconst REGISTRY: unique symbol = Symbol.for(\"palbase.backend.allControllers\") as never;\n\nfunction registry(): unknown[] {\n const g = globalThis as unknown as Record<symbol, unknown[] | undefined>;\n const existing = g[REGISTRY];\n if (existing) return existing;\n const fresh: unknown[] = [];\n g[REGISTRY] = fresh;\n return fresh;\n}\n\n/**\n * The controller classes this process has loaded, in decoration order.\n *\n * Decoration order is import order, which the bundler fixes by sorting the\n * files it emits imports for — so two builds of one tree produce the same\n * route table, and route precedence is not a function of module-resolution\n * accidents.\n */\nexport function getRegisteredControllers(): readonly unknown[] {\n return registry().slice();\n}\n\n/** Empty the registry. For tests, which load controllers repeatedly. */\nexport function __resetRegisteredControllers(): void {\n registry().length = 0;\n}\n\n/**\n * The APPLICATION-level default auth.\n *\n * Held on globalThis under a well-known Symbol for exactly the reason\n * {@link REGISTRY} is: a deployed bundle inlines its own copy of this package,\n * and two copies keeping two defaults is how a security setting silently\n * becomes two different settings.\n */\nconst APP_DEFAULT_AUTH: unique symbol = Symbol.for(\"palbase.backend.appDefaultAuth\") as never;\n\nfunction appAuthSlot(): Record<symbol, AuthSpec | undefined> {\n return globalThis as unknown as Record<symbol, AuthSpec | undefined>;\n}\n\n/**\n * Declare the default auth for EVERY route in the application — the ring the\n * cascade consults when neither the route nor its controller says anything.\n *\n * The measured problem it removes: `auth: { verifiedEmail: true }` repeated by\n * hand on ten `@Controller`s. A security setting that must be repeated is a\n * security setting that will be forgotten — the eleventh controller opens the\n * door and nothing says so.\n *\n * Call it at MODULE SCOPE in a file the application imports (the controllers'\n * own barrel, or a module a controller imports). The cascade reads this slot\n * when the route table is built and when the spec is emitted — both of which\n * run after module loading — so declaration order does not matter, but being\n * imported at all does.\n *\n * @example\n * defineDefaultAuth({ verifiedEmail: true }); // every route, unless it says otherwise\n */\nexport function defineDefaultAuth(auth: AuthSpec): void {\n appAuthSlot()[APP_DEFAULT_AUTH] = auth;\n}\n\n/** The declared application default, or `undefined` when none was declared. */\nexport function getDefaultAuth(): AuthSpec | undefined {\n return appAuthSlot()[APP_DEFAULT_AUTH];\n}\n\n/** Clear the application default. For tests, which declare it repeatedly. */\nexport function __resetDefaultAuth(): void {\n delete appAuthSlot()[APP_DEFAULT_AUTH];\n}\n\n/**\n * THE auth cascade: route → controller → application → `true`.\n *\n * One function, every caller — the route table (`engine/router.ts`) and the\n * spec emitter (`openapi/controllers.ts`) ASK for the answer instead of\n * spelling the chain themselves. Two hand-written copies of a cascade is how\n * the build-time answer and the runtime answer come to disagree about who may\n * call an endpoint, and the disagreement shows up as an open door.\n *\n * The terminal `true` is secure-by-default and is load-bearing: a route that\n * declared nothing, under a controller that declared nothing, in an\n * application that declared nothing, is CLOSED.\n */\nexport function resolveEffectiveAuth(\n routeAuth: AuthSpec | undefined,\n controllerAuth: AuthSpec | undefined,\n): AuthSpec {\n return routeAuth ?? controllerAuth ?? getDefaultAuth() ?? true;\n}\n\n/** A class carrying the stamped controller metadata + discriminant. */\ninterface ControllerCarrier {\n __palbase?: \"controller\";\n [CONTROLLER_META]?: ControllerMeta;\n}\n\n/** The one path segment the platform owns. The isolate matches\n * `^/webhooks/([^/]+)$` on the raw request path BEFORE controller dispatch, so\n * anything a controller resolves to under it answers `404 webhook_not_found`\n * and never runs. */\nconst RESERVED_FIRST_SEGMENT = \"webhooks\";\n\n/**\n * Throw if `path` resolves under the reserved segment. Segments are compared the\n * way the isolate compares them — `split(\"/\").filter(Boolean)` — NOT by string\n * prefix, because empty segments collapse there: `@Controller(\"/\")` +\n * `@Post(\"/webhooks/x\")` composes to `//webhooks/x`, which the isolate serves as\n * `/webhooks/x`. A prefix check reads that as safe; the segment check does not.\n * `/webhooksy` stays allowed for the same reason — it is a different segment.\n *\n * Every verb is refused, not just the POST the isolate currently intercepts: the\n * reservation is of the URL namespace, so a `@Get(\"/webhooks/x\")` that happens\n * to work today would be silently shadowed the moment the isolate's method gate\n * widens. Refusing at build is recoverable; discovering it as a 404 is not.\n */\nfunction assertNotReserved(path: string, subject: string): void {\n const [first] = path.split(\"/\").filter(Boolean);\n if (first === RESERVED_FIRST_SEGMENT) {\n throw new Error(\n `${subject} resolves under the reserved /${RESERVED_FIRST_SEGMENT} path — ` +\n \"inbound webhooks are served there and would shadow this route\",\n );\n }\n}\n\n/**\n * Mark a class as a Palbase backend controller. `basePath` is the mount path\n * for every route the class declares; `options.auth` sets the controller-level\n * default auth (a route's own `auth` overrides it; absent ⇒ secure-by-default).\n *\n * @example\n * \\@Controller(\"/todos\", { auth: false })\n * export class TodosController {\n * \\@Get(\"\") list(\\@QueryParams(ListTodosQuery) q: ListTodosQuery): TodoSchema[] { … }\n * }\n */\nexport function Controller(basePath: string, options: ControllerOptions = {}) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n // /webhooks/* belongs to the platform: the isolate matches the inbound\n // webhook route before controller dispatch, so a controller mounted here\n // would never receive a request. Silent shadowing is the failure mode this\n // whole change exists to remove, so refuse it at build.\n //\n // The COMPOSED path is what gets shadowed, not the base path. `@Controller(\"\")`\n // and `@Controller(\"/\")` both pass a base-path-only check while a\n // `@Post(\"/webhooks/stripe\")` inside them resolves to exactly the path the\n // isolate intercepts. Method decorators run BEFORE the class decorator (TS\n // evaluates members first), so every route this class declares is already in\n // the registry here — which is why the composed check can live at this one\n // seam instead of on the dispatch read path. The `@Controller(\"\") +\n // @Post(\"/webhooks/stripe\")` test is the lock on that ordering: if it ever\n // stopped holding, that test goes red.\n assertNotReserved(basePath, `@Controller(\"${basePath}\")`);\n for (const route of getRoutes(ctor)) {\n assertNotReserved(\n `${basePath}${route.subpath}`,\n `@${route.method}(\"${route.subpath}\") in @Controller(\"${basePath}\")`,\n );\n }\n\n const carrier = ctor as unknown as ControllerCarrier;\n const meta: ControllerMeta = {\n __palbase: \"controller\",\n basePath,\n ...(options.auth !== undefined ? { defaultAuth: options.auth } : {}),\n };\n // Non-enumerable so it doesn't leak onto instances / structural checks.\n Object.defineProperty(carrier, CONTROLLER_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // The bare `__palbase` discriminant is the cheap detection marker the\n // runtime/extractor checks; keep it readable but non-enumerable.\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"controller\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // Record it, so importing the file is enough and exporting is optional.\n // Guarded against a double-decoration re-entering the same class twice.\n const all = registry();\n if (!all.includes(ctor)) all.push(ctor);\n return ctor;\n };\n}\n\n/** True when `value` is a `@Controller`-decorated class (cheap discriminant\n * check). Accepts the class constructor (the default export of a controller\n * file). */\nexport function isController(value: unknown): boolean {\n if (typeof value !== \"function\" && (typeof value !== \"object\" || value === null)) {\n return false;\n }\n const carrier = value as ControllerCarrier;\n return carrier.__palbase === \"controller\" && carrier[CONTROLLER_META] !== undefined;\n}\n\n/** Read the resolved controller metadata off a `@Controller`-decorated class.\n * Throws if the class was not decorated — callers should gate with\n * {@link isController} first (the loader does). */\nexport function resolveController(ctor: unknown): ControllerMeta {\n if (typeof ctor !== \"function\" && (typeof ctor !== \"object\" || ctor === null)) {\n throw new TypeError(\"resolveController: value is not a class\");\n }\n const meta = (ctor as ControllerCarrier)[CONTROLLER_META];\n if (!meta) {\n throw new TypeError(\n \"resolveController: class is not a @Controller — every controller file must `export default` a @Controller-decorated class\",\n );\n }\n return meta;\n}\n\n/**\n * A class the runtime constructs takes NO constructor parameters.\n *\n * ONE writer, four callers (controller, hook, job, webhook) and the build's own\n * check. Four hand-written copies of this message is how the four come to\n * disagree about what is refused — and the disagreement is silent, because a\n * class that slips past one of them still ends up with `undefined` fields.\n *\n * Why it is refused rather than injected: there is no container. The parameter\n * would arrive `undefined`, the code would compile, deploy, and fail at the\n * first request that touches the field — the most expensive place to learn it.\n */\nexport function assertZeroArgConstructor(Ctrl: unknown, kind: string): void {\n const arity = (Ctrl as { length?: number }).length ?? 0;\n if (arity === 0) return;\n const name = (Ctrl as { name?: string }).name ?? \"<anonymous>\";\n throw new Error(\n `${kind} ${name} declares a constructor with ${arity} parameter(s). ` +\n `A ${kind} is constructed by the runtime with a zero-argument constructor — ` +\n `there is no injector to supply them, so every parameter would arrive as ` +\n `undefined. Hold the dependency as a module-level singleton the ${kind} ` +\n \"imports (`const repo = makeRepo()` beside the class), and construct the \" +\n \"service directly in tests (e.g. `new TodoService(fakeDatabase().db)`).\",\n );\n}\n","/**\n * engine/router.ts — the route table, built from the SDK's own registry.\n *\n * No third-party router. The table is known at boot (the decorators wrote it),\n * so matching is a segment walk over a small array rather than a compiled\n * pattern engine. Both authoring forms for a path parameter are accepted:\n * `{id}` (what the decorators are written with) and `:id`.\n */\nimport { getRoutes } from \"../decorators/registry.js\";\nimport type { RouteMeta } from \"../decorators/registry.js\";\nimport { resolveEffectiveAuth, assertZeroArgConstructor } from \"../decorators/controller.js\";\nimport type { AuthSpec } from \"../endpoint.js\";\n\nconst ROOM_META: unique symbol = Symbol.for(\"palbase.backend.room\") as never;\nconst CONTROLLER_META = Symbol.for(\"palbase.backend.controllerMeta\");\n\nexport interface RouteEntry {\n method: string;\n /** Path segments; a parameter segment is stored as `:name`. */\n segments: string[];\n meta: RouteMeta;\n /** The controller instance the method is invoked on. */\n instance: Record<string, (...args: unknown[]) => unknown>;\n /** `GET /todos/{id}` — stable, human-readable, used as the rate-limit key. */\n id: string;\n /** The auth spec that applies when the route itself declares none —\n * controller default ?? application default ?? `true`, resolved once at boot\n * by `resolveEffectiveAuth`. `engine/index.ts` reconciles the route's own\n * spec against it per request. */\n controllerAuth: AuthSpec;\n}\n\nfunction toSegments(path: string): string[] {\n return path\n .split(\"/\")\n .filter(Boolean)\n .map((s) => (s.startsWith(\"{\") && s.endsWith(\"}\") ? `:${s.slice(1, -1)}` : s));\n}\n\n/**\n * Build the table from controller classes.\n *\n * @throws when a class carries no routes — a controller that collected zero\n * endpoints is the silent failure this whole runtime is built to refuse, and\n * it must be loud at boot rather than a 404 in production.\n * @throws when a class declares constructor parameters — the same class of\n * silence one level down (FR-010): nothing here has an argument to pass, so\n * the field would simply be `undefined` in production.\n */\nexport function buildRouteTable(controllers: readonly unknown[]): RouteEntry[] {\n const table: RouteEntry[] = [];\n for (const Ctrl of controllers) {\n // A ROOM is not a routeless controller, it is a class with no HTTP surface\n // at all — server code a device reaches over the socket. It arrives here\n // because rooms and controllers share ONE registry slot (the loader's\n // `controllersOf` hands over everything a bundle declared), and the zero-route\n // refusal below is correct for a controller and wrong for a room.\n //\n // Measured on the live stack: the fixture's `@Room` reached this line and the\n // runtime refused to boot with \"controller ProbeRoom collected zero routes\" —\n // a message naming a class that was perfectly correct.\n if ((Ctrl as Record<symbol, unknown>)[ROOM_META] !== undefined) continue;\n // The `new ()` in this cast is a CLAIM — that the class is constructible with\n // no arguments — and the arity check below is what makes it true. Without it\n // the cast quietly held for `constructor(dep: Repo)` too: the call compiled,\n // deployed, and handed `this.dep` the value `undefined`.\n const ctor = Ctrl as { new (): Record<string, (...a: unknown[]) => unknown> } & Record<\n symbol,\n { basePath?: string; defaultAuth?: AuthSpec } | undefined\n >;\n const meta = ctor[CONTROLLER_META];\n const basePath = meta?.basePath ?? \"\";\n const routes = getRoutes(Ctrl as never) as RouteMeta[];\n if (routes.length === 0) {\n const name = (Ctrl as { name?: string }).name ?? \"<anonymous>\";\n throw new Error(\n `controller ${name} collected zero routes. Either it declares no @Get/@Post/… , ` +\n `or its decorator metadata was erased at build time — check that the bundle was ` +\n `compiled with experimentalDecorators enabled.`,\n );\n }\n assertZeroArgConstructor(Ctrl, \"controller\");\n const instance = new ctor();\n for (const r of routes) {\n const full = `${basePath}${r.subpath ?? \"\"}` || \"/\";\n table.push({\n method: r.method,\n segments: toSegments(full),\n meta: r,\n instance,\n id: `${r.method} ${full}`,\n // The route's OWN spec is deliberately not folded in here: this field\n // is what applies when the route is silent, and `effectiveAuth` puts\n // the route level back on top per request.\n controllerAuth: resolveEffectiveAuth(undefined, meta?.defaultAuth),\n });\n }\n }\n return table;\n}\n\nexport interface RouteMatch {\n entry: RouteEntry;\n params: Record<string, string>;\n}\n\n/** First match wins; the table is small and declaration order is the tiebreak. */\nexport function matchRoute(\n table: readonly RouteEntry[],\n method: string,\n pathname: string,\n): RouteMatch | null {\n const parts = pathname.split(\"/\").filter(Boolean);\n for (const entry of table) {\n if (entry.method !== method || entry.segments.length !== parts.length) continue;\n const params: Record<string, string> = {};\n let ok = true;\n for (let i = 0; i < entry.segments.length; i++) {\n const seg = entry.segments[i];\n const got = parts[i];\n if (seg === undefined || got === undefined) { ok = false; break; }\n if (seg.charCodeAt(0) === 58 /* ':' */) {\n params[seg.slice(1)] = decodeURIComponent(got);\n } else if (seg !== got) {\n ok = false;\n break;\n }\n }\n if (ok) return { entry, params };\n }\n return null;\n}\n","/**\n * upload.ts — the engine's half of `@Upload`.\n *\n * THE SHAPE, because it is unusual and the reason matters:\n *\n * client ──[ multipart: file + request body ]──► storage\n * storage ──[ authorize: which bucket, which path? ]──► THIS process\n * storage ── writes the bytes, renders the variants\n * storage ──[ signed: uploadedObject + request body ]──► THIS process\n * THIS process ── the handler runs, returns its typed result\n * storage ──[ that result ]──► client\n *\n * The tenant's code NEVER sees the bytes. It sees the metadata and the request\n * body, and it answers — which is what a completion handler is for. A 1 GB\n * video would otherwise stream through this process to reach the same place.\n *\n * Two calls arrive here, both from storage and neither from a browser:\n *\n * - AUTHORIZE asks which bucket and path a route writes to. Storage cannot\n * know: the answer lives in `@Upload({bucket, pathTemplate})`, which is\n * TypeScript, in the deployed bundle. Asking the process that HAS the\n * routes is what stops the client from naming its own bucket.\n * - COMPLETION runs the handler.\n *\n * Both are signed. An unsigned completion would let anyone with the route path\n * invent an upload that never happened.\n */\n\nimport type { RouteEntry } from \"./router.js\";\n\n/** What authorize answers: where this route's bytes go, and what they may be. */\nexport interface UploadGrant {\n bucket: string;\n path: string;\n maxBytes: number | null;\n mimeTypes: string[] | null;\n /**\n * Who is uploading, or null when nobody is signed in.\n *\n * Storage records this on the object row so deleting the user takes their\n * files with them. It is reported rather than DECIDED here — this process\n * already resolved the caller to render `{userId}` in a path template, and\n * storage has no identity of its own to derive one from. Authorization stays\n * exactly where it was (the route's own `auth` declaration); this is\n * attribution, which is a different question with the same answer already in\n * hand.\n *\n * null is the anonymous upload, and it stays null: a file uploaded by nobody\n * belongs to nobody, and attributing it to whoever signs in next on that\n * device would file one person's upload under another's name.\n */\n ownerUid: string | null;\n}\n\n/** The completion input storage sends after the bytes have landed. */\nexport interface CompletionEnvelope {\n uploadedObject: {\n uploadId: string;\n path: string;\n bucket: string;\n size: number;\n contentType: string;\n checksum: string;\n width?: number;\n height?: number;\n thumbhash?: string;\n variants: Record<string, string>;\n };\n /** The request body the client sent alongside the file. */\n body: unknown;\n}\n\n/** The internal path storage calls to ask where a route's bytes go. */\nexport const AUTHORIZE_PATH = \"/__palbase/upload/authorize\";\n\n/** Header carrying the shared-secret signature on both internal calls. */\nexport const SIGNATURE_HEADER = \"x-palbase-upload-signature\";\n\n/**\n * renderPath fills a `pathTemplate` on the SERVER.\n *\n * The client never chooses where its bytes land. `{filename}` is the one token\n * that comes from the caller, and it is sanitised to a single path segment:\n * without that, `../../../etc/passwd` is a filename, and a template that looks\n * like a folder structure becomes a way to write anywhere in the bucket.\n */\nexport function renderPath(template: string, tokens: {\n userId?: string | null;\n uploadId: string;\n filename?: string;\n}): string {\n return template\n .replaceAll(\"{userId}\", sanitizeSegment(tokens.userId ?? \"anonymous\"))\n .replaceAll(\"{uploadId}\", sanitizeSegment(tokens.uploadId))\n .replaceAll(\"{filename}\", sanitizeSegment(tokens.filename ?? \"file\"));\n}\n\n/**\n * sanitizeSegment reduces a value to something safe inside one path segment.\n *\n * Slashes, dots and control characters go. Keeping dots would allow `..`;\n * keeping slashes would allow a client to climb out of the prefix the template\n * put it in, which is the whole point of having a template.\n */\nexport function sanitizeSegment(raw: string): string {\n const cleaned = raw\n .replace(/[\\x00-\\x1F\\x7F]/g, \"\")\n .replace(/[/\\\\]/g, \"-\")\n .replace(/\\.{2,}/g, \".\")\n .replace(/^\\.+/, \"\")\n .trim();\n return cleaned === \"\" ? \"file\" : cleaned.slice(0, 200);\n}\n\n/**\n * grantFor resolves a route's upload configuration into a concrete grant.\n *\n * Returns null when the route is not an upload route — which is a refusal, not\n * an oversight: storage asking about a route with no `@Upload` means somebody\n * is trying to write through an endpoint that never offered to accept a file.\n */\nexport function grantFor(\n entry: RouteEntry | undefined,\n ctx: { userId: string | null; uploadId: string; filename?: string },\n bucketLimits?: { maxBytes: number | null; mimeTypes: string[] | null },\n): UploadGrant | null {\n const cfg = entry?.meta?.options?.uploadConfig;\n if (!cfg) return null;\n return {\n bucket: cfg.bucket,\n path: renderPath(cfg.pathTemplate, {\n userId: ctx.userId,\n uploadId: ctx.uploadId,\n filename: ctx.filename,\n }),\n maxBytes: bucketLimits?.maxBytes ?? null,\n mimeTypes: bucketLimits?.mimeTypes ?? null,\n ownerUid: ctx.userId ?? null,\n };\n}\n\n/**\n * CompletionLedger makes a completion run its handler EXACTLY ONCE per upload.\n *\n * The completion is a mutation — it writes the row that makes the uploaded\n * bytes mean something — and it is delivered over a network by a caller that\n * retries. A retried completion must not create a second post for one photo, so\n * the second call is answered with the FIRST call's response rather than being\n * refused: to storage, and therefore to the client waiting on it, a retry that\n * succeeds is indistinguishable from the original, which is the point.\n *\n * Bounded, and oldest-first: an upload id is interesting for as long as a retry\n * could still arrive, not forever. The cap is what keeps a long-lived process\n * from turning this into a leak — a ledger that remembered every upload would\n * be a slow way to run out of memory.\n */\nexport class CompletionLedger {\n private readonly seen = new Map<string, CompletedResponse>();\n\n constructor(private readonly capacity = 1024) {}\n\n recall(uploadId: string): CompletedResponse | undefined {\n return this.seen.get(uploadId);\n }\n\n remember(uploadId: string, response: CompletedResponse): void {\n // Delete-then-set so a repeat moves to the back: Map iterates in insertion\n // order, and the eviction below takes the front.\n this.seen.delete(uploadId);\n this.seen.set(uploadId, response);\n while (this.seen.size > this.capacity) {\n const oldest = this.seen.keys().next();\n if (oldest.done) break;\n this.seen.delete(oldest.value);\n }\n }\n\n get size(): number {\n return this.seen.size;\n }\n}\n\n/** A completion's answer, kept verbatim so a retry receives what the first call did. */\nexport interface CompletedResponse {\n status: number;\n body: string | null;\n contentType: string | null;\n}\n\n/**\n * verifySignature compares a presented signature against the expected one in\n * constant time.\n *\n * Constant time because a leaky comparison on a shared secret is recoverable\n * byte by byte, and this secret authorises running a tenant's handler with an\n * upload the caller describes.\n */\nexport function verifySignature(presented: string, expected: string): boolean {\n if (presented.length !== expected.length) return false;\n let diff = 0;\n for (let i = 0; i < presented.length; i++) {\n diff |= presented.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0;\n}\n","// engine/sse.ts — the Server-Sent Events mechanics, extracted from the request\n// pipeline so they can be tested without driving a whole request.\n//\n// This mirrors engine/upload.ts, which extracts renderPath / grantFor /\n// verifySignature and is consumed from engine/index.ts. Keeping the mechanics\n// here means the frame format, the ordering guarantee and the first-write hook\n// each have a test that names them, rather than being reachable only through a\n// full request.\n//\n// The problem being served: a provider on the server streams from a session;\n// while a client is connected its frames reach that client, and when the client\n// disconnects the provider must stop being pulled. This file owns the first\n// half — turning handler writes into wire frames, in order, without letting\n// anything escape before the request phase has been settled.\n\nimport type { SseWriter } from \"../decorators/sse.js\";\n\n/** The response content type for every `@Sse` route. */\nexport const SSE_CONTENT_TYPE = \"text/event-stream\";\n\n/**\n * Encode one value as an SSE `data:` frame.\n *\n * The payload is JSON, and that is load-bearing rather than merely convenient:\n * a raw newline inside a frame ends it and the remainder is parsed as a new\n * field, so a handler streaming user-influenced text could otherwise forge\n * events. JSON encoding escapes the newline, which makes the frame boundary\n * something only this function decides.\n */\nexport function encodeFrame(value: unknown): string {\n return `data: ${JSON.stringify(value)}\\n\\n`;\n}\n\n/**\n * Encode the terminal frame for a handler that threw AFTER it had already\n * written. The status line is long gone by then — 200 and the stream headers\n * were committed with the first frame — so the only honest way to report the\n * failure is in-band, and named, so a client can tell \"the stream ended\" from\n * \"the stream broke\".\n */\nexport function encodeErrorFrame(requestId: string): string {\n return `event: error\\ndata: ${JSON.stringify({ requestId })}\\n\\n`;\n}\n\n/** What `makeSseWriter` returns: the handler-facing writer plus the two members\n * the engine needs. `SseWriter` itself stays minimal — a handler author sees\n * only `write`. */\nexport interface EngineSseWriter extends SseWriter {\n /** Whether anything has been written yet. The engine chooses between an\n * ordinary error envelope (nothing written — the status line is still ours)\n * and a terminal error frame (already streaming) on this answer. */\n started(): boolean;\n /** Resolves when every queued frame has been enqueued. The engine awaits it\n * before closing the stream, so a handler that returns immediately after its\n * last write does not truncate it. */\n drained(): Promise<void>;\n}\n\nexport interface SseWriterOptions {\n /** Hand one encoded frame to the transport. */\n enqueue(chunk: string): void;\n /**\n * Runs ONCE, before the first frame is enqueued, and nothing is emitted until\n * it resolves. This is the seam where the request's database transaction is\n * settled: the handler runs inside that transaction, and a stream that lives\n * for minutes must not hold one open.\n */\n onFirstWrite(): Promise<void>;\n}\n\n/**\n * Build the writer handed to an `@Sse` handler.\n *\n * `write` is SYNCHRONOUS on purpose: a handler relaying a provider writes inside\n * a `for await` loop, and making every chunk awaitable would put a promise in\n * the hot path of every token for no benefit the caller can act on. The cost is\n * that the asynchronous first-write hook has to be absorbed here — so frames are\n * queued on a promise chain and emitted in exactly the order they were written.\n *\n * Values are encoded EAGERLY, inside `write`, not when the queue drains: a\n * handler that writes a mutable object and then keeps mutating it should see the\n * value as it was at the moment it wrote, which is also the only reading that\n * survives being queued.\n */\nexport function makeSseWriter(opts: SseWriterOptions): EngineSseWriter {\n let begun = false;\n let chain: Promise<void> = Promise.resolve();\n\n return {\n write(value: unknown): void {\n const frame = encodeFrame(value);\n if (!begun) {\n begun = true;\n chain = chain.then(() => opts.onFirstWrite()).then(() => opts.enqueue(frame));\n return;\n }\n chain = chain.then(() => opts.enqueue(frame));\n },\n started(): boolean {\n return begun;\n },\n drained(): Promise<void> {\n return chain;\n },\n };\n}\n","/**\n * engine/fence.ts — what the tenant's own code may reach.\n *\n * The isolate used to answer this by construction: tenant code ran in a realm\n * with no ambient network and an environment scrubbed of every secret, and each\n * privileged call hopped to a host that held the credentials. Running the\n * backend as one process removes that wall, so the two guarantees it carried\n * have to be re-made here — deliberately, and with the honest note that a\n * same-process fence is a SPEED BUMP against the tenant's own code, not a\n * sandbox. The real boundary is the machine: each tenant has its own.\n *\n * That is not a hole, it is a scope. The tenant owns this database and this\n * network namespace; the thing worth preventing is an ACCIDENT — a dependency\n * that reads `process.env` and posts it somewhere, a handler that opens its own\n * unscoped connection and quietly serves every user's rows — not a determined\n * operator attacking their own stack.\n */\n\n/** Names the engine holds and the tenant's code must not find lying around. */\nconst SECRET_ENV = [\n \"DATABASE_URL\",\n \"PALBASE_SERVICE_ROLE_KEY\",\n \"REALTIME_INGESTION_SECRET\",\n \"INTERNAL_API_SECRET\",\n \"STACK_ROOT_KEY\",\n \"PEPPER\",\n \"LOCAL_JWT_PEM\",\n] as const;\n\nexport interface ScrubResult {\n removed: string[];\n kept: string[];\n}\n\n/**\n * Delete the engine's own credentials from `process.env`.\n *\n * MUST run AFTER the config is read and BEFORE the tenant bundle is imported —\n * a bundle's module-level code runs at import, so a scrub that comes later has\n * already lost the race.\n *\n * The tenant's OWN variables (`PALBASE_VAR_*` and anything else) are untouched:\n * this removes what the platform put there, not what the operator did.\n *\n * Why RLS makes this matter: the engine binds every request to the caller with\n * `set_config('role', …)` so Postgres does the row filtering. Code that finds\n * `DATABASE_URL` can open its own connection as the owner and read every user's\n * rows — not by attacking anything, just by using a driver.\n */\nexport function scrubSecrets(env: Record<string, string | undefined>): ScrubResult {\n const removed: string[] = [];\n const kept: string[] = [];\n for (const name of SECRET_ENV) {\n if (env[name] === undefined) continue;\n delete env[name];\n removed.push(name);\n }\n for (const name of Object.keys(env)) if (name.startsWith(\"PALBASE_VAR_\")) kept.push(name);\n return { removed, kept };\n}\n\nexport interface EgressPolicy {\n /** Hostnames the tenant declared. Empty ⇒ no declaration was made. */\n allow: readonly string[];\n /** Per-call ceiling in ms. 0 ⇒ no ceiling declared. */\n timeoutMs: number;\n /** What to do when nothing was declared. */\n whenUndeclared: \"allow\" | \"deny\";\n /**\n * Hosts the BACKEND ITSELF needs: its module surface, the JWKS it verifies\n * tokens against, the artifact store it reloads from.\n *\n * These are not egress. `config/egress.ts` declares where the tenant's own\n * code may reach; a call to the platform this backend is part of is internal\n * traffic, and fencing it means the first deploy with an allowlist takes the\n * backend down — which is exactly what happened when this list did not exist:\n * every request 500'd with \"egress denied: palsvc is not in this backend's\n * declared allowlist\", and the artifact reload loop stopped with it.\n */\n alwaysAllow?: readonly string[];\n}\n\n/** `api.stripe.com` matches itself; `*.stripe.com` matches any subdomain. */\nexport function hostAllowed(host: string, allow: readonly string[]): boolean {\n const h = host.toLowerCase();\n for (const raw of allow) {\n const pattern = raw.trim().toLowerCase();\n if (!pattern) continue;\n if (pattern === h) return true;\n if (pattern.startsWith(\"*.\") && h.endsWith(pattern.slice(1)) && h.length > pattern.length - 1) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Install the tenant's declared outbound allowlist over `globalThis.fetch`.\n *\n * The engine's own traffic is exempted by HOST (`alwaysAllow`), not by holding\n * a captured reference: the module clients and the verifier resolve\n * `globalThis.fetch` at CALL time, so a captured original never reaches them.\n * That distinction is not academic — the first version of this file claimed the\n * capture worked, and every request 500'd on the first deploy that declared an\n * allowlist.\n *\n * @returns the original fetch, for the engine's own use.\n */\nexport function installEgressFence(policy: EgressPolicy): typeof fetch {\n const original = globalThis.fetch.bind(globalThis);\n const declared = policy.allow.length > 0;\n const platform = (policy.alwaysAllow ?? []).map((h) => h.toLowerCase()).filter(Boolean);\n\n if (!declared && policy.whenUndeclared === \"allow\") return original;\n\n const fenced: typeof fetch = async (input, init) => {\n const url =\n typeof input === \"string\"\n ? new URL(input)\n : input instanceof URL\n ? input\n : new URL((input as Request).url);\n\n // The backend's own platform first — internal traffic is not egress.\n if (platform.includes(url.hostname.toLowerCase())) return original(input, init);\n\n if (!declared || !hostAllowed(url.hostname, policy.allow)) {\n throw new Error(\n `egress denied: ${url.hostname} is not in this backend's declared allowlist. ` +\n `Add it to config/egress.ts and deploy.`,\n );\n }\n if (policy.timeoutMs > 0) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), policy.timeoutMs);\n try {\n return await original(input, { ...init, signal: init?.signal ?? controller.signal });\n } finally {\n clearTimeout(timer);\n }\n }\n return original(input, init);\n };\n\n globalThis.fetch = fenced;\n return original;\n}\n"],"mappings":"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","names":["resolveTx","reason","reason"]}