@palbase/backend 28.0.0 → 29.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/palbase-backend.cjs +151 -12
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +3 -3
- package/dist/{chunk-75YROPRZ.js → chunk-DHJ3SYAE.js} +152 -15
- package/dist/chunk-DHJ3SYAE.js.map +1 -0
- package/dist/{chunk-IVZERLTM.js → chunk-ENZ2RFFJ.js} +2 -2
- package/dist/{chunk-RVP6BTEZ.js → chunk-ESSQ3YML.js} +13 -4
- package/dist/chunk-ESSQ3YML.js.map +1 -0
- package/dist/{chunk-SNDXY565.js → chunk-SG4UTNOP.js} +5 -2
- package/dist/chunk-SG4UTNOP.js.map +1 -0
- package/dist/db/index.cjs +4 -1
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +2 -2
- package/dist/engine/index.cjs +151 -12
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +3 -3
- package/dist/engine/index.d.ts +3 -3
- package/dist/engine/index.js +3 -3
- package/dist/{index-dTTLlHIn.d.ts → index-BOe82fsK.d.ts} +162 -8
- package/dist/{index-BbvOoZFr.d.ts → index-BYDUKexK.d.ts} +29 -7
- package/dist/{index-9C3JHxg-.d.cts → index-BZfmdRmh.d.cts} +29 -7
- package/dist/{index-DtISj9QX.d.cts → index-ChvoVczS.d.cts} +162 -8
- package/dist/index.cjs +15 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -3
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/{registry-qIPM5BQe.d.cts → registry-B2KfKWv1.d.cts} +1 -1
- package/dist/{registry-JQNIX-eA.d.ts → registry-DaqHsOq8.d.ts} +1 -1
- package/dist/test/index.cjs +56 -0
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +56 -0
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +49 -0
- package/docs/llms-full.txt +50 -1
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/dist/chunk-75YROPRZ.js.map +0 -1
- package/dist/chunk-RVP6BTEZ.js.map +0 -1
- package/dist/chunk-SNDXY565.js.map +0 -1
- /package/dist/{chunk-IVZERLTM.js.map → chunk-ENZ2RFFJ.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime.ts","../src/refusals.ts","../src/db/env-gen.ts","../src/decorators/injectable.ts","../src/decorators/kinds.ts","../src/decorators/module.ts","../src/container.ts"],"sourcesContent":["/**\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 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\";\nimport { withRetry } from \"./db/typed-db.js\";\nimport { qualifiedTableKey } from \"./db/schema-json.js\";\nimport type { DollarOps } from \"./db/typed-db.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. */\nexport interface 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 // DÖRDÜNCÜ FİİL, aynı gerekçeyle: tip söz veriyor, ops katmanı\n // uyguluyor, ve bir handler'ın gerçekten dokunduğu yer BURASI.\n // `runtime-table-verbs` kapısı bunu adıyla saydı.\n insertMany: (\n rows: readonly Record<string, unknown>[],\n opts?: { onConflict: readonly string[]; action?: \"ignore\" | \"update\" },\n ) => ops().insertMany(name, rows, opts),\n update: (q: { where: { id: string }; set: Record<string, unknown> }) =>\n ops().update(name, q.where.id, q.set),\n delete: (id: string) => ops().delete(name, id),\n findById: (id: string) => ops().findById(name, id),\n findMany: (q?: Record<string, unknown>) => {\n // `where` AYIKLANIR; kalan alanlar (orderBy/limit/offset) ham op'un\n // ikinci parametresine gider. Tümünü geçirmek `where`'i tel üstünde\n // ikinci kez gönderirdi — `typed-db.test.ts` bunu yakalıyor.\n const { where, ...opts } = q ?? {};\n return ops().findMany(\n name,\n where as Record<string, unknown> | undefined,\n opts as Parameters<DBOps[\"findMany\"]>[2],\n );\n },\n put: (q: { data: Record<string, unknown>; onConflict: readonly string[] }) =>\n ops().put(name, q.data, { onConflict: q.onConflict }),\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: (q: { where: Record<string, unknown>; set: Record<string, unknown> }) =>\n ops().updateMany(name, q.where, q.set),\n deleteMany: (q: { where: Record<string, unknown> }) => ops().deleteMany(name, q.where),\n count: (q?: { where?: Record<string, unknown> }) => ops().count(name, q?.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 claim: (unique: Record<string, unknown>, extra?: Record<string, unknown>) =>\n ops().claim(name, unique, extra),\n };\n },\n },\n );\n}\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 // `$` ÖNEKİ AÇIKÇA YAZILIR, dinamik üretilmez.\n //\n // Bir tur `Object.fromEntries(Object.entries(ops).map(…))` ile üretilmişti ve\n // `database.test.ts`'in sayımı onu göremedi: sayım DEKLARASYONLARI okuyor,\n // string literal'leri değil. Görünmeyen bir yüzey denetlenemez — ve o testin\n // varlık sebebi tam olarak budur (FR-044: yüzeyde bağlantı bilgisi olmadığını\n // kanıtlamak, ama önce yüzeye gerçekten ULAŞTIĞINI kanıtlamak).\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 $put: (table: string, data: Record<string, unknown>, opts: { onConflict: readonly string[] }) =>\n raw.put(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 $claim: (table: string, unique: Record<string, unknown>, extra?: Record<string, unknown>) =>\n reco.claim(table, unique, extra),\n $lockRows: (table: string, ids: readonly string[]) => reco.lockRows(table, ids),\n $advisoryXactLock: (key: string) => reco.advisoryXactLock(key),\n $insertMany: (\n table: string,\n rows: readonly Record<string, unknown>[],\n opts?: { onConflict: readonly string[]; action?: \"ignore\" | \"update\" },\n ) => raw.insertMany(table, rows, opts),\n $supersede: (table: string, id: string, row: Record<string, unknown>) =>\n raw.supersede(table, id, row),\n } satisfies DollarOps<Omit<DBOps & RecoOps, \"attempt\">>;\n // `ops` DOĞRUDAN verilir, spread edilmez: sayım (`database.test.ts`) nesneyi\n // deklarasyonundan takip ediyor ve bir spread onu kaybettiriyor. Görünmeyen\n // yüzey denetlenemez.\n const base = Object.assign(ops as unknown as Record<string, unknown>, {\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 $transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n opts?: { retry?: number },\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 //\n // Retry de HER DENEMEDE taze bir builder istiyor (FR-037): önceki denemenin\n // op'ları planda kalsaydı ikinci deneme birincinin yazmalarını TEKRAR\n // gönderirdi. Bu yüzden builder döngünün İÇİNDE kuruluyor.\n return withRetry(() => {\n const builder = new TxPlanBuilder();\n return runTxPlan(raw, makeTxPlanHandle(builder), builder, fn) as Promise<\n Materialized<T>\n >;\n }, opts ?? {}) as Promise<Materialized<T>>;\n },\n });\n // ŞEMA ERİŞİMİ BİR PROXY'DİR, çünkü hangi şemaların bildirildiğini yalnız TİP\n // bilir — runtime'da `Database.billing` diye bir üye yoktur, o ada dokunulduğu\n // anda üretilir. `$`'la başlamayan her ad bir ŞEMA adıdır; ayrım tam olarak\n // budur ve tip tarafındaki DollarOps ile aynı kuralı uygular.\n return new Proxy(base, {\n get(target, prop, receiver) {\n // `tables` DOĞRUDAN YÜZEYDE DE public'in takma adı.\n //\n // Plan tutamağı `tx.tables.todos`'u öğretiyor (göç notu da öyle), ama\n // `Database.tables.todos` aynı kelimeyi ADI `tables` OLAN BİR ŞEMA sanıp\n // tele `tables.todos` yazıyordu. Tip onu reddettiği için derlenen kodda\n // erişilemezdi — ama `as any` ya da düz JS ile geçen biri sessizce\n // olmayan bir şemaya gidiyordu, ve iki yüzeyin aynı kelimeye zıt cevap\n // vermesi bu run'ın kapattığı sınıfın kendisi (gözcü M-6).\n if (prop === \"tables\") return makeTableProxy(() => reco, \"\");\n if (typeof prop === \"string\" && !prop.startsWith(\"$\") && !(prop in target)) {\n // Nitelikli tablo anahtarının kuralı BURADA TEKRARLANMAZ (FR-058): tek\n // yazıcı `qualifiedTableKey` ve `table-key-single-source.test.ts` ikinci\n // bir yazıcıyı reddediyor. Prefix ondan türetilir — boş tablo adıyla\n // çağrıldığında geriye ya \"\" (public) ya \"<şema>.\" kalır.\n return makeTableProxy(() => reco, qualifiedTableKey(prop, \"\"));\n }\n return Reflect.get(target, prop, receiver);\n },\n }) as unknown as EnvServiceDatabase;\n}\n\n/**\n * `makeTableProxy`'nin plan ikizi: `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, prefix = \"\"): 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(prefix + prop);\n },\n },\n );\n return tablesProxy as TxTables;\n}\n\n/**\n * Plan tutamağı — `Database` ile AYNI şekil: `tx.public.x`, `tx.<şema>.x`, ve\n * geriye dönük `tx.tables.x`.\n *\n * Şema adı tablo adının ÖNÜNE geçiyor (`billing.invoices`), tıpkı doğrudan\n * yüzeyin `makeTypedSurface` proxy'sinin yaptığı gibi — ve motor artık onu\n * `quoteTable` ile İKİ parça hâlinde tırnaklıyor. Bu ikisi olmadan `billing`\n * şemasındaki iki tabloyu tek atomik planda yazmak imkânsızdı.\n *\n * `tables` ve `public` DIŞINDAKİ HER ad şema kabul edilir ve altındaki tablolar\n * `<ad>.<tablo>` diye adlanır. Yanlış bir şema adı TİPTE yakalanıyor\n * (`keyof Schemas`) — `tx.constructor.x` ve `tx.toString.x` dahil, ölçüldü.\n *\n * TİPTEN KAÇAN bir ad için savunma `quoteTable`'ın KAÇIŞIDIR, başka bir şey\n * değil: `runPlanOp` `op.table`'ı doğrulamadan ona veriyor ve `quoteTable`\n * tırnak ikizleyerek tek bir tanımlayıcı üretiyor. Ölçüldü: `a\"; DROP TABLE t; --`\n * → `\"a\"\"; DROP TABLE t; --\"`, yani enjeksiyon değil, `relation does not exist`.\n * (Bu yorum bir zamanlar `validateSchemaIdentifier`'a atıf yapıyordu — o\n * fonksiyon Go tarafında yaşıyor ve BU yolu hiç görmüyor; gözcü yakaladı.)\n */\nfunction makeTxPlanHandle(builder: TxPlanBuilder): TxPlan {\n const publicTables = makeTxTablesAccessor(builder);\n return new Proxy(\n {},\n {\n get(_t, prop: string | symbol) {\n if (typeof prop !== \"string\") return undefined;\n if (prop === \"tables\") return publicTables;\n // ÖNEK TEK YAZICIDAN (FR-058): `qualifiedTableKey`. Bu kuralı burada\n // elle yazmıştım — public'i çıplak bırakıp diğerine nokta ekleyen bir\n // if/return çifti — ve FR-058 kapısı onu GÖRMEDİ, çünkü kapı yalnız\n // ternary arıyordu. (Kural burada KELİMEYLE anlatılıyor, kod biçiminde\n // DEĞİL: kapı metni tarıyor ve bir yorumdaki kopya da onu tetikler.)\n // İkinci bir yazıcı, kapının var olma sebebi olan sınıfın kendisi:\n // `env-gen.ts`'in kendi kopyası bir public FK'yi başka bir şemanın\n // tablosuna etiketlemişti ve hiçbir şey bunu söylememişti.\n // Boş tablo adıyla çağrılınca geriye ya \"\" (public) ya \"<şema>.\" kalır.\n return makeTxTablesAccessor(builder, qualifiedTableKey(prop, \"\"));\n },\n },\n ) as TxPlan;\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.public.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().public.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}) as unknown as EnvTypedDatabase;\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 * The two ways a stack refuses to boot — and they are two because their CURES\n * are two.\n *\n * A LEAF MODULE ON PURPOSE. `db/` does not import from `engine/` and must not\n * start: the schema layer is below the engine, and a refusal both of them raise\n * cannot live in either. Anything imported here would invert that.\n *\n * WHY THE SPLIT EXISTS AT ALL — measured live on 2026-09-04.\n *\n * `8qitbtucm` ran for days on an image whose `setSchema` did not build\n * relations. Moved onto one that does, the same artifact hit\n * `buildRelations` at boot, threw a bare `Error`, and the runtime — which waits\n * only on its own `ArtifactRefused` — treated it as fatal. The supervisor took\n * the pod down, palsvc with it. CrashLoopBackOff, back-off 5m, and palsvc is\n * THE PROCESS THAT ACCEPTS THE PUSH the message asks for.\n *\n * That is verbatim the lesson `v2/runtime/src/loader.ts` already carries for\n * ABI refusals: *\"the cure was named in the error and made impossible by the\n * exit that carried it.\"* It cost a tenant a third time because the second\n * refusal had no type to be recognised by.\n *\n * SO THE RULE IS THE CURE, NOT THE SEVERITY:\n *\n * {@link DeclarationRefused} — what was PUSHED cannot be built. Restarting\n * re-reads the same bytes and fails identically; only a new artifact\n * changes the answer. The runtime WAITS on this, keeps palsvc alive, and\n * says the reason out loud.\n *\n * {@link BootRefused} — the ENVIRONMENT this stack was handed is unusable\n * (no DATABASE_URL, an unparseable PORT, no SQL driver). No push fixes it;\n * waiting for one would be a lie told in a log line forever. Stays fatal.\n *\n * NOT A MESSAGE PATTERN. The runtime's loader already says why: *\"The\n * distinction is the loader's TYPE, not a pattern over its wording.\"* A gate\n * that reads wording drifts from the thing it claims to measure the first time\n * someone improves an error message.\n */\n\n/**\n * The tag that survives a realm boundary.\n *\n * `instanceof` compares constructor identity, and identity is per module\n * instance. In the pod today the runtime and the bundle share one install\n * (measured: both frames resolve to `/app/node_modules/@palbase/backend`), so\n * `instanceof` would work — but it works by a coincidence of packaging, and a\n * bundle that ever carries its own copy would make every declaration refusal\n * silently fatal again. `Symbol.for` reads from the process-wide registry, so\n * the tag means the same thing in every copy.\n *\n * Exported so the runtime can recognise the refusal without importing the\n * class — see {@link isDeclarationRefused}.\n */\nexport const DECLARATION_REFUSAL = Symbol.for(\"palbase.backend.declarationRefusal\");\n\n/**\n * What was pushed cannot be built. The cure is a NEW ARTIFACT.\n *\n * Thrown by the declaration layer — relation naming, ownership, entry points —\n * wherever a fact about the author's code makes the app impossible to\n * construct. Never thrown for anything the environment could change.\n */\nexport class DeclarationRefused extends Error {\n /** @see DECLARATION_REFUSAL — realm-safe, unlike `instanceof`. */\n readonly [DECLARATION_REFUSAL] = true as const;\n\n constructor(message: string) {\n super(message);\n this.name = \"DeclarationRefused\";\n }\n}\n\n/**\n * True for a refusal whose only cure is a new artifact — across realms.\n *\n * Takes `unknown` because every caller is a `catch`. A non-object, a null, a\n * plain `Error`: all false, and false is the safe answer — it means \"keep\n * treating this as fatal\", which is what the code did before this type existed.\n */\nexport function isDeclarationRefused(e: unknown): e is DeclarationRefused {\n return typeof e === \"object\" && e !== null && (e as Record<symbol, unknown>)[DECLARATION_REFUSAL] === true;\n}\n","/**\n * env-gen.ts — generate the `palbase-env.d.ts` text from a `defineSchema()`\n * result.\n *\n * The CLI (`palbase build`) and the deploy pipeline call\n * {@link makeEnvDts} with the project's schema and write the returned string to\n * `palbase-env.d.ts` at the project root. That file AUGMENTS the\n * `@palbase/backend/env` `Tables` interface (controlled global augmentation,\n * C5) so `Database.public.<name>` is typed with no import and no generic.\n *\n * The output is FLAT: each table gets a `{ row: {...}; insert: {...} }` entry\n * with plain TypeScript object types. The phantom `ColumnBuilder<...>` type\n * NEVER appears in the generated `.d.ts` — that type only lives at authoring\n * time inside the project's `db/*.ts` schema files.\n */\nimport { DeclarationRefused } from \"../refusals.js\";\n\nimport type { ColumnDef } from \"./columns.js\";\n// FR-058: the \"public is bare, everything else is qualified\" rule lives in ONE\n// helper. This file used to carry two more copies of it — a module-level\n// `qualify` and a second, identical local one inside `makeEnvDts` — and the\n// duplication was not cosmetic: re-deriving the key here instead of reading the\n// one `resolveReferences` already wrote is exactly how a public foreign key got\n// relabelled onto another schema's table. Two names for one truth are two\n// interpreters of it.\nimport { qualifiedTableKey } from \"./schema-json.js\";\nimport type { SchemaDef, TableDef } from \"./schema.js\";\n\n/** The TypeScript value type for a column, ignoring nullability (added by the\n * caller). Mirrors the `ColValue` mapped type in columns.ts exactly. */\nfunction baseTsType(def: ColumnDef): string {\n switch (def.type) {\n case \"uuid\":\n case \"text\":\n case \"timestamp\":\n return \"string\";\n case \"integer\":\n return \"number\";\n // Both are exact-precision in Postgres and lossy as a JSON number, so the\n // database proxy serializes them as strings — measured: 9007199254740993\n // used to arrive as ...992 and 41.00821234567890123 as 41.0082123456789.\n // numeric had no case at all and fell through to `unknown`, which typed\n // every numeric column out of existence.\n case \"bigint\":\n case \"numeric\":\n return \"string\";\n case \"boolean\":\n return \"boolean\";\n case \"jsonb\":\n return \"unknown\";\n // FR-008: the authoring type of a pgvector column. The default `unknown`\n // branch below STAYS — an unknown wire type is refused on the Go side\n // (FR-005), never papered over here.\n case \"vector\":\n return \"number[]\";\n case \"enum\": {\n const values = def.enumValues ?? [];\n if (values.length === 0) return \"string\";\n return values.map((v) => JSON.stringify(v)).join(\" | \");\n }\n default:\n return \"unknown\";\n }\n}\n\n/** The full row type for a column: base type, `| null` when nullable. */\n/**\n * Kolonun POSTGRES tipi, tipin İÇİNDE taşınan bir marka olarak.\n *\n * TypeScript `numeric`, `bigint`, `text`, `uuid` ve `timestamp`'i tek bir\n * `string`'e düşürüyor. Yani `integer ↔ numeric` (Postgres'te geçerli) ile\n * `integer ↔ text` (geçersiz) tipte AYNI görünüyordu ve `col()` hangi kuralı\n * koyarsa koysun bir tarafta yanılıyordu (D-021: yanlış ret mi yanlış kabul mü\n * seçilecekti — ikisi de yanlıştı).\n *\n * Marka o bilgiyi geri getiriyor. `& { readonly __pg?: \"…\" }` seçilmesinin\n * nedeni ÖLÇÜLDÜ: isteğe bağlı bir alanla kesişim, satırı hâlâ düz `string`\n * olarak okunabilir ve düz bir değerle YAZILABİLİR bırakıyor — yani marka\n * yalnız karşılaştırma kurallarının gördüğü, kullanıcının hiç görmediği bir\n * bilgi. Zorunlu bir alan olsaydı `{ balance: \"10.00\" }` derlenmezdi.\n *\n * `enum` KİMLİĞİYLE markalanıyor: iki FARKLI enum'u Postgres de karşılaştırmaz,\n * ve düz `\"enum\"` markası onları aynı sayardı.\n */\nfunction pgBrand(def: ColumnDef): string {\n if (def.type === \"enum\") {\n const values = [...(def.enumValues ?? [])].sort();\n return values.length === 0 ? \"enum\" : `enum:${values.join(\"|\")}`;\n }\n return def.type;\n}\n\nfunction rowType(def: ColumnDef): string {\n const base = baseTsType(def);\n // `unknown` MARKALANAMAZ: marka bir kesişim ve `unknown & X` doğrudan `X`'e\n // çöker. `jsonb` kolonu `Pg<unknown, \"jsonb\">` yazılınca tipi\n // `{ readonly __pg?: \"jsonb\" }` oluyordu — yani kolon DARALDI ve meşru bir\n // nesne yazılamaz hâle geldi. GERÇEK bir projede ölçüldü: 33 tablolu bir\n // şemada `user_preferences`'ın jsonb kolonlarına yazan iki çağrı kırıldı.\n //\n // Markasız kalan kolon eski (gevşek) kurala düşer — jsonb için bu zaten\n // bugünkü davranış, yani hiçbir şey kötüleşmiyor.\n if (base === \"unknown\") return def.nullable ? `${base} | null` : base;\n // Takma ad, ham kesişim yerine: bu dosyayı GELİŞTİRİCİ de açıyor ve\n // `(string) & { readonly __pg?: \"uuid\" }` satırları okunmaz kılıyordu.\n // `Pg<string, \"uuid\">` hem kısa hem kolonun Postgres tipini SÖYLÜYOR.\n // Takma ad ayrıca `enum` birleşimlerini tip argümanı olarak sarmalıyor —\n // ham kesişimde `A | B & C`, `A | (B & C)` diye ayrışıp bir dalı markasız\n // bırakırdı.\n const branded = `Pg<${base}, ${JSON.stringify(pgBrand(def))}>`;\n return def.nullable ? `${branded} | null` : branded;\n}\n\n/** True when a column may be omitted on INSERT — nullable OR has any default.\n * Mirrors `ColIsOptionalOnInsert` in columns.ts. */\nfunction optionalOnInsert(def: ColumnDef): boolean {\n return (\n def.nullable === true ||\n def.defaultRandom === true ||\n def.defaultNow === true ||\n def.defaultValue !== undefined\n );\n}\n\n\n\nexport type Relation = {\n name: string;\n to: string;\n kind: \"one\" | \"many\";\n /**\n * The foreign-key COLUMN the relation runs through.\n *\n * Without it \"there is a relation\" is half the fact, and everything that\n * consumes the map — the query builder, the seed engine, the cross-boundary\n * lock — has to re-derive the column: a second interpreter of the same graph.\n */\n via: string;\n};\n\n/** `list_id` → `list`; anything else keeps its column name (FR-019). */\nfunction forwardName(column: string): string {\n return column.endsWith(\"_id\") ? column.slice(0, -3) : column;\n}\n\n/**\n * Where a relation name came from, so a refusal can say it out loud.\n *\n * A collision on a parent table can be between two REVERSE edges, or between a\n * reverse edge and the parent's own FORWARD one — `lists.todos_id` names a\n * forward `todos`, and `todos.list_id` reverses onto `lists` as `todos` too.\n * The old message called both sides \"reverse relations\", which sent the reader\n * looking for a second reverse edge that was never there.\n */\ntype NameOrigin = {\n /** The table the foreign-key COLUMN is declared on. */\n table: string;\n column: string;\n direction: \"forward\" | \"reverse\";\n def: ColumnDef;\n};\n\nfunction describeOrigin(o: NameOrigin): string {\n return o.direction === \"forward\"\n ? `the foreign key \"${o.table}.${o.column}\"`\n : `the reverse of \"${o.table}.${o.column}\"`;\n}\n\n/**\n * The call that renames THIS relation — named per verb, because the verbs do\n * not take the same options.\n *\n * NFR-002 asks every refusal to name a remedy the reader can apply. The old\n * message said `references(() => …, { as: \"…\" })` for every case, and\n * `ownedByUser()` takes no arguments at all while `userRef` /\n * `installationRef` take `{ onDelete, as }` — so following it literally was\n * impossible for exactly the columns that most often collide.\n *\n * A reverse edge only ever exists for a target that is a DECLARED table, and\n * only `references()` can point at one: `auth.*` is not declared (no reverse\n * edge) and a self-reference has no separate parent (skipped). So the reverse\n * remedy has one form and it is always the right one.\n */\nfunction renameCall(o: NameOrigin): string {\n if (o.direction === \"reverse\") return `references(() => …, { reverseAs: \"…\" })`;\n if (o.def.owns === true) {\n return `ownedByUser() takes no { as } — if \"${o.column}\" only POINTS at a user, declare it userRef({ onDelete: … }) instead`;\n }\n const target = o.def.references?.table;\n if (target === \"auth.users\") return `userRef({ onDelete: …, as: \"…\" })`;\n if (target === \"auth.installations\") return `installationRef({ onDelete: …, as: \"…\" })`;\n if (o.def.selfRefColumn !== undefined) return `selfReferences(\"…\", { as: \"…\" })`;\n return `references(() => …, { as: \"…\" })`;\n}\n\n/**\n * Derive the relation graph from the declared foreign keys.\n *\n * Until now a SECOND foreign key onto the same parent was silently dropped: only\n * the first column in declaration order was recorded, and the other one quietly\n * became an ordinary writable column. Which relation you got was decided by the\n * order somebody happened to type the columns in. That silence is what this\n * function exists to end — ambiguity is rejected and named, never resolved by\n * declaration order.\n *\n * THE HAZARD IS ONE NAME WITH TWO RELATIONS (FR-022), not two foreign keys onto\n * one target. Those are not the same set, and treating them as one refused the\n * package's own documented shape: a table with `ownedByUser()` beside a\n * `userRef()` has two foreign keys onto `auth.users` and no ambiguity whatever —\n * the names are `owner` and the pointing column's own, and `auth.users` is not a\n * declared table, so neither takes a reverse edge to collide over. The gate\n * counted the owner toward the total while exempting it from the naming\n * requirement, so `docs/schema.md`'s example threw, naming a remedy no verb in\n * it accepts.\n *\n * The two directions are named SEPARATELY. `as` sets the forward name (FR-019),\n * `reverseAs` sets the reverse one (FR-020, whose default is the child table's\n * name). One option cannot set both: two children that each name their forward\n * edge `author` collided on the parent as `author`, and the refusal asked for\n * the `{ as }` they had both already written — a refusal with no exit.\n */\nexport function buildRelations(schemas: readonly SchemaDef[]): Map<string, Relation[]> {\n const out = new Map<string, Relation[]>();\n /** Per table key: relation name → where that name came from. */\n const taken = new Map<string, Map<string, NameOrigin>>();\n for (const schema of schemas) {\n for (const t of Object.values(schema.tables)) {\n const key = qualifiedTableKey(schema.name, t.name);\n out.set(key, []);\n taken.set(key, new Map());\n }\n }\n\n /** Record one edge on `tableKey`, or refuse the name it would take twice. */\n const claim = (tableKey: string, name: string, origin: NameOrigin, edge: Relation): void => {\n const names = taken.get(tableKey);\n if (names === undefined) return;\n const held = names.get(name);\n if (held !== undefined) {\n // FR-015 asks this one to LIST the conflicting columns; it used to name\n // neither, so the reader had to find them.\n if (held.def.owns === true && origin.def.owns === true) {\n throw new DeclarationRefused(\n `table \"${tableKey}\" declares TWO owner columns (${held.column}, ${origin.column}) — a table has at most ONE ownedByUser(). If the other column only POINTS at a user, declare it userRef({ onDelete: … }) instead.`,\n );\n }\n const heldFix = renameCall(held);\n const originFix = renameCall(origin);\n const remedy =\n heldFix === originFix\n ? `rename one of them: ${heldFix}`\n : `rename one of them — \"${held.table}.${held.column}\": ${heldFix}; \"${origin.table}.${origin.column}\": ${originFix}`;\n throw new DeclarationRefused(\n `table \"${tableKey}\": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name \"${name}\" — ${remedy}.`,\n );\n }\n names.set(name, origin);\n out.get(tableKey)?.push(edge);\n };\n\n for (const schema of schemas) {\n for (const table of Object.values(schema.tables)) {\n const childKey = qualifiedTableKey(schema.name, table.name);\n if (!out.has(childKey)) continue;\n\n for (const [col, builder] of Object.entries(table.columns)) {\n const def = builder._def;\n if (def.references === undefined) continue;\n // `references.table` IS the canonical key — `resolveReferences` wrote it\n // with `qualifiedTableKey`, so public is bare and everything else is\n // qualified, `auth.users` included.\n //\n // It used to be re-derived here from a bare-name → key map, which gave a\n // DIFFERENT answer in exactly one case: two schemas declaring the same\n // table name. The map kept whichever was declared LAST, so a public FK\n // was relabelled onto another schema's table and the real parent got no\n // reverse edge — silently, while RefJSON (and therefore the DDL) went on\n // pointing at the right one. The generated type and the database\n // disagreed, and nothing said so.\n const targetKey = def.references.table;\n\n const name = def.owns === true ? \"owner\" : (def.refAs ?? forwardName(col));\n claim(\n childKey,\n name,\n { table: table.name, column: col, direction: \"forward\", def },\n { name, to: targetKey, kind: \"one\", via: col },\n );\n\n // Reverse edge, unless the FK points outside the declared schemas (auth.users)\n // or back at the declaring table (a self-reference has no separate parent).\n if (!out.has(targetKey) || targetKey === childKey) continue;\n // FR-020: the reverse name is the CHILD TABLE's, not the forward name.\n // `as` used to set this too, which both broke FR-020 for a single named\n // FK (`users.author` where `users.posts` was required) and left two\n // children that chose the same forward name with no way to be declared.\n const reverse = def.reverseAs ?? table.name;\n claim(\n targetKey,\n reverse,\n { table: table.name, column: col, direction: \"reverse\", def },\n { name: reverse, to: childKey, kind: \"many\", via: col },\n );\n }\n }\n }\n return out;\n}\n\n\n\n\n/** Emit the `row` / `insert` / `relations` blocks for one table at the given\n * base indentation. */\nfunction tableBlock(table: TableDef, relations: Relation[], indent: string): string {\n const cols = Object.entries(table.columns);\n const rowLines = cols.map(([col, builder]) => {\n return `${indent} ${col}: ${rowType(builder._def)};`;\n });\n const insertLines = cols.map(([col, builder]) => {\n const def = builder._def;\n const opt = optionalOnInsert(def) ? \"?\" : \"\";\n return `${indent} ${col}${opt}: ${rowType(def)};`;\n });\n const relEntries = relations\n .map(\n (r) =>\n `${r.name}: { to: ${JSON.stringify(r.to)}; kind: ${JSON.stringify(r.kind)}; via: ${JSON.stringify(r.via)} }`,\n )\n .join(\"; \");\n return [\n `${indent}${table.name}: {`,\n `${indent} row: {`,\n ...rowLines,\n `${indent} };`,\n `${indent} insert: {`,\n ...insertLines,\n `${indent} };`,\n `${indent} relations: {${relEntries === \"\" ? \"\" : ` ${relEntries} `}};`,\n // searchable: vector kolonu YA DA search beyanı → EnvTypedTable'da search()\n // üyesini açan yapısal bayrak (FR-013). Yokken satır hiç üretilmez ki\n // mevcut şemaların d.ts'i bayt-aynı kalsın.\n ...(cols.some(([, b]) => b._def.type === \"vector\") || table.search !== undefined\n ? [`${indent} searchable: true;`]\n : []),\n // appendOnly (FR-031): EnvTypedTable'ın altı yazma üyesini KALDIRAN yapısal\n // bayrak. `searchable` ile aynı desen ve aynı OMIT disiplini — bayrak yokken\n // satır hiç üretilmez ki mevcut şemaların d.ts'i bayt-aynı kalsın.\n ...(table.appendOnly === true ? [`${indent} appendOnly: true;`] : []),\n `${indent}};`,\n ].join(\"\\n\");\n}\n\n/**\n * Generate the full `palbase-env.d.ts` text for the project's schemas.\n *\n * The emitted file ends in `export {};` — same as `makeStackDts`. Without it the\n * `.d.ts` is a global script, and `declare module \"…\"` there DECLARES an ambient\n * module (shadowing the real one, so every export of `@palbase/backend/env`\n * silently becomes invalid) instead of AUGMENTING it. Measured on a minimal tsc\n * repro: with the line, exit 0; without it, `TS2305: Module '\"…\"' has no\n * exported member`. The line was dropped once in a rewrite and nothing caught\n * it, so `env-gen.test.ts` now gates it directly.\n *\n * @example\n * import { makeEnvDts } from \"@palbase/backend\";\n * import publicSchema from \"./db/public.js\";\n * import billing from \"./db/billing.js\";\n * writeFileSync(\"palbase-env.d.ts\", makeEnvDts([publicSchema, billing]));\n */\nexport function makeEnvDts(schemas: readonly SchemaDef[]): string {\n // No pruning: `relations` is a flat literal map, so it cannot expand into an\n // infinite type the way the old recursive `children` could. Dropping a back-edge\n // here would delete a REAL relation and make the type lie about the schema.\n const relations = buildRelations(schemas);\n\n const publicSchema = schemas.find((s) => s.name === \"public\");\n const others = schemas.filter((s) => s.name !== \"public\");\n\n const publicBlocks = Object.keys(publicSchema?.tables ?? {}).map((name) =>\n tableBlock(publicSchema!.tables[name]!, relations.get(name) ?? [], \" \"),\n );\n const body = publicBlocks.length > 0 ? `\\n${publicBlocks.join(\"\\n\")}\\n ` : \"\";\n\n const schemaBlocks = others.map((schema) => {\n const inner = Object.keys(schema.tables).map((name) =>\n tableBlock(schema.tables[name]!, relations.get(qualifiedTableKey(schema.name, name)) ?? [], \" \"),\n );\n return ` ${schema.name}: {\\n${inner.join(\"\\n\")}\\n };`;\n });\n const schemasBody = schemaBlocks.length > 0 ? `\\n${schemaBlocks.join(\"\\n\")}\\n ` : \"\";\n\n return `// AUTO-GENERATED by @palbase/backend — DO NOT EDIT.\n// Regenerated from db/*.ts by \\`palbase build\\` and by every deploy.\n// Augments the @palbase/backend/env \\`Tables\\` interface so \\`Database.public.*\\`\n// is typed with no import and no generic. Schemas other than \\`public\\` land\n// under \\`Schemas\\`, reached with \\`Database.schema(\"<name>\").tables.*\\`.\n\n/**\n * Kolonun POSTGRES tipini tipte tasiyan marka.\n *\n * __pg ISTEGE BAGLI oldugu icin satir hala duz string/number gibi okunur ve duz\n * bir degerle yazilir — marka yalniz col() ve now() karsilastirma kurallarinin\n * gordugu bir bilgidir. TypeScript numeric, bigint, text, uuid ve timestamp'i\n * tek string'e dusurdugu icin bu bilgi olmadan integer<->numeric (gecerli) ile\n * integer<->text (gecersiz) ayirt edilemiyordu.\n */\ntype Pg<T, N extends string> = T & { readonly __pg?: N };\n\ndeclare module \"@palbase/backend/env\" {\n interface Tables {${body}}\n interface Schemas {${schemasBody}}\n}\n\nexport {};\n`;\n}\n","import { type Token } from \"./module.js\";\n\n/**\n * The slot injectable declarations accumulate in.\n *\n * On `globalThis` under a well-known Symbol for the same reason `DI_MODULES` is\n * (see `module.ts`): a tenant bundle inlines its OWN copy of `@palbase/backend`\n * and the engine that loads it carries another, so a module-local array would\n * have the decorators push into one and the container read the other.\n */\nexport const DI_INJECTABLES: unique symbol = Symbol.for(\n \"palbase.backend.diInjectables\",\n) as never;\n\n/**\n * The marker `@Injectable()` leaves ON the class.\n *\n * Two signals, because two questions are being asked and only one of them can be\n * answered by a list. \"WHICH classes were declared in this build\" needs an\n * enumeration and gets the claimable slot below. \"IS this class decorated\" needs\n * an answer that survives Bun's module cache: a rollback re-imports an artifact\n * whose body does not run again, so the slot comes back empty while the modules\n * still list the same classes. Reading the slot for that question refused a\n * correct app — measured in `engine.test.ts`, where the second `createApp` in\n * one process saw an emptied slot and called every provider undecorated.\n */\nexport const INJECTABLE: unique symbol = Symbol.for(\"palbase.backend.injectable\") as never;\n\n/** Does this class carry `@Injectable()`? Reads the class, not a registry. */\nexport const isInjectable = (c: unknown): boolean =>\n (c as Record<symbol, unknown> | null)?.[INJECTABLE] === true;\n\nfunction slot(): Token[] {\n const g = globalThis as unknown as Record<symbol, Token[] | undefined>;\n return (g[DI_INJECTABLES] ??= []);\n}\n\n/**\n * Marks a class the container can resolve.\n *\n * TWO JOBS, and the first one is why the decorator has to exist at all:\n * TypeScript under `emitDecoratorMetadata` emits `design:paramtypes` for\n * DECORATED classes only. Measured — an undecorated class with the same\n * constructor carries no metadata, and `Reflect.getMetadata` answers\n * `undefined`.\n *\n * The second is being COUNTABLE. Ownership, visibility and permission are still\n * read from a single `@Module` and never from this decorator — recording the\n * class here decides nothing. It only makes \"carries `@Injectable()` and\n * appears in no module\" a question the build can ask, which FR-010 requires it\n * to answer by name. The body was empty until 2026-09-02, and the consequence\n * was measured through the CLI: an `@Injectable()` service in no module built\n * clean, while this file's own comment claimed the build named it.\n */\nexport function Injectable(): ClassDecorator {\n return (target) => {\n (target as unknown as Record<symbol, unknown>)[INJECTABLE] = true;\n slot().push(target as unknown as Token);\n };\n}\n\n/**\n * TAKES the accumulated declarations — it does not read them.\n *\n * Same claim semantics as `__claimModules`, and for the same reason: a\n * candidate bundle is imported into the SAME process as the live app it might\n * replace, so reading would let a candidate be judged against the live app's\n * classes and a discarded candidate would leave its own behind.\n */\nexport function __claimInjectables(): Token[] {\n return slot().splice(0);\n}\n","import type { Container, Token } from \"../container.js\";\n\n/**\n * Which of a container's classes are entry points of each kind.\n *\n * Discovery used to be a DIRECTORY: `jobs/*.ts` was the list of jobs, and\n * `@Job` recorded metadata but registered nothing. That made the file system a\n * second declaration — a class could carry `@Job`, sit outside `jobs/`, and\n * never run; or sit inside it, be listed in no module, and run anyway.\n *\n * Now a module lists it and the decorator says what it is. One declaration\n * answers ownership, and the metadata answers kind. These four predicates are\n * the only place that mapping lives.\n */\nconst JOB = Symbol.for(\"palbase.backend.jobMeta\");\nconst WEBHOOK = Symbol.for(\"palbase.backend.webhookMeta\");\nconst HOOK_BLOCKING = Symbol.for(\"palbase.backend.hookBlocking\");\nconst HOOK_LISTENERS = Symbol.for(\"palbase.backend.webhookEvents\");\nconst ROOM = Symbol.for(\"palbase.backend.room\");\nconst CONTROLLER = Symbol.for(\"palbase.backend.controllerMeta\");\n\nconst has = (c: unknown, s: symbol): boolean =>\n (c as Record<symbol, unknown>)[s] !== undefined;\n\n/**\n * Does this class carry one of the surface decorators?\n *\n * The container asks, because `providers` legitimately holds `@Job`, `@Hook`,\n * `@Webhook` and `@Room` classes alongside `@Injectable()` ones, and the rule it\n * enforces there — a provider must be DECORATED, so it is constructible and its\n * constructor's types were emitted — has to know that. The predicate lives here\n * because this file is the one place the marker symbols are named.\n */\nexport const isEntryPointClass = (c: unknown): boolean =>\n has(c, JOB) || has(c, WEBHOOK) || has(c, ROOM) || has(c, CONTROLLER) ||\n has(c, HOOK_BLOCKING) || has(c, HOOK_LISTENERS);\n\nconst owned = (container: Container): Token[] => [...container.owned];\n\nexport const jobsOf = (container: Container): Token[] => owned(container).filter((c) => has(c, JOB));\n\nexport const webhooksOf = (container: Container): Token[] =>\n owned(container).filter((c) => has(c, WEBHOOK));\n\n/**\n * A hook class carries handler entries and NO class-level marker, so it is\n * recognised by having handlers while being neither a webhook nor a controller.\n * `@On` is shared with `@Webhook`, which is why the webhook marker is what\n * separates them.\n */\nexport const hooksOf = (container: Container): Token[] =>\n owned(container).filter(\n (c) =>\n !has(c, WEBHOOK) &&\n !has(c, CONTROLLER) &&\n (has(c, HOOK_BLOCKING) || has(c, HOOK_LISTENERS)),\n );\n\nexport const roomsOf = (container: Container): Token[] =>\n owned(container).filter((c) => has(c, ROOM));\n\nexport const controllersOf = (container: Container): Token[] =>\n owned(container).filter((c) => has(c, CONTROLLER));\n","/**\n * A class the container can resolve, named by its own constructor.\n *\n * There is NO separate token concept — no strings, no symbols, no `@Inject`.\n * An abstraction is an `abstract class`, which is still a runtime value and so\n * is still a token. `never[]` on the parameters makes a token something you can\n * NAME but not call: `Token` is an identity, not a factory.\n */\nexport type Token<T = unknown> = abstract new (...args: never[]) => T;\n\n/**\n * The four lists a module declares.\n *\n * `providers` is OWNERSHIP — a class belongs to exactly one module and this is\n * where that is said. `exports` is VISIBILITY — what other modules may reach.\n * `imports` is PERMISSION — whose exports this module may reach. `controllers`\n * are the entry points the module owns.\n *\n * Position in a list means nothing; ownership is read from this declaration and\n * from nowhere else — not from a directory, not from a file name, not from the\n * class's own decorator (spec FR-009).\n */\nexport interface ModuleDef {\n imports?: Token[];\n controllers?: Token[];\n providers?: Token[];\n exports?: Token[];\n}\n\n/**\n * The slot module declarations accumulate in.\n *\n * On `globalThis` under a well-known Symbol, for the same reason\n * `lifecycleHooks` is (runtime.ts:210): a tenant bundle inlines its OWN copy of\n * `@palbase/backend`, and the engine that loads it carries another. Two\n * module-local arrays would mean the engine reads the empty one — decorators\n * push into the bundle's copy, `createApp` claims from the engine's, and every\n * module silently disappears.\n */\nexport const DI_MODULES: unique symbol = Symbol.for(\"palbase.backend.diModules\") as never;\n\n/** One `@Module` declaration: the class that carried it, and what it declared. */\nexport interface ModuleEntry {\n mod: Token;\n def: ModuleDef;\n}\n\nfunction slot(): ModuleEntry[] {\n const g = globalThis as unknown as Record<symbol, ModuleEntry[] | undefined>;\n return (g[DI_MODULES] ??= []);\n}\n\n/**\n * Declares a module.\n *\n * There is no root module and nothing to mount it into: registration IS the\n * decorator running, which happens when the file is imported. A project with no\n * module file at all is not an error — it simply owns nothing, and every entry\n * point it declares is refused by name (FR-035) rather than quietly served.\n */\nexport function Module(def: ModuleDef): ClassDecorator {\n return (target) => {\n slot().push({ mod: target as unknown as Token, def });\n };\n}\n\n/**\n * TAKES the accumulated declarations — it does not read them.\n *\n * Same reason `__runStartHooks` splices (runtime.ts:297): a candidate bundle is\n * imported into the SAME process as the live app it might replace. Reading\n * would let the candidate build a container out of the live app's modules, and\n * a discarded candidate would leave its own behind for the next release to\n * adopt. Claiming makes each `createApp` see exactly the modules imported since\n * the last one, and a rollback leave nothing behind.\n */\nexport function __claimModules(): ModuleEntry[] {\n return slot().splice(0);\n}\n","import \"reflect-metadata\";\n\nimport { DECLARATION_REFUSAL } from \"./refusals.js\";\n\nimport { __claimInjectables, isInjectable } from \"./decorators/injectable.js\";\nimport { isEntryPointClass } from \"./decorators/kinds.js\";\nimport { __claimModules, type ModuleDef, type Token } from \"./decorators/module.js\";\n\n/**\n * `Token` is born in `decorators/module.ts` — the atom of a module's lists — and\n * re-exported here so a reader meets it on the container's surface too. ONE\n * definition: two would be two `abstract new (...)` signatures free to drift.\n */\nexport type { Token };\n\n/**\n * How a container refuses.\n *\n * Every refusal is one of these, and every one names the class involved. There\n * is deliberately no \"unknown\" member: a failure this list cannot classify is a\n * failure the error surface has not been taught to explain, and that is a defect\n * rather than a category.\n */\nexport type DiKind =\n | \"unresolvable dependency\"\n | \"private dependency\"\n | \"missing import\"\n | \"unowned class\"\n | \"dependency cycle\"\n | \"metadata missing\"\n | \"generic dependency\"\n | \"duplicate ownership\"\n | \"unknown export\"\n | \"unknown import\"\n | \"undeclared provider\";\n\n/**\n * A refusal carries four parts: what kind, the full resolution path, where\n * exactly, and what to do about it.\n *\n * The shape is borrowed on purpose — Angular's path, Awilix's failure kind, and\n * Nest's list of potential solutions — because each of the three answers a\n * question the other two leave open: what broke, where in the graph, and what\n * the author should type next.\n */\nexport class DiError extends Error {\n /**\n * EVERY `DiKind` IS A FACT ABOUT THE AUTHOR'S DECLARATIONS — an unresolvable\n * dependency, a cycle, a class no module owns. Not one of them is something\n * the environment could change, so restarting re-reads the same bytes and\n * fails identically. The cure is a new artifact, and the tag is how the\n * runtime learns that without matching on wording.\n */\n readonly [DECLARATION_REFUSAL] = true as const;\n\n constructor(\n readonly kind: DiKind,\n readonly path: string[],\n readonly at: string,\n detail: string,\n readonly fixes: string[],\n ) {\n super(\n `\\nKind: ${kind}\\n` +\n `Path: ${path.length > 0 ? path.join(\" -> \") : \"(none)\"}\\n` +\n `At: ${at}\\n` +\n `${detail}\\n\\n` +\n `Potential solutions:\\n${fixes.map((f) => ` - ${f}`).join(\"\\n\")}\\n`,\n );\n this.name = \"DiError\";\n }\n}\n\n/** How often a module appears in the OTHERS' `imports`. */\nexport interface ModulePressure {\n module: string;\n pct: number;\n /**\n * How many OTHER modules there were — the denominator.\n *\n * Without it the percentage cannot be read. Measured 2026-09-02: a project\n * with two modules, one importing the other, reports 100% — which is true and\n * says nothing, because \"all of the others\" is one module. A reader deciding\n * whether a module has become ambient needs to know whether 80% was four\n * modules or one.\n */\n of: number;\n}\n\nexport interface Container {\n get<T>(t: Token<T>): T;\n /** Every class a module claimed — the set an entry point must be in. */\n readonly owned: ReadonlySet<Token>;\n /**\n * Where `@Global()` pressure is accumulating.\n *\n * A module that appears in more than ~80% of the others' `imports` is one the\n * design is asking to be ambient. That is a JUDGEMENT — how much sharing is\n * too much depends on the domain — so this is reported as a number and never\n * enforced as a gate. Lives on the container rather than in a module-level\n * variable: the runtime builds a candidate's container beside the live app's,\n * and a shared variable would have one overwrite the other's report.\n */\n readonly pressure: readonly ModulePressure[];\n}\n\nconst nameOf = (c: unknown): string => (c as { name?: string } | null)?.name ?? String(c);\n\n/**\n * Values a transpiler emits when a parameter's type has no runtime class.\n *\n * `Object` is the sentinel — an interface, a type alias and a union all collapse\n * to it — and that it is DISTINGUISHABLE from a real class is what lets the\n * container refuse loudly instead of injecting something arbitrary. The\n * primitives are here for the same reason: they are runtime values, so a naive\n * check would happily try to `new` them.\n */\nconst UNRESOLVABLE = new Set<unknown>([\n Object,\n Function,\n String,\n Number,\n Boolean,\n Array,\n Symbol,\n Promise,\n Date,\n undefined,\n null,\n]);\n\n/** The subset worth naming separately: these say \"you passed DATA\" (FR-036). */\nconst DATA = new Set<unknown>([String, Number, Boolean, Date, Symbol]);\n\n/**\n * Does this class SAY what its constructor asks for?\n *\n * The one predicate for the metadata-against-arity cross-check.\n * `assertZeroArgConstructor` calls this rather than re-deriving it: two copies\n * of the rule are two rules, free to drift the moment one is edited.\n */\nexport function declaresDependencies(ctor: unknown): boolean {\n const arity = (ctor as { length?: number } | null)?.length ?? 0;\n if (arity === 0) return true;\n const meta = Reflect.getMetadata(\"design:paramtypes\", ctor as object) as unknown[] | undefined;\n return meta !== undefined && meta.length === arity;\n}\n\n/**\n * Validates the declared modules and returns a container over them.\n *\n * Validation runs in a fixed order, and the order is the point: each stage may\n * assume the previous one held, so a message never has to hedge. Ownership\n * before exports, exports before dependencies, dependencies before cycles,\n * cycles before construction.\n *\n * Stages 3-5 (dependencies and visibility, cycles, resolution) are added by the\n * tasks that follow; this file grows, it is not replaced.\n */\nexport function buildContainer(): Container {\n // CLAIMS the declarations rather than reading them — see `__claimModules`.\n const entries = __claimModules();\n // Claimed HERE even when the graph is about to be refused below, so a failed\n // build cannot leave a previous import's classes for the next one to inherit.\n const declared = __claimInjectables();\n\n // 0 · a project declares at least one module.\n //\n // There is no implicit module. An implicit one would be a SECOND way for a\n // class to become owned, and the whole design rests on there being one: read\n // the module, know the answer.\n if (entries.length === 0) {\n throw new DiError(\n \"unowned class\",\n [],\n \"project\",\n \"no module was declared — every project declares at least one @Module.\",\n [\n \"create `<domain>.module.ts` with @Module({ controllers: [...], providers: [...] })\",\n \"`palbase init` scaffolds one for you\",\n ],\n );\n }\n\n // 1 · ownership — a class belongs to at most one module.\n //\n // `providers` and `controllers` share ONE namespace: a class is owned or it is\n // not, and being listed as both would make \"which module owns it\" a question\n // with two answers.\n const declaredModules = new Set<Token>(entries.map((e) => e.mod));\n\n const owner = new Map<Token, string>();\n for (const { mod, def } of entries) {\n const m = nameOf(mod);\n for (const c of [...(def.providers ?? []), ...(def.controllers ?? [])]) {\n const prev = owner.get(c);\n if (prev !== undefined) {\n throw new DiError(\n \"duplicate ownership\",\n [nameOf(c)],\n `${prev} & ${m}`,\n `${nameOf(c)} is listed by two modules, so which one owns it has two answers.`,\n [\n `remove ${nameOf(c)} from ${prev}`,\n `or remove it from ${m}`,\n `if both modules need it, keep ONE owner and export it, then import that module`,\n ],\n );\n }\n owner.set(c, m);\n }\n }\n\n // 1a · every provider is a class the container can actually BUILD.\n //\n // Measured 02.09.2026: a module that listed an `abstract class` in its\n // `providers` got `new Clock()` — which succeeds in JavaScript and returns an\n // object missing every abstract member — injected into everything that asked\n // for it, and the failure surfaced mid-request as `c.now is not a function`.\n // FR-055 already refuses that shape when the abstraction is named as a\n // DEPENDENCY; this is the same defect coming in through the other door, and\n // the SDK's own test asserted the broken shape was legal.\n //\n // The signal is the decorator. An abstraction in this design is an UNDECORATED\n // `abstract class` (the scaffold's `NoteRepo`), and an implementation carries\n // `@Injectable()`; surfaces carry `@Job`/`@Hook`/`@Webhook`/`@Room`. So a\n // provider carrying none of them is either an abstraction listed in the wrong\n // place or a class somebody forgot to decorate — and the second is not benign\n // either: without a decorator TypeScript emits no `design:paramtypes`, so\n // every constructor parameter it asks for would arrive `undefined`.\n {\n for (const { mod, def } of entries) {\n for (const p of def.providers ?? []) {\n if (isInjectable(p) || isEntryPointClass(p)) continue;\n // A class whose constructor ASKS for something but carries no emitted\n // types is a different fault with a better message — `metadata missing`\n // in stage 3, which explains `emitDecoratorMetadata` and the bundler.\n // Leaving it to that stage keeps each refusal pointed at one cause. The\n // abstract seam this rule is for has a zero-argument constructor\n // (`abstract class NoteRepo { abstract findMany(…) }`), so it lands\n // here.\n if (!declaresDependencies(p)) continue;\n throw new DiError(\n \"undeclared provider\",\n [nameOf(mod), nameOf(p)],\n `${nameOf(mod)}.providers`,\n `${nameOf(p)} is listed in ${nameOf(mod)}.providers but carries no decorator, ` +\n `so the container cannot know it is constructible or what its constructor asks for.`,\n [\n `mark ${nameOf(p)} \\`@Injectable()\\` if it is a concrete class`,\n `if ${nameOf(p)} is an \\`abstract class\\`, list the class that \\`extends\\` it instead — ` +\n `name the abstraction as the DEPENDENCY and the container resolves it`,\n ],\n );\n }\n }\n }\n\n // 1b · every declared class is OWNED by a module (FR-010).\n //\n // `@Injectable()` decides nothing — ownership is read from a module and from\n // nowhere else — but it makes the class COUNTABLE, and this is the question\n // that needs counting: a service written, imported, and listed in no module.\n // It has no entry point, so `assertNoOrphanEntryPoints` never sees it; it has\n // no dependent, so the resolution stages never reach it. It simply does not\n // exist, silently, which is the one outcome this design refuses everywhere\n // else. Measured through the CLI on 2026-09-02: the build said \"build OK\".\n //\n // Not in `isolated()`: that builds a graph without consulting this file at\n // all, deliberately, because a unit test is not a second opinion about the\n // architecture.\n {\n const orphans = declared.filter((c) => !owner.has(c));\n if (orphans.length > 0) {\n const names = orphans.map(nameOf);\n throw new DiError(\n \"unowned class\",\n names,\n \"module declarations\",\n `${names.join(\", \")} ${orphans.length === 1 ? \"is\" : \"are\"} marked @Injectable() ` +\n `but listed in no module's providers, so nothing can reach ${orphans.length === 1 ? \"it\" : \"them\"}.`,\n [\n `add ${names.length === 1 ? names[0] : \"each of them\"} to a module's \\`providers\\``,\n \"or delete the class — one no module lists is never built\",\n ],\n );\n }\n }\n\n // 2 · exports — a module may only open up what it OWNS.\n //\n // Re-exporting someone else's class would be a hole in the boundary the\n // module system exists to draw: the owner's decision about who may reach it\n // would stop being the owner's.\n const exported = new Map<string, Set<Token>>();\n const importsOf = new Map<string, Set<string>>();\n for (const { mod, def } of entries) {\n const m = nameOf(mod);\n for (const e of def.exports ?? []) {\n if (owner.get(e) !== m) {\n const holder = owner.get(e);\n throw new DiError(\n \"unknown export\",\n [m],\n `${m}.exports`,\n holder === undefined\n ? `${m} exports ${nameOf(e)}, but no module owns it.`\n : `${m} exports ${nameOf(e)}, but ${holder} owns it — a module cannot re-export another's class.`,\n holder === undefined\n ? [`add ${nameOf(e)} to ${m}.providers`, `or remove it from ${m}.exports`]\n : [\n `remove ${nameOf(e)} from ${m}.exports`,\n `and have ${holder} export it instead, then add ${holder} to the importing module's imports`,\n ],\n );\n }\n }\n // An `imports` entry must BE a module. Measured before this check existed:\n // `@Module({ imports: [NotAModule] })` built cleanly and did nothing — the\n // name simply never matched an owner, so every dependency it was meant to\n // unlock kept being refused for a reason that pointed elsewhere.\n for (const i of def.imports ?? []) {\n // Self-import is expressible — legacy decorators run after the class\n // binding exists, so `@Module({ imports: [M] }) class M {}` compiles and\n // ran silently before this check. It grants a module access to its own\n // exports, which it already has, so it is always a typo for another name.\n if (i === mod) {\n throw new DiError(\n \"unknown import\",\n [m],\n `${m}.imports`,\n `${m} imports itself, which grants nothing it does not already have.`,\n [`remove ${m} from its own imports`, \"or name the module you meant instead\"],\n );\n }\n if (!declaredModules.has(i)) {\n throw new DiError(\n \"unknown import\",\n [m],\n `${m}.imports`,\n `${m} imports ${nameOf(i)}, which is not a module.`,\n [\n `add @Module({ ... }) to ${nameOf(i)}`,\n `or remove ${nameOf(i)} from ${m}.imports — to reach a class, import the module that OWNS it`,\n ],\n );\n }\n }\n\n exported.set(m, new Set(def.exports ?? []));\n importsOf.set(m, new Set((def.imports ?? []).map(nameOf)));\n }\n\n // 3 · dependencies — metadata against arity, then type validity, then module\n // visibility. In that order, because each answer makes the next question\n // meaningful.\n const deps = new Map<Token, Token[]>();\n\n /**\n * The owned classes that EXTEND `t`.\n *\n * `abstract` does not exist at runtime — JavaScript happily runs `new Clock()`\n * and returns an object missing every abstract member. Measured before this\n * existed: the container injected exactly that, the build was green, and the\n * failure surfaced mid-request as `c.now is not a function`.\n *\n * So an abstraction is resolved through its implementation, and the\n * relationship is read from the prototype chain — which is what `extends`\n * builds. That is a DECLARATION the class makes about itself, not an\n * inference from where its file sits.\n *\n * Only consulted for a token NOTHING owns. A class that IS owned is the\n * answer to its own name, so an unrelated `extends` elsewhere can never\n * change what an existing dependency resolves to.\n */\n const implementorsOf = (t: Token): Token[] =>\n [...owner.keys()].filter(\n (c) => c !== t && Object.prototype.isPrototypeOf.call(t as object, c as object),\n );\n\n // Is missing metadata GLOBAL or local? Decided BEFORE any per-class message,\n // because the two faults look identical one class at a time and lead to\n // opposite fixes: all of them missing means the build ran without\n // `emitDecoratorMetadata` (or without `reflect-metadata`, whose absence makes\n // the emitted helper a silent no-op); some of them missing means the author\n // forgot `@Injectable()` on those. Telling someone to decorate a class when\n // the flag is off sends them to edit a file that is not the problem.\n //\n // NOT a synthetic canary. An earlier design embedded a probe class in the SDK\n // and asked whether IT carried metadata — but the SDK is built with tsup, and\n // esbuild emits zero `__metadata` (measured), so that probe would report a\n // global fault on every healthy boot. The tenant's OWN classes are the only\n // honest sample of the tenant's build.\n const withArity = [...owner.keys()].filter(\n (c) => (c as unknown as { length: number }).length > 0,\n );\n const missingMeta = withArity.filter(\n (c) => Reflect.getMetadata(\"design:paramtypes\", c) === undefined,\n );\n // TWO is the smallest sample this inference is honest on. With ONE class,\n // \"all of them are missing\" is also what a single forgotten `@Injectable()`\n // looks like, and telling that author their build is broken sends them to the\n // wrong file. Below the threshold the per-class message runs, which names the\n // class and the decorator.\n if (withArity.length >= 2 && missingMeta.length === withArity.length) {\n throw new DiError(\n \"metadata missing\",\n withArity.map(nameOf),\n \"the whole build\",\n `no class carries constructor metadata — every one of the ${withArity.length} ` +\n `class(es) that asks for a dependency is missing it, so this is the build, ` +\n `not the classes.`,\n [\n \"set `emitDecoratorMetadata: true` in the project's tsconfig.json\",\n \"and import `reflect-metadata` before any decorated class evaluates — without it the emitted helper is a silent no-op\",\n \"if the build is fine, then none of these classes carries @Injectable()\",\n ],\n );\n }\n\n for (const [cls, m] of owner) {\n const arity = (cls as unknown as { length: number }).length;\n\n // ARITY IS THE GROUND TRUTH. It survives every transpile; metadata does not.\n // Measured: a decorated class with no constructor carries `undefined`\n // metadata and a decorated one with an empty constructor carries `[]` —\n // both ask for nothing, and only arity says so. Treating absent metadata as\n // a fault would refuse every dependency-free class that never wrote a\n // constructor, which is most of them.\n if (arity === 0) {\n deps.set(cls, []);\n continue;\n }\n\n // Asked through the shared predicate, so \"does this class say what it needs\"\n // has ONE definition — the same one `assertZeroArgConstructor` answers with.\n if (!declaresDependencies(cls)) {\n const meta = Reflect.getMetadata(\"design:paramtypes\", cls) as unknown[] | undefined;\n throw new DiError(\n \"metadata missing\",\n [nameOf(cls)],\n `${nameOf(cls)} constructor`,\n `${nameOf(cls)} declares ${arity} parameter(s) but carries ` +\n `${meta === undefined ? \"no\" : String(meta.length)} metadata entries, ` +\n `so every parameter would arrive as undefined.`,\n [\n `add @Injectable() to ${nameOf(cls)} — metadata is emitted for DECORATED classes only`,\n \"or the build ran without emitDecoratorMetadata: check tsconfig.json\",\n ],\n );\n }\n\n const meta = Reflect.getMetadata(\"design:paramtypes\", cls) as unknown[];\n const list: Token[] = [];\n meta.forEach((t, i) => {\n const at = `${nameOf(cls)} constructor, parameter ${i}`;\n\n if (typeof t !== \"function\" || UNRESOLVABLE.has(t)) {\n throw new DiError(\n \"unresolvable dependency\",\n [nameOf(cls)],\n at,\n `parameter ${i} has no runtime class — an interface, a type alias, a ` +\n `union, or a data type. The container has nothing to construct.`,\n DATA.has(t)\n ? [\n \"an injectable's constructor takes dependencies, not data\",\n \"move the value to a method argument instead\",\n \"or make this a plain value class (no @Injectable, in no module) and `new` it yourself\",\n ]\n : [\n \"depend on a concrete class or an abstract class\",\n \"a TypeScript interface does not exist at runtime — there is nothing to inject\",\n ],\n );\n }\n\n const dep = t as Token;\n\n {\n let dm = owner.get(dep);\n if (dm === undefined) {\n // An ABSTRACTION, resolved to its one implementation (FR-055).\n //\n // Read from `extends`, not from a second syntax: `class SystemClock\n // extends Clock` is the class declaring \"I am a Clock\", and that is a\n // declaration — not an inference from where a file sits.\n const impls = implementorsOf(dep);\n if (impls.length === 1) {\n const impl = impls[0] as Token;\n list.push(impl);\n dm = owner.get(impl) as string;\n if (dm !== m) {\n if (!importsOf.get(m)?.has(dm)) {\n throw new DiError(\n \"missing import\",\n [nameOf(cls), nameOf(impl)],\n at,\n `${nameOf(impl)} implements ${nameOf(dep)} and is owned by ${dm}, which ${m} does not import.`,\n [`add ${dm} to ${m}.imports`],\n );\n }\n if (!exported.get(dm)?.has(impl)) {\n throw new DiError(\n \"private dependency\",\n [nameOf(cls), nameOf(impl)],\n at,\n `${nameOf(impl)} implements ${nameOf(dep)} but is internal to ${dm}.`,\n [`add ${nameOf(impl)} to ${dm}.exports (and say why)`],\n );\n }\n }\n return;\n }\n if (impls.length > 1) {\n const names = impls.map(nameOf).sort();\n throw new DiError(\n \"duplicate ownership\",\n [nameOf(cls), nameOf(dep)],\n at,\n `${names.join(\" and \")} both extend ${nameOf(dep)}, so which one ` +\n `${nameOf(cls)} should receive has two answers.`,\n [\n `keep ONE class extending ${nameOf(dep)} in this graph`,\n `or depend on ${names[0]} or ${names[1]} directly, by name`,\n ],\n );\n }\n throw new DiError(\n \"unowned class\",\n [nameOf(cls), nameOf(dep)],\n at,\n `${nameOf(dep)} belongs to no module, and nothing in this graph extends it — ` +\n `so there is nothing to construct. (An abstract class cannot be built: ` +\n `\\`abstract\\` is a type-level claim, and \\`new\\` on one returns an object ` +\n `missing every abstract member.)`,\n [\n `add ${nameOf(dep)} to a module's providers if it is concrete`,\n `or add a class that \\`extends ${nameOf(dep)}\\` to a module's providers`,\n ],\n );\n }\n if (dm !== m) {\n if (!importsOf.get(m)?.has(dm)) {\n throw new DiError(\n \"missing import\",\n [nameOf(cls), nameOf(dep)],\n at,\n `${nameOf(dep)} is owned by ${dm}, which ${m} does not import.`,\n [`add ${dm} to ${m}.imports`],\n );\n }\n if (!exported.get(dm)?.has(dep)) {\n throw new DiError(\n \"private dependency\",\n [nameOf(cls), nameOf(dep)],\n at,\n `${nameOf(dep)} is internal to ${dm} — it is not exported.`,\n [\n `use one of ${dm}'s exported classes`,\n `or add ${nameOf(dep)} to ${dm}.exports (and say why it should be public)`,\n ],\n );\n }\n }\n }\n\n list.push(dep);\n });\n\n deps.set(cls, list);\n }\n\n // 4 · cycles — refused, with the path written out by name.\n //\n // There is NO `forwardRef`-style escape, and the reason is that the shape one\n // exists to rescue cannot be built: a real ESM cycle dies at import. Measured\n // in the spike — Bun throws `Cannot access 'CB' before initialization` before\n // the container is ever consulted. What CAN still be assembled is a cycle\n // inside one file, so the detector earns its place; what it never has to do is\n // offer a way to keep one.\n const state = new Map<Token, 0 | 1 | 2>();\n const stack: Token[] = [];\n const walk = (c: Token): void => {\n if (state.get(c) === 1) {\n // Slice from where this class first entered the stack, so the message is\n // the CYCLE and not the path that happened to reach it.\n const cyc = [...stack.slice(stack.indexOf(c)), c].map(nameOf);\n throw new DiError(\n \"dependency cycle\",\n cyc,\n `${cyc[0]} constructor`,\n `the dependency graph contains a cycle: ${cyc.join(\" -> \")}.`,\n [\n \"extract the shared part into a third class both can depend on\",\n \"or invert one direction — have the callee raise an event the caller listens for\",\n ],\n );\n }\n if (state.get(c) === 2) return;\n state.set(c, 1);\n stack.push(c);\n // A platform token needs no special case: it has no `deps` entry, so the\n // walk reaches it, finds nothing to follow, and marks it done. A guard here\n // would be an inert check — it was written, measured against a mutation, and\n // removed when removing it changed nothing.\n for (const d of deps.get(c) ?? []) walk(d);\n stack.pop();\n state.set(c, 2);\n };\n for (const c of owner.keys()) walk(c);\n\n // 5 · resolution — ONE lifetime, singleton.\n //\n // No `transient`, no `request`. Request scope already exists and it is an\n // AsyncLocalStorage, not an object lifetime: what varies per request is the\n // database handle and the claims, and the engine opens that scope around the\n // handler. Making the OBJECTS per-request would duplicate that mechanism and\n // then have to keep the two in agreement.\n //\n // The consequence is a rule about constructors: they stay synchronous and do\n // nothing but wiring. Real I/O belongs in `onStart`, where it can fail loudly\n // at boot instead of halfway through the first request.\n const cache = new Map<Token, unknown>();\n const make = (c: Token): unknown => {\n // A token this container never validated is NOT built. Measured before this\n // check existed: `get(Stranger)` found no `deps` entry, fell through to\n // `new Stranger()` with zero arguments, and returned it — so a class in no\n // module could still be constructed through the container's own front door,\n // which is the hole the module system exists to close (FR-053).\n //\n // There is no platform escape hatch here: platform services (Database, Log,\n // …) are AMBIENT — imported, not injected — because they are request-scoped\n // and a boot-time singleton holding one would capture the first request's\n // client forever (FR-005). Nothing supplies a platform map, so having one\n // would be an inert extension point.\n if (!owner.has(c)) {\n throw new DiError(\n \"unowned class\",\n [nameOf(c)],\n \"container.get\",\n `${nameOf(c)} belongs to no module, so this container never validated it ` +\n `and will not build it.`,\n [\n `add ${nameOf(c)} to a module's providers`,\n \"or, if it is a plain value class, construct it yourself with `new`\",\n ],\n );\n }\n const hit = cache.get(c);\n if (hit !== undefined) return hit;\n const args = (deps.get(c) ?? []).map(make);\n const inst = new (c as unknown as new (...a: unknown[]) => unknown)(...args);\n cache.set(c, inst);\n return inst;\n };\n\n return {\n get: <T,>(t: Token<T>): T => make(t) as T,\n owned: new Set(owner.keys()),\n pressure: computePressure(entries),\n };\n}\n\n/**\n * What fraction of the OTHER modules import each module.\n *\n * `total - 1` is the denominator because a module never imports itself, so the\n * most any module can reach is everyone else. Under two modules there is nothing\n * to compare and the answer is an empty list rather than a misleading 100%.\n */\nfunction computePressure(entries: { mod: Token; def: ModuleDef }[]): ModulePressure[] {\n // No `total < 2` guard, and none is needed: a single module cannot import\n // anything (there is no other module, and both self-import and non-module\n // imports are refused above), so `count` is empty and the division below never\n // runs. The guard was written, measured against a mutation, and removed when\n // removing it changed nothing — an inert check still draws a number.\n const total = entries.length;\n const count = new Map<string, number>();\n for (const { def } of entries) {\n for (const i of def.imports ?? []) {\n const n = nameOf(i);\n count.set(n, (count.get(n) ?? 0) + 1);\n }\n }\n return [...count]\n .map(([module, c]) => ({ module, pct: Math.round((c / (total - 1)) * 100), of: total - 1 }))\n .sort((a, b) => b.pct - a.pct);\n}\n\n/** Kept so the module surface is stable while stages 3-5 land. */\nexport type { ModuleDef };\n\n/**\n * Refuses an entry point that no module lists (FR-035).\n *\n * A decorated class registers itself — `@Controller` pushes into a globalThis\n * slot the moment its file is imported — so before this check a class listed in\n * no module still reached the route table, the dispatcher and the OpenAPI\n * document. It worked, which is the problem: nothing said the module system had\n * been bypassed.\n *\n * After this, a successful boot means the two sets are EQUAL: what decorated\n * itself and what a module claimed. That equality is what lets `src/openapi/`\n * stay untouched — it renders the list it is handed, and the list is now the\n * module's.\n */\nexport function assertNoOrphanEntryPoints(\n registered: readonly unknown[],\n owned: ReadonlySet<Token>,\n): void {\n const orphans = registered.filter((c) => !owned.has(c as Token));\n if (orphans.length === 0) return;\n const names = orphans.map((c) => (c as { name?: string }).name ?? \"<anonymous>\");\n throw new DiError(\n \"unowned class\",\n names,\n \"module declarations\",\n `${names.join(\", \")} ${orphans.length === 1 ? \"is\" : \"are\"} decorated as an entry ` +\n `point but listed in no module, so nothing decides whether it should be served.`,\n [\n \"add it to a module's `controllers` (for @Controller) or `providers` (for @Room/@Job/@Hook/@Webhook)\",\n \"an entry point no module lists is never mounted and never reaches the OpenAPI document\",\n ],\n );\n}\n"],"mappings":"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","names":["AsyncLocalStorage","__requestALS","AsyncLocalStorage","runtime","__setRuntime","services","__runWithRuntime","fn","run","__getRuntime","scoped","getStore","Error","LIFECYCLE","Symbol","for","declaredLifecycle","g","globalThis","start","shutdown","onStart","name","hook","push","onShutdown","reason","err","message","String","drain","hooks","h","reverse","console","error","__runStartHooks","slot","splice","cause","drained","__resetLifecycleHooks","makeServiceProxy","key","handler","get","_target","prop","receiver","client","value","Reflect","bind","Proxy","makeTableProxy","ops","prefix","_t","undefined","insert","data","insertMany","rows","opts","update","q","where","id","set","delete","findById","findMany","put","onConflict","updateMany","deleteMany","count","search","params","similar","recommend","facets","supersede","row","claim","unique","extra","rawDatabase","makeTypedSurface","raw","reco","$query","sql","query","$insert","table","$update","$delete","$findById","$findMany","$put","$updateMany","$deleteMany","$count","$search","$similar","$recommend","$facets","$claim","$lockRows","ids","lockRows","$advisoryXactLock","advisoryXactLock","$insertMany","$supersede","base","Object","assign","$attempt","attempt","$transaction","withRetry","builder","TxPlanBuilder","runTxPlan","makeTxPlanHandle","target","startsWith","qualifiedTableKey","makeTxTablesAccessor","tablesProxy","publicTables","Database","$asService","asService","Documents","makeBucketsAccessor","storage","bucket","rawStorage","Storage","buckets","Cache","Secrets","Log","Notifications","rawFlags","Flags","isEnabled","flagName","context","getVariant","getAll","defaultOrContext","maybeContext","setOverride","Realtime","DECLARATION_REFUSAL","Symbol","for","DeclarationRefused","Error","message","name","isDeclarationRefused","e","baseTsType","def","type","values","enumValues","length","map","v","JSON","stringify","join","pgBrand","sort","rowType","base","nullable","branded","optionalOnInsert","defaultRandom","defaultNow","defaultValue","undefined","forwardName","column","endsWith","slice","describeOrigin","o","direction","table","renameCall","owns","target","references","selfRefColumn","buildRelations","schemas","out","Map","taken","schema","t","Object","tables","key","qualifiedTableKey","name","set","claim","tableKey","origin","edge","names","get","held","DeclarationRefused","heldFix","originFix","remedy","push","childKey","has","col","builder","entries","columns","_def","targetKey","refAs","to","kind","via","reverse","reverseAs","tableBlock","relations","indent","cols","rowLines","insertLines","opt","relEntries","r","some","b","search","appendOnly","makeEnvDts","publicSchema","find","s","others","filter","publicBlocks","keys","body","schemaBlocks","inner","schemasBody","DI_INJECTABLES","Symbol","for","INJECTABLE","isInjectable","c","slot","g","globalThis","Injectable","target","push","__claimInjectables","splice","JOB","Symbol","for","WEBHOOK","HOOK_BLOCKING","HOOK_LISTENERS","ROOM","CONTROLLER","has","c","s","undefined","isEntryPointClass","owned","container","jobsOf","filter","webhooksOf","hooksOf","roomsOf","controllersOf","DI_MODULES","Symbol","for","slot","g","globalThis","Module","def","target","push","mod","__claimModules","splice","DiError","Error","DECLARATION_REFUSAL","kind","path","at","detail","fixes","length","join","map","f","name","nameOf","c","String","UNRESOLVABLE","Set","Object","Function","Number","Boolean","Array","Symbol","Promise","Date","undefined","DATA","declaresDependencies","ctor","arity","meta","Reflect","getMetadata","buildContainer","entries","__claimModules","declared","__claimInjectables","declaredModules","e","mod","owner","Map","def","m","providers","controllers","prev","get","set","p","isInjectable","isEntryPointClass","orphans","filter","has","names","exported","importsOf","exports","holder","i","imports","deps","implementorsOf","t","keys","prototype","isPrototypeOf","call","withArity","missingMeta","cls","list","forEach","dep","dm","impls","impl","push","sort","state","stack","walk","cyc","slice","indexOf","d","pop","cache","make","hit","args","inst","owned","pressure","computePressure","total","count","n","module","pct","Math","round","of","a","b","assertNoOrphanEntryPoints","registered"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/db/typed-db.ts","../src/db/schema-json.ts"],"sourcesContent":["/**\n * typed-db.ts — Task 2: TypedDB schema-derived insert/row shapes.\n *\n * Derives INSERT and full-row TypeScript types from a `defineSchema()` result\n * and wraps the untyped runtime `DBClient` with a typed facade.\n *\n * No value-any. No `as unknown as X`. The two narrow `as` casts in\n * `makeTypedTable` are safe because:\n * - `data as Record<string, unknown>`: InsertShape<T> maps string keys to\n * typed values; all value types are subsets of `unknown`, so the cast is\n * structurally sound.\n * - `result as RowShape<T>`: The runtime DBClient returns `Record<string,\n * unknown>` which is the erased form of the typed row; we're narrowing back\n * to the precise shape that the schema declared.\n * Both casts are narrowing only (not widening) and correctness is guaranteed\n * by the schema the caller provides.\n */\n\nimport type { ColValue, ColIsOptionalOnInsert, ColumnBuilder } from \"./columns.js\";\nimport type { TableDef, SchemaDef } from \"./schema.js\";\nimport type { Tables, Schemas, TableTypes } from \"./env.js\";\nimport type { DBClient, DBOps } from \"../endpoint.js\";\nimport type { RecoOps } from \"../runtime.js\";\nimport type { Materialized, TxPlanHandle, TxTable, TxColumnExpr, TxNow } from \"./tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./tx-plan.js\";\nimport { isColRef, brandRef } from \"./input-guards.js\";\nimport { isRetryable } from \"../errors.js\";\n\n// ---------------------------------------------------------------------------\n// Key discriminators — split a column map into required vs optional keys.\n// ---------------------------------------------------------------------------\n\n/** Keys of C whose columns are required on INSERT (not nullable, no default). */\ntype RequiredKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? never : K;\n}[keyof C];\n\n/** Keys of C whose columns are optional on INSERT (nullable or has a default). */\ntype OptionalKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? K : never;\n}[keyof C];\n\n// ---------------------------------------------------------------------------\n// Public shape types — exported so callers can reference them directly.\n// ---------------------------------------------------------------------------\n\n/**\n * The TypeScript type for an INSERT payload for table `T`.\n * - Required: columns that are NOT NULL and have no DB-level default.\n * - Optional: columns that are nullable or carry a default.\n *\n * When all columns are optional, `RequiredKeys<C>` resolves to `never` and\n * the first part becomes `{}`, which is a neutral element for `&`.\n */\nexport type InsertShape<T extends TableDef> = {\n [K in RequiredKeys<T[\"columns\"]>]: ColValue<T[\"columns\"][K]>;\n} & {\n [K in OptionalKeys<T[\"columns\"]>]?: ColValue<T[\"columns\"][K]>;\n};\n\n/**\n * The TypeScript type for a full row returned by the DB for table `T`.\n * Every column is present; nullable columns resolve to `T | null`.\n */\nexport type RowShape<T extends TableDef> = {\n [K in keyof T[\"columns\"]]: ColValue<T[\"columns\"][K]>;\n};\n\n// ---------------------------------------------------------------------------\n// TypedTable + TypedDB interfaces.\n// ---------------------------------------------------------------------------\n\n/** A typed table accessor that mirrors the runtime DBClient surface. */\nexport interface TypedTable<T extends TableDef> {\n insert(data: InsertValues<InsertShape<T>>): Promise<RowShape<T>>;\n /** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı. */\n insertMany(\n rows: readonly InsertValues<InsertShape<T>>[],\n opts?: { onConflict: readonly string[]; action?: \"ignore\" | \"update\" },\n ): Promise<RowShape<T>[]>;\n put(q: { data: InsertShape<T>; onConflict: readonly string[] }): Promise<RowShape<T>>;\n /** Update the row by id; resolves to the updated row, or `null` if no row\n * matched (absent or RLS-hidden) — an idempotent outcome, mirroring\n * `findById`. The runtime returns a null row rather than throwing. */\n update(q: { where: { id: string }; set: SetShape<InsertShape<T>> }): Promise<RowShape<T> | null>;\n delete(id: string): Promise<void>;\n findById(id: string): Promise<RowShape<T> | null>;\n /** Rows matching the filter. Operators, ordering and paging are the ENGINE's\n * surface — this declaration is what makes them callable. */\n findMany<K extends keyof RowShape<T> = keyof RowShape<T>>(\n q?: QueryInput<RowShape<T>, K>,\n ): Promise<Pick<RowShape<T>, K>[]>;\n /**\n * Update every matching row in one statement; an empty filter is refused.\n *\n * **0 satır dönmesi hata DEĞİL, başarı da değil** (FR-014): koşulu `where`'e\n * koyup dönen diziyi kontrol etmek, \"önce oku sonra yaz\"ın yarış koşulu\n * olmayan hâlidir.\n *\n * ```ts\n * const [row] = await Database.public.accounts.updateMany({\n * where: { id, balance: { gte: amount } },\n * set: { balance: decrement(amount) },\n * });\n * if (row === undefined) throw new Conflict(\"yetersiz bakiye\");\n * ```\n */\n updateMany(q: MutateInput<RowShape<T>, InsertShape<T>>): Promise<RowShape<T>[]>;\n /** Delete every matching row; resolves to how many. Empty filter refused. */\n deleteMany(q: { where: WhereFilter<RowShape<T>> | SqlFragment }): Promise<number>;\n /** How many rows match. An empty filter is legitimate: counting is a read. */\n count(q?: { where?: WhereFilter<RowShape<T>> | SqlFragment }): Promise<number>;\n}\n\n/** A typed DB facade covering all tables declared in schema `S`. */\nexport interface TypedDB<S extends SchemaDef> {\n tables: {\n [K in keyof S[\"tables\"]]: TypedTable<S[\"tables\"][K]>;\n };\n /** Run a transaction plan. See {@link EnvTypedDatabase.transaction}. */\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>>;\n}\n\n/** The plan-building handle a `TypedDB<S>` transaction callback receives: the\n * schema's tables, expressed as plan operations rather than awaited calls.\n *\n * YALNIZ `tables`, ve ÇALIŞMA ZAMANI DA yalnız onu veriyor.\n *\n * Bir süre runtime `{ tables, public }` döndürüyordu ama tip yalnız `tables`\n * söylüyordu: `tx.public.x` derlenmiyor, koşsaydı çalışacaktı — tipin çalışma\n * zamanından AZ söylemesi (gözcü M-8). Tipe `public` EKLEMEK yanlış düzeltmeydi\n * ve `check:api` onu adıyla reddetti: `TypedTx` dışa açık, ve zorunlu bir üye\n * eklemek onu İNŞA EDEN müşterinin kodunu kırar — \"the new shape demands more\n * than the recorded one\". Yalan runtime'dan kaldırılarak kapatıldı; ikisi artık\n * aynı şeyi söylüyor. `Database.$transaction`'ın `tx.public`'i ayrı bir yüzey\n * (`TxPlan`) ve orada tip de runtime da onu taşıyor. */\nexport type TypedTx<S extends SchemaDef> = TxPlanHandle<{\n [K in keyof S[\"tables\"]]: TxTable<RowShape<S[\"tables\"][K]>, InsertShape<S[\"tables\"][K]>>;\n}>;\n\n// ---------------------------------------------------------------------------\n// Runtime factory.\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a typed table accessor that delegates every call to `raw` using the\n * runtime table name string. Two narrow `as` casts bridge the mapped-type\n * shapes to/from `Record<string, unknown>` — see module-level doc comment.\n *\n * The `raw` param is typed `DBOps` (the six string-keyed ops) because this only\n * ever calls those — never `txPlan`, which builds its own operations rather than\n * delegating to these.\n */\nfunction makeTypedTable<T extends TableDef<Record<string, ColumnBuilder>>>(\n name: string,\n raw: DBOps,\n): TypedTable<T> {\n return {\n insert: (data: InsertShape<T>) =>\n raw.insert(name, data as Record<string, unknown>) as Promise<RowShape<T>>,\n\n insertMany: (\n rows: readonly InsertValues<InsertShape<T>>[],\n opts?: { onConflict: readonly string[]; action?: \"ignore\" | \"update\" },\n ) =>\n raw.insertMany(name, rows as readonly Record<string, unknown>[], opts) as Promise<RowShape<T>[]>,\n\n put: (q: { data: InsertShape<T>; onConflict: readonly string[] }) =>\n raw.put(name, q.data as Record<string, unknown>, { onConflict: q.onConflict }) as Promise<RowShape<T>>,\n\n update: (q: { where: { id: string }; set: Partial<InsertShape<T>> }) =>\n raw.update(name, q.where.id, q.set as Record<string, unknown>) as Promise<RowShape<T> | null>,\n\n delete: (id: string) => raw.delete(name, id),\n\n findById: (id: string) =>\n raw.findById(name, id) as Promise<RowShape<T> | null>,\n\n findMany: (q?: QueryInput<RowShape<T>>) => {\n // `where` AYIKLANIR: kalan alanlar (orderBy/limit/offset) opts'a gider.\n // Tümünü opts diye geçirmek `where`'i tel üstünde İKİ KEZ gönderirdi.\n const { where, ...opts } = q ?? {};\n return raw.findMany(\n name,\n where as Record<string, unknown> | undefined,\n opts as Parameters<typeof raw.findMany>[2],\n ) as Promise<RowShape<T>[]>;\n },\n\n updateMany: (q: MutateInput<RowShape<T>, InsertShape<T>>) =>\n raw.updateMany(\n name,\n q.where as Record<string, unknown>,\n q.set as Record<string, unknown>,\n ) as Promise<RowShape<T>[]>,\n\n deleteMany: (q: { where: WhereFilter<RowShape<T>> | SqlFragment }) =>\n raw.deleteMany(name, q.where as Record<string, unknown>),\n\n count: (q?: { where?: WhereFilter<RowShape<T>> }) =>\n raw.count(name, q?.where as Record<string, unknown> | undefined),\n };\n}\n\n/**\n * Wraps a raw `DBClient` with the type-safe `TypedDB<S>` facade derived from\n * the provided schema. No behavior change for the direct ops — all calls\n * delegate to `raw` with the table name as a plain string.\n *\n * `transaction` does NOT delegate to a per-op client: the callback describes a\n * plan against a fresh {@link TxPlanBuilder}, and the whole plan travels in one\n * `raw.txPlan` call. The schema is used only for its table NAMES; the values\n * are typed by `S` at compile time and are plain strings at run time.\n *\n * The `as` casts are single structural narrowings from a dynamically-built\n * object to the precise mapped type (TS cannot infer the mapped-type result\n * through `Object.keys` iteration) — see the module-level doc comment.\n */\nexport function makeTypedDB<S extends SchemaDef>(\n schema: S,\n raw: DBClient,\n): TypedDB<S> {\n const tables = {} as Record<string, TypedTable<TableDef>>;\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) {\n tables[key] = makeTypedTable(tableDef.name, raw);\n }\n }\n\n const result = {\n tables,\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n const builder = new TxPlanBuilder();\n const planTables: Record<string, unknown> = {};\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) planTables[key] = builder.table(tableDef.name);\n }\n // Two narrowings at the same seam: the plan tables are built by NAME, so\n // TS cannot see the mapped type through the loop, and the driver erases\n // the callback's return type (see runTxPlan's doc). Both are the erasure\n // this facade exists to undo.\n // `runTxPlan` artık TUTAMAĞIN TAMAMINI alıyor (şema yüzeyi dahil).\n //\n // Burada tutamak YALNIZ `tables` taşıyor, çünkü `TypedTx<S>` de yalnız\n // onu söylüyor. Bir ara `public`'i de veriyordu ve tip onu bilmiyordu —\n // çalışma zamanının tipten FAZLA sunması da bir yalan. `makeTypedDB` tek\n // şemalı bir cephe; çok şemalı yüzey `Database.$transaction`.\n return runTxPlan(\n raw,\n { tables: planTables } as TypedTx<S>,\n builder,\n fn,\n ) as Promise<Materialized<T>>;\n },\n };\n\n // Narrow cast: `result.tables` is structurally identical to\n // TypedDB<S>[\"tables\"] — each key maps to a TypedTable for the matching\n // TableDef. TS cannot infer the mapped-type result through Object.keys\n // iteration, so a single `as` bridges the gap.\n return result as TypedDB<S>;\n}\n\n// ---------------------------------------------------------------------------\n// Env-augmentation-driven typed surface — the typed-by-default `Database`.\n//\n// These types read the globally-augmented `Tables` interface from\n// `@palbase/backend/env` (filled by the generated `palbase-env.d.ts`). They\n// back `Database.public.<name>` so handler code is typed with no import and no\n// generic (C5). They DELIBERATELY do not reference `ColumnBuilder` — the env\n// `Tables` interface carries flat `row`/`insert` object types.\n// ---------------------------------------------------------------------------\n\n/** Bir where değeri: düz eşitlik YA DA operatör nesnesi (FR-016). */\n/**\n * Metin operatörleri YALNIZ metin kolonlarında görünür (FR-005).\n *\n * `contains` bir sayı kolonunda anlamsızdır ve onu tipte sunmak \"ifade edilemez\n * kıl\" ilkesinin tersidir: derleme anında yakalanabilecek bir hata çalışma\n * zamanına ertelenir. Koşullu tip ÖZYİNELEMESİZDİR (N-2).\n */\n/**\n * Bir KOLONA yapılan referans (FR-011) — karşılaştırmanın sağ tarafında değer\n * yerine durabilen tek şey.\n *\n * Şekli okunabilir (`{ $col: \"…\" }`) ama KİMLİĞİ şekli değil: nesne\n * `Symbol.for(\"palbase.db.ref\")` ile markalanır. Şekil tek başına yetseydi\n * güvenilmeyen bir istek gövdesi `{\"$col\":\"tenant_id\"}` gönderip kiracılık\n * predikatını `t.\"tenant_id\" = t.\"tenant_id\"` totolojisine çevirebilirdi —\n * ölçüldü (W2-A/C1). Marka enumerable olmadığı için JSON round-trip'i onu\n * düşürür; süreç içinde (transaction planı dahil) korunur.\n */\nexport type ColRef<N extends string = string> = { readonly $col: N };\n\nexport { isColRef };\n\n/**\n * `total > amount_paid` — bugün bunu yazmanın tek yolu ham SQL'e düşmekti,\n * çünkü sağ taraf bir DEĞER değil.\n *\n * Ad literal olarak yakalanır (`const N`), ve doğruluğu ÇAĞRIDA değil\n * KULLANIM YERİNDE kanıtlanır: filtre `WhereFilter<Row>` beklediği için\n * `ColRef<\"yok_boyle\">` oraya atanamaz. Yani `col()`'a satır tipini elle\n * vermek gerekmiyor, yanlış ad yine de derleme hatası (P5).\n *\n * Dönen nesne MARKALIDIR (`brandRef`): telden gelen `{\"$col\":\"x\"}` bir kolon\n * referansı SAYILMAZ, \"bilinmeyen operatör\" diye reddedilir. Gerekçe\n * `db/input-guards.ts`'te ölçümüyle birlikte yazılı.\n */\nexport function col<const N extends string>(name: N): ColRef<N> {\n return brandRef({ $col: name }, \"col\");\n}\n\n/** Bu satırın kolonlarından birine referans. `Row` bilinmiyorsa hiçbiri. */\n/**\n * Bir kolonun karşılaştırma AİLESİ — ve neden PG tipi değil de bu.\n *\n * ÖLÇÜLDÜ (gözcü, canlı pg16): TS tarafı PG tipini TAŞIMIYOR. `numeric`,\n * `bigint`, `text`, `uuid` ve `timestamp` hepsi `string`'e, `integer` `number`'a\n * düşüyor (`env-gen.ts:30-60`). Bu yüzden TS tipine kurulan HİÇBİR kural doğru\n * olamaz — kural ne olursa olsun bir taraf yanlışa düşer:\n *\n * { qty: { gt: col(\"amount\") } } integer ↔ numeric PG: GEÇERLİ\n * { total: { gt: col(\"note\") } } integer ↔ text PG: GEÇERSİZ\n *\n * İkisi de TS'te \"number ↔ string\". Ayırt edecek bilgi tipte YOK.\n *\n * YANLIŞ RET, YANLIŞ KABULDEN KÖTÜDÜR — ve tercih buna göre yapıldı. Yanlış bir\n * ret meşru bir sorguyu İFADE EDİLEMEZ kılar, yani yazarı `$query`'ye düşürür:\n * bu yüzeyin kapatmak için var olduğu şey. Yanlış bir kabul ise Postgres'in\n * GÜRÜLTÜLÜ hatasına çıkar (`operator does not exist: integer > text`) — kötü\n * ama sessiz değil.\n *\n * O yüzden aile ayrımı yalnız TS'in GERÇEKTEN ayırdığı yerlerde yapılıyor:\n * `boolean`, vektör dizisi ve `Date` kendi başlarına; metin ve sayı ise TEK\n * ailede, çünkü aralarındaki PG ayrımı tipte yok.\n *\n * KALICI ÇÖZÜM tipte değil ÜRETİMDE: `env-gen` kolon başına bir PG-tip markası\n * bassın (`string & { readonly __pg?: \"numeric\" }`). O zaman `numeric ↔ integer`\n * kabul, `numeric ↔ text` ret olur ve ikisi de DOĞRU olur. Defterde teklif.\n */\ntype PgFamily<V> = [NonNullable<V>] extends [boolean]\n ? \"bool\"\n : [NonNullable<V>] extends [readonly (number | string)[]]\n ? \"array\"\n : [NonNullable<V>] extends [Date]\n ? \"date\"\n : [NonNullable<V>] extends [string | number]\n ? \"scalar\"\n : \"opaque\";\n\n/**\n * Kolonun BİLDİRİLMİŞ Postgres tipi — `env-gen`'in bastığı markadan.\n *\n * Marka yoksa `\"?\"`: elle yazılmış bir `Tables` (testler) ya da yeniden\n * üretilmemiş bir `palbase-env.d.ts`. O durumda eski TS-tipi sezgiseline\n * düşülüyor, çünkü marka olmadan söylenebilecek daha doğru bir şey yok.\n */\ntype PgTag<V> = [NonNullable<V>] extends [{ readonly __pg?: infer N }]\n ? [N] extends [string]\n ? N\n : \"?\"\n : \"?\";\n\n/**\n * Postgres'te birbirleriyle karşılaştırılabilen tipler tek \"cins\".\n *\n * `integer`, `bigint` ve `numeric` örtük sayısal dönüşümle karşılaştırılır;\n * geri kalan her tip yalnız kendisiyle. `uuid ↔ text` ve `enum ↔ text`\n * Postgres'te `operator does not exist` verir — D-021'de CANLI ölçülmüştü ve\n * tip bunu göremediği için kabul ediyordu.\n */\ntype PgKind<P> = P extends \"integer\" | \"bigint\" | \"numeric\" ? \"num\" : P;\n\n/** İki tarafın da markası var mı — yoksa sezgisele düşülür. */\ntype BothBranded<A, B> = \"?\" extends PgTag<A> ? false : \"?\" extends PgTag<B> ? false : true;\n\ntype PgSameKind<A, B> = [PgKind<PgTag<A>>] extends [PgKind<PgTag<B>>]\n ? [PgKind<PgTag<B>>] extends [PgKind<PgTag<A>>]\n ? true\n : false\n : false;\n\n/**\n * `A` kolonu `B` ile karşılaştırılabilir mi.\n *\n * Marka varsa CEVAP KESİN: ne yanlış ret ne yanlış kabul. D-021 bu kuralı\n * \"doğru olamaz\" diye kaydetmişti çünkü tipte ayırt edecek bilgi yoktu; bilgi\n * artık tipte.\n */\ntype ColComparable<A, B> = BothBranded<A, B> extends true\n ? PgSameKind<A, B>\n : [PgFamily<A>] extends [PgFamily<B>]\n ? true\n : false;\n\n/** `Row`'un `V` ile karşılaştırılabilir kolonları. */\ntype ColumnsComparableTo<Row, V> = {\n [K in keyof Row]-?: ColComparable<Row[K], V> extends true ? K : never;\n}[keyof Row];\n\n/**\n * Bu satırın kolonlarından birine referans. `Row` bilinmiyorsa hiçbiri.\n *\n * İKİNCİ PARAMETRE kolonun tipi. Verilmezse (`unknown`) KISIT YOKTUR — bu\n * `findMany`'nin `Row`'u bilmediği yolların ve jsonb kolonlarının hâli, ve\n * ikisinde de tipin söyleyebileceği bir şey yok.\n */\nexport type ColRefOf<Row, V = unknown> = [keyof Row] extends [never]\n ? never\n : [unknown] extends [V]\n ? ColRef<Extract<keyof Row, string>>\n : ColRef<Extract<ColumnsComparableTo<Row, V>, string>>;\n\n/**\n * Doğrulanmış, GÖMÜLEBİLİR bir SQL parçası (FR-018, FR-019).\n *\n * Wire şekli `{ $sql: { text, values } }`: `text` parçalar hâlinde tutulur ve\n * değerler ARADA durur, çünkü birleştirilmiş tek bir string'in içinden hangi\n * kısmın kullanıcı verisi olduğunu bir daha kimse çıkaramaz — enjeksiyonun\n * doğduğu yer tam olarak orasıdır.\n */\nexport type SqlFragment = {\n readonly $sql: { readonly text: readonly string[]; readonly values: readonly unknown[] };\n};\n\n/**\n * Retryable bir hatada işlemi yeniden dener (FR-037).\n *\n * D-016: retry'SIZ bir izolasyon yükseltmesi sunmak defect'tir — kullanıcıya\n * çalışmayan bir düğme vermektir. `SerializationFailure`'ın metni\n * *\"{ retry: n } verebilirsiniz\"* diyor; bu fonksiyon o düğmenin gerçekten\n * çalışan yarısı.\n *\n * VARSAYILAN SIFIR. Sessiz bir varsayılan retry, idempotent OLMAYAN bir işlemi\n * çağıranın haberi olmadan iki kez çalıştırırdı — bir para transferini iki kez.\n * Tekrar denemek çağıranın kararı.\n *\n * Yalnız `isRetryable(e)` olan hatalar tekrarlanır. Küme dar tutuluyor: `23505`\n * buraya girseydi tekrar denemek aynı cevabı verir ve döngü boşuna dönerdi.\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n opts: { retry?: number } = {},\n): Promise<T> {\n const budget = opts.retry ?? 0;\n let attempt = 0;\n for (;;) {\n try {\n return await fn();\n } catch (e) {\n // Bütçe bittiğinde SON hata fırlatılıyor, sarmalanmıyor: çağıranın\n // gördüğü şey Postgres'in söylediği şey olsun.\n if (attempt >= budget || !isRetryable(e)) throw e;\n attempt += 1;\n }\n }\n}\n\n/**\n * K3: sorgudan KAÇMAK için değil, sorgunun İÇİNE girmek için kaçış kapağı.\n *\n * ```ts\n * Database.public.notes.findMany({\n * where: sqlFragment`similarity(title, ${q}) > 0.3`,\n * orderBy: { column: \"created_at\", direction: \"desc\" },\n * limit: 20,\n * })\n * ```\n *\n * `select` / `orderBy` / `limit` / RLS aynen çalışmaya devam eder — \"yetmedi,\n * ham SQL'e geçeyim\" anının bugünkü maliyeti tam olarak bunları kaybetmekti.\n *\n * TANIMLAYICI GÖMME YÜZEYİ YOK (`.raw` / `.unsafe` / `.identifier`). Drizzle'ın\n * CVE-2026-39356'sı ve Knex'in CVE-2019-10757'si tam o kapakta doğdu.\n *\n * Ve kapak fonksiyonun ÜSTÜNDE olmakla bitmiyordu: parça MARKALI değilken\n * `{\"$sql\":{\"text\":[\"1=1 -- pwned\"],\"values\":[]}}` düz JSON'dan uydurulup\n * guard'ın tamamını atlıyordu (W2-B/C3, ölçüldü). Marka o kapağı wire ŞEKLİNE\n * de koyuyor — parça yalnız bu template tag'inden çıkabilir.\n */\nexport function sqlFragment(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): SqlFragment {\n return brandRef({ $sql: { text: [...strings], values } }, \"sql\");\n}\n\nexport type TextOps<V> = V extends string\n ? { contains?: string; icontains?: string; startsWith?: string; endsWith?: string }\n : Record<never, never>;\n\n/** Operatör gövdesi, kolon-referans tipi DIŞARIDAN verilmiş hâliyle.\n *\n * `C` bir parametre, çünkü `ColRefOf<Row, V>` aksi hâlde altı operatör\n * konumunda AYRI AYRI instantiate edilirdi — kolon başına altı mapped type.\n * Böyle kolon başına BİR tane (N-2). */\n/**\n * `now()` HANGİ kolonlarda karşılaştırma değeri olabilir.\n *\n * `timestamp` TypeScript'e `string` olarak geliyor — `text` ile aynı tip. Yani\n * \"yalnız zaman kolonları\" tip düzeyinde İFADE EDİLEMEZ (D-021'in tam olarak\n * kaydettiği sınır: TS numeric/bigint/text/uuid/timestamp'ı `string`'e\n * çöktürüyor). İki seçenekten yanlış KABUL, yanlış RET'e tercih ediliyor:\n * `now()`'ı bir metin kolonunda yazmak Postgres hatası verir, ama zaman\n * kolonunda YASAKLAMAK yazarı bu yüzden `sqlFragment`e düşürürdü — ve bu\n * özelliğin var olma nedeni tam olarak o düşüşü kaldırmak.\n */\ntype NowComparable<V> = \"?\" extends PgTag<V>\n ? [NonNullable<V>] extends [string | Date]\n ? TxNow\n : never\n : PgTag<V> extends \"timestamp\"\n ? TxNow\n : never;\n\ntype WhereOpBody<V, C> = {\n gt?: V | C | NowComparable<V>;\n gte?: V | C | NowComparable<V>;\n lt?: V | C | NowComparable<V>;\n lte?: V | C | NowComparable<V>;\n neq?: V | C | NowComparable<V>;\n in?: V[];\n /** `IS NULL` / `IS NOT NULL` (FR-006) — `= NULL` SQL'de her zaman UNKNOWN'dır. */\n isNull?: boolean;\n} & TextOps<V>;\n\nexport type WhereOp<V, Row = unknown> = WhereOpWith<V, ColRefOf<Row, V>>;\n\n/**\n * Operatör sözlüğü, kolon-referans/plan-tutamağı konumu DIŞARIDAN verilmiş.\n *\n * `export`, çünkü plan yüzeyi (`tx-plan.ts`) aynı sözlüğü `C = ColRefOf<…> |\n * Ref<…>` ile kuruyor: bir plan filtresi ÖNCEKİ bir işlemin sonucuna\n * bakabiliyor, `findMany` bakamıyor. Ref'i `V`'ye eklemek YANLIŞ olurdu —\n * `TextOps<V>` `V extends string` diye soruyor ve `string | Ref<string>` o\n * soruya HAYIR der, yani `contains`/`startsWith` sessizce KAYBOLURDU.\n */\nexport type WhereOpWith<V, C> = V | C | NowComparable<V> | WhereOpBody<V, C>;\n\n/**\n * A filter over a row: every field optional, each one a plain value (equality)\n * or an operator object. THE filter language — `findMany`, `updateMany`,\n * `deleteMany` and `count` all take this one, because two spellings of a filter\n * is how the two come to disagree.\n */\nexport type WhereFilter<Row> = { [K in keyof Row]?: WhereOp<Row[K], Row> } & {\n /**\n * Boolean bileşimi (FR-007). Dallar aynı filtre dilidir — iki yazım olmaz.\n *\n * ÖZYİNELEME BURADA BAŞLIYOR ve N-2'nin izlediği şey tam olarak budur:\n * Kysely'nin TS7'de 9,8M instantiation üreten vakası derin generic\n * özyinelemeydi. Burada derinlik yazarın filtresi kadardır ve pratikte\n * bir-iki seviyedir; tip maliyeti T001'in tavanına karşı ölçülür.\n *\n * Dal bir `sqlFragment` DE olabilir. Motor bunu zaten derliyordu — parantezli\n * ve parametreli (`… AND (((expires_at > now())) AND (t.\"city\" = $2))`) —\n * ama tip yalnız üst düzey `where`'de fragment'e izin veriyordu. Yani\n * \"fragment sorgudan KAÇMAK için değil, sorgunun İÇİNE girmek için\" sözü tam\n * da bileşim anında kırılıyordu: bir koşulu bir fragment'le birleştirmek\n * isteyen yazar SORGUNUN TAMAMINI ham SQL'e taşımak zorunda kalıyordu.\n * Ölçüldü: bir müşteri sorgusunda tam olarak bu oldu.\n */\n OR?: (WhereFilter<Row> | SqlFragment)[];\n AND?: (WhereFilter<Row> | SqlFragment)[];\n NOT?: WhereFilter<Row> | SqlFragment;\n};\n\n/**\n * Ordering and paging for a read.\n *\n * `column` is `keyof Row`, not `string`: a mistyped column name is a compile\n * error here rather than a runtime rejection three layers down. `offset`\n * without `limit` is refused by the engine — a page with no size is not a page.\n */\nexport type OrderBySpec<Row> = {\n column: Extract<keyof Row, string>;\n direction?: \"asc\" | \"desc\";\n /** NULL'ların yeri (FR-008). Verilmezse Postgres varsayılanı geçerlidir ve o\n * varsayılan YÖNE GÖRE DEĞİŞİR: ASC'de NULLS LAST, DESC'te NULLS FIRST. */\n nulls?: \"first\" | \"last\";\n};\n\ntype FindManyOpts<Row> = {\n /** Tek sıralama ya da SIRALI liste — sıra korunur (FR-008). */\n orderBy?: OrderBySpec<Row> | OrderBySpec<Row>[];\n limit?: number;\n offset?: number;\n};\n\n/**\n * Bir okumanın TEK parametresi (FR-004b).\n *\n * `where` bir ALAN, konumsal bir argüman değil. Kullanıcının kararı: \"deterministik\n * olması lazım, tek düzlem\" — aynı bilginin iki yere dağılması, alanlar çoğaldıkça\n * (select/include/orderBy) \"hangisi nereye\" sorusunu ezberlenecek bir şeye çevirir.\n * Prisma ve Drizzle de tek obje kullanıyor. Bedeli açık ve kabul edildi: en sık\n * kullanım uzuyor — `findMany({ where: { owner: uid } })`.\n *\n * ÖZYİNELEMESİZ kalmak zorunda (N-2): tip maliyeti şekilden değil özyineleme\n * derinliğinden geliyor (Kysely'nin TS7'de 9,8M instantiation vakası).\n */\n/**\n * `has` — İLİŞKİ ÜZERİNDEN SÜZME, JOIN'in ihtiyaç duyulmayan hâli.\n *\n * ```ts\n * Database.public.interests.findMany({\n * where: { has: { user_interests: { user_id: uid } } },\n * orderBy: [{ column: \"sort_order\" }, { column: \"name\" }],\n * })\n * ```\n * → `… WHERE t.\"id\" IN (SELECT r1.\"interest_id\" FROM \"user_interests\" r1\n * WHERE r1.\"user_id\" = $1)`\n *\n * İlişki ADLARI ve gittikleri kolonlar `palbase-env.d.ts`'in ZATEN bastığı\n * `relations` bloğundan geliyor — yabancı anahtarlardan türetiliyorlar, yazar\n * hiçbir kolon adı yazmıyor. O blok üretiliyordu ve HİÇBİR okuma onu\n * kullanmıyordu; `has` onun karşılığı.\n *\n * İç filtre AYNI dil: bir tablo ötesinde de `gt`, `icontains`, `OR`, ve iç içe\n * `has` yazılabiliyor.\n */\n/**\n * İlişkinin HEDEF TABLOSU — anahtar ŞEMA NİTELİKLİ gelir.\n *\n * `buildRelations` `to`'yu `qualifiedTableKey` ile yazıyor: public için düz ad\n * (`\"interests\"`), başka şema için noktalı (`\"billing.invoices\"`). `Tables`\n * yalnız public'i taşır, diğerleri `Schemas`'tadır — noktalı anahtarı doğrudan\n * `Tables`'ta aramak HER ZAMAN ıskalar ve iç filtre sessizce `Record<string,\n * unknown>`'a düşerdi: bilinmeyen kolon da, yanlış tip de derlenirdi (ölçüldü).\n */\ntype RelatedTable<To> = To extends `${infer S}.${infer T}`\n ? S extends keyof Schemas\n ? T extends keyof Schemas[S]\n ? Schemas[S][T]\n : never\n : never\n : To extends keyof Tables\n ? Tables[To]\n : never;\n\ntype RelatedRow<To> = RelatedTable<To> extends { row: infer R } ? R : Record<string, unknown>;\ntype RelatedRels<To> = RelatedTable<To> extends { relations: infer R } ? R : unknown;\n\n/**\n * İç içe `has` ÜÇ seviyeyle sınırlı.\n *\n * Üretilen `relations` bloğu ÇİFT YÖNLÜ: `customers.invoices` ile\n * `invoices.customer` birbirini gösteriyor, yani grafiğin kendisi döngülü.\n * Sınırsız açılım bu döngüyü sonsuz bir tipe çevirirdi — TypeScript'in\n * \"excessively deep\" hatası, yazılan sorgunun karmaşıklığından değil ŞEMANIN\n * şeklinden gelirdi. Üç seviye, ölçtüğümüz tüm gerçek sorguların üstünde.\n */\ntype HasDepth = 0 | 1 | 2 | 3;\ntype HasDec = [0, 0, 1, 2];\ntype HasNest<Rels, D extends HasDepth> = [keyof Rels] extends [never]\n ? unknown\n : D extends 0\n ? unknown\n : { has?: HasFilter<Rels, HasDec[D]> };\n\ntype HasFilter<Rels, D extends HasDepth = 3> = {\n [R in keyof Rels]?: Rels[R] extends { to: infer To }\n ? WhereFilter<RelatedRow<To>> & HasNest<RelatedRels<To>, D>\n : never;\n};\n\n/** İlişki bilgisi taşıyan bir tablo tipinin filtre yüzeyi. */\nexport type WhereWithRelations<Row, Rels> = WhereFilter<Row> & { has?: HasFilter<Rels> };\n\n/**\n * `has` dalı — SADECE `has`, satır filtresi olmadan.\n *\n * Plan yolunun filtre dili (`TxWhere`) düz op'unkiyle aynı değil: orada bir\n * alan ÖNCEKİ bir işlemin satırına referans (`Ref`) taşıyabiliyor. `has`'ı\n * plana taşımak için o dili kopyalamak gerekmiyor — kesişimle EKLENİYOR.\n * İlişki yoksa `unknown` dönüyor, çünkü `X & unknown = X`: dal yok olur ve\n * `has` fazla-alan denetimine takılır.\n */\nexport type HasOnly<Rels> = [unknown] extends [Rels]\n ? unknown\n : [keyof Rels] extends [never]\n ? unknown\n : { has?: HasFilter<Rels> };\n\n/**\n * `has` dalı NE ZAMAN var olur.\n *\n * İlişkisi OLMAYAN bir tabloda `has` hiç yazılamamalı. `HasFilter<{}>` boş bir\n * nesne tipidir ve boş nesne tipi HER nesneyi kabul eder — yani dalı koşulsuz\n * eklemek, ilişkisiz bir tabloda `has: { neyse_ne: {} }`'yi SESSİZCE geçirirdi\n * (ölçüldü: kapı yeşil, çalışma anında \"böyle bir ilişki yok\" hatası).\n */\ntype HasBranch<Row, Rels> = [unknown] extends [Rels]\n ? never\n : [keyof Rels] extends [never]\n ? never\n : WhereWithRelations<Row, Rels>;\n\nexport type QueryInput<Row, K extends keyof Row = keyof Row, Rels = unknown> = {\n /**\n * Filtre — ya tipli filtre dili ya da bir `sqlFragment` (FR-018). İkisi de\n * AYNI alandır: kademe atlamak bir parametre değişikliği, ayrı bir çağrı\n * yolu değil (P1).\n */\n where?: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;\n /**\n * Projeksiyon (FR-009): yalnız bu kolonlar çekilir ve DÖNÜŞ TİPİ buna daralır.\n *\n * Tip `Pick<Row, K>` ile TÜRETİLİR, üretilmez: `select` kombinasyonları için\n * tip basmak, üretilen `.d.ts`'i kombinatoryal olarak şişirirdi (N-1: tablo\n * başına ≤ 25 satır).\n */\n select?: readonly K[];\n} & FindManyOpts<Row>;\n\n/** Bir yazmanın TEK parametresi: neyi (`where`) neye çevirdiğin (`set`). */\nexport type MutateInput<Row, Insert, Rels = unknown> = {\n where: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;\n set: SetShape<Insert>;\n};\n\n/**\n * `set`'e yazılabilen değer (FR-012): kolonun kendi tipi ya da — sayısal\n * kolonlarda — kolonun ŞU ANKİ değerini okuyan bir ifade.\n *\n * `increment()` metin ya da boolean kolonda YOK: \"kolona ekle\"nin orada bir\n * anlamı olmadığı için ifade edilemez kılınıyor (P5 — anlatmak değil, ifade\n * edilemez kılmak). `numeric` kolonlar TypeScript'te `string` taşır, o yüzden\n * string de sayısal sayılır; ayrımı burada yapamayız, ama D-007 zaten miktarın\n * JS `number`'a hiç uğramamasını istiyor.\n */\n/** `increment()`/`decrement()` HANGİ kolonlarda anlamlı — bildirilmiş PG tipine\n * göre. Marka yoksa eski sezgisel (`number | string`), ki o `text` kolonda da\n * izin veriyordu: Postgres `text + 1` demez. */\ntype NumericCol<V> = \"?\" extends PgTag<V>\n ? NonNullable<V> extends number | string\n ? TxColumnExpr\n : never\n : PgKind<PgTag<V>> extends \"num\"\n ? TxColumnExpr\n : never;\n\n/**\n * Bir EKLEME yolunda yazılabilecek değer.\n *\n * Kolonun kendi tipi ya da — zaman kolonlarında — sunucu saati. `increment()`\n * burada YOK ve olamaz: satır henüz yokken \"kolonun şu anki değeri\" diye bir\n * şey yok, motor da bunu adıyla reddediyor.\n *\n * Var olma nedeni ölçülmüş: introspect edilmiş şemalarda zaman kolonlarının\n * çoğu varsayılansız (`timestamp()`), yani \"eklerken sunucu saatini yaz\"ın tek\n * karşılığı istemci saatiydi — 33 tablolu bir projede 12 yerde.\n */\nexport type InsertValues<Insert> = {\n [K in keyof Insert]: Insert[K] | NowComparable<Insert[K]>;\n};\n\nexport type SetValue<V> =\n | V\n | NumericCol<V>\n // `now()` doğrudan yolda da geçerli: motor onu `SET col = now()` diye\n // derliyor (plan yolunun her zaman yaptığı gibi). Tipte yasaklamak, çalışan\n // bir çağrıyı ifade edilemez kılardı — P5'in tersi.\n //\n // VE TAM OLARAK BUNU YAPIYORDU: koşul `Date` idi, oysa `timestamp` kolonlar\n // TypeScript'e `string` geliyor. Yani `set: { updated_at: now() }` —\n // yazılabilecek en sık yazma ifadesi — HİÇBİR üretilmiş şemada derlenmiyordu\n // (ölçüldü). Marka o koşulu doğru yazılabilir kıldı.\n | NowComparable<V>;\n\n/** Bir update'in `set`'i: insert şeklinin herhangi bir alt kümesi, ifadelerle. */\nexport type SetShape<Insert> = { [K in keyof Insert]?: SetValue<Insert[K]> };\n\n/** search() parametreleri, satır tipiyle koşullanmış (FR-013). `offset` BİLEREK yok (UD-013). */\nexport interface SearchParamsTyped<T extends TableTypes> {\n /** Metin sorgusu: FTS kolunu besler; embed beyanlıysa sorgu vektörü de bundan üretilir. */\n query?: string;\n /** Hazır sorgu vektörü — verilirse embed çağrısı olmaz (FR-025). */\n vector?: number[];\n /** `findMany`'nin filtre dili — İKİNCİ tip argümanıyla, yoksa `Row` sessizce\n * `unknown`'a düşer ve `col()` burada ifade edilemez olurdu. Motor `search`\n * için aynı `compileWhereBare`'i kullanıyor; yetenek orada (gözcü I7). */\n where?: { [K in keyof T[\"row\"]]?: WhereOp<T[\"row\"][K], T[\"row\"]> };\n /** default 20, tavan 100 (engine uygular). */\n limit?: number;\n /** Birden çok vektör kolonunda hedef seçimi (model geçişi, FR-013/using). */\n using?: string;\n mode?: \"hybrid\" | \"text\" | \"vector\";\n /** Nihai (RRF-sonrası) skor alt eşiği — süzme LIMIT'ten önce uygulanır (FR-001). */\n minScore?: number;\n /** Chunk-modunda satır başına en iyi blok sayısı (1..10, vars. 3; FR-015). */\n blocksPerRow?: number;\n /** Tazelik çürümesi: nihai skor RRF-sonrası exp(-ln(2)*yaş/halfLife) ile çarpılır;\n * field bir timestamp kolonu, halfLife \"90s\" | \"15m\" | \"12h\" | \"30d\" biçiminde (FR-004). */\n recency?: { field: Extract<keyof T[\"row\"], string>; halfLife: string };\n /** Satır-modunda FTS eşleşme vurgusu: sonuç satırına `_highlight` ekler;\n * 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 versiyon;\n * \"all\" tüm versiyonlar; {asOf} o anda geçerli olan (FR-029). */\n validity?: \"all\" | { asOf: string };\n /** Alan-boost (FR-030): skor * (1 + w·x/(1+x)) — sayısal kolonla sınırlı\n * çarpan, dış servissiz; bileşim RRF → boost → recency → minScore. */\n boost?: { field: Extract<keyof T[\"row\"], string>; weight: number };\n}\n\n/**\n * `facets()` dönüşü (FR-027, FR-058): kolon adı → o kolonun top-20 değeri ve\n * sayacı.\n *\n * Bu tip bir zamanlar `search()` dönüş DİZİSİNİN üstünde taşınıyordu; dizi-üstü\n * özellik `JSON.stringify`'da kayboluyor, yani bir kontrolcü onu döndürmeye\n * çalıştığında yanıt gövdesinde hiç görünmüyordu. Sayaçlar artık BAĞIMSIZ\n * dönüşle geliyor ve tip de o dönüşü adlandırıyor.\n */\nexport type SearchFacets = Record<string, { value: string | null; count: number }[]>;\n\n/** similar()/recommend() taşıyıcı opsiyonları (T018, FR-022): search'ün\n * paramlarından query/vector/mode düşer — hedef vektörü metodun kendisi\n * DB'den kurar; facets/highlight de düşer (T020) — engine bu ikisini\n * similar/recommend'e geçirmez, tip vaadi gerçekle aynı kalır. */\nexport type SimilarParamsTyped<T extends TableTypes> = Omit<\n SearchParamsTyped<T>,\n \"query\" | \"vector\" | \"mode\" | \"facets\" | \"highlight\"\n>;\n\n/** recommend() parametreleri (T018, FR-023). */\nexport type RecommendParamsTyped<T extends TableTypes> = SimilarParamsTyped<T> & {\n /** Kaynak beğeniler — hedef vektör bunların DB-içi avg'ı; boş olamaz. */\n positive: string[];\n /** İtilen örnekler — hedef pos.v + (pos.v - neg.v) ile yönlenir. */\n negative?: string[];\n};\n\n/**\n * Tablonun ilişki bloğu — env `Tables` girdisinden.\n *\n * TEK yerde türetiliyor ve HER op'a aynısı veriliyor: `has` yalnız `findMany`'de\n * olsaydı, \"aynı filtre dili her op'ta\" sözü ilk `deleteMany`'de kırılırdı.\n */\ntype RelsOf<T> = T extends { relations: infer R } ? R : unknown;\n\n/** Temel tablo erişimcisi — search'süz beş op. */\nexport interface EnvTypedTableBase<T extends TableTypes> {\n insert(data: InsertValues<T[\"insert\"]>): Promise<T[\"row\"]>;\n /**\n * Çok satırı TEK statement'la ekle (tek gidiş-dönüş).\n *\n * ```ts\n * await Database.public.journey_stops.insertMany(\n * stops.map((s, i) => ({ journey_id, name: s.name, sort_order: i })),\n * );\n * ```\n *\n * Satırların anahtar kümesi AYNI olmalı: tek statement kolon listesini\n * paylaşır, yani farklı şekilli bir satırın fazla kolonu sessizce yazılmaz\n * ve eksiği yanlış sütuna kayardı. Eksik alan için `null` yazın.\n *\n * Boş dizi boş sonuç döner — hata değil: \"eklenecek bir şey yoktu\".\n */\n insertMany(\n rows: readonly InsertValues<T[\"insert\"]>[],\n opts?: {\n /** Çakışmanın ARANDIĞI kolonlar — benzersiz bir kısıt ya da index taşımalı. */\n onConflict: readonly Extract<keyof T[\"row\"], string>[];\n /** `\"ignore\"` (VARSAYILAN, plan yoluyla aynı) çakışanı atlar ve o satır\n * SONUÇTA DÖNMEZ — Postgres yalnız yazdıklarını döndürür; `\"update\"`\n * üzerine yazar. */\n action?: \"ignore\" | \"update\";\n },\n ): Promise<T[\"row\"][]>;\n /**\n * Bir idempotency anahtarını sahiplen (FR-033).\n *\n * ```ts\n * const { inserted, row } = await Database.public.payments.claim(\n * { idem_key: req.headers[\"idempotency-key\"] },\n * { amount, user_id },\n * );\n * if (!inserted) return row; // aynı istek ikinci kez geldi\n * ```\n *\n * `inserted: false` bir HATA DEĞİL: dönen satır ilk çağrının satırıdır.\n * İlk argüman satırı BULAN alanlar, ikincisi yalnız yazılanlar — ikinci çağrı\n * farklı bir yük gönderse bile satır anahtarla bulunur.\n */\n claim(\n unique: Partial<T[\"insert\"]>,\n extra?: Partial<InsertValues<T[\"insert\"]>>,\n ): Promise<{ inserted: boolean; row: T[\"row\"] }>;\n /**\n * Satırı yaz; `onConflict` kolonlarında çakışırsa ÜZERİNE yaz (FR-034).\n *\n * ```ts\n * await Database.public.settings.put({\n * data: { user_id, theme: \"dark\" },\n * onConflict: [\"user_id\"],\n * });\n * ```\n *\n * `onConflict` kolonları benzersiz bir kısıt ya da index taşımalı — Postgres\n * onlarla eşleştirir — ve güncellemeden dışlanırlar, çünkü eşleşen şey onlar.\n *\n * **`upsert`'ün yerine geldi ve adı bilerek değişti.** `upsert` tek isim\n * altında iki niyet taşıyordu: \"yoksa ekle varsa güncelle\" (bu) ve \"idempotent\n * yaz\" (artık {@link EnvTypedTableBase.claim}). İkincisi için ÖLÇÜLMÜŞ biçimde\n * yanlıştı: `DO UPDATE` ikinci çağrının verisiyle birincininkini EZİYOR\n * (10.00 → 999.00 ölçüldü). İki niyeti tek isimde tutmak, yanlış olanı\n * seçmeyi kolay yapıyordu.\n */\n put(q: {\n data: InsertValues<T[\"insert\"]>;\n onConflict: readonly Extract<keyof T[\"row\"], string>[];\n }): Promise<T[\"row\"]>;\n /** Update the row by id; resolves to the updated row, or `null` if no row\n * matched (absent or RLS-hidden) — an idempotent outcome, mirroring\n * `findById`. The runtime returns a null row rather than throwing. */\n update(q: { where: { id: string }; set: SetShape<T[\"insert\"]> }): Promise<T[\"row\"] | null>;\n delete(id: string): Promise<void>;\n findById(id: string): Promise<T[\"row\"] | null>;\n /** Rows matching the filter. See {@link WhereFilter} / {@link FindManyOpts} —\n * this declaration is what makes the engine's operators callable. */\n findMany<K extends keyof T[\"row\"] = keyof T[\"row\"]>(\n q?: QueryInput<T[\"row\"], K, RelsOf<T>>,\n ): Promise<Pick<T[\"row\"], K>[]>;\n /**\n * Update every matching row in one statement; an empty filter is refused.\n *\n * **0 satır dönmesi hata DEĞİL, başarı da değil** (FR-014): koşulu `where`'e\n * koyup dönen diziyi kontrol etmek, \"önce oku sonra yaz\"ın yarış koşulu\n * olmayan hâlidir.\n *\n * ```ts\n * const [row] = await Database.public.accounts.updateMany({\n * where: { id, balance: { gte: amount } },\n * set: { balance: decrement(amount) },\n * });\n * if (row === undefined) throw new Conflict(\"yetersiz bakiye\");\n * ```\n */\n updateMany(q: MutateInput<T[\"row\"], T[\"insert\"], RelsOf<T>>): Promise<T[\"row\"][]>;\n /** Delete every matching row; resolves to how many. Empty filter refused. */\n deleteMany(q: { where: WhereFilter<T[\"row\"]> | SqlFragment | HasBranch<T[\"row\"], RelsOf<T>> }): Promise<number>;\n /** How many rows match. An empty filter is legitimate: counting is a read. */\n count(q?: { where?: WhereFilter<T[\"row\"]> | SqlFragment | HasBranch<T[\"row\"], RelsOf<T>> }): Promise<number>;\n /** Validity'li tabloda satırın yeni versiyonu (FR-029, C-9): eski satır\n * kapanır (valid_to/superseded_by), yenisi TEK savepoint'te eklenir; dönüş\n * yeni satır. Validity beyanı olmayan tabloda adlandırılmış çalışma-zamanı\n * hatası — tip düzeyinde ayrım env `Tables` bayrağı taşımadığından yapılamaz. */\n supersede(id: string, row: InsertValues<T[\"insert\"]>): Promise<T[\"row\"]>;\n}\n\n/** Tablo erişimcisi: env girdisi `searchable: true` taşıyorsa (vector kolonu ya da\n * search beyanı — env-gen üretir) `search()` üyesi VARDIR; yoksa üye hiç yoktur ve\n * çağrı derleme hatasıdır (FR-013). Yapısal koşul TableTypes'ı genişletmeden çalışır. */\n/**\n * `appendOnly` tabloda YAYIMLANMAYAN üyeler (FR-031).\n *\n * Altısı da ayrı ayrı: biri unutulursa append-only sözü o üye üzerinden sessizce\n * delinir. `insert` ve okuma üyeleri kalır — düzeltme SİLMEKLE değil, telafi\n * kaydı EKLEMEKLE yapılır (FR-032).\n */\ntype AppendOnlyForbidden = \"update\" | \"updateMany\" | \"delete\" | \"deleteMany\" | \"put\" | \"supersede\";\n\nexport type EnvTypedTable<T extends TableTypes> = (T extends { appendOnly: true }\n ? Omit<EnvTypedTableBase<T>, AppendOnlyForbidden>\n : EnvTypedTableBase<T>) &\n (T extends { searchable: true }\n ? {\n search(\n params: SearchParamsTyped<T>,\n ): Promise<Array<T[\"row\"] & { _score: number; _highlight?: string }>>;\n /** \"Bu satıra benzeyenler\" (FR-022): hedef vektör DB'den okunur,\n * kaynak satır sonuçta yoktur; id yoksa adlandırılmış hata. */\n similar(id: string, params?: SimilarParamsTyped<T>): Promise<Array<T[\"row\"] & { _score: number }>>;\n /** D-021: sayaçlar bağımsız dönüşle — search'ün dizi-üstü _facets'i\n * JSON.stringify'da kaybolur; ciddi sözleşme budur. */\n facets(params: { facets: Array<keyof T[\"row\"] & string>; where?: Partial<T[\"row\"]>; validity?: \"all\" | { asOf: string } }): Promise<SearchFacets>;\n /** positive/negative beğenilerden öneri (FR-023): hedef vektör DB-içi\n * avg CTE'leriyle; kaynak id'ler sonuçta yoktur. */\n recommend(params: RecommendParamsTyped<T>): Promise<Array<T[\"row\"] & { _score: number }>>;\n }\n : Record<never, never>);\n\n/** The `tables` map exposed on `Database`/`tx`, keyed by the env `Tables`\n * interface. When no schema is declared `Tables` is empty, so `tables` is an\n * empty object — accessing `.tables.foo` is then a compile error (no member). */\nexport type EnvTables = {\n [K in keyof Tables]: EnvTypedTable<Tables[K]>;\n};\n\n/**\n * The project's NON-public schemas, keyed by schema name, each exposing its own\n * `tables` map — the shape `Database.schema(\"billing\")` returns.\n *\n * The intermediate `tables` is there for the reason {@link EnvTables} sits under\n * `.tables`: a schema's table names must not share a namespace with anything the\n * accessor itself might grow.\n *\n * Empty by default. The generated `palbase-env.d.ts` augments `Schemas` with one\n * member per declared schema other than `public`, so a project that declares\n * none has `keyof Schemas = never` and every `schema(...)` call is a compile\n * error rather than a runtime surprise.\n */\n/**\n * @deprecated ARTIK VAR OLMAYAN BİR ŞEKLİ tarif ediyor. Bu tip her şemayı\n * `{ tables: … }` altında gösteriyor; yüzey FR-001 ile `Database.<şema>.<tablo>`\n * oldu ve `.tables` ara katmanı KALKTI. Güncel şekil: {@link EnvSchemaSurface}.\n *\n * Kaldırılmadı çünkü dışa açık bir tip ve kaldırmak SEKİZİNCİ bir kırıcı olurdu;\n * ama bir tip, çalışma zamanının ÜRETMEDİĞİ bir şekli tarif ediyorsa yalan\n * söylüyor demektir — `const x: EnvSchemas[\"billing\"] = Database.billing`\n * açıklanamayan bir derleme hatası verir. Bir sonraki kırıcı sürümde silinmeli\n * (defter D-18).\n *\n * Bu tipi ÜRETEN iki fonksiyon (`makeTablesAccessor`, `makeSchemaAccessor`)\n * ölçüldü: hiçbir yerden çağrılmıyorlardı ve silindiler. Canlı yol\n * `makeTypedSurface`'ın proxy'si.\n */\nexport type EnvSchemas = {\n [S in keyof Schemas]: {\n tables: {\n [T in keyof Schemas[S]]: EnvTypedTable<Extract<Schemas[S][T], TableTypes>>;\n };\n };\n};\n\n/** The project's tables as PLAN operations, keyed by the env `Tables`\n * interface. The transaction twin of {@link EnvTables}. */\n/** `appendOnly` bir tabloda transaction planının da kaybettiği üyeler. Doğrudan\n * yüzeyin `AppendOnlyForbidden`'ının plan-yolu ikizi; adlar farklı çünkü plan\n * yüzeyinin üye adları farklı. */\ntype TxAppendOnlyForbidden = \"put\" | \"updateWhere\" | \"deleteWhere\";\n\n/**\n * Plan yüzeyi de `appendOnly`'yi UYGULUYOR — ve uygulamıyor olması bir kusurdu.\n *\n * `EnvTypedTable` altı üyeyi Omit ediyordu, ama `TxTables` hiçbirini: yani\n * `tx.tables.entries.updateWhere(…)` ve `.put(…)` DERLENİYORDU. Tip bir şeyi\n * \"ifade edilemez\" ilan edip ikinci bir kapıda ifade edilebilir bırakırsa,\n * ilan yalandır (doğrulayıcı gözcü, FR-031).\n *\n * Motor da aynı üçünü adıyla reddediyor — tip atlanınca susmaması için.\n */\nexport type TxTables = {\n [K in keyof Tables]: Tables[K] extends { appendOnly: true }\n ? Omit<TxTable<Tables[K][\"row\"], Tables[K][\"insert\"], RelsOf<Tables[K]>>, TxAppendOnlyForbidden>\n : TxTable<Tables[K][\"row\"], Tables[K][\"insert\"], RelsOf<Tables[K]>>;\n};\n\n/** Bir şemanın tabloları PLAN operasyonları olarak — `TxTables`'ın public\n * DIŞI şemalar için ikizi. */\ntype TxTablesOf<S> = {\n [T in keyof S]: Extract<S[T], TableTypes> extends { appendOnly: true }\n ? Omit<\n TxTable<\n Extract<S[T], TableTypes>[\"row\"],\n Extract<S[T], TableTypes>[\"insert\"],\n RelsOf<Extract<S[T], TableTypes>>\n >,\n TxAppendOnlyForbidden\n >\n : TxTable<\n Extract<S[T], TableTypes>[\"row\"],\n Extract<S[T], TableTypes>[\"insert\"],\n RelsOf<Extract<S[T], TableTypes>>\n >;\n};\n\n/**\n * Plan tutamağının şema yüzeyi — `EnvSchemaSurface`'ın BİREBİR ikizi.\n *\n * NEDEN AYNI ŞEKİL: `Database.billing.invoices` yazılabiliyorken\n * `tx.billing.invoices` yazılamıyordu, yani `billing` şemasındaki iki tabloyu\n * TEK ATOMİK PLANDA yazmak imkânsızdı — yazar `$query`'ye düşüyor, tipi ve RLS\n * yardımını kaybediyordu. Bu yüzeyin kapatmak için var olduğu düşüşün ta\n * kendisi, ve GOAL'ün \"ciddi ölçekli fintech\" yarısının tam ortasında\n * (nihai inceleme I-6).\n */\nexport type TxSchemaSurface = { public: TxTables } & {\n [S in keyof Schemas]: TxTablesOf<Schemas[S]>;\n};\n\n/**\n * The handle a `Database.$transaction(…)` callback receives.\n *\n * Tables only — no `query`, no `findById`, no `asService`. A read whose value\n * the plan does not write belongs outside the transaction, where it costs one\n * round trip and is an ordinary value you can branch on.\n *\n * `tx.public.x` ve `tx.<şema>.x`, `Database` ile aynı şekil. `tx.tables.x`\n * public'in TAKMA ADI olarak duruyor: bu run'ın göç notu onu öğretiyor ve her\n * mevcut çağrı onu kullanıyor — kaldırmak sekizinci bir kırıcı olurdu ve\n * hiçbir şey kazandırmazdı.\n */\nexport type TxPlan = TxPlanHandle<TxTables> & TxSchemaSurface;\n\n/**\n * The RLS-bypass sibling returned by `Database.$asService()`. Same typed surface\n * as {@link EnvTypedDatabase} — `tables`, the raw string ops, and a typed\n * `transaction` — but it does NOT re-expose `asService` (no double-bypass).\n * Every op it performs runs as the `service_role` (BYPASSRLS).\n */\nexport type EnvServiceDatabase = EnvSchemaSurface & {\n /** Ham SQL. Generic verilmezse `unknown[]` döner (FR-021). */\n $query: DBClient[\"query\"];\n $insert: DBClient[\"insert\"];\n $update: DBClient[\"update\"];\n $delete: DBClient[\"delete\"];\n $findById: DBClient[\"findById\"];\n $findMany: DBClient[\"findMany\"];\n $put: DBClient[\"put\"];\n $updateMany: DBClient[\"updateMany\"];\n $deleteMany: DBClient[\"deleteMany\"];\n $count: DBClient[\"count\"];\n $search: DBClient[\"search\"];\n $similar: RecoOps[\"similar\"];\n $recommend: RecoOps[\"recommend\"];\n $facets: DBClient[\"facets\"];\n $supersede: DBClient[\"supersede\"];\n $claim: DBClient[\"claim\"];\n $lockRows: DBClient[\"lockRows\"];\n $advisoryXactLock: DBClient[\"advisoryXactLock\"];\n $attempt: DBClient[\"attempt\"];\n /** Bkz. {@link EnvTypedDatabase.$transaction}. */\n /**\n * `opts.retry` verilirse, `SerializationFailure` / `DeadlockDetected`\n * alındığında plan BAŞTAN kurulup yeniden çalıştırılır (FR-037).\n * Varsayılan 0 — sessiz bir retry, idempotent olmayan bir işlemi çağıranın\n * haberi olmadan iki kez çalıştırırdı.\n */\n $transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n opts?: { retry?: number },\n ): Promise<Materialized<T>>;\n }\n\n/**\n * The typed-by-default Database surface: the raw string-keyed `DBClient` ops\n * PLUS a `tables` map typed against the project's generated `palbase-env.d.ts`,\n * a `transaction` that runs a whole plan in one request, and `asService()` for\n * the explicit RLS-bypass sibling.\n *\n * The low-level `txPlan` op is deliberately NOT re-exposed here: `transaction`\n * is the surface, and a hand-built plan would bypass the ref/guard machinery\n * that makes one safe to write.\n */\nexport type EnvSchemaSurface = { public: EnvTables } & {\n [S in keyof Schemas]: {\n [T in keyof Schemas[S]]: EnvTypedTable<Extract<Schemas[S][T], TableTypes>>;\n };\n};\n\n/**\n * `$` öneki, sistem üyelerini kullanıcı adlarından AYIRAN şeydir (FR-002/003).\n *\n * `Database` altında on beşten fazla string-anahtarlı op var ve çoğu son derece\n * makul bir tablo adı — `transaction` bir fintech şemasında neredeyse kaçınılmaz.\n * Şema doğrulayıcısı bir tablo/şema adının `$` ile başlamasına izin vermediği\n * için (`^[a-zA-Z_][a-zA-Z0-9_]*`), önek çakışmayı MATEMATİKSEL olarak imkânsız\n * kılar: bir isim ya `$`'la başlar (sistem) ya başlamaz (kullanıcı).\n */\nexport type DollarOps<T> = { [K in keyof T as `$${string & K}`]: T[K] };\n\n// NOT: `EnvTypedDatabase` bu yardımcıyı KULLANMIYOR, üyelerini AÇIKÇA yazıyor.\n// Sebep ölçüldü: `database.test.ts`'in sayımı TypeScript checker'ıyla yürüyor ve\n// her property'nin declaration'ını arıyor; mapped type ile yeniden adlandırılan\n// property'ler SYNTHETIC'tir, declaration taşımaz, dolayısıyla sayımda GÖRÜNMEZ.\n// Görünmeyen bir yüzey denetlenemez — o testin varlık sebebi de bu. Yardımcı,\n// runtime tarafındaki `satisfies` kontrolü için duruyor.\n\n/**\n * Projenin veri yüzeyi: `Database.<şema>.<tablo>` + `$` önekli sistem üyeleri.\n *\n * Bugünkü `tables` ve `schema(\"x\")` ikilisinin yerine geçer (FR-001). İki yol\n * tek yola iner: `public` de diğer şemalar gibi adıyla anılır, ara katman yoktur.\n *\n * @example\n * await Database.public.notes.findMany({ where: { owner: uid } });\n * await Database.billing.invoices.findMany({ where: { paid: false } });\n * await Database.$transaction((tx) => { … });\n */\nexport type EnvTypedDatabase = EnvSchemaSurface & {\n /** Ham SQL. Generic verilmezse `unknown[]` döner (FR-021). */\n $query: DBClient[\"query\"];\n $insert: DBClient[\"insert\"];\n $update: DBClient[\"update\"];\n $delete: DBClient[\"delete\"];\n $findById: DBClient[\"findById\"];\n $findMany: DBClient[\"findMany\"];\n $put: DBClient[\"put\"];\n $updateMany: DBClient[\"updateMany\"];\n $deleteMany: DBClient[\"deleteMany\"];\n $count: DBClient[\"count\"];\n $search: DBClient[\"search\"];\n $similar: RecoOps[\"similar\"];\n $recommend: RecoOps[\"recommend\"];\n $facets: DBClient[\"facets\"];\n $supersede: DBClient[\"supersede\"];\n $claim: DBClient[\"claim\"];\n $lockRows: DBClient[\"lockRows\"];\n $advisoryXactLock: DBClient[\"advisoryXactLock\"];\n $attempt: DBClient[\"attempt\"];\n /** RLS'i bypass eden kardeş yüzey. Kendisi `$asService` TAŞIMAZ — çift bypass yok. */\n $asService(): EnvServiceDatabase;\n /**\n * Bir transaction çalıştırır. Callback işlemleri TARİF eder; tarifin tamamı\n * tek istekte gider ve broker onu tek bir transaction içinde koşturur.\n * Callback SENKRONDUR: döndüğünde hiçbir şey çalışmamıştır.\n */\n /**\n * `opts.retry` verilirse, `SerializationFailure` / `DeadlockDetected`\n * alındığında plan BAŞTAN kurulup yeniden çalıştırılır (FR-037).\n * Varsayılan 0 — sessiz bir retry, idempotent olmayan bir işlemi çağıranın\n * haberi olmadan iki kez çalıştırırdı.\n */\n $transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n opts?: { retry?: number },\n ): Promise<Materialized<T>>;\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.\n// Politika ifadesinin tel şekli `policy.ts`'te TEK kez bildiriliyor. İki kopya\n// olsaydı biri `exists` düğümünü alır, diğeri almaz ve fark ancak Go tarafı\n// bilmediği bir `kind` gördüğünde ortaya çıkardı.\nimport type { PolicyExpr as PolicyExprJSON } from \"./policy.js\";\nexport type { PolicyExpr as PolicyExprJSON } from \"./policy.js\";\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 /** FR-044: türev FK index'i kapatılmışsa `false`. Bildirilmemişse alan YOK. */\n index?: boolean;\n /** FR-049: kolon increment() ile güncelleniyorsa `true`. Aksi hâlde alan YOK. */\n counter?: boolean;\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 /**\n * `USING (...)` — ham string (kaçış kapağı, FR-028) ya da YAPI (FR-022).\n *\n * Go tarafı ikisini de okur: string olan verbatim emit edilir, yapı olan\n * `generator.go`'da SQL'e çevrilir (C-6). Yapı hâli InitPlan sarmalamasını\n * ve `TO <rol>` daraltmasını GÜVENLE yapılabilir kılan şey — string üstünde\n * regex'le denemek yorum içindeki bir `auth.uid()`'yi de sarmalardı.\n */\n using: string | PolicyExprJSON | null;\n withCheck: string | PolicyExprJSON | null;\n permissive: boolean;\n}\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?: IndexJSON[];\n /**\n * appendOnly (FR-030): tablo yalnız INSERT kabul eder. Sıfır değerde OMIT —\n * bildirmeyen tablolar wire'da bayt-aynı kalır.\n */\n appendOnly?: boolean;\n search?: SearchJSON;\n memory?: MemoryJSON;\n}\n\n/**\n * Bir index'in wire şekli — Go'nun `IndexJSON`'ıyla ALAN-ADI SÖZLEŞMESİ.\n *\n * `name` + `columns` bugünkü hâl; kalanı FR-041…043'ün taşıyıcısı. Hepsi sıfır\n * değerde OMIT edilir: bildirmeyen bir index wire'da eskisiyle bayt-aynı kalır,\n * yoksa dokunulmamış her şema diff'te değişmiş görünür ve her deploy churn üretir.\n */\nexport interface IndexJSON {\n name: string;\n columns: string[];\n /** Partial index koşulu (FR-042) — filtre şekli `WhereFilter` ile aynı. */\n where?: unknown;\n /** İfade index'i (FR-043), ör. `lower(email)`. `columns` ile birlikte kullanılmaz. */\n expression?: string;\n /** Kolon sırası (FR-043). */\n sort?: \"asc\" | \"desc\";\n /** NULL sırası (FR-043). */\n nulls?: \"first\" | \"last\";\n /** Covering index — `INCLUDE (...)` (FR-043). */\n include?: string[];\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 // Yalnız `false` taşınıyor: \"bildirilmedi\" ile \"açık\" aynı şey ve wire'a\n // yazmak bildirmeyen her kolonu diff'te değişmiş gösterirdi.\n if (def.index === false) out.index = false;\n if (def.counter === true) out.counter = true;\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) => {\n // `columns` expression-index'te YOKTUR (ikisi birbirinin alternatifi).\n // Boş dizi ile taşınır: Go tarafı `expression` doluysa onu kullanır.\n const ix: IndexJSON = { name: i.name, columns: i.columns ? [...i.columns] : [] };\n if (i.where !== undefined) ix.where = i.where;\n if (i.expression !== undefined) ix.expression = i.expression;\n if (i.sort !== undefined) ix.sort = i.sort;\n if (i.nulls !== undefined) ix.nulls = i.nulls;\n if (i.include !== undefined) ix.include = [...i.include];\n return ix;\n });\n }\n // Sıfır değerde YAZILMAZ: `appendOnly: false` ile \"bildirilmemiş\" wire'da\n // ayırt edilemez olmalı, yoksa her eski şema diff'te değişmiş görünür.\n if (table.appendOnly === true) out.appendOnly = true;\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"],"mappings":"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","names":["makeTypedTable","name","raw","insert","data","insertMany","rows","opts","put","q","onConflict","update","where","id","set","delete","findById","findMany","updateMany","deleteMany","count","makeTypedDB","schema","tables","key","Object","keys","tableDef","undefined","result","transaction","fn","builder","TxPlanBuilder","planTables","table","runTxPlan","col","name","brandRef","$col","withRetry","fn","opts","budget","retry","attempt","e","isRetryable","sqlFragment","strings","values","$sql","text","defOf","column","_def","columnToJSON","def","out","type","nullable","primaryKey","defaultValue","undefined","defaultRandom","defaultNow","renamedFrom","ignored","owns","references","table","onDeleteAction","index","counter","enumName","enumValues","unique","dimensions","policyToJSON","policy","name","command","roles","using","withCheck","permissive","commonSearchFields","search","synonyms","Object","keys","length","fromEntries","entries","map","word","alts","validity","searchToJSON","vectorColumn","from","model","textCols","text","Array","isArray","columns","v","metric","embed","provider","apiKeyName","baseURL","staleness","mode","chunks","c","size","sizeChars","overlap","overlapChars","vector","legs","leg","memoryToJSON","m","into","subject","extract","tableToJSON","schemaName","schema","rls","policies","uniqueConstraints","u","raw","rawConstraints","r","up","down","checks","expr","indexes","i","ix","where","expression","sort","nulls","include","appendOnly","find","sj","memory","qualifiedTableKey","tableName","toSchemaJSON","schemas","tables","extensions","meta","seen","Set","has","Error","add","values","json","push","exposed"]}
|
|
File without changes
|