@palbase/backend 25.0.0 → 25.0.1

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.
Files changed (43) hide show
  1. package/dist/bin/palbase-backend.cjs +2 -0
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +2 -2
  4. package/dist/{chunk-43A3KGWL.js → chunk-34I4GB7D.js} +4 -2
  5. package/dist/{chunk-43A3KGWL.js.map → chunk-34I4GB7D.js.map} +1 -1
  6. package/dist/{chunk-ZQRWW37O.js → chunk-35PNTIRN.js} +5 -1
  7. package/dist/chunk-35PNTIRN.js.map +1 -0
  8. package/dist/{chunk-OEQBHE2Z.js → chunk-HBOJLP2Z.js} +19 -4
  9. package/dist/chunk-HBOJLP2Z.js.map +1 -0
  10. package/dist/{chunk-5CMLOAEF.js → chunk-YOY5DFQS.js} +2 -2
  11. package/dist/db/env.cjs.map +1 -1
  12. package/dist/db/env.d.cts +2 -1
  13. package/dist/db/env.d.ts +2 -1
  14. package/dist/db/index.cjs +17 -3
  15. package/dist/db/index.cjs.map +1 -1
  16. package/dist/db/index.d.cts +1 -1
  17. package/dist/db/index.d.ts +1 -1
  18. package/dist/db/index.js +1 -1
  19. package/dist/engine/index.cjs +2 -0
  20. package/dist/engine/index.cjs.map +1 -1
  21. package/dist/engine/index.d.cts +2 -2
  22. package/dist/engine/index.d.ts +2 -2
  23. package/dist/engine/index.js +2 -2
  24. package/dist/{index-Ct1iiB4N.d.ts → index-B4CcpqLb.d.ts} +23 -16
  25. package/dist/{index-BF1f0DfA.d.ts → index-B8v6hVyU.d.ts} +1 -1
  26. package/dist/{index-CwaWRhyc.d.cts → index-DmVyY6N7.d.cts} +23 -16
  27. package/dist/{index-CoaDN9dL.d.cts → index-VsjBQ4Kw.d.cts} +1 -1
  28. package/dist/index.cjs +75 -49
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +8 -7
  31. package/dist/index.d.ts +8 -7
  32. package/dist/index.js +58 -49
  33. package/dist/index.js.map +1 -1
  34. package/dist/openapi/index.cjs +1 -1
  35. package/dist/openapi/index.cjs.map +1 -1
  36. package/dist/openapi/index.js +3 -3
  37. package/dist/openapi/index.js.map +1 -1
  38. package/docs/llms-full.txt +36 -5
  39. package/docs/schema.md +36 -5
  40. package/package.json +1 -1
  41. package/dist/chunk-OEQBHE2Z.js.map +0 -1
  42. package/dist/chunk-ZQRWW37O.js.map +0 -1
  43. /package/dist/{chunk-5CMLOAEF.js.map → chunk-YOY5DFQS.js.map} +0 -0
@@ -1323,7 +1323,8 @@ export const invoices = defineTable("invoices", {
1323
1323
 
1324
1324
  Chainable modifiers: `.primaryKey()`, `.notNull()` (default), `.nullable()`,
1325
1325
  `.default(value)`, `.defaultRandom()` (uuid → `gen_random_uuid()`),
1326
- `.defaultNow()` (timestamp → `now()`), `.references(() => table.column, opts?)`,
1326
+ `.defaultNow()` (timestamp → `now()`),
1327
+ `.references(() => table.column, { as?, reverseAs?, onDelete? })`,
1327
1328
  `.selfReferences("column", opts?)`,
1328
1329
  `.onDelete("cascade" | "set null" | "restrict" | "no action")`, `.ignored()`.
1329
1330
 
@@ -1368,14 +1369,38 @@ export const orgs = defineTable("orgs", {
1368
1369
  });
1369
1370
  ```
1370
1371
 
1371
- **Two foreign keys to the same table** would derive the same relation name from
1372
- their columns, so name one of them:
1372
+ ### Relation names
1373
+
1374
+ Every foreign key produces **two** named relations, and the two names are derived
1375
+ separately:
1376
+
1377
+ | Direction | Where it appears | Default name | Option that changes it |
1378
+ |---|---|---|---|
1379
+ | forward (child → parent) | on the child | the column minus `_id` — `list_id` → `list` | `as` |
1380
+ | reverse (parent → children) | on the parent | the **child table's** name — `lists.todos` | `reverseAs` |
1381
+
1382
+ So `todos.list_id → lists` gives `todos.list` and `lists.todos`, and neither
1383
+ needs declaring. `as` renames the forward side only: `author_id` declared
1384
+ `{ as: "author" }` gives `posts.author` and still gives `users.posts`. That is
1385
+ why the two options exist separately — `posts` and `comments` can both call their
1386
+ forward relation `author` without colliding, because what lands on `users` is
1387
+ `posts` and `comments`.
1388
+
1389
+ **Two foreign keys from one table to the same parent** collide on the reverse
1390
+ side: both reverse relations want the child table's name. Name them:
1373
1391
 
1374
1392
  ```ts
1375
- billing_address_id: uuid().references(() => addresses.id, { as: "billing_address" }),
1376
- shipping_address_id: uuid().references(() => addresses.id, { as: "shipping_address" }),
1393
+ billing_address_id: uuid().references(() => addresses.id, { reverseAs: "billed_orders" }),
1394
+ shipping_address_id: uuid().references(() => addresses.id, { reverseAs: "shipped_orders" }),
1377
1395
  ```
1378
1396
 
1397
+ The forward names here (`billing_address`, `shipping_address`) are already
1398
+ distinct, so no `as` is needed. Add one when two columns WOULD derive the same
1399
+ forward name.
1400
+
1401
+ Any two relations resolving to one name on one table are refused at push, with
1402
+ both relations named and the option that separates them.
1403
+
1379
1404
  ## Rows that belong to a user
1380
1405
 
1381
1406
  There is no `public.users` table: auth users live in the `auth` schema of the same
@@ -1397,6 +1422,12 @@ device_id: installationRef({ onDelete: "cascade" }),
1397
1422
  | Account erasure follows it | yes | no | no |
1398
1423
  | Per table | **at most one** | unlimited | unlimited |
1399
1424
 
1425
+ Several `userRef` columns on one table are fine — they are ordinary foreign keys
1426
+ and each takes its own relation name from its column (`created_by`, `edited_by`).
1427
+ Only two of them resolving to the SAME name is refused, and `userRef({ onDelete,
1428
+ as })` is how you separate them. `auth.users` is not a table of your schema, so
1429
+ none of these produce a reverse relation to collide over.
1430
+
1400
1431
  `ownedByUser()` takes no `onDelete` because there is only one correct answer:
1401
1432
  ownership is what account erasure walks, so a row owned by an account has to go
1402
1433
  when the account does. `"set null"` on a `userRef` needs a `.nullable()` column.
package/docs/schema.md CHANGED
@@ -121,7 +121,8 @@ export const invoices = defineTable("invoices", {
121
121
 
122
122
  Chainable modifiers: `.primaryKey()`, `.notNull()` (default), `.nullable()`,
123
123
  `.default(value)`, `.defaultRandom()` (uuid → `gen_random_uuid()`),
124
- `.defaultNow()` (timestamp → `now()`), `.references(() => table.column, opts?)`,
124
+ `.defaultNow()` (timestamp → `now()`),
125
+ `.references(() => table.column, { as?, reverseAs?, onDelete? })`,
125
126
  `.selfReferences("column", opts?)`,
126
127
  `.onDelete("cascade" | "set null" | "restrict" | "no action")`, `.ignored()`.
127
128
 
@@ -166,14 +167,38 @@ export const orgs = defineTable("orgs", {
166
167
  });
167
168
  ```
168
169
 
169
- **Two foreign keys to the same table** would derive the same relation name from
170
- their columns, so name one of them:
170
+ ### Relation names
171
+
172
+ Every foreign key produces **two** named relations, and the two names are derived
173
+ separately:
174
+
175
+ | Direction | Where it appears | Default name | Option that changes it |
176
+ |---|---|---|---|
177
+ | forward (child → parent) | on the child | the column minus `_id` — `list_id` → `list` | `as` |
178
+ | reverse (parent → children) | on the parent | the **child table's** name — `lists.todos` | `reverseAs` |
179
+
180
+ So `todos.list_id → lists` gives `todos.list` and `lists.todos`, and neither
181
+ needs declaring. `as` renames the forward side only: `author_id` declared
182
+ `{ as: "author" }` gives `posts.author` and still gives `users.posts`. That is
183
+ why the two options exist separately — `posts` and `comments` can both call their
184
+ forward relation `author` without colliding, because what lands on `users` is
185
+ `posts` and `comments`.
186
+
187
+ **Two foreign keys from one table to the same parent** collide on the reverse
188
+ side: both reverse relations want the child table's name. Name them:
171
189
 
172
190
  ```ts
173
- billing_address_id: uuid().references(() => addresses.id, { as: "billing_address" }),
174
- shipping_address_id: uuid().references(() => addresses.id, { as: "shipping_address" }),
191
+ billing_address_id: uuid().references(() => addresses.id, { reverseAs: "billed_orders" }),
192
+ shipping_address_id: uuid().references(() => addresses.id, { reverseAs: "shipped_orders" }),
175
193
  ```
176
194
 
195
+ The forward names here (`billing_address`, `shipping_address`) are already
196
+ distinct, so no `as` is needed. Add one when two columns WOULD derive the same
197
+ forward name.
198
+
199
+ Any two relations resolving to one name on one table are refused at push, with
200
+ both relations named and the option that separates them.
201
+
177
202
  ## Rows that belong to a user
178
203
 
179
204
  There is no `public.users` table: auth users live in the `auth` schema of the same
@@ -195,6 +220,12 @@ device_id: installationRef({ onDelete: "cascade" }),
195
220
  | Account erasure follows it | yes | no | no |
196
221
  | Per table | **at most one** | unlimited | unlimited |
197
222
 
223
+ Several `userRef` columns on one table are fine — they are ordinary foreign keys
224
+ and each takes its own relation name from its column (`created_by`, `edited_by`).
225
+ Only two of them resolving to the SAME name is refused, and `userRef({ onDelete,
226
+ as })` is how you separate them. `auth.users` is not a table of your schema, so
227
+ none of these produce a reverse relation to collide over.
228
+
198
229
  `ownedByUser()` takes no `onDelete` because there is only one correct answer:
199
230
  ownership is what account erasure walks, so a row owned by an account has to go
200
231
  when the account does. `"set null"` on a `userRef` needs a `.nullable()` column.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palbase/backend",
3
- "version": "25.0.0",
3
+ "version": "25.0.1",
4
4
  "description": "Palbase Backend SDK — class controllers (@Controller/@Get/@Post + @Body/@QueryParams/@Param), error classes, schema DSL",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/db/schema-json.ts","../src/db/policy.ts","../src/db/schema.ts","../src/db/extensions.ts","../src/db/columns.ts","../src/db/raw.ts","../src/db/embedding.ts","../src/db/typed-db.ts"],"sourcesContent":["// The wire shape of a declared schema — what the deploy reads.\n//\n// `defineSchema(...)` produces a value full of builders and phantom types, which\n// is the right shape for authoring and the wrong shape for anything outside this\n// process. The deploy is Go: it introspects the live database, diffs it against\n// the declaration, and applies the difference. So the declaration has to leave\n// TypeScript as data, and this file is where that happens.\n//\n// It lives in the SDK because the SDK owns the DSL. The alternative — a script\n// beside the deploy that reaches into `._def` — is a second reading of a private\n// shape, and it drifts the moment a column gains a property: the DSL keeps\n// working, the emitter silently omits it, and the database is missing something\n// nobody can see in the source.\n//\n// The field names below are a CONTRACT with Go's `schema.SchemaJSON`. Renaming\n// one here without renaming it there produces a declaration that parses to\n// something emptier than it was — the failure mode being a column, a policy, or\n// a whole table that quietly never gets created.\nimport type { ColumnBuilder, ColumnDef } from \"./columns.js\";\nimport type { PolicyDef } from \"./policy.js\";\nimport type { MemoryDecl, SchemaDef, SearchDecl, TableDef } from \"./schema.js\";\n\n/** One column, flattened. Mirrors Go's `schema.ColumnJSON`. */\nexport interface ColumnJSON {\n type: string;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n renamedFrom?: string;\n /** See Go's `schema.ColumnJSON.Ignored` — the contraction gate's only signal. */\n ignored?: boolean;\n references?: { table: string; column: string };\n onDeleteAction?: string;\n enumName?: string;\n enumValues?: string[];\n unique?: boolean;\n dimensions?: number;\n}\n\n/** One RLS policy. Mirrors Go's `schema.PolicyJSON`. */\nexport interface PolicyJSON {\n name: string;\n command: string;\n roles: string[];\n using: string | null;\n withCheck: string | null;\n permissive: boolean;\n}\n\n/** One table. Mirrors Go's `schema.TableJSON`. */\nexport interface TableJSON {\n /**\n * The schema this table lives in. `public` unless declared otherwise.\n *\n * The table carries it because the diff iterates over KEYS but passes the\n * VALUE around: a bare name inside a qualified key space writes the migration\n * into the wrong schema, silently.\n */\n schema: string;\n name: string;\n columns: Record<string, ColumnJSON>;\n rls: boolean;\n policies: PolicyJSON[];\n primaryKey?: string[];\n uniqueConstraints?: { name: string; columns: string[] }[];\n rawConstraints?: { name: string; up: string; down: string | null }[];\n checks?: { name: string; expr: string }[];\n indexes?: { name: string; columns: string[] }[];\n search?: SearchJSON;\n memory?: MemoryJSON;\n}\n\n/** C-11 wire şekli — Go'nun MemoryJSON'ıyla alan-adı sözleşmesi (D-019).\n * Beyansız tablolarda alan OMIT — eski şemalar bayt-aynı (NFR-B1). */\nexport interface MemoryJSON {\n from: string[];\n into: string;\n subject?: string;\n extract: { provider: string; model: string };\n}\n\n/** A whole declaration. Mirrors Go's `schema.SchemaJSON`. */\nexport interface SchemaJSON {\n tables: Record<string, TableJSON>;\n extensions: string[];\n /**\n * Every declared schema, with its HTTP reachability.\n *\n * The flag has nowhere else to live: `/v1/db` must know which schemas are\n * reachable, and introspection must know which schemas the project DECLARED —\n * a live database also contains internal module schemas that are none of the\n * diff's business.\n */\n schemas: SchemaMetaJSON[];\n}\n\nexport interface SchemaMetaJSON {\n name: string;\n exposed: boolean;\n}\n\n/** The definition behind a column, whichever side of the builder it arrives on. */\nfunction defOf(column: ColumnBuilder | ColumnDef): ColumnDef {\n return \"_def\" in column ? column._def : column;\n}\n\nfunction columnToJSON(column: ColumnBuilder | ColumnDef): ColumnJSON {\n const def = defOf(column);\n const out: ColumnJSON = {\n type: def.type,\n nullable: def.nullable,\n primaryKey: def.primaryKey,\n };\n // Every optional field is omitted rather than emitted as undefined: Go\n // distinguishes \"absent\" from \"present and empty\" on several of these, and a\n // `defaultValue: null` is a real default that says NULL.\n if (def.defaultValue !== undefined) out.defaultValue = def.defaultValue;\n if (def.defaultRandom === true) out.defaultRandom = true;\n if (def.defaultNow === true) out.defaultNow = true;\n if (def.renamedFrom !== undefined) out.renamedFrom = def.renamedFrom;\n // Go'daki schema.ColumnJSON'un aynası. `omitempty` karşılığı: yalnız TRUE ise yazılır,\n // böylece işaretsiz bir şemanın JSON'u bu alandan önceki hâliyle byte-eş kalır.\n if (def.ignored === true) out.ignored = true;\n if (def.references !== undefined) {\n out.references = { table: def.references.table, column: def.references.column };\n }\n if (def.onDeleteAction !== undefined) out.onDeleteAction = def.onDeleteAction;\n if (def.enumName !== undefined) out.enumName = def.enumName;\n if (def.enumValues !== undefined) out.enumValues = [...def.enumValues];\n if (def.unique === true) out.unique = true;\n if (def.dimensions !== undefined) out.dimensions = def.dimensions;\n return out;\n}\n\nfunction policyToJSON(policy: PolicyDef): PolicyJSON {\n return {\n name: policy.name,\n command: policy.command ?? \"all\",\n roles: policy.roles ? [...policy.roles] : [],\n // null rather than omitted: a policy with no USING clause is a different\n // thing from one whose clause the emitter forgot, and Go reads the\n // difference.\n using: policy.using ?? null,\n withCheck: policy.withCheck ?? null,\n permissive: policy.permissive !== false,\n };\n}\n\n/** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).\n * `mode`/`chunks` yalnız yeni-biçim chunk-modunda emit edilir (D-010);\n * satır-modu ve eski biçim bayt-aynı kalır (NFR-B1). */\nexport interface SearchJSON {\n text?: { columns: string[] };\n vector?: {\n column?: string;\n metric: string;\n embed?: { provider: string; model: string; from: string[]; apiKeyName?: string; dimensions?: number; baseURL?: string };\n staleness?: \"null\" | \"keep\";\n mode?: \"row\" | \"chunks\";\n chunks?: { sizeChars?: number; overlapChars?: number };\n }[];\n /** FR-026: sorgu-yeniden-yazımı haritası — beyan yoksa OMIT (NFR-B1). */\n synonyms?: Record<string, string[]>;\n /** C-1: sonuç yeniden-sıralama beyanı — beyan yoksa OMIT. */\n /** FR-029: geçerlilik türevleri — beyan yoksa OMIT. */\n validity?: boolean;\n}\n\n/** T020 (C-1): iki biçimin de üst-düzey ortak alanları — beyan yoksa OMIT,\n * boş synonyms haritası da OMIT (NFR-B1 baytları kımıldamaz). */\nfunction commonSearchFields(search: SearchDecl, out: SearchJSON): void {\n if (search.synonyms !== undefined && Object.keys(search.synonyms).length > 0) {\n out.synonyms = Object.fromEntries(\n Object.entries(search.synonyms).map(([word, alts]) => [word, [...alts]]),\n );\n }\n if (search.validity === true) out.validity = true;\n}\n\n/** Beyanı normalize eder: vector her zaman DİZİ, metric her zaman dolu (vars. cosine),\n * authoring'deki `from`/`model` wire'da `embed` altında toplanır. Alan yoksa OMIT —\n * search'süz şema bayt-aynı kalır (NFR-006). */\nfunction searchToJSON(search: SearchDecl, vectorColumn: string | undefined): SearchJSON {\n if (search.from !== undefined && search.model !== undefined) {\n // YENİ biçim (D-007): from tek listedir — FTS'i de embed'i de besler.\n // Mod ŞEMADAN türer (D-010): tabloda vector kolonu varsa satır-modu\n // (column yazılır, mode OMIT — eski davranışla aynı wire), yoksa\n // chunk-modu (mode:\"chunks\", column yok — vektörler türev tabloda).\n const out: SearchJSON = {};\n const textCols =\n search.text === false ? undefined : Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from;\n if (textCols !== undefined) out.text = { columns: [...textCols] };\n const v: NonNullable<SearchJSON[\"vector\"]>[number] = { metric: search.metric ?? \"cosine\" };\n if (vectorColumn !== undefined) v.column = vectorColumn;\n v.embed = {\n provider: search.model.provider,\n model: search.model.model,\n from: [...search.from],\n ...(search.model.apiKeyName !== undefined ? { apiKeyName: search.model.apiKeyName } : {}),\n ...(search.model.dimensions !== undefined ? { dimensions: search.model.dimensions } : {}),\n ...(search.model.baseURL !== undefined ? { baseURL: search.model.baseURL } : {}),\n };\n if (search.staleness !== undefined) v.staleness = search.staleness;\n if (vectorColumn === undefined) {\n v.mode = \"chunks\";\n if (search.chunks !== undefined) {\n const c: NonNullable<typeof v.chunks> = {};\n if (search.chunks.size !== undefined && search.chunks.size > 0) c.sizeChars = search.chunks.size;\n if (search.chunks.overlap !== undefined && search.chunks.overlap > 0) c.overlapChars = search.chunks.overlap;\n if (Object.keys(c).length > 0) v.chunks = c;\n }\n }\n out.vector = [v];\n commonSearchFields(search, out);\n return out;\n }\n const out: SearchJSON = {};\n // Eski biçimde text yalnız dizi olabilir (boolean'ı defineSchema zaten\n // reddediyor); Array.isArray hem tipi daraltır hem o sözleşmeyi belgeler.\n if (Array.isArray(search.text) && search.text.length > 0) out.text = { columns: [...search.text] };\n const legs = search.vector === undefined ? []\n : Array.isArray(search.vector) ? search.vector : [search.vector];\n if (legs.length > 0) {\n out.vector = legs.map((leg) => {\n const v: NonNullable<SearchJSON[\"vector\"]>[number] = { metric: leg.metric ?? \"cosine\" };\n if (leg.column !== undefined) v.column = leg.column;\n if (leg.staleness !== undefined) v.staleness = leg.staleness;\n if (leg.model !== undefined) {\n v.embed = {\n provider: leg.model.provider,\n model: leg.model.model,\n from: [...(leg.from ?? [])],\n ...(leg.model.apiKeyName !== undefined ? { apiKeyName: leg.model.apiKeyName } : {}),\n ...(leg.model.dimensions !== undefined ? { dimensions: leg.model.dimensions } : {}),\n ...(leg.model.baseURL !== undefined ? { baseURL: leg.model.baseURL } : {}),\n };\n }\n return v;\n });\n }\n commonSearchFields(search, out);\n return out;\n}\n\nfunction memoryToJSON(m: MemoryDecl): MemoryJSON {\n return {\n from: [...m.from],\n into: m.into,\n ...(m.subject !== undefined ? { subject: m.subject } : {}),\n extract: { provider: m.extract.provider, model: m.extract.model },\n };\n}\n\nfunction tableToJSON(table: TableDef, schemaName: string): TableJSON {\n const columns: Record<string, ColumnJSON> = {};\n for (const [name, column] of Object.entries(table.columns)) {\n columns[name] = columnToJSON(column);\n }\n\n const out: TableJSON = {\n name: table.name,\n schema: schemaName,\n columns,\n // Read, not re-derived. `defineSchema` already resolves the fail-closed\n // default (RLS on unless the author wrote `rls: false`, and forced on by any\n // policy), and a second copy of a SECURITY default is exactly the thing that\n // drifts — the direction it drifted last time was \"expose everything\", and\n // the live proof was one user reading another's rows.\n rls: table.rls,\n policies: (table.policies ?? []).map(policyToJSON),\n };\n\n if (table.primaryKey !== undefined && table.primaryKey.length > 0) {\n out.primaryKey = [...table.primaryKey];\n }\n if (table.unique !== undefined && table.unique.length > 0) {\n out.uniqueConstraints = table.unique.map((u) => ({ name: u.name, columns: [...u.columns] }));\n }\n if (table.raw !== undefined && table.raw.length > 0) {\n out.rawConstraints = table.raw.map((r) => ({\n name: r.name,\n up: r.up,\n down: r.down ?? null,\n }));\n }\n if (table.checks !== undefined && table.checks.length > 0) {\n out.checks = table.checks.map((c) => ({ name: c.name, expr: c.expr }));\n }\n if (table.indexes !== undefined && table.indexes.length > 0) {\n out.indexes = table.indexes.map((i) => ({ name: i.name, columns: [...i.columns] }));\n }\n if (table.search !== undefined) {\n // D-010 mod kararının tek girdisi: tabloda dimensions'lı (vector) kolon\n // adı. Birden çoksa ilkini yazmak YANLIŞ olurdu — o durum eski biçimin\n // işidir ve yeni biçim + çoklu vector kolonu apply'da reddedilir.\n const vectorColumn = Object.entries(columns).find(([, c]) => c.dimensions !== undefined)?.[0];\n const sj = searchToJSON(table.search, vectorColumn);\n if (sj.text !== undefined || sj.vector !== undefined) out.search = sj;\n }\n if (table.memory !== undefined) {\n out.memory = memoryToJSON(table.memory);\n }\n return out;\n}\n\n/**\n * The key a table answers to in `SchemaJSON.tables`.\n *\n * A public table is BARE, anything else is schema-qualified. This is not a new\n * convention: `RefJSON.Table` already carries `auth.users`, and introspection\n * already returns a public referent bare and a non-public one qualified. Adding\n * a second key space would make two interpreters of the same database.\n */\nexport function qualifiedTableKey(schemaName: string, tableName: string): string {\n return schemaName === \"public\" ? tableName : `${schemaName}.${tableName}`;\n}\n\n/**\n * Serialize declared schemas into the JSON the deploy applies.\n *\n * Takes every schema the project declares — one file per schema — because a\n * cross-schema foreign key can only be checked when both ends are in hand.\n */\nexport function toSchemaJSON(schemas: readonly SchemaDef[]): SchemaJSON {\n const tables: Record<string, TableJSON> = {};\n const extensions: string[] = [];\n const meta: SchemaMetaJSON[] = [];\n const seen = new Set<string>();\n for (const schema of schemas) {\n if (seen.has(schema.name)) {\n throw new Error(`two schemas declare the name \"${schema.name}\" — schema names must be unique`);\n }\n seen.add(schema.name);\n for (const table of Object.values(schema.tables)) {\n const json = tableToJSON(table, schema.name);\n tables[qualifiedTableKey(schema.name, json.name)] = json;\n }\n extensions.push(...(schema.extensions ?? []));\n // The schema list travels because the flag has nowhere else to live: without\n // it /v1/db cannot know which schemas are reachable over HTTP, and nothing\n // downstream can read the DECLARED schema set that introspection needs.\n meta.push({ name: schema.name, exposed: schema.exposed });\n }\n return { tables, extensions: [...new Set(extensions)], schemas: meta };\n}\n","/**\n * policy.ts — the RLS policy authoring DSL.\n *\n * `policy(name)` returns a fluent builder that mirrors the `ColumnBuilder`\n * style in columns.ts: each chainable method mutates the underlying\n * definition and returns the builder so calls compose. The terminal value is\n * a plain {@link PolicyDef} — the exact JSON shape the runtime's\n * `schema_extract.js` reads off the bundled module and the Go side parses into\n * `PolicyJSON` (CONTRACT-POLICY).\n *\n * @example\n * import { policy } from \"@palbase/backend\";\n *\n * policy(\"owner_select\")\n * .for(\"select\")\n * .to(\"authenticated\")\n * .using(\"owner = (select auth.uid())\");\n */\n\n/** The SQL command a policy applies to. `\"all\"` covers SELECT/INSERT/UPDATE/DELETE. */\nexport type PolicyCommand = \"all\" | \"select\" | \"insert\" | \"update\" | \"delete\";\n\n/** Whether a policy is permissive (OR-combined, the default) or restrictive\n * (AND-combined). Mirrors Postgres `CREATE POLICY ... AS PERMISSIVE|RESTRICTIVE`. */\nexport type PolicyMode = \"permissive\" | \"restrictive\";\n\n/**\n * The compiled, serializable policy definition — the EXACT shape consumed by\n * `schema_extract.js` → Go `PolicyJSON` (CONTRACT-POLICY).\n *\n * - `roles`: the DB roles this policy applies to (`TO` clause). An empty array\n * means the policy applies to PUBLIC (all roles) — the Postgres default.\n * - `using`: the `USING (...)` row-visibility expression, or `null` when none.\n * - `withCheck`: the `WITH CHECK (...)` write-validation expression, or `null`.\n * - `permissive`: `true` for `AS PERMISSIVE` (default), `false` for restrictive.\n */\nexport interface PolicyDef {\n name: string;\n command: PolicyCommand;\n roles: string[];\n using: string | null;\n withCheck: string | null;\n permissive: boolean;\n}\n\n/**\n * Fluent RLS policy builder.\n *\n * Defaults (documented, applied at construction):\n * - `command`: `\"all\"` — applies to every SQL command unless `.for(...)` narrows it.\n * - `roles`: `[\"authenticated\"]` — the common case is \"rule applies to signed-in\n * users\". Call `.to(...)` to override; pass `.to()` with no roles (or never\n * call it after a reset) to target PUBLIC.\n * - `using` / `withCheck`: `null` — no row filter / write check until set.\n * - `permissive`: `true` — `AS PERMISSIVE` (policies OR together).\n *\n * Each method mutates `_def` in place and returns `this`, so the chain is a\n * single builder instance (no per-call allocation, like a tagged-template\n * compile target). The terminal `PolicyDef` is read directly off `_def` by\n * `schema_extract.js`.\n */\n/** Quote an identifier for the policy expression. Table and column names reach\n * here from the schema author; neither is allowed to become syntax. */\nfunction quote(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nexport class PolicyBuilder {\n readonly _def: PolicyDef;\n\n constructor(name: string) {\n this._def = {\n name,\n command: \"all\",\n roles: [\"authenticated\"],\n using: null,\n withCheck: null,\n permissive: true,\n };\n }\n\n /** Restrict the policy to a single SQL command (default `\"all\"`). */\n for(command: PolicyCommand): this {\n this._def.command = command;\n return this;\n }\n\n /**\n * Set the DB roles the policy applies to (the `TO` clause), replacing any\n * previously-set roles. Call with no arguments to target PUBLIC (all roles).\n *\n * @example\n * policy(\"p\").to(\"authenticated\")\n * policy(\"p\").to(\"authenticated\", \"service_role\")\n * policy(\"p\").to() // PUBLIC\n */\n to(...roles: string[]): this {\n this._def.roles = roles;\n return this;\n }\n\n /** Set the `USING (...)` row-visibility expression (raw SQL). */\n using(sqlExpr: string): this {\n this._def.using = sqlExpr;\n return this;\n }\n\n /**\n * \"Rows of THIS table whose owner the caller is a member of\" — the membership\n * pattern, written so it cannot recurse.\n *\n * THE TRAP IT EXISTS FOR. Written by hand, membership policies point at each\n * other: `channels` is visible to members, so its policy reads\n * `channel_members`; `channel_members` is visible to members, so its policy\n * reads `channels`. Postgres refuses the pair at query time with `infinite\n * recursion detected in policy for relation ...`, and the error names the\n * relation but not the cycle. The way out is asymmetry — the MEMBERSHIP table\n * is protected by `user_id = auth.uid()` and nothing else, and every other\n * table subqueries INTO it. That shape was in the platform's own schema and\n * written down nowhere; a customer recovered it by reading that schema.\n *\n * `(select auth.uid())` rather than a bare call: the scalar subquery is\n * evaluated ONCE per statement instead of per row.\n *\n * @example\n * // channels: visible to members. The membership table gets the simple one.\n * policy(\"member_read\").for(\"select\").to(\"authenticated\")\n * .memberOf(\"channel_members\", \"channel_id\")\n * // → id IN (SELECT \"channel_id\" FROM \"channel_members\"\n * // WHERE \"user_id\" = (select auth.uid()))\n */\n memberOf(\n membershipTable: string,\n foreignKey: string,\n options: { column?: string; userColumn?: string } = {},\n ): this {\n if (this._def.using !== null) {\n // Silently AND-ing the two would hide whichever the author meant; silently\n // replacing would hide the one they wrote. Neither is a thing to guess.\n throw new Error(\n `policy(${this._def.name}).memberOf(): this policy already has a using() expression. ` +\n \"Write one or the other — memberOf IS the using expression.\",\n );\n }\n const column = options.column ?? \"id\";\n const userColumn = options.userColumn ?? \"user_id\";\n this._def.using =\n `${quote(column)} IN (SELECT ${quote(foreignKey)} FROM ${quote(membershipTable)} ` +\n `WHERE ${quote(userColumn)} = (select auth.uid()))`;\n return this;\n }\n\n /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */\n withCheck(sqlExpr: string): this {\n this._def.withCheck = sqlExpr;\n return this;\n }\n\n /** Set the policy mode: `\"permissive\"` (default, OR-combined) or\n * `\"restrictive\"` (AND-combined). */\n as(mode: PolicyMode): this {\n this._def.permissive = mode === \"permissive\";\n return this;\n }\n}\n\n/**\n * Start authoring an RLS policy. Returns a {@link PolicyBuilder}; the resulting\n * `PolicyBuilder` is accepted directly in a table's `policies: [...]` array\n * (its `_def` is read at schema-extract time).\n *\n * @param name The policy name. Palbase reconciliation keys policies by\n * `(table, name)`, so names must be unique per table.\n */\nexport function policy(name: string): PolicyBuilder {\n return new PolicyBuilder(name);\n}\n","import type { ColumnBuilder } from \"./columns.js\";\nimport { qualifiedTableKey } from \"./schema-json.js\";\nimport { PolicyBuilder } from \"./policy.js\";\nimport type { PolicyDef } from \"./policy.js\";\nimport type { PalbaseExtension } from \"./extensions.js\";\nimport type { RawConstraintDef } from \"./raw.js\";\nimport type { ChatModelRef, EmbeddingModelRef } from \"./embedding.js\";\n\n/**\n * A map of column builders keyed by column name — the value you write under\n * the `columns` key of `defineTable(\"<name>\", { columns })`.\n *\n * The default `Record<string, ColumnBuilder>` keeps bare references compiling\n * without a type argument.\n */\nexport type ColumnMap = Record<string, ColumnBuilder>;\n\n/**\n * The author-facing value written under each table key:\n * `{ columns, rls?, policies? }`.\n *\n * - `columns`: the column map (required).\n * - `rls`: enable + FORCE row-level security on this table. **Defaults to\n * `true`**, and is forced on when `policies` is non-empty. A table with RLS\n * and no policies is deny-all, which is the starting state: nothing reads it\n * until a policy says who may. Set `rls: false` only for a genuinely public\n * table — it is an explicit opt-out that a reviewer can grep for, not\n * something you get by forgetting.\n * - `policies`: the RLS policies for this table, authored with `policy(name)`.\n * Each entry may be a {@link PolicyBuilder} (the normal `policy(...)` chain)\n * or a raw {@link PolicyDef} object.\n *\n * The `C` type parameter preserves the precise per-column phantom types so the\n * typed `Database.tables.*` surface keeps inferring insert/row shapes.\n */\n/** Arama metriği — tek kelime; opclass ve operatör bundan türetilir, asla yüzeye çıkmaz (D-5/D-6). */\nexport type SearchMetric = \"cosine\" | \"euclidean\" | \"inner_product\";\n\n/** Bir vektör arama kolu. `model` varsa auto-embed: platform yazma+sorgu embedding'ini üstlenir (D-9). */\nexport interface VectorSearchDecl {\n /** Hedef vector kolonu; tabloda TEK vector kolonu varsa atlanabilir (Go apply çözer, FR-010). */\n column?: string;\n /** Varsa auto-embed. Deskriptor düz veridir — şemayla serileşir (C-3). */\n model?: EmbeddingModelRef;\n /** model varsa ZORUNLU: embed kaynak kolonları = trigger'ın UPDATE OF listesi (C-2). */\n from?: string[];\n metric?: SearchMetric;\n /** Kaynak metin değişince ara-dönem davranışı (yalnız auto-embed'de):\n * \"null\" (vars.) — embedding anında NULL'lanır; satır yeni vektör yazılana\n * dek anlamsal aramada aday değildir. Bayat eşleşme asla servis edilmez.\n * \"keep\" — eski vektör aramada kalır, platform yenisini yazınca sessizce\n * değişir. Görünürlük penceresi sıfır; bedeli saniyeler süren bayat\n * eşleşme riski (Confluence-tipi sync yükleri için). */\n staleness?: \"null\" | \"keep\";\n}\n\n/** Tablonun arama beyanı — İKİ biçim (D-007, tek yüzey):\n *\n * YENİ (önerilen): `{ from, model, ... }` — `from` kolonları hem FTS'e hem\n * embed'e girer. Tabloda vector kolonu declare edilmişse SATIR-modu; yoksa\n * CHUNK-modu otomatiktir (D-010): vektörler türev `__palbase_chunks`\n * tablosunda yaşar, içerik otomatik bölünür. `text: false` FTS'i kapatır,\n * `text: [..]` FTS kolonlarını from'dan ayırır. `chunks` yalnız ince ayar.\n *\n * ESKİ: `text: string[]` + `vector: {...}` — aynen çalışır, wire çıktısı\n * bayt-aynı kalır (NFR-B1). İki biçim KARIŞTIRILAMAZ. */\nexport interface SearchDecl {\n text?: string[] | boolean;\n vector?: VectorSearchDecl | VectorSearchDecl[];\n /** Yeni biçim: arama kaynağı kolonlar (FTS + embed). Varlığı yeni biçimi seçer. */\n from?: string[];\n /** Yeni biçim: auto-embed modeli (zorunlu — BYO için eski biçimi kullanın). */\n model?: EmbeddingModelRef;\n metric?: SearchMetric;\n staleness?: \"null\" | \"keep\";\n /** Chunk-modu ince ayarı (yalnız vector kolonsuz tabloda anlamlı). */\n chunks?: { size?: number; overlap?: number };\n /** Sorgu-yeniden-yazımı: tek yönlü eş anlamlı haritası (FR-026). */\n synonyms?: Record<string, string[]>;\n /** Geçerlilik kolonları türetilir; arama varsayılan yalnız günceli tarar (FR-029). */\n validity?: boolean;\n}\n\n/** Hafıza beyanı (FR-032, D-019): kaynak tablonun yazımlarından platform\n * fact damıtır ve `into` tablosuna yazar. Hedef NORMAL declared tablodur —\n * kendi search/unique/validity beyanlarıyla. Okuma = Database.search(into).\n * subject default \"owner\": fact'in kime ait olduğu kolonu (iki tabloda da). */\nexport interface MemoryDecl {\n from: string[];\n into: string;\n extract: ChatModelRef;\n subject?: string;\n}\n\nexport interface TableInput<C extends ColumnMap = ColumnMap> {\n columns: C;\n rls?: boolean;\n policies?: (PolicyBuilder | PolicyDef)[];\n /** Composite/named primary key (ordered column names). Omit for single-column inline .primaryKey(). */\n primaryKey?: string[];\n /** Named multi-column UNIQUE constraints. */\n unique?: { name: string; columns: string[] }[];\n /** Named raw-SQL DDL objects (EXCLUDE, triggers, views) that the typed DSL cannot express. */\n raw?: RawConstraintDef[];\n /**\n * Named first-class CHECK constraints. Diffed by NAME with a BODY compare:\n * a changed `expr` (after pg normalization) recreates the constraint\n * (DROP + ADD). `expr` is trusted SQL emitted verbatim (like policy USING),\n * `name` is identifier-validated.\n */\n checks?: { name: string; expr: string }[];\n /**\n * Plain (non-unique) btree indexes over an ordered column list, emitted as\n * standalone `CREATE INDEX [IF NOT EXISTS] name ON table (col1, col2)`\n * statements (NOT a table clause — a separate migration statement category).\n * Structural compare by NAME (no expression normalization). `name` and each\n * column are identifier-validated by the Go differ.\n *\n * Scope: columns-only plain btree. Partial (`where`) and expression indexes\n * are a deliberate follow-up — modelling them needs the same raw-SQL\n * normalization round-trip CHECK uses (Task 10), so they are NOT in this\n * type yet to avoid a half-working partial-index path.\n */\n indexes?: { name: string; columns: string[] }[];\n /** Arama beyanı — bkz. SearchDecl. */\n search?: SearchDecl;\n /** Hafıza beyanı — bkz. MemoryDecl (FR-032). */\n memory?: MemoryDecl;\n}\n\n/**\n * A table definition — the runtime value the Go runtime's `schema_extract.js`\n * reads. It keys tables by `tableDef.name`, reads `tableDef.columns` for the\n * column DDL, and `tableDef.rls` + `tableDef.policies` for RLS.\n *\n * `defineSchema` derives `name` from the object key, so authors never repeat\n * the table name. `rls`/`policies` are always present after normalization\n * (defaulted to `true`/`[]`).\n *\n * The `C` type parameter preserves the precise per-column phantom types so that\n * downstream mapped types (InsertShape, RowShape) can discriminate on them.\n */\nexport interface TableDef<C extends ColumnMap = ColumnMap> {\n name: string;\n columns: C;\n rls: boolean;\n policies: PolicyDef[];\n primaryKey?: string[];\n unique?: { name: string; columns: string[] }[];\n /** Named raw-SQL DDL objects emitted verbatim on deploy. Tracked by name. */\n raw?: RawConstraintDef[];\n /** Named first-class CHECK constraints. Diffed by name + (normalized) body. */\n checks?: { name: string; expr: string }[];\n /** Plain btree indexes (columns-only), emitted as standalone CREATE INDEX. Diffed by name. */\n indexes?: { name: string; columns: string[] }[];\n /** Arama beyanı, doğrulanmış ve taşınmış hali. */\n search?: SearchDecl;\n /** Hafıza beyanı, doğrulanmış ve taşınmış hali (FR-032). */\n memory?: MemoryDecl;\n}\n\n/**\n * A schema definition containing multiple tables, keyed by table name.\n *\n * The `T` type parameter preserves the exact `TableDef<...>` type for each\n * table so that `SchemaDef[\"tables\"][\"rooms\"]` resolves to the precise\n * `TableDef<{ id: ColumnBuilder<'uuid', false, true, never>; ... }>`.\n */\nexport interface SchemaDef<\n T extends Record<string, TableDef> = Record<string, TableDef>,\n> {\n /** The schema's own name — `public`, `billing`, … Declared, never derived. */\n name: string;\n /** Reachable over HTTP? False unless the author opts in. */\n exposed: boolean;\n tables: T;\n /** Postgres extensions to install on deploy. Normalized to `[]` when absent. */\n extensions: PalbaseExtension[];\n}\n\n/** The author-facing input to `defineSchema` — a `tables` map whose keys are\n * the table names and whose values are `{ columns, rls?, policies? }`, plus an\n * optional `extensions` allowlist. */\nexport interface SchemaInput<\n T extends Record<string, TableInput> = Record<string, TableInput>,\n> {\n tables: T;\n /**\n * Postgres extensions to enable for this project, e.g. `[\"vector\"]`.\n * Config-as-code: installed by the deploy (CREATE EXTENSION … SCHEMA\n * extensions) with the privileged deploy connection. The type is an\n * allowlist union, so unsupported names fail typecheck.\n */\n extensions?: PalbaseExtension[];\n}\n\n/** Map the author's `{ tables: { <name>: { columns } } }` input to the\n * `{ tables: { <name>: TableDef<columns> } }` runtime/type shape, threading the\n * per-table column map `T[K][\"columns\"]` so column-level inference survives. */\ntype TablesByName<T extends readonly TableHandle[]> = {\n [K in T[number] as K[typeof TABLE_META][\"name\"]]: K[typeof TABLE_META];\n};\n\n/** Normalize a single `policies` entry into a plain `PolicyDef` (read off a\n * `PolicyBuilder._def`, or passed through when already a `PolicyDef`). */\nfunction toPolicyDef(p: PolicyBuilder | PolicyDef): PolicyDef {\n return p instanceof PolicyBuilder ? p._def : p;\n}\n\n/**\n * How a schema file reads. One file per schema — `db/public.ts`, `db/billing.ts`\n * — and the schema says its own name:\n *\n * const todos = defineTable(\"todos\", {\n * columns: {\n * id: uuid().primaryKey().defaultRandom(),\n * owner: text().notNull(),\n * title: text().notNull(),\n * },\n * rls: true,\n * policies: [\n * policy(\"owner_all\").for(\"all\").to(\"authenticated\")\n * .using(\"owner = (select auth.uid())\")\n * .withCheck(\"owner = (select auth.uid())\"),\n * ],\n * });\n *\n * export default defineSchema(\"public\", { tables: [todos] });\n *\n * The dictionary form `defineSchema({ tables: { todos: {…} } })` is RETIRED and\n * refused by name: a table whose name comes from a key does not know what it is\n * called while it is being built, so it cannot resolve `references(() =>\n * other.id)`, and a schema that does not say its own name cannot tell one\n * `invoices` from another schema's `invoices`.\n *\n * The returned value is `{ name, tables: { todos: { name, columns, rls,\n * policies } }, extensions, exposed }` — the exact shape the runtime schema\n * extractor parses. Per-column phantom types are preserved so\n * `Database.tables.todos.insert({...})` stays typed.\n *\n * RLS normalization: `rls` defaults to **`true`**, `policies` to `[]`. A table\n * that declares neither is therefore deny-all — nothing reads it until a policy\n * says who may, which is the safe starting point rather than a bug. Declare\n * `rls: false` for a genuinely public table; that is an explicit, greppable\n * statement of intent instead of an omission. When `policies` is non-empty,\n * `rls` is forced on (ENABLE + FORCE) regardless of the declared flag — a table\n * with policies must have RLS enabled or the policies would be inert.\n */\n/**\n * Where a table's metadata lives.\n *\n * The table VALUE is its columns, so `lists.id` is the column — which means a\n * column called `name` would overwrite the table's own name if metadata sat in\n * a plain field. Measured, not imagined: the existing `users` / `rooms` tests\n * (both declare a `name` column) produced an `[object Object]` table key.\n * `columns`, `rls`, `search`, `memory`, `unique` and `indexes` are all plausible\n * column names too. A column cannot collide with a symbol.\n */\nexport const TABLE_META: unique symbol = Symbol.for(\"palbase.table.meta\");\n\n/** A value produced by `defineTable`: the columns, plus metadata behind the symbol. */\nexport type TableHandle<C extends ColumnMap = ColumnMap, N extends string = string> =\n C & { readonly [TABLE_META]: TableDef<C> & { name: N } };\n\n/**\n * Declare one table as a standalone value that KNOWS ITS OWN NAME.\n *\n * The name lives here, not in a dictionary key. A table whose name comes from a\n * key cannot resolve `references(() => other.id)` when it is built — it does not\n * know what to call itself — which forces a two-phase resolution with an\n * empty-name intermediate state. One name source, no empty identity.\n *\n * The returned object spreads its own columns, so a sibling can point at it:\n * `references(() => lists.id)`.\n */\nexport function defineTable<const N extends string, C extends ColumnMap>(\n name: N,\n input: TableInput<C>,\n): TableHandle<C, N> {\n if (name.trim() === \"\") {\n throw new Error(\"defineTable(name, …): name must not be empty\");\n }\n const policies = (input.policies ?? []).map(toPolicyDef);\n // Fail closed. RLS is on unless the author explicitly says `rls: false`, and\n // policies force it on regardless — a policy on a table without RLS enabled is\n // inert, so declaring both resolves towards the safe reading.\n //\n // This defaulted to `false` until 2026-08-07, which meant a table nobody\n // thought about had no row-level security while `typed-db.ts` documented the\n // default `Database.*` path as RLS-enforced. The live proof settled it: user B\n // read user A's row in full through the typed client, while the same request\n // against a table declaring `rls: true` returned 0 of 165 rows. With no\n // policies this is deny-all.\n const rls = policies.length > 0 || input.rls !== false;\n const def = {\n name,\n columns: input.columns,\n rls,\n policies,\n } as TableDef<C> & { name: N };\n if (input.primaryKey !== undefined) def.primaryKey = input.primaryKey;\n if (input.unique !== undefined) def.unique = input.unique;\n if (input.raw !== undefined && input.raw.length > 0) def.raw = input.raw.slice();\n if (input.checks !== undefined && input.checks.length > 0) def.checks = input.checks.slice();\n if (input.indexes !== undefined && input.indexes.length > 0) def.indexes = input.indexes.slice();\n if (input.search !== undefined) {\n const s = input.search;\n // Erken, beyan-anı doğrulama (apply doğrulamasını İKAME ETMEZ — yazım\n // hatası deploy'a gitmeden yazarın yüzüne söylenir).\n if (s.from !== undefined) {\n // YENİ biçim (D-007). Eski alanlarla karışım tek biçime zorlanır:\n // iki yarım beyanın hangisinin kazandığını okuyucu bilemez.\n if (s.vector !== undefined) {\n throw new Error(\n `table ${name}: search beyanında tek biçim kullanın — 'from' (yeni) ile 'vector' (eski) birlikte olamaz`,\n );\n }\n if (s.from.length === 0) {\n throw new Error(`table ${name}: search.from boş olamaz`);\n }\n if (s.model === undefined) {\n throw new Error(\n `table ${name}: search.from model'siz anlamsız — auto-embed için model verin (BYO için eski 'vector' biçimini kullanın)`,\n );\n }\n if (Array.isArray(s.text) && s.text.length === 0) {\n throw new Error(`table ${name}: search.text boş dizi olamaz — FTS istemiyorsan text: false yazın`);\n }\n } else {\n // ESKİ biçim — davranış ve hata metinleri aynen (NFR-B1'in DX yarısı).\n if (typeof s.text === \"boolean\") {\n throw new Error(`table ${name}: text:${String(s.text)} yalnız yeni biçimde ('from' ile) geçerli`);\n }\n if (s.text === undefined && s.vector === undefined) {\n throw new Error(\n `table ${name}: search beyanı boş — en az bir kol (text ya da vector) verin, yoksa alanı hiç yazmayın`,\n );\n }\n if (s.text !== undefined && s.text.length === 0) {\n throw new Error(`table ${name}: search.text boş olamaz — FTS kolu istemiyorsan alanı hiç yazma`);\n }\n const legs = s.vector === undefined ? [] : Array.isArray(s.vector) ? s.vector : [s.vector];\n for (const leg of legs) {\n if (leg.model !== undefined && (leg.from === undefined || leg.from.length === 0)) {\n throw new Error(`table ${name}: search.vector.model beyan edildi ama 'from' yok — embed kaynağı kolonlar zorunlu (C-2)`);\n }\n if (leg.model === undefined && leg.from !== undefined) {\n throw new Error(`table ${name}: search.vector.from model'siz anlamsız — auto-embed için model verin`);\n }\n }\n }\n def.search = s;\n }\n if (input.memory !== undefined) {\n if (input.memory.from.length === 0) {\n throw new Error(`table ${name}: memory.from boş olamaz`);\n }\n def.memory = input.memory;\n }\n // Every column learns which table owns it, so a reference thunk can name its\n // target when `defineSchema` resolves it.\n for (const b of Object.values(input.columns)) {\n (b as { _def: { ownerTable?: unknown } })._def.ownerTable = def;\n }\n // Columns are the enumerable surface; metadata hangs off a non-enumerable\n // symbol so it survives spreads and cannot be shadowed by a column name.\n const handle = { ...input.columns } as TableHandle<C, N>;\n Object.defineProperty(handle, TABLE_META, { value: def, enumerable: false });\n return handle;\n}\n\n/**\n * Which schema declared a table.\n *\n * A `TableDef` cannot carry it: `defineTable` runs before any schema exists, and\n * `defineSchema` is where the answer arrives. It lives OUTSIDE the def rather\n * than on it because the def is serialized — a field here would either leak into\n * the wire shape or need a second rule saying not to. A WeakMap keyed by the def\n * object is the same fact with no surface.\n *\n * It exists because a foreign key names its target and that name is only half a\n * name without the schema. `resolveReferences` reads it to write the referent\n * the way `qualifiedTableKey` writes every other table name.\n */\nconst declaringSchemaOf = new WeakMap<object, string>();\n\n/**\n * Resolve every pending reference thunk.\n *\n * Runs inside `defineSchema`, where all table bindings exist and every table\n * already carries its name — which is why the name lives on the table and not in\n * a dictionary key: resolving against a table that does not yet know what it is\n * called would need a second pass over an empty-name intermediate state.\n *\n * The written referent follows the ONE naming convention (`qualifiedTableKey`):\n * a `public` table is bare, anything else is schema-qualified. The deciding fact\n * is the REFERENT's schema, not whether the key crosses a schema boundary —\n * exactly the CASE Go's introspection uses when it reads a live FK back\n * (`introspect.go`: `CASE WHEN rn.nspname = 'public' THEN rt.relname ELSE\n * rn.nspname || '.' || rt.relname END`). Writing `invoices` for a table that\n * lives in `billing` made Go read it as `public.invoices`: a FK onto a table\n * that does not exist, or — worse and silently — onto a DIFFERENT table that\n * happened to share the name.\n */\nfunction resolveReferences(tables: Record<string, TableDef>, schemaName: string): void {\n for (const table of Object.values(tables)) {\n for (const [colName, builder] of Object.entries(table.columns)) {\n const def = (builder as { _def: ColumnDefLike })._def;\n if (def.selfRefColumn !== undefined) {\n if (!(def.selfRefColumn in table.columns)) {\n throw new Error(\n `table \"${table.name}\" column \"${colName}\": selfReferences(\"${def.selfRefColumn}\") — no such column on this table`,\n );\n }\n // A self-reference is a reference: its referent is this table, in THIS\n // schema, so it is written by the same rule as any other.\n def.references = {\n table: qualifiedTableKey(schemaName, table.name),\n column: def.selfRefColumn,\n };\n continue;\n }\n if (def.referencesThunk === undefined) continue;\n const target = def.referencesThunk();\n const owner = (target as { _def?: ColumnDefLike } | undefined)?._def?.ownerTable;\n if (owner === undefined) {\n throw new Error(\n `table \"${table.name}\" column \"${colName}\": references(() => …) must point at a column of a table declared with defineTable(...)`,\n );\n }\n const targetColumn = Object.entries(owner.columns).find(\n ([, b]) => (b as { _def: unknown })._def === (target as { _def: unknown })._def,\n )?.[0];\n if (targetColumn === undefined) {\n throw new Error(\n `table \"${table.name}\" column \"${colName}\": the referenced column was not found on table \"${owner.name}\"`,\n );\n }\n const targetSchema = declaringSchemaOf.get(owner);\n if (targetSchema === undefined) {\n // Assuming `public` here is the exact silence this resolution closes:\n // it would produce a FK onto a table that does not exist, or onto a\n // same-named one that does. Name the gap instead.\n throw new Error(\n `table \"${table.name}\" column \"${colName}\": references(() => …) points at table ` +\n `\"${owner.name}\", which no defineSchema(...) has claimed yet — a foreign key cannot ` +\n `be written without its target's schema. Declare that table's schema first ` +\n `(one file per schema: db/public.ts, db/billing.ts …, imported by this one).`,\n );\n }\n def.references = {\n table: qualifiedTableKey(targetSchema, owner.name),\n column: targetColumn,\n };\n }\n }\n}\n\ntype ColumnDefLike = {\n references?: { table: string; column: string };\n referencesThunk?: () => unknown;\n selfRefColumn?: string;\n ownerTable?: { name: string; columns: Record<string, unknown> };\n};\n\n/**\n * Collect declared tables into one schema.\n *\n * Takes an ARRAY, not a dictionary: the tables already carry their names, and a\n * second name source is a second thing that can disagree.\n */\nexport function defineSchema<const T extends readonly TableHandle[]>(\n name: string,\n input: { tables: T; exposed?: boolean; extensions?: PalbaseExtension[] },\n): SchemaDef<TablesByName<T>> {\n // The TYPE first, then the value. The retired one-argument form passes an\n // object here, and a guard that only asks whether the name is blank calls\n // `.trim()` on it — which threw `name.trim is not a function` out of the child\n // process that runs `db/*.ts` during push: no file, no form, nothing to act\n // on. `references(\"t\", \"c\")` already answers its own retirement by name.\n if (typeof name !== \"string\") {\n throw new Error(\n `defineSchema(...) takes the schema NAME first: ` +\n `defineSchema(\"public\", { tables: [todos, lists] }). ` +\n `The one-argument form defineSchema({ tables: { … } }) is gone — a schema that does not ` +\n `say its own name cannot be told apart from another schema's table of the same name, ` +\n `which is what a cross-schema foreign key has to do. ` +\n `Migrate db/public.ts (one file per schema: db/public.ts, db/billing.ts …): name the ` +\n `schema, and lift each table key onto the table itself with ` +\n `defineTable(\"todos\", { columns: { … } }), then list the tables in the array.`,\n );\n }\n if (name.trim() === \"\") {\n throw new Error(\"defineSchema(name, …): name must not be empty\");\n }\n const tables = {} as Record<string, TableDef>;\n for (const handle of input.tables) {\n const table = handle[TABLE_META];\n if (tables[table.name] !== undefined) {\n throw new Error(\n `defineSchema(\"${name}\"): two tables declare the name \"${table.name}\" — table names must be unique within a schema`,\n );\n }\n tables[table.name] = table;\n // Stamped BEFORE resolution: a reference from this schema to a sibling in it\n // must find the sibling's schema, and the sibling may be declared later in\n // the array than the table pointing at it.\n declaringSchemaOf.set(table, name);\n }\n // Thunks are invoked HERE: every binding exists and every name is already set.\n resolveReferences(tables, name);\n // memory beyanları TABLOLAR-ARASI doğrulanır (into/subject/fact) — tüm\n // tablolar kurulduktan sonra: beyan sırasına bağımlılık olmasın (FR-032).\n for (const [name, def] of Object.entries(tables)) {\n const m = (def as TableDef).memory;\n if (m === undefined) continue;\n const target = Object.values(tables).find((t) => (t as TableDef).name === m.into) as TableDef | undefined;\n if (target === undefined) {\n throw new Error(`table ${name}: memory.into \"${m.into}\" şemada declared değil`);\n }\n const subject = m.subject ?? \"owner\";\n if (!(subject in (def as TableDef).columns)) {\n throw new Error(`table ${name}: memory.subject \"${subject}\" kolonu kaynak tabloda yok`);\n }\n if (!(subject in target.columns)) {\n throw new Error(`table ${name}: memory.subject \"${subject}\" kolonu hedef \"${m.into}\" tablosunda yok`);\n }\n const factCol = target.columns[\"fact\"];\n const factDef = factCol !== undefined && \"_def\" in (factCol as object)\n ? (factCol as { _def: { type?: string } })._def\n : (factCol as { type?: string } | undefined);\n if (factDef === undefined || factDef.type !== \"text\") {\n throw new Error(`table ${name}: memory.into \"${m.into}\" tablosunda \"fact\" (text) kolonu zorunlu`);\n }\n for (const c of m.from) {\n if (!(c in (def as TableDef).columns)) {\n throw new Error(`table ${name}: memory.from kolonu \"${c}\" kaynak tabloda yok`);\n }\n }\n }\n // Dedupe + normalize extensions (order-independent; deploy resolves deps).\n const extensions = [...new Set(input.extensions ?? [])];\n // Declaring a schema is not the same as putting it on the internet, so\n // `exposed` is false unless the author says otherwise — EXCEPT for `public`,\n // which is reachable today and stays reachable. Making the default uniform\n // would silently 404 every existing project's /v1/db traffic on upgrade.\n return {\n name,\n tables: tables as TablesByName<T>,\n extensions,\n exposed: input.exposed ?? name === \"public\",\n };\n}\n","/**\n * Postgres extensions a Palbase project can enable from its schema.\n *\n * Extensions are config-as-code: declare them in `defineSchema({ extensions })`\n * and the deploy installs them (CREATE EXTENSION … SCHEMA extensions) using the\n * deploy path's privileged connection. They are NOT toggled live from Studio —\n * CREATE EXTENSION requires a superuser role that only the deploy path holds.\n *\n * The list is an allowlist (a string-literal union) so editors autocomplete the\n * supported names and a typo fails typecheck. It is intentionally extensible:\n * add a name here (+ confirm the base image ships it) to support more.\n */\nexport const PALBASE_EXTENSIONS = [\n // Search & text\n \"vector\", // pgvector: AI embeddings + vector similarity search (semantic search / RAG).\n // NB: the Postgres extension is named \"vector\", not \"pgvector\" — declare \"vector\".\n \"pg_trgm\", // trigram fuzzy / typo-tolerant text search\n \"unaccent\", // accent-insensitive text search\n \"citext\", // case-insensitive text type\n // Geospatial / location\n \"cube\", // multi-dimensional cubes (dependency of earthdistance)\n \"earthdistance\", // great-circle distance (needs cube)\n // Data types & structures\n \"hstore\", // key/value pairs in a single column\n \"ltree\", // hierarchical tree-structured labels\n // Indexing & constraints\n \"btree_gist\", // GiST operator classes for scalar types — needed for EXCLUDE\n // constraints that mix \"=\" with a range/&& overlap (e.g. no-double-booking).\n // Scheduling\n // Crypto / ids (also installed by default; listable for explicitness)\n \"pgcrypto\", // cryptographic functions (hashing, encryption)\n \"uuid-ossp\", // UUID generation functions\n] as const;\n\n/** A Postgres extension supported by Palbase (allowlist union). */\nexport type PalbaseExtension = (typeof PALBASE_EXTENSIONS)[number];\n\n/**\n * Extensions that depend on another extension. The deploy installs\n * dependencies first; declaring `earthdistance` without `cube` still works\n * because the deploy resolves the order, but listing both is clearer.\n */\nexport const EXTENSION_DEPENDENCIES: Partial<Record<PalbaseExtension, PalbaseExtension[]>> = {\n earthdistance: [\"cube\"],\n};\n\n/** Runtime guard: is `name` a supported Palbase extension? */\nexport function isPalbaseExtension(name: string): name is PalbaseExtension {\n return (PALBASE_EXTENSIONS as readonly string[]).includes(name);\n}\n","/** On delete action for foreign key references. */\nexport type OnDeleteAction = 'cascade' | 'set null' | 'restrict' | 'no action';\n\n/**\n * The ON DELETE actions permitted on a foreign key to the built-in auth users\n * (`auth.users`). Both let a user's rows be removed (`cascade`) or detached\n * (`set null`) when the account is erased; `restrict` / `no action` would BLOCK\n * erasure and are therefore excluded. This is the CLIENT-SIDE mirror of the\n * server's auth-FK deletion policy — the server (validateAuthUserFK) is the real\n * boundary, this narrows the type so the common mistake is caught at compile time.\n */\nexport type AuthUserOnDelete = Extract<OnDeleteAction, 'cascade' | 'set null'>;\n\n/** Column type identifiers. */\nexport type ColumnType =\n | 'uuid'\n | 'text'\n | 'integer'\n | 'bigint'\n | 'numeric'\n | 'boolean'\n | 'timestamp'\n | 'jsonb'\n | 'enum'\n | 'vector';\n\n/** Base column definition shared by all column types. */\nexport interface ColumnDef {\n type: ColumnType;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n references?: { table: string; column: string };\n /** Pending FK target, resolved by `defineSchema` once every binding exists. */\n referencesThunk?: () => ColumnBuilder;\n /** FK onto THIS table — no thunk needed, the target is the declaring table. */\n selfRefColumn?: string;\n /** This column OWNS the row: erasure, RLS and the `owner` relation read it. */\n owns?: true;\n /** Explicit relation name, when the derived one would be ambiguous. */\n refAs?: string;\n /** The table this column belongs to; set by `defineTable`. */\n ownerTable?: { name: string; columns: Record<string, ColumnBuilder> };\n /**\n * The name this column used to have. A diff cannot tell a rename from a drop and\n * an add — both leave one name gone and another present — so the intent has to be\n * declared. Without it, renaming a column loses its data.\n */\n renamedFrom?: string;\n /**\n * This release's PROMISE that it does not reference this column — neither\n * reads it nor writes it, and never names it in a filter, a sort or a SET.\n *\n * The contraction gate reads it and nothing else does: dropping a column is\n * refused while the RUNNING release's declaration still lacks this mark, so\n * removing a column is two deploys — mark it, ship, then drop it.\n *\n * The word is `ignored` and not `deprecated` deliberately: RFC 9745 defines\n * deprecation as changing NO behaviour, and this changes what a deploy will\n * accept. Rails calls the same thing `ignored_columns`.\n */\n ignored?: boolean;\n onDeleteAction?: OnDeleteAction;\n enumName?: string;\n enumValues?: string[];\n unique?: boolean;\n /**\n * The value is written by the DATABASE — a trigger, a rule, an identity — not by\n * the author and not by a DEFAULT this schema declares. It makes the column\n * optional on INSERT without putting a DEFAULT in the DDL.\n *\n * Before this existed the only way to keep a trigger-filled column off the\n * INSERT type was to give it a fake `default()`: a value the schema claimed to\n * write and the trigger immediately overwrote. That made the schema lie about\n * its own data.\n */\n dbAssigned?: boolean;\n /** vector(n): the declared dimension count — part of the TYPE (typmod), read\n * by the wire serializer and the deploy's auto-index (FR-001). */\n dimensions?: number;\n /**\n * How the stored value is projected in and out of this process (FR-009).\n *\n * NOT part of the DDL: the column's Postgres type is unchanged and this pair\n * is never serialized into a migration. It exists so the row surface can hand\n * back the type the application actually works with.\n */\n transform?: ColumnTransform;\n}\n\n/**\n * The read/write pair a column may declare (FR-009).\n *\n * `fromDb` takes whatever the driver produced for this column and returns the\n * value the application sees; `toDb` is its inverse on the way out. Kept\n * deliberately unexported — a column declares one inline, nobody needs to name\n * the shape.\n */\ninterface ColumnTransform<T = unknown> {\n fromDb: (value: unknown) => T;\n toDb: (value: T) => unknown;\n}\n\n/** FR-002: a vector column cannot carry keys/defaults/references — the modifier\n * is named in the error so the author fixes the right line. */\nfunction refuseOnVector(def: ColumnDef, modifier: string): void {\n if (def.type === 'vector') {\n throw new Error(`vector column: .${modifier}() is not supported (FR-002 — allowed: nullable()/notNull())`);\n }\n}\n\n// Phantom brand symbols — never have runtime values; exist only to force\n// TypeScript's structural type system to distinguish ColumnBuilder instances\n// with different type-param combinations. Without these, TS sees all\n// ColumnBuilder<K,...> as structurally identical and the first branch of\n// ColValue matches everything.\ndeclare const __colKind: unique symbol;\ndeclare const __colNullable: unique symbol;\ndeclare const __colHasDefault: unique symbol;\ndeclare const __colEnumValues: unique symbol;\ndeclare const __colPayload: unique symbol;\ndeclare const __colTransform: unique symbol;\n\n/**\n * Fluent column builder with phantom type params:\n * K — ColumnType literal (e.g. \"text\", \"integer\")\n * N — boolean: true when nullable() has been called last (false = NOT NULL)\n * D — boolean: true when a default has been set\n * E — enum value union (never for non-enum columns)\n * P — jsonb payload shape (unknown unless jsonb<T>() supplied one)\n * T — transform target type (`never` when the column declares no transform;\n * `never` is the sentinel because it is the only type that survives\n * `[T] extends [never]` and never collides with a real target type)\n *\n * All six params have defaults so bare `ColumnBuilder` (no args) still\n * satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.\n *\n * The six `declare readonly` brand fields carry the phantom types into the\n * structural shape so that conditional types like ColValue<C> can discriminate\n * on K without requiring runtime values on those fields.\n */\nexport class ColumnBuilder<\n K extends ColumnType = ColumnType,\n N extends boolean = boolean,\n D extends boolean = boolean,\n E = unknown,\n P = unknown,\n // `unknown`, not `never`: the schema's own constraint is a BARE\n // `ColumnBuilder`, whose T lands on this default. With `never` there, a\n // column that declares `.transform<number>()` is not assignable to the\n // constraint at all — `number` does not extend `never` — so a transform\n // could not appear in a schema and the whole table's `RowShape` collapsed.\n // Measured: TS2322 on `defineSchema`.\n T = unknown,\n> {\n // These fields exist only in the type layer (declared, never initialised at\n // runtime — TypeScript allows declared class members without an initializer\n // in strict mode as long as they're never read at runtime).\n declare readonly [__colKind]: K;\n declare readonly [__colNullable]: N;\n declare readonly [__colHasDefault]: D;\n declare readonly [__colEnumValues]: E;\n declare readonly [__colPayload]: P;\n declare readonly [__colTransform]: T;\n\n readonly _def: ColumnDef;\n\n constructor(type: K, existingDef?: ColumnDef) {\n this._def = existingDef ?? {\n type,\n nullable: false,\n primaryKey: false,\n };\n }\n\n /** Mark this column as the primary key. */\n primaryKey(): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, 'primaryKey');\n this._def.primaryKey = true;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /** Mark this column as NOT NULL (default). */\n notNull(): ColumnBuilder<K, false, D, E, P, T> {\n this._def.nullable = false;\n return new ColumnBuilder<K, false, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /** Allow NULL values. */\n nullable(): ColumnBuilder<K, true, D, E, P, T> {\n this._def.nullable = true;\n return new ColumnBuilder<K, true, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /** Set a default value. */\n default(value: unknown): ColumnBuilder<K, N, true, E, P, T> {\n refuseOnVector(this._def, 'default');\n this._def.defaultValue = value;\n return new ColumnBuilder<K, N, true, E, P, T>(this._def.type as K, this._def);\n }\n\n /** UUID: generate a random default (gen_random_uuid()). */\n defaultRandom(): ColumnBuilder<K, N, true, E, P, T> {\n refuseOnVector(this._def, 'defaultRandom');\n this._def.defaultRandom = true;\n return new ColumnBuilder<K, N, true, E, P, T>(this._def.type as K, this._def);\n }\n\n /** Timestamp: default to now(). */\n defaultNow(): ColumnBuilder<K, N, true, E, P, T> {\n refuseOnVector(this._def, 'defaultNow');\n this._def.defaultNow = true;\n return new ColumnBuilder<K, N, true, E, P, T>(this._def.type as K, this._def);\n }\n\n /**\n * The DATABASE assigns this column's value — a trigger, a rule, an identity.\n *\n * The column becomes optional on INSERT (the author has nothing to send) while\n * the DDL stays free of a DEFAULT this schema would not honour. It is NOT\n * `default()`: that declares a value the schema promises to write.\n *\n * Naming: deliberately not `generated()`. Postgres has GENERATED columns and\n * they are a different thing; borrowing the word would send a reader — or a\n * model writing a schema — to the wrong feature.\n */\n dbAssigned(): ColumnBuilder<K, N, true, E, P, T> {\n this._def.dbAssigned = true;\n return new ColumnBuilder<K, N, true, E, P, T>(this._def.type as K, this._def);\n }\n\n /** Add a foreign key reference. */\n /**\n * Declares that this column used to be called `previous`.\n *\n * A schema diff sees one name gone and another present; it cannot know whether\n * you renamed a column or dropped one and added another, and the two are very\n * different — the second loses every value. Saying so here turns the plan into\n * `ALTER TABLE … RENAME COLUMN` instead.\n *\n * Once the rename has been applied the annotation is inert (the old name is no\n * longer there to rename), so it can be deleted at your leisure.\n */\n renamedFrom(previous: string): ColumnBuilder<K, N, D, E, P, T> {\n this._def.renamedFrom = previous;\n return this as unknown as ColumnBuilder<K, N, D, E, P, T>;\n }\n\n /**\n * See {@link ColumnDef.ignored}.\n *\n * COPIES the def rather than mutating it. The constructor takes an existing\n * def BY REFERENCE, so every builder derived from another shares one object —\n * `const a = slug.unique()` leaves `a._def === slug._def`. An in-place\n * `ignored = true` therefore marks every column sharing that def, including\n * one another table actively reads, and the gate would let THAT column be\n * dropped. Measured before this copy existed.\n *\n * The aliasing is older than this method and other fields leak through it too.\n * The reason this one cannot wait: every other leak produces a VISIBLE schema\n * difference — the plan shows it, the DDL shows it. This one is invisible by\n * design (no DDL, no diff, no plan line), so its only effect is to disarm a\n * safety gate in silence.\n */\n ignored(): ColumnBuilder<K, N, D, E, P, T> {\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, {\n ...this._def,\n ignored: true,\n });\n }\n\n /**\n * Foreign key onto another table's column.\n *\n * The target is a THUNK, not a direct reference. In a cycle (`x → y`, `y → x`)\n * the second table does not exist yet when the first is built; a direct\n * reference makes TypeScript chase its own tail (TS7022 — measured, and making\n * the return type independent of the target does NOT help). The thunk is\n * invoked in `defineSchema`, where every binding exists and every table\n * already knows its name.\n *\n * In a cycle, ONE side needs an explicit return type:\n * `references((): AnyColumn => y.id)`. One side is enough — measured.\n * For a self-reference use `selfReferences(column)`: no thunk, no annotation.\n */\n references(\n target: () => AnyColumn,\n opts?: { as?: string; onDelete?: OnDeleteAction },\n ): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, 'references');\n if (typeof target !== 'function') {\n // Fail where the mistake is. Storing a non-thunk here surfaces three\n // layers later as \"def.referencesThunk is not a function\", inside\n // defineSchema, naming neither the column nor the call that was wrong.\n throw new Error(\n `references(...) takes a callback: write references(() => otherTable.column). ` +\n `The two-string form references(\"table\", \"column\") is gone — a string cannot be type-checked ` +\n `and cannot point at a table that does not exist yet.`,\n );\n }\n this._def.referencesThunk = target;\n if (opts?.as !== undefined) this._def.refAs = opts.as;\n if (opts?.onDelete !== undefined) this._def.onDeleteAction = opts.onDelete;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /**\n * Foreign key onto THIS table (`parent_id → id`) — category trees, comment\n * replies, org charts.\n *\n * No thunk and no type annotation: the target table is the one being declared,\n * so there is nothing to defer and nothing for TypeScript to chase in a circle.\n * Drizzle forces an explicit `(): AnyPgColumn =>` here because its reference\n * always goes through a callback; measured, we do not need one.\n */\n selfReferences(\n column: string,\n opts?: { as?: string; onDelete?: OnDeleteAction },\n ): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, 'selfReferences');\n this._def.selfRefColumn = column;\n if (opts?.as !== undefined) this._def.refAs = opts.as;\n if (opts?.onDelete !== undefined) this._def.onDeleteAction = opts.onDelete;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n\n\n /** Set the ON DELETE action for a foreign key reference. */\n onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E, P, T> {\n this._def.onDeleteAction = action;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /** Add a single-column UNIQUE constraint. */\n unique(): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, 'unique');\n this._def.unique = true;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /**\n * Declare how this column's value is projected in and out of the process.\n *\n * The DDL does not move: `numeric` stays `numeric`, and the driver still hands\n * back what Postgres sent. What changes is the type the row surface exposes —\n * it becomes `Target`:\n *\n * amount: numeric().transform<number>({ fromDb: Number, toDb: String })\n *\n * `numeric` surfacing as `string` is CORRECT (a JS number cannot hold\n * arbitrary precision), and that is exactly why this exists: application code\n * that does arithmetic on the column otherwise rewrites the same\n * `Number(row.amount)` / `String(x)` pair in every controller that touches it,\n * and each rewrite is a place the two directions can drift apart.\n *\n * A transform is a PROJECTION, never a constraint: it lives only in this\n * process, so it can neither validate nor migrate what is stored.\n */\n transform<Target>(fns: ColumnTransform<Target>): ColumnBuilder<K, N, D, E, P, Target> {\n // The cast is the variance, not a shortcut: `toDb` takes `Target`, and a\n // `ColumnTransform<unknown>` would have to accept anything. The stored pair\n // is only ever called with this column's own values.\n this._def.transform = fns as ColumnTransform;\n return new ColumnBuilder<K, N, D, E, P, Target>(this._def.type as K, this._def);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Type extractors — imported by Task 2 to derive insert/row shapes.\n// ---------------------------------------------------------------------------\n\n/**\n * Extracts the TypeScript value type for a column, respecting nullability.\n * - \"uuid\" | \"text\" | \"timestamp\" | \"bigint\" | \"numeric\" → string (or string | null when N = true)\n * Note: bigint/numeric surface as string — JS number loses precision past 2^53,\n * and pgx/PostgREST serialize int8/numeric as strings. App code uses\n * BigInt(row.amount) for bigint, or a decimal lib for numeric.\n * - \"integer\" → number\n * - \"boolean\" → boolean\n * - \"jsonb\" → P (the dev-supplied payload shape from jsonb<T>(), else unknown)\n * - \"enum\" → E (the union of literal values)\n *\n * A declared `.transform<T>()` OVERRIDES the table above: the column then\n * surfaces as T (or T | null when nullable), because that is the value the\n * application is handed. Nullability is still the column's, not the\n * transform's — `fromDb` is not called for a NULL.\n */\nexport type ColValue<C> =\n C extends ColumnBuilder<ColumnType, infer N, boolean, unknown, unknown, infer T>\n ? [unknown] extends [T]\n ? ColStoredValue<C>\n : N extends true\n ? T | null\n : T\n : never;\n\n/** The value as the DATABASE hands it over — the branch table above, before any\n * transform. This is what a column's `fromDb` receives. */\ntype ColStoredValue<C> =\n C extends ColumnBuilder<'uuid' | 'text' | 'timestamp' | 'bigint' | 'numeric', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? string | null\n : string\n : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? number | null\n : number\n : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? boolean | null\n : boolean\n : C extends ColumnBuilder<'jsonb', infer N, infer _D, infer _E, infer P>\n ? N extends true\n ? P | null\n : P\n : C extends ColumnBuilder<'vector', infer N, infer _D, infer _E, infer _P>\n ? N extends true\n ? number[] | null\n : number[]\n : C extends ColumnBuilder<'enum', infer N, infer _D, infer E, infer _P>\n ? N extends true\n ? E | null\n : E\n : never;\n\n/**\n * True when a column is optional on INSERT:\n * - nullable columns (N = true) — the DB allows NULL so the field may be omitted\n * - columns with a default (D = true) — the DB fills in the value when absent\n */\nexport type ColIsOptionalOnInsert<C> =\n C extends ColumnBuilder<ColumnType, true, boolean, unknown, unknown, unknown>\n ? true\n : C extends ColumnBuilder<ColumnType, boolean, true, unknown, unknown, unknown>\n ? true\n : false;\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/** Create a UUID column. */\nexport function uuid(): ColumnBuilder<'uuid', false, false, never> {\n return new ColumnBuilder('uuid');\n}\n\n/** Create a TEXT column. */\nexport function text(): ColumnBuilder<'text', false, false, never> {\n return new ColumnBuilder('text');\n}\n\n/** Create an INTEGER column. Emits int4 (max ~2.1B). */\nexport function integer(): ColumnBuilder<'integer', false, false, never> {\n return new ColumnBuilder('integer');\n}\n\n/**\n * Create a BIGINT column (Postgres int8, max ~9.2×10^18).\n * Surfaces as `string` in row/insert types — JS number loses precision past 2^53\n * and pgx/PostgREST serialize int8 as a JSON string. Use BigInt(row.column) in app code.\n */\nexport function bigint(): ColumnBuilder<'bigint', false, false, never> {\n return new ColumnBuilder('bigint');\n}\n\n/**\n * Create a NUMERIC column (Postgres `numeric`/`decimal`, arbitrary precision).\n * For exact fractional values (money with cents as a decimal, rates, weights)\n * where int4/int8 don't fit. Surfaces as `string` in row/insert types — JS\n * number can't hold arbitrary-precision decimals without rounding, and\n * pgx/PostgREST serialize numeric as a JSON string. Parse with a decimal lib\n * (or BigInt for scaled integers) in app code.\n */\nexport function numeric(): ColumnBuilder<'numeric', false, false, never> {\n return new ColumnBuilder('numeric');\n}\n\n/** Create a BOOLEAN column. */\nexport function boolean(): ColumnBuilder<'boolean', false, false, never> {\n return new ColumnBuilder('boolean');\n}\n\n/** Create a TIMESTAMP column. */\nexport function timestamp(): ColumnBuilder<'timestamp', false, false, never> {\n return new ColumnBuilder('timestamp');\n}\n\n/**\n * Create a JSONB column. Pass a payload type to make the generated row/insert\n * type concrete instead of `unknown`:\n *\n * tags: jsonb<string[]>() // row.tags: string[]\n * meta: jsonb<{ tier: string }>() // row.meta: { tier: string }\n * raw: jsonb() // row.raw: unknown (back-compat)\n *\n * The runtime accepts a plain JS object/array directly (no JSON.stringify); the\n * generic only refines the TYPE the env codegen emits.\n */\nexport function jsonb<T = unknown>(): ColumnBuilder<'jsonb', false, false, never, T> {\n return new ColumnBuilder('jsonb');\n}\n\n/**\n * Create an ENUM column.\n * @param name The PostgreSQL enum type name (used in DDL).\n * @param values A readonly tuple of valid string values — kept `const` so the\n * union `V[number]` is as narrow as possible.\n */\nexport function enumType<const V extends readonly string[]>(\n name: string,\n values: V,\n): ColumnBuilder<'enum', false, false, V[number]> {\n const builder = new ColumnBuilder<'enum', false, false, V[number]>('enum');\n builder._def.enumName = name;\n builder._def.enumValues = [...values];\n return builder;\n}\n\n/** vector(n) — pgvector kolonu. n TİPİN parçasıdır (typmod) ve [1, 2000] —\n * 2000 = pgvector'ün HNSW-indekslenebilir tavanı; auto-index bu beyanla bağlı\n * (spec FR-001, D-3). */\nexport function vector(dimensions: number): ColumnBuilder<'vector', false, false, unknown, number[]> {\n if (!Number.isInteger(dimensions) || dimensions < 1 || dimensions > 2000) {\n throw new Error(`vector(): dimensions must be an integer in [1, 2000], got ${String(dimensions)}`);\n }\n const b = new ColumnBuilder('vector') as ColumnBuilder<'vector', false, false, unknown, number[]>;\n (b._def as { dimensions?: number }).dimensions = dimensions;\n return b;\n}\n\n/**\n * Any column, whatever its type parameters.\n *\n * Exported so a cycle can be broken from ONE side:\n * `references((): AnyColumn => y.id)`.\n */\nexport type AnyColumn = ColumnBuilder;\n\n/**\n * The column that OWNS this row: a `text` FK onto `auth.users(id)`, NOT NULL,\n * ON DELETE CASCADE.\n *\n * Ownership drives account erasure, so cascade is the only correct action and\n * takes no argument. The referencing column must be `text` (palauth ids are\n * `usr_<uuid>`) and NOT NULL — both are implied here rather than left to the\n * caller, so three rules the type could not express before become UNWRITABLE.\n *\n * At most ONE per table. The old shape let several columns reference\n * `auth.users` and picked the FIRST IN DECLARATION ORDER as the owner — moving a\n * `created_by` above a `user_id` silently changed which rows an account deletion\n * took with it. A second one is now rejected at push.\n *\n * For a column that merely POINTS at a user without owning the row\n * (`created_by`, `edited_by`), use `userRef({ onDelete })`.\n */\nexport function ownedByUser(): ColumnBuilder<'text', false, false, never> {\n const b = new ColumnBuilder<'text', false, false, never>('text');\n b._def.nullable = false;\n b._def.references = { table: 'auth.users', column: 'id' };\n b._def.onDeleteAction = 'cascade';\n b._def.owns = true;\n return b;\n}\n\n/**\n * A plain FK onto `auth.users(id)` that does NOT own the row.\n *\n * `created_by` / `edited_by`: deleting that user must not delete the row. ON\n * DELETE is required and limited to `cascade | set null` so an erasure request\n * is never blocked by a lingering FK; `set null` needs a nullable column.\n */\nexport function userRef(opts: { onDelete: AuthUserOnDelete; as?: string }): ColumnBuilder<'text', boolean, false, never> {\n const b = new ColumnBuilder<'text', boolean, false, never>('text');\n b._def.references = { table: 'auth.users', column: 'id' };\n b._def.onDeleteAction = opts.onDelete;\n if (opts.as !== undefined) b._def.refAs = opts.as;\n return b;\n}\n\n/**\n * A plain FK onto `auth.installations(id)` — the app-scoped verified-device\n * anchor.\n *\n * An installation is an APP INSTALL, not a user: this is NOT ownership. A\n * user-owned row still needs its own `ownedByUser()` so account erasure removes\n * it; an installation reference alone does not tie a row to a user's deletion.\n */\nexport function installationRef(opts: { onDelete: AuthUserOnDelete; as?: string }): ColumnBuilder<'text', boolean, false, never> {\n const b = new ColumnBuilder<'text', boolean, false, never>('text');\n b._def.references = { table: 'auth.installations', column: 'id' };\n b._def.onDeleteAction = opts.onDelete;\n if (opts.as !== undefined) b._def.refAs = opts.as;\n return b;\n}\n","/**\n * A named raw-SQL DDL object declared in db/schema.ts for anything the typed DSL\n * cannot express (EXCLUDE, CHECK, partial/expression indexes, triggers, views).\n * The deploy emits `up` verbatim on the privileged DDL connection — same trust\n * posture as policy().using(). Tracked by NAME (not by diffing the body), so a\n * changed body needs a new name or an explicit drop+add.\n */\nexport interface RawConstraintDef {\n name: string;\n up: string;\n down?: string;\n}\n\nexport function raw(name: string, up: string, opts?: { down?: string }): RawConstraintDef {\n return { name, up, ...(opts?.down != null ? { down: opts.down } : {}) };\n}\n","/** Embedding sağlayıcı DESKRIPTORU — canlı istemci değil, düz veri: şemayla\n * birlikte serileşir, çağrıyı Go worker (yazma) ve engine (sorgu) yapar.\n * Adlandırma Vercel AI SDK'nın aynasıdır (openai.embedding(\"...\")) ama paket\n * bağımlılığı bilinçli olarak YOKTUR (spec C-3, UD-016). v1 sağlayıcı: openai (D-10). */\nexport interface EmbeddingModelRef {\n provider: \"openai\";\n model: string;\n dimensions?: number;\n apiKeyName?: string;\n baseURL?: string;\n}\n/** Chat/damıtma modeli DESKRIPTORU (C-11, D-019) — memory beyanının extract'i.\n * Embedding gibi düz veridir; çağrıyı worker yapar, anahtar vault'taki\n * OPENAI_API_KEY'dir (D-017: aynı sağlayıcı, yeni dış sistem yok). */\nexport interface ChatModelRef {\n provider: \"openai\";\n model: string;\n}\nexport const openai = {\n embedding(\n model: string,\n opts?: { dimensions?: number; apiKeyName?: string; baseURL?: string },\n ): EmbeddingModelRef {\n return { provider: \"openai\", model, apiKeyName: opts?.apiKeyName ?? \"OPENAI_API_KEY\",\n ...(opts?.dimensions !== undefined ? { dimensions: opts.dimensions } : {}),\n ...(opts?.baseURL !== undefined ? { baseURL: opts.baseURL } : {}) };\n },\n chat(model: string): ChatModelRef {\n return { provider: \"openai\", model };\n },\n};\n","/**\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 { Materialized, TxPlanHandle, TxTable } from \"./tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./tx-plan.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: InsertShape<T>): Promise<RowShape<T>>;\n upsert(data: InsertShape<T>, opts: { 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(id: string, data: Partial<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(\n query?: WhereFilter<RowShape<T>>,\n opts?: FindManyOpts<RowShape<T>>,\n ): Promise<RowShape<T>[]>;\n /** Update every matching row in one statement; an empty filter is refused. */\n updateMany(\n where: WhereFilter<RowShape<T>>,\n set: Partial<InsertShape<T>>,\n ): Promise<RowShape<T>[]>;\n /** Delete every matching row; resolves to how many. Empty filter refused. */\n deleteMany(where: WhereFilter<RowShape<T>>): Promise<number>;\n /** How many rows match. An empty filter is legitimate: counting is a read. */\n count(where?: WhereFilter<RowShape<T>>): 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. */\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 upsert: (data: InsertShape<T>, opts: { onConflict: readonly string[] }) =>\n raw.upsert(name, data as Record<string, unknown>, opts) as Promise<RowShape<T>>,\n\n update: (id: string, data: Partial<InsertShape<T>>) =>\n raw.update(name, id, data 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: (query?: WhereFilter<RowShape<T>>, opts?: FindManyOpts<RowShape<T>>) =>\n raw.findMany(name, query as Record<string, unknown> | undefined, opts) as Promise<RowShape<T>[]>,\n\n updateMany: (where: WhereFilter<RowShape<T>>, set: Partial<InsertShape<T>>) =>\n raw.updateMany(\n name,\n where as Record<string, unknown>,\n set as Record<string, unknown>,\n ) as Promise<RowShape<T>[]>,\n\n deleteMany: (where: WhereFilter<RowShape<T>>) =>\n raw.deleteMany(name, where as Record<string, unknown>),\n\n count: (where?: WhereFilter<RowShape<T>>) =>\n raw.count(name, 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 return runTxPlan(\n raw,\n planTables as TypedTx<S>[\"tables\"],\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.tables.<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). */\nexport type WhereOp<V> = V | { gt?: V; gte?: V; lt?: V; lte?: V; neq?: V; in?: V[] };\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]> };\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 FindManyOpts<Row> = {\n orderBy?: { column: Extract<keyof Row, string>; direction?: \"asc\" | \"desc\" };\n limit?: number;\n offset?: number;\n};\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 where?: { [K in keyof T[\"row\"]]?: WhereOp<T[\"row\"][K]> };\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 /** Filtrelenmiş küme üzerinde kolon başına top-20 değer sayacı — dönüş\n * dizisinin `_facets` özelliği (FR-027). */\n facets?: Extract<keyof T[\"row\"], 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/** search() dönüş dizisinin sorgu-düzeyi ekleri (FR-027): `_facets` dizinin\n * ÖZELLİĞİDİR, satırlara kopyalanmaz (JSON'a satır başına şişme olması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/** Temel tablo erişimcisi — search'süz beş op. */\nexport interface EnvTypedTableBase<T extends TableTypes> {\n insert(data: T[\"insert\"]): Promise<T[\"row\"]>;\n /**\n * Insert the row, or update it when it collides on `onConflict`.\n *\n * The conflict columns must carry a unique constraint or index — that is what\n * Postgres matches on — and they are excluded from the update, since they are\n * what matched.\n */\n upsert(data: T[\"insert\"], opts: { onConflict: readonly Extract<keyof T[\"row\"], string>[] }): 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(id: string, data: Partial<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(\n query?: WhereFilter<T[\"row\"]>,\n opts?: FindManyOpts<T[\"row\"]>,\n ): Promise<T[\"row\"][]>;\n /** Update every matching row in one statement; an empty filter is refused. */\n updateMany(where: WhereFilter<T[\"row\"]>, set: Partial<T[\"insert\"]>): Promise<T[\"row\"][]>;\n /** Delete every matching row; resolves to how many. Empty filter refused. */\n deleteMany(where: WhereFilter<T[\"row\"]>): Promise<number>;\n /** How many rows match. An empty filter is legitimate: counting is a read. */\n count(where?: WhereFilter<T[\"row\"]>): 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: 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. */\nexport type EnvTypedTable<T extends TableTypes> = EnvTypedTableBase<T> &\n (T extends { searchable: true }\n ? {\n search(\n params: SearchParamsTyped<T>,\n ): Promise<Array<T[\"row\"] & { _score: number }> & { _facets?: SearchFacets }>;\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<Record<string, { value: string | null; count: number }[]>>;\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 */\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}. */\nexport type TxTables = {\n [K in keyof Tables]: TxTable<Tables[K][\"row\"], Tables[K][\"insert\"]>;\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 */\nexport type TxPlan = TxPlanHandle<TxTables>;\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 interface EnvServiceDatabase extends Omit<DBClient, \"txPlan\" | \"asService\"> {\n tables: EnvTables;\n /** See {@link EnvTypedDatabase.schema}. The bypass sibling reaches every\n * schema the default surface does — a `billing` table is no less reachable\n * because the caller asked to run as the service role. */\n schema<S extends keyof Schemas>(name: S): EnvSchemas[S];\n transaction<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T): 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 interface EnvTypedDatabase extends Omit<DBClient, \"txPlan\" | \"asService\"> {\n tables: EnvTables;\n /**\n * The tables of a schema other than `public`.\n *\n * `Database.tables.*` is the PUBLIC schema and only the public schema. Two\n * schemas may declare the same table name — `public.invoices` and\n * `billing.invoices` are different tables — so one flat namespace would make\n * `Database.tables.invoices` resolve by declaration order. It does not: the\n * bare name is always public's, and everything else is asked for by schema.\n *\n * The name is `keyof Schemas`, so a schema the project never declared is a\n * compile error. On the wire the table travels schema-qualified\n * (`billing.invoices`); `public` stays bare.\n *\n * Declaring a schema does not publish it — reachability over HTTP is the\n * schema's own `exposed` flag, checked by the broker.\n *\n * @example\n * const inv = await Database.schema(\"billing\").tables.invoices.findById(id);\n */\n schema<S extends keyof Schemas>(name: S): EnvSchemas[S];\n /**\n * Run a transaction. The callback DESCRIBES the operations; the whole\n * description travels in one request and the broker runs it inside a single\n * transaction — committing when it finishes, rolling back on any failure.\n *\n * The callback is SYNCHRONOUS: nothing has run when it returns, so there is\n * nothing to await. `async` on it and `await` inside it are compile errors.\n * Values a later operation needs are {@link Ref}s, written straight into the\n * next operation; values the CALLER needs are returned and substituted before\n * this promise resolves.\n *\n * @example\n * const { statementId } = await Database.transaction((tx) => {\n * const st = tx.tables.statements\n * .insert({ household_id: hid, file_sha256: sha, status: \"reviewing\" })\n * .expectOne(new Internal(\"statement insert failed\"));\n *\n * tx.tables.statement_lines.insertMany(\n * lines.map((l) => ({ statement_id: st.id, category: resolveCategory(l) })),\n * );\n *\n * return { statementId: st.id };\n * });\n */\n transaction<T>(fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T): Promise<Materialized<T>>;\n /**\n * Run `fn` inside a SAVEPOINT, so a write that fails in it does not poison the\n * rest of the request.\n *\n * A request is ONE Postgres transaction: a failed statement aborts it and\n * every later one answers `current transaction is aborted`. That is why\n * \"insert, catch the unique violation, update instead\" cannot be written\n * directly — and why {@link EnvTypedTableBase.upsert} exists for the common\n * case. Reach for `attempt` when the recovery is not an upsert.\n *\n * The handle is a parameter, not the ambient `Database`: only what `tx` writes\n * is inside the boundary, so a concurrent branch of the same request cannot be\n * rolled back by someone else's failure.\n *\n * @example\n * const claimed = await Database.attempt(async (tx) => {\n * await tx.insert(\"seats\", { row: 4, seat: 12, user_id: user.id });\n * return true;\n * }).catch(() => false);\n */\n attempt<T>(fn: (tx: Omit<DBClient, \"attempt\" | \"txPlan\" | \"asService\">) => Promise<T>): Promise<T>;\n /**\n * Return a sibling that bypasses RLS by running as the `service_role`. Use\n * sparingly and explicitly — the default `Database.*` path is RLS-enforced.\n *\n * @example\n * const all = await Database.asService().tables.todos.findMany({});\n * const rows = await Database.asService().query(\"SELECT * FROM todos\");\n */\n asService(): EnvServiceDatabase;\n}\n"],"mappings":"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","names":["policy","out","name","raw"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/decorators/registry.ts","../src/decorators/controller.ts","../src/errors.ts"],"sourcesContent":["// The decorator registry — the single plain-data store the method + parameter\n// decorators write into, and the deploy/dispatch pipeline reads back. No\n// `reflect-metadata`, no `emitDecoratorMetadata`: the registry is built from the\n// decorator arguments + the parameter INDEX that esbuild/tsc preserve for legacy\n// parameter decorators (verified — see the design spec §0/§4.1).\n//\n// A controller class carries its route metadata on a symbol-keyed static\n// property (`ROUTES`). `@Get`/`@Post`/… append a {@link RouteMeta} entry;\n// `@Body`/`@User`/… append a {@link ParamMeta} entry onto the route for the\n// method they decorate. Because parameter decorators run BEFORE the method\n// decorator for the same member (TS evaluates innermost-first, params before the\n// method), the route entry may not exist yet when a param decorator fires — so\n// param metadata is buffered per method name and merged when the method\n// decorator creates the route entry.\nimport type { AuthSpec, RateLimitConfig } from \"../endpoint.js\";\nimport type { UploadConfig } from \"./upload.js\";\nimport type { SseConfig } from \"./sse.js\";\nimport type { ZodTypeAny } from \"zod\";\n\n/** The HTTP verbs a route may declare, upper-cased (the runtime router +\n * OpenAPI lower-case on their own). */\nexport type HttpMethodUpper = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"QUERY\";\n\n/** Route-level options accepted by the method decorators (`@Get`/`@Post`/…). */\nexport interface RouteOptions {\n /** OVERRIDES the controller-level default auth for this one route. */\n auth?: AuthSpec;\n /** Per-route rate limit. */\n rateLimit?: RateLimitConfig;\n /** Direct-storage upload config — present ONLY on `@Upload` routes (the\n * `@Get`/`@Post`/… decorators never set it). Its presence is what MARKS a\n * route as an upload route through the whole pipeline (registry → flatten →\n * openapi → codegen). The bytes go client→storage directly; the method body\n * runs as the completion handler. See {@link UploadConfig} (decorators/upload.ts). */\n uploadConfig?: UploadConfig;\n /** Streaming config — present ONLY on `@Sse` routes (the `@Get`/`@Post`/…\n * decorators never set it). Its presence is what MARKS a route as a streaming\n * route through the whole pipeline (registry → flatten → openapi → codegen),\n * exactly as `uploadConfig` does for uploads — never a special HTTP verb. An\n * `@Sse` route registers POST like any input-bearing route, so the verb cannot\n * carry the distinction. See {@link SseConfig} (decorators/sse.ts). */\n sseConfig?: SseConfig;\n}\n\n/** The kind of value a parameter decorator injects. Drives both dispatch\n * (which request slice to inject) and codegen (which OpenAPI parameter source a\n * schema-bearing kind maps to). */\nexport type ParamKind =\n | \"body\"\n | \"query\"\n | \"param\"\n | \"headers\"\n | \"user\"\n | \"optionalUser\"\n | \"client\"\n | \"requestId\"\n | \"traceId\"\n | \"req\"\n // `@UploadedObject()` — injects the uploaded object (completion input) on an\n // `@Upload` route. No schema (the shape is the fixed UploadedObject type).\n | \"uploadedObject\"\n // `@SseOut()` — injects the frame writer on an `@Sse` route. No schema (the\n // shape is the fixed SseWriter type).\n | \"sseOut\"\n // `@Signal()` — injects the request's AbortSignal, which aborts when the\n // client disconnects. No schema. NOT derivable from `@Req()`: PBRequest\n // carries only request-scoped data and has no signal (endpoint.ts:358-363).\n | \"signal\";\n\n/** One parameter decorator's recorded metadata. `index` is the parameter\n * position esbuild/tsc preserve; `schema` is present for the schema-bearing\n * kinds (`body`/`query`/`headers`); `name` is the path-param name for `param`. */\nexport interface ParamMeta {\n index: number;\n kind: ParamKind;\n /** Zod schema for `body`/`query`/`headers` (validation + codegen source). */\n schema?: ZodTypeAny;\n /** Path-param name for `@Param(\"id\")`. */\n name?: string;\n}\n\n/** One inferred throw site: the error CLASS name (e.g. \"TodoLocked\") and its\n * wire code (e.g. \"todo_locked\"). `status`, `hasData`, and the data JSON schema\n * are NOT carried here — they resolve from the error registry by `code` at\n * extract/openapi time (single source of truth). */\nexport interface ThrowDescriptor {\n name: string;\n code: string;\n}\n\n/** One route's recorded metadata: the verb + subpath + method name + options,\n * the ordered parameter metas, and the resolved return schema (injected by the\n * codegen step — see `returnSchema`). */\nexport interface RouteMeta {\n method: HttpMethodUpper;\n subpath: string;\n fnName: string;\n options: RouteOptions;\n params: ParamMeta[];\n /** Response schema for the route, if any. Derived from the method's RETURN\n * TYPE by codegen and written here via `recordReturn` (a generated top-level\n * IIFE injected per controller), not by an author-written decorator. */\n returnSchema?: ZodTypeAny;\n /** Error classes this route can throw, if inferred. Derived from the method\n * body + service call graph by the deploy stager's throw analysis and written\n * here via `recordThrows` (a generated top-level IIFE injected per controller,\n * the `recordReturn` twin), not by an author-written decorator. */\n throws?: ThrowDescriptor[];\n}\n\n/** Symbol the route metadata list is stored under on a controller class. Using\n * a symbol (not a string key) keeps it off the public structural surface and\n * avoids any chance of an authored property collision. */\nexport const ROUTES: unique symbol = Symbol.for(\"palbase.backend.routes\");\n\n/** Symbol the per-method buffered parameter metas are stored under while a class\n * is being decorated. Parameter decorators fire before the method decorator, so\n * they buffer here keyed by method name; the method decorator drains the buffer\n * into the route entry it creates. */\nconst PARAM_BUFFER: unique symbol = Symbol.for(\"palbase.backend.paramBuffer\");\n\n/** A room's own slots. Rooms are NOT routes — no verb, no path, no params — so\n * they get their own carrier slots instead of being squeezed into RouteMeta. */\nconst ROOM: unique symbol = Symbol.for(\"palbase.backend.room\");\nconst ROOM_HOOKS: unique symbol = Symbol.for(\"palbase.backend.roomHooks\");\n\n/** Symbol the per-method buffered return-type schemas are stored under while a\n * class's registry is being populated. The codegen-injected `recordReturn` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordReturn`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its return schema — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst RETURN_BUFFER: unique symbol = Symbol.for(\"palbase.backend.returnBuffer\");\n\n/** Symbol the per-method buffered throw descriptors are stored under while a\n * class's registry is being populated. The stager-injected `recordThrows` call\n * can fire before OR after the method decorator; it buffers here keyed by method\n * name and `recordRoute` drains it into the route entry (and `recordThrows`\n * writes through if the route already exists). Buffering on BOTH sides means a\n * fully-formed route entry always carries its throw descriptors — a raw-symbol\n * reader (the runtime) never has to re-merge. */\nconst THROWS_BUFFER: unique symbol = Symbol.for(\"palbase.backend.throwsBuffer\");\n\n/** A class constructor carrying the symbol-keyed registry slots. We type the\n * registry-bearing class as this so the decorators can read/write the slots\n * without `any` — a plain `Function` does not carry index signatures. */\ninterface RegistryCarrier {\n [ROUTES]?: RouteMeta[];\n [PARAM_BUFFER]?: Record<string, ParamMeta[]>;\n [ROOM]?: RoomMeta;\n [ROOM_HOOKS]?: RoomBuffer;\n [RETURN_BUFFER]?: Record<string, ZodTypeAny>;\n [THROWS_BUFFER]?: Record<string, ThrowDescriptor[]>;\n}\n\n/** Coerce a decorated target (class constructor or its prototype) into the\n * registry carrier that owns the slots. Method/param decorators receive the\n * PROTOTYPE as their target; the class decorator receives the constructor. We\n * always anchor the registry on the CONSTRUCTOR so `getRoutes(ctor)` finds it. */\nfunction carrierOf(target: object): RegistryCarrier {\n // For instance-member decorators, `target` is the prototype; its `.constructor`\n // is the class. For a static member or the class decorator, `target` is the\n // constructor already. Resolve to the constructor either way.\n const ctor =\n typeof target === \"function\"\n ? (target as unknown as RegistryCarrier)\n : (((target as { constructor?: unknown }).constructor ??\n target) as unknown as RegistryCarrier);\n return ctor;\n}\n\n/** Get (creating if absent) the own route list for a class constructor. Own —\n * not inherited — so a subclass does not mutate its base's routes. */\nfunction ownRoutes(carrier: RegistryCarrier): RouteMeta[] {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROUTES)) {\n carrier[ROUTES] = [];\n }\n return carrier[ROUTES] as RouteMeta[];\n}\n\n/** Get (creating if absent) the own per-method param buffer for a class. */\nfunction ownParamBuffer(carrier: RegistryCarrier): Record<string, ParamMeta[]> {\n if (!Object.prototype.hasOwnProperty.call(carrier, PARAM_BUFFER)) {\n carrier[PARAM_BUFFER] = {};\n }\n return carrier[PARAM_BUFFER] as Record<string, ParamMeta[]>;\n}\n\n/** Record a route (called by the method decorators). Drains any parameter\n * metas already buffered for `fnName` into the new route entry, then sorts them\n * by parameter index so dispatch can inject positionally. */\nexport function recordRoute(\n target: object,\n fnName: string,\n method: HttpMethodUpper,\n subpath: string,\n options: RouteOptions,\n): void {\n const carrier = carrierOf(target);\n const routes = ownRoutes(carrier);\n const buffer = ownParamBuffer(carrier);\n const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);\n const route: RouteMeta = { method, subpath, fnName, options, params };\n // Drain a buffered return schema (the recordReturn-ran-first ordering) so the\n // route entry is complete the moment it's created — a raw-symbol consumer\n // (the runtime extractor/worker) sees the return schema without re-merging.\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer && returnBuffer[fnName] !== undefined) {\n route.returnSchema = returnBuffer[fnName];\n }\n // Same drain for buffered throw descriptors (the recordThrows-ran-first\n // ordering) — the route entry is complete the moment it's created.\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer && throwsBuffer[fnName] !== undefined) {\n route.throws = throwsBuffer[fnName];\n }\n routes.push(route);\n}\n\n/** Record one parameter decorator (called by `@Body`/`@User`/…). Buffers per\n * method name; the method decorator merges the buffer into the route entry. If\n * the route already exists (method decorator ran first — TS does evaluate the\n * method decorator AFTER its parameter decorators, but we stay order-robust),\n * the meta is also appended directly so neither ordering loses it. */\nexport function recordParam(target: object, fnName: string, meta: ParamMeta): void {\n const carrier = carrierOf(target);\n const buffer = ownParamBuffer(carrier);\n (buffer[fnName] ??= []).push(meta);\n\n // Order-robust: if the route already exists, merge in place + keep sorted.\n const routes = carrier[ROUTES];\n if (routes) {\n const route = routes.find((r) => r.fnName === fnName);\n if (route) {\n route.params.push(meta);\n route.params.sort((a, b) => a.index - b.index);\n }\n }\n}\n\n/** Attach a return schema to the route for `fnName` (called by the codegen\n * injection that reads the method's return type). If the route does not exist\n * yet, the schema is buffered (RETURN_BUFFER) and drained into the route by\n * `recordRoute` when the method decorator runs. */\nexport function recordReturn(target: object, fnName: string, schema: ZodTypeAny): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.returnSchema = schema;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, RETURN_BUFFER)) {\n carrier[RETURN_BUFFER] = {};\n }\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) returnBuffer[fnName] = schema;\n}\n\n/** Attach the inferred throw descriptors to the route for `fnName` (called by\n * the stager-injected IIFE that carries the throw analysis result — the\n * `recordReturn` twin). If the route does not exist yet, the descriptors are\n * buffered (THROWS_BUFFER) and drained into the route by `recordRoute` when the\n * method decorator runs. */\nexport function recordThrows(target: object, fnName: string, throws: ThrowDescriptor[]): void {\n const carrier = carrierOf(target);\n const routes = carrier[ROUTES];\n const route = routes?.find((r) => r.fnName === fnName);\n if (route) {\n route.throws = throws;\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(carrier, THROWS_BUFFER)) {\n carrier[THROWS_BUFFER] = {};\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) throwsBuffer[fnName] = throws;\n}\n\n/** Read the route metadata for a controller class (the deploy/dispatch entry\n * point). Applies any buffered return schemas + throw descriptors (for the\n * recordReturn/recordThrows-runs-before orderings) and returns a defensive copy\n * so callers cannot mutate the registry.\n */\nexport function getRoutes(ctor: object): RouteMeta[] {\n const carrier = carrierOf(ctor);\n const routes = carrier[ROUTES] ?? [];\n const returnBuffer = carrier[RETURN_BUFFER];\n if (returnBuffer) {\n for (const route of routes) {\n const buffered = returnBuffer[route.fnName];\n if (buffered && route.returnSchema === undefined) {\n route.returnSchema = buffered;\n }\n }\n }\n const throwsBuffer = carrier[THROWS_BUFFER];\n if (throwsBuffer) {\n for (const route of routes) {\n const buffered = throwsBuffer[route.fnName];\n if (buffered && route.throws === undefined) {\n route.throws = buffered;\n }\n }\n }\n return routes.map((r) => ({\n ...r,\n params: r.params.slice(),\n ...(r.throws !== undefined ? { throws: r.throws.slice() } : {}),\n }));\n}\n\n// ── rooms ───────────────────────────────────────────────────────────────────\n\n/** Which lifecycle hook a method is bound to. */\nexport type RoomHook = \"authorize\" | \"first\" | \"join\" | \"leave\" | \"empty\";\n\nexport interface RoomMessageMeta {\n fnName: string;\n schema: ZodTypeAny;\n}\n\nexport interface RoomMeta {\n pattern: string;\n events: Record<string, ZodTypeAny>;\n graceMs: number;\n /** hook → the method name that implements it. */\n hooks: Partial<Record<RoomHook, string>>;\n /** inbound message name → its method and payload schema. */\n messages: Record<string, RoomMessageMeta>;\n}\n\ninterface RoomBuffer {\n hooks: Partial<Record<RoomHook, string>>;\n messages: Record<string, RoomMessageMeta>;\n}\n\n/** Get (creating if absent) the own hook buffer. Own — not inherited — so a\n * subclass never mutates its base's hooks. Member decorators fill this BEFORE\n * the class decorator runs; controller.ts:203 depends on the same ordering. */\nfunction ownRoomBuffer(carrier: RegistryCarrier): RoomBuffer {\n if (!Object.prototype.hasOwnProperty.call(carrier, ROOM_HOOKS)) {\n carrier[ROOM_HOOKS] = { hooks: {}, messages: {} };\n }\n return carrier[ROOM_HOOKS] as RoomBuffer;\n}\n\n/** Record a lifecycle hook. A second method for the same hook is refused: two\n * answers to \"who handles this\" cannot be resolved at dispatch, and silently\n * keeping one is how a hook stops running without anyone being told. */\nexport function recordRoomHook(target: object, hook: RoomHook, fnName: string): void {\n const buffer = ownRoomBuffer(carrierOf(target));\n const existing = buffer.hooks[hook];\n if (existing !== undefined && existing !== fnName) {\n const label = `On${hook.charAt(0).toUpperCase()}${hook.slice(1)}`;\n throw new Error(\n `@${label} is declared twice in one room (${existing} and ${fnName}). ` +\n `A room has one of each hook.`,\n );\n }\n buffer.hooks[hook] = fnName;\n}\n\n/** Record an inbound message handler. */\nexport function recordRoomMessage(\n target: object,\n name: string,\n fnName: string,\n schema: ZodTypeAny,\n): void {\n const buffer = ownRoomBuffer(carrierOf(target));\n const existing = buffer.messages[name];\n if (existing !== undefined && existing.fnName !== fnName) {\n throw new Error(\n `@OnMessage(\"${name}\") is declared twice in one room (${existing.fnName} and ${fnName}).`,\n );\n }\n buffer.messages[name] = { fnName, schema };\n}\n\n/** Record the room itself (called by the class decorator), draining the buffer\n * the member decorators already filled. */\nexport function recordRoom(\n ctor: object,\n meta: Omit<RoomMeta, \"hooks\" | \"messages\">,\n): void {\n const carrier = carrierOf(ctor);\n const buffer = ownRoomBuffer(carrier);\n carrier[ROOM] = { ...meta, hooks: buffer.hooks, messages: buffer.messages };\n}\n\n/** The room a class declares, or undefined. A class with no `@Room` is not a\n * room — the marker is the CONFIG's presence, never a name or a base class\n * (the rule upload.ts:13-16 states for uploads). */\nexport function getRoom(ctor: object): RoomMeta | undefined {\n const carrier = carrierOf(ctor);\n if (!Object.prototype.hasOwnProperty.call(carrier, ROOM)) return undefined;\n return carrier[ROOM] as RoomMeta;\n}\n","// `@Controller(basePath, options?)` — the class decorator that marks a class as\n// a Palbase backend controller. It stamps a non-enumerable `__palbase`\n// discriminant + the resolved controller metadata onto the class so the\n// deploy/dispatch pipeline (and `isController`/`resolveController`) can detect\n// and read it without `reflect-metadata`.\nimport type { AuthSpec } from \"../endpoint.js\";\nimport { getRoutes } from \"./registry.js\";\n\n/** The controller metadata stamped onto a `@Controller`-decorated class. The\n * default export of a `controllers/*.controller.ts` file resolves to this via\n * {@link resolveController}. */\nexport interface ControllerMeta {\n /** Discriminant the runtime + tooling read. */\n readonly __palbase: \"controller\";\n /** The base path every route in this controller mounts under (e.g. \"/todos\"). */\n basePath: string;\n /** Controller-level default auth, applied to routes that don't set their own\n * (`@Get(\"/x\", { auth })` overrides this). `undefined` ⇒ the application\n * default ({@link defineDefaultAuth}), and secure-by-default below that —\n * see {@link resolveEffectiveAuth} for the whole cascade. */\n defaultAuth?: AuthSpec;\n}\n\n/** Options accepted by `@Controller`. */\nexport interface ControllerOptions {\n /** Default auth for ALL routes in this controller (route-level overrides;\n * omitting it falls through to the application default declared with\n * {@link defineDefaultAuth}). */\n auth?: AuthSpec;\n}\n\n/** Symbol the controller metadata is stamped under. Symbol-keyed (not a string\n * property) so it never collides with an authored member and stays off the\n * structural surface. */\nexport const CONTROLLER_META: unique symbol = Symbol.for(\"palbase.backend.controllerMeta\");\n\n/**\n * Every class `@Controller` has decorated, in decoration order.\n *\n * This is what lets a controller file need no export at all: importing the file\n * runs the decorator, the decorator records the class here, and the runtime\n * reads the list. Without it the only handle on a class is its export name, so\n * every controller had to be exported AND named in a generated entry — the\n * ceremony NestJS still charges (`export class` PLUS\n * `@Module({controllers:[…]})`).\n *\n * Keyed on a well-known Symbol against globalThis rather than held in a module\n * variable, because a deployed bundle inlines its own copy of this package: two\n * copies would keep two lists, and the runtime would read the empty one. The\n * same hazard `runtimeHooks` exists for, closed the same way — one shared slot.\n */\nconst REGISTRY: unique symbol = Symbol.for(\"palbase.backend.allControllers\") as never;\n\nfunction registry(): unknown[] {\n const g = globalThis as unknown as Record<symbol, unknown[] | undefined>;\n const existing = g[REGISTRY];\n if (existing) return existing;\n const fresh: unknown[] = [];\n g[REGISTRY] = fresh;\n return fresh;\n}\n\n/**\n * The controller classes this process has loaded, in decoration order.\n *\n * Decoration order is import order, which the bundler fixes by sorting the\n * files it emits imports for — so two builds of one tree produce the same\n * route table, and route precedence is not a function of module-resolution\n * accidents.\n */\nexport function getRegisteredControllers(): readonly unknown[] {\n return registry().slice();\n}\n\n/** Empty the registry. For tests, which load controllers repeatedly. */\nexport function __resetRegisteredControllers(): void {\n registry().length = 0;\n}\n\n/**\n * The APPLICATION-level default auth.\n *\n * Held on globalThis under a well-known Symbol for exactly the reason\n * {@link REGISTRY} is: a deployed bundle inlines its own copy of this package,\n * and two copies keeping two defaults is how a security setting silently\n * becomes two different settings.\n */\nconst APP_DEFAULT_AUTH: unique symbol = Symbol.for(\"palbase.backend.appDefaultAuth\") as never;\n\nfunction appAuthSlot(): Record<symbol, AuthSpec | undefined> {\n return globalThis as unknown as Record<symbol, AuthSpec | undefined>;\n}\n\n/**\n * Declare the default auth for EVERY route in the application — the ring the\n * cascade consults when neither the route nor its controller says anything.\n *\n * The measured problem it removes: `auth: { verifiedEmail: true }` repeated by\n * hand on ten `@Controller`s. A security setting that must be repeated is a\n * security setting that will be forgotten — the eleventh controller opens the\n * door and nothing says so.\n *\n * Call it at MODULE SCOPE in a file the application imports (the controllers'\n * own barrel, or a module a controller imports). The cascade reads this slot\n * when the route table is built and when the spec is emitted — both of which\n * run after module loading — so declaration order does not matter, but being\n * imported at all does.\n *\n * @example\n * defineDefaultAuth({ verifiedEmail: true }); // every route, unless it says otherwise\n */\nexport function defineDefaultAuth(auth: AuthSpec): void {\n appAuthSlot()[APP_DEFAULT_AUTH] = auth;\n}\n\n/** The declared application default, or `undefined` when none was declared. */\nexport function getDefaultAuth(): AuthSpec | undefined {\n return appAuthSlot()[APP_DEFAULT_AUTH];\n}\n\n/** Clear the application default. For tests, which declare it repeatedly. */\nexport function __resetDefaultAuth(): void {\n delete appAuthSlot()[APP_DEFAULT_AUTH];\n}\n\n/**\n * THE auth cascade: route → controller → application → `true`.\n *\n * One function, every caller — the route table (`engine/router.ts`) and the\n * spec emitter (`openapi/controllers.ts`) ASK for the answer instead of\n * spelling the chain themselves. Two hand-written copies of a cascade is how\n * the build-time answer and the runtime answer come to disagree about who may\n * call an endpoint, and the disagreement shows up as an open door.\n *\n * The terminal `true` is secure-by-default and is load-bearing: a route that\n * declared nothing, under a controller that declared nothing, in an\n * application that declared nothing, is CLOSED.\n */\nexport function resolveEffectiveAuth(\n routeAuth: AuthSpec | undefined,\n controllerAuth: AuthSpec | undefined,\n): AuthSpec {\n return routeAuth ?? controllerAuth ?? getDefaultAuth() ?? true;\n}\n\n/** A class carrying the stamped controller metadata + discriminant. */\ninterface ControllerCarrier {\n __palbase?: \"controller\";\n [CONTROLLER_META]?: ControllerMeta;\n}\n\n/** The one path segment the platform owns. The isolate matches\n * `^/webhooks/([^/]+)$` on the raw request path BEFORE controller dispatch, so\n * anything a controller resolves to under it answers `404 webhook_not_found`\n * and never runs. */\nconst RESERVED_FIRST_SEGMENT = \"webhooks\";\n\n/**\n * Throw if `path` resolves under the reserved segment. Segments are compared the\n * way the isolate compares them — `split(\"/\").filter(Boolean)` — NOT by string\n * prefix, because empty segments collapse there: `@Controller(\"/\")` +\n * `@Post(\"/webhooks/x\")` composes to `//webhooks/x`, which the isolate serves as\n * `/webhooks/x`. A prefix check reads that as safe; the segment check does not.\n * `/webhooksy` stays allowed for the same reason — it is a different segment.\n *\n * Every verb is refused, not just the POST the isolate currently intercepts: the\n * reservation is of the URL namespace, so a `@Get(\"/webhooks/x\")` that happens\n * to work today would be silently shadowed the moment the isolate's method gate\n * widens. Refusing at build is recoverable; discovering it as a 404 is not.\n */\nfunction assertNotReserved(path: string, subject: string): void {\n const [first] = path.split(\"/\").filter(Boolean);\n if (first === RESERVED_FIRST_SEGMENT) {\n throw new Error(\n `${subject} resolves under the reserved /${RESERVED_FIRST_SEGMENT} path — ` +\n \"inbound webhooks are served there and would shadow this route\",\n );\n }\n}\n\n/**\n * Mark a class as a Palbase backend controller. `basePath` is the mount path\n * for every route the class declares; `options.auth` sets the controller-level\n * default auth (a route's own `auth` overrides it; absent ⇒ secure-by-default).\n *\n * @example\n * \\@Controller(\"/todos\", { auth: false })\n * export class TodosController {\n * \\@Get(\"\") list(\\@QueryParams(ListTodosQuery) q: ListTodosQuery): TodoSchema[] { … }\n * }\n */\nexport function Controller(basePath: string, options: ControllerOptions = {}) {\n return function <T extends abstract new (...args: never[]) => object>(ctor: T): T {\n // /webhooks/* belongs to the platform: the isolate matches the inbound\n // webhook route before controller dispatch, so a controller mounted here\n // would never receive a request. Silent shadowing is the failure mode this\n // whole change exists to remove, so refuse it at build.\n //\n // The COMPOSED path is what gets shadowed, not the base path. `@Controller(\"\")`\n // and `@Controller(\"/\")` both pass a base-path-only check while a\n // `@Post(\"/webhooks/stripe\")` inside them resolves to exactly the path the\n // isolate intercepts. Method decorators run BEFORE the class decorator (TS\n // evaluates members first), so every route this class declares is already in\n // the registry here — which is why the composed check can live at this one\n // seam instead of on the dispatch read path. The `@Controller(\"\") +\n // @Post(\"/webhooks/stripe\")` test is the lock on that ordering: if it ever\n // stopped holding, that test goes red.\n assertNotReserved(basePath, `@Controller(\"${basePath}\")`);\n for (const route of getRoutes(ctor)) {\n assertNotReserved(\n `${basePath}${route.subpath}`,\n `@${route.method}(\"${route.subpath}\") in @Controller(\"${basePath}\")`,\n );\n }\n\n const carrier = ctor as unknown as ControllerCarrier;\n const meta: ControllerMeta = {\n __palbase: \"controller\",\n basePath,\n ...(options.auth !== undefined ? { defaultAuth: options.auth } : {}),\n };\n // Non-enumerable so it doesn't leak onto instances / structural checks.\n Object.defineProperty(carrier, CONTROLLER_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // The bare `__palbase` discriminant is the cheap detection marker the\n // runtime/extractor checks; keep it readable but non-enumerable.\n Object.defineProperty(carrier, \"__palbase\", {\n value: \"controller\",\n enumerable: false,\n configurable: true,\n writable: false,\n });\n // Record it, so importing the file is enough and exporting is optional.\n // Guarded against a double-decoration re-entering the same class twice.\n const all = registry();\n if (!all.includes(ctor)) all.push(ctor);\n return ctor;\n };\n}\n\n/** True when `value` is a `@Controller`-decorated class (cheap discriminant\n * check). Accepts the class constructor (the default export of a controller\n * file). */\nexport function isController(value: unknown): boolean {\n if (typeof value !== \"function\" && (typeof value !== \"object\" || value === null)) {\n return false;\n }\n const carrier = value as ControllerCarrier;\n return carrier.__palbase === \"controller\" && carrier[CONTROLLER_META] !== undefined;\n}\n\n/** Read the resolved controller metadata off a `@Controller`-decorated class.\n * Throws if the class was not decorated — callers should gate with\n * {@link isController} first (the loader does). */\nexport function resolveController(ctor: unknown): ControllerMeta {\n if (typeof ctor !== \"function\" && (typeof ctor !== \"object\" || ctor === null)) {\n throw new TypeError(\"resolveController: value is not a class\");\n }\n const meta = (ctor as ControllerCarrier)[CONTROLLER_META];\n if (!meta) {\n throw new TypeError(\n \"resolveController: class is not a @Controller — every controller file must `export default` a @Controller-decorated class\",\n );\n }\n return meta;\n}\n\n/**\n * A class the runtime constructs takes NO constructor parameters.\n *\n * ONE writer, four callers (controller, hook, job, webhook) and the build's own\n * check. Four hand-written copies of this message is how the four come to\n * disagree about what is refused — and the disagreement is silent, because a\n * class that slips past one of them still ends up with `undefined` fields.\n *\n * Why it is refused rather than injected: there is no container. The parameter\n * would arrive `undefined`, the code would compile, deploy, and fail at the\n * first request that touches the field — the most expensive place to learn it.\n */\nexport function assertZeroArgConstructor(Ctrl: unknown, kind: string): void {\n const arity = (Ctrl as { length?: number }).length ?? 0;\n if (arity === 0) return;\n const name = (Ctrl as { name?: string }).name ?? \"<anonymous>\";\n throw new Error(\n `${kind} ${name} declares a constructor with ${arity} parameter(s). ` +\n `A ${kind} is constructed by the runtime with a zero-argument constructor — ` +\n `there is no injector to supply them, so every parameter would arrive as ` +\n `undefined. Hold the dependency as a module-level singleton the ${kind} ` +\n \"imports (`const repo = makeRepo()` beside the class), and construct the \" +\n \"service directly in tests (e.g. `new TodoService(fakeDatabase().db)`).\",\n );\n}\n","/**\n * The brand that identifies an HttpError ACROSS SDK instances.\n *\n * A process legitimately holds more than one copy of this SDK — the runtime\n * loads the engine from its own node_modules while the tenant's bundle carries\n * an inlined copy, which is why the controller registry and the error registry\n * are both anchored on `Symbol.for`. The one place that did not follow the\n * pattern was the engine's catch: `err instanceof HttpError` compares CLASS\n * IDENTITY, so a `throw new NotFound()` from the bundle's copy did not match\n * the engine's copy and every typed error in every deployed backend degraded to\n * `500 internal_error`. Measured through the edge on a real deploy: a route\n * throwing `NotFound` answered 500 while the runtime's own log printed the\n * error object with `status: 404` right beside it.\n *\n * `Symbol.for` puts this in the cross-realm registry, so every copy of the SDK\n * agrees on it by VALUE rather than by identity.\n */\nexport const HTTP_ERROR_BRAND: unique symbol = Symbol.for(\"palbase.backend.httpError\");\n\n/**\n * Set on an `HttpError` the ENGINE built out of a driver failure, as opposed to\n * one the author constructed to ANSWER a request.\n *\n * The distinction cannot be read off the status, and 409 is why. The scaffold\n * teaches `throw new Conflict(\"title already taken\")` as the way to answer\n * (template/AGENTS.md), and the engine raises `UniqueViolation` — also a 409 —\n * when a write hits a unique index. Logging by status therefore either loses the\n * engine's event or writes an \"unhandled\" line every time an author takes the\n * documented path. Measured: it did the second.\n *\n * `Symbol.for` so the mark survives the bundle/runtime SDK split, the same way\n * {@link HTTP_ERROR_BRAND} does.\n */\nexport const ENGINE_RAISED: unique symbol = Symbol.for(\"palbase.backend.engineRaised\") as never;\n\n/** Mark `e` as engine-raised and return it, so a conversion site reads as one expression. */\nexport function markEngineRaised<E extends object>(e: E): E {\n (e as Record<symbol, unknown>)[ENGINE_RAISED] = true;\n return e;\n}\n\n/** Whether the engine built this error, rather than the author throwing it to answer. */\nexport function isEngineRaised(e: unknown): boolean {\n return typeof e === \"object\" && e !== null && (e as Record<symbol, unknown>)[ENGINE_RAISED] === true;\n}\n\n/**\n * Whether a thrown value is an HttpError from ANY copy of this SDK.\n *\n * The shape is checked as well as the brand: the brand says \"this claims to be\n * one of ours\", the fields say the envelope can actually be built from it, and\n * a half-formed object must fall through to the 500 path rather than produce a\n * malformed response.\n */\nexport function isHttpError(err: unknown): err is HttpError {\n if (typeof err !== \"object\" || err === null) return false;\n const e = err as Record<PropertyKey, unknown>;\n return (\n e[HTTP_ERROR_BRAND] === true &&\n typeof e.status === \"number\" &&\n typeof e.error === \"string\" &&\n typeof e.errorDescription === \"string\"\n );\n}\n\n/** HTTP error with structured error response format.\n *\n * The base class for the throwable error classes (`PalError`, `Conflict`,\n * `NotFound`, …). Construct one directly with `throw new HttpError(404,\n * \"todo_not_found\", \"No such todo\")`, or throw a named subclass\n * (`throw new NotFound(\"todo not found\")`). The runtime catches any `HttpError`\n * and emits the standard envelope; on the wire (and to iOS) it surfaces as\n * `BackendError.server(code, status, message, requestId)`.\n *\n * The optional `data` field carries a structured payload alongside the\n * standard envelope — for errors that need to ship extra context\n * (e.g. `new Conflict(\"locked\", \"title_locked\", { retryAfter: 30 })`). It rides\n * through to the iOS typed enum's associated value.\n */\nexport class HttpError extends Error {\n public readonly status: number;\n public readonly error: string;\n public readonly errorDescription: string;\n public readonly data?: unknown;\n /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */\n public readonly [HTTP_ERROR_BRAND] = true;\n\n constructor(status: number, error: string, errorDescription: string, data?: unknown) {\n super(errorDescription);\n this.name = \"HttpError\";\n this.status = status;\n this.error = error;\n this.errorDescription = errorDescription;\n if (data !== undefined) {\n this.data = data;\n }\n }\n\n /**\n * Serialize to the standard Palbase error response format.\n * The `requestId` is injected by the runtime layer from the request context.\n * When called without arguments (e.g. JSON.stringify), request_id is omitted.\n * When `data` is set, it is appended as a strict-superset field.\n */\n toJSON(requestId?: string): {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } {\n const result: {\n error: string;\n error_description: string;\n status: number;\n request_id?: string;\n data?: unknown;\n } = {\n error: this.error,\n error_description: this.errorDescription,\n status: this.status,\n };\n if (requestId) {\n result.request_id = requestId;\n }\n if (this.data !== undefined) {\n result.data = this.data;\n }\n return result;\n }\n}\n\n/**\n * Throw with a custom HTTP status + wire code. The general-purpose escape hatch\n * when none of the named classes (`Conflict`/`NotFound`/…) fits.\n *\n * @example\n * throw new PalError(418, \"teapot\", \"I'm a teapot\");\n */\nexport class PalError extends HttpError {\n constructor(status: number, code: string, description: string, data?: unknown) {\n super(status, code, description, data);\n this.name = \"PalError\";\n }\n}\n\n/** Base for the named status classes. Each subclass fixes its HTTP status; the\n * `code` defaults to the class's canonical wire code (overridable), and the\n * `message` defaults to a human-readable label (overridable). */\nabstract class NamedHttpError extends HttpError {\n protected constructor(\n status: number,\n defaultCode: string,\n name: string,\n message?: string,\n code?: string,\n data?: unknown,\n ) {\n super(status, code ?? defaultCode, message ?? defaultMessage(name), data);\n this.name = name;\n }\n}\n\n/** Derive a default human-readable message from a class name\n * (\"NotFound\" → \"Not found\", \"TooManyRequests\" → \"Too many requests\"). */\nfunction defaultMessage(name: string): string {\n const spaced = name.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\");\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\n/**\n * 400 — the request was malformed or failed validation. Carries a fixed typed\n * payload: `new BadRequest({ fields: [{ field: \"email\", message: \"invalid\" }] })`.\n * The shape is declared once in the SDK so codegen surfaces `error.data.fields`\n * typed on the client.\n */\nexport class BadRequest extends NamedHttpError {\n public declare readonly data: BadRequestData;\n constructor(data: BadRequestData, message?: string) {\n super(400, \"bad_request\", \"BadRequest\", message, undefined, data);\n }\n}\n\n/** 401 — the caller is not authenticated. */\nexport class Unauthorized extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(401, \"unauthorized\", \"Unauthorized\", message, code, data);\n }\n}\n\n/** 403 — the caller is authenticated but not allowed. */\nexport class Forbidden extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(403, \"forbidden\", \"Forbidden\", message, code, data);\n }\n}\n\n/** 404 — the requested resource does not exist. */\nexport class NotFound extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(404, \"not_found\", \"NotFound\", message, code, data);\n }\n}\n\n/** 409 — the request conflicts with the current state. */\nexport class Conflict extends NamedHttpError {\n constructor(message?: string, code?: string, data?: unknown) {\n super(409, \"conflict\", \"Conflict\", message, code, data);\n }\n}\n\n/**\n * 409 — a write was refused because it would duplicate an existing row.\n * Carries the NAME of the unique constraint Postgres named (`users_email_key`).\n *\n * The engine produces it: a statement rejected with SQLSTATE `23505` is\n * converted here rather than surfacing as an opaque driver error (see\n * `engine/db.ts`, `diagnosingDriver`). What that removes is the string match —\n * before this, the only way to act on a duplicate was to test the driver\n * message for \"duplicate key value violates unique constraint\", a contract\n * nobody signed that breaks on a Postgres upgrade, a locale, or a constraint\n * rename, silently and in production.\n *\n * THE NAME IS A FIELD AND STAYS OUT OF THE DEFAULT MESSAGE. The two are not\n * the same audience. `constraint` is read by the code that catches this — the\n * developer, who already knows the schema. `errorDescription` is the HTTP\n * response body, and an UNCAUGHT duplicate puts it in front of the\n * application's end user: `users_email_key` there discloses how the schema is\n * built to whoever sent the request. The platform's own data API took the same\n * decision one surface over and wrote down why —\n * `v2/internal/modules/database/internal/handler/pgerror.go:83-87` collapses\n * every 23xxx to a generic conflict, \"never disclose the constraint/column\n * name\". A thrower who WANTS the name on the wire passes it deliberately\n * (`new UniqueViolation(c, \\`\\${c} already exists\\`)`, or through `data`).\n *\n * @example\n * try {\n * await Database.tables.users.insert({ email });\n * } catch (e) {\n * if (UniqueViolation.is(e) && e.constraint === \"users_email_key\") {\n * throw new Conflict(\"That email is taken\", \"email_taken\");\n * }\n * throw e;\n * }\n */\nexport class UniqueViolation extends Conflict {\n /**\n * Whether `e` is a unique violation — REGARDLESS of which copy of this SDK\n * constructed it.\n *\n * Use this instead of `instanceof`. Measured on a live stack: a controller\n * bundle INLINES its own copy of `@palbase/backend`, and the engine that\n * raises this error is the runtime's copy. Two copies, two class identities,\n * and `e instanceof UniqueViolation` is false in the one place a caller\n * writes it — a check that reads as correct and silently never matches.\n */\n static is(e: unknown): e is UniqueViolation {\n return (\n typeof e === \"object\" &&\n e !== null &&\n (e as { name?: unknown }).name === \"UniqueViolation\" &&\n typeof (e as { constraint?: unknown }).constraint === \"string\"\n );\n }\n\n /** The unique constraint the statement violated, as Postgres named it.\n * `\"\"` when the driver did not say which — see `engine/db.ts`. */\n public readonly constraint: string;\n\n constructor(constraint: string, message?: string, code?: string, data?: unknown) {\n super(message ?? \"Unique constraint violated\", code ?? \"unique_violation\", data);\n this.name = \"UniqueViolation\";\n this.constraint = constraint;\n }\n}\n\n/** A single field-level validation failure carried by {@link BadRequest}. */\nexport interface FieldError {\n /** The offending field's name (dotted path for nested fields). */\n field: string;\n /** Human-readable reason the field failed. */\n message: string;\n}\n\n/** The fixed, typed payload {@link BadRequest} ships. */\nexport interface BadRequestData {\n /** The fields that failed validation. */\n fields: FieldError[];\n}\n\n/** The fixed, typed payload {@link TooManyRequests} ships. */\nexport interface TooManyRequestsData {\n /** Seconds the caller should wait before retrying. */\n retryAfter: number;\n}\n\n/**\n * 429 — the caller has exceeded the rate limit. Carries a fixed typed payload:\n * `new TooManyRequests({ retryAfter: 30 })`. The shape is declared once in the\n * SDK (error-registry pre-seed) so codegen surfaces `error.data.retryAfter`\n * typed on the client — no per-project definition needed.\n */\nexport class TooManyRequests extends NamedHttpError {\n public declare readonly data: TooManyRequestsData;\n constructor(data: TooManyRequestsData, message?: string) {\n super(429, \"too_many_requests\", \"TooManyRequests\", message, undefined, data);\n }\n}\n"],"mappings":";AAiHO,IAAM,SAAwB,uBAAO,IAAI,wBAAwB;AAMxE,IAAM,eAA8B,uBAAO,IAAI,6BAA6B;AAI5E,IAAM,OAAsB,uBAAO,IAAI,sBAAsB;AAC7D,IAAM,aAA4B,uBAAO,IAAI,2BAA2B;AASxE,IAAM,gBAA+B,uBAAO,IAAI,8BAA8B;AAS9E,IAAM,gBAA+B,uBAAO,IAAI,8BAA8B;AAkB9E,SAAS,UAAU,QAAiC;AAIlD,QAAM,OACJ,OAAO,WAAW,aACb,SACE,OAAqC,eACtC;AACR,SAAO;AACT;AAIA,SAAS,UAAU,SAAuC;AACxD,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,SAAS,MAAM,GAAG;AAC1D,YAAQ,MAAM,IAAI,CAAC;AAAA,EACrB;AACA,SAAO,QAAQ,MAAM;AACvB;AAGA,SAAS,eAAe,SAAuD;AAC7E,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,SAAS,YAAY,GAAG;AAChE,YAAQ,YAAY,IAAI,CAAC;AAAA,EAC3B;AACA,SAAO,QAAQ,YAAY;AAC7B;AAKO,SAAS,YACd,QACA,QACA,QACA,SACA,SACM;AACN,QAAM,UAAU,UAAU,MAAM;AAChC,QAAM,SAAS,UAAU,OAAO;AAChC,QAAM,SAAS,eAAe,OAAO;AACrC,QAAM,UAAU,OAAO,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAC9E,QAAM,QAAmB,EAAE,QAAQ,SAAS,QAAQ,SAAS,OAAO;AAIpE,QAAM,eAAe,QAAQ,aAAa;AAC1C,MAAI,gBAAgB,aAAa,MAAM,MAAM,QAAW;AACtD,UAAM,eAAe,aAAa,MAAM;AAAA,EAC1C;AAGA,QAAM,eAAe,QAAQ,aAAa;AAC1C,MAAI,gBAAgB,aAAa,MAAM,MAAM,QAAW;AACtD,UAAM,SAAS,aAAa,MAAM;AAAA,EACpC;AACA,SAAO,KAAK,KAAK;AACnB;AAOO,SAAS,YAAY,QAAgB,QAAgB,MAAuB;AACjF,QAAM,UAAU,UAAU,MAAM;AAChC,QAAM,SAAS,eAAe,OAAO;AACrC,GAAC,OAAO,MAAM,MAAM,CAAC,GAAG,KAAK,IAAI;AAGjC,QAAM,SAAS,QAAQ,MAAM;AAC7B,MAAI,QAAQ;AACV,UAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AACpD,QAAI,OAAO;AACT,YAAM,OAAO,KAAK,IAAI;AACtB,YAAM,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,IAC/C;AAAA,EACF;AACF;AA0BO,SAAS,aAAa,QAAgB,QAAgB,QAAiC;AAC5F,QAAM,UAAU,UAAU,MAAM;AAChC,QAAM,SAAS,QAAQ,MAAM;AAC7B,QAAM,QAAQ,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AACrD,MAAI,OAAO;AACT,UAAM,SAAS;AACf;AAAA,EACF;AACA,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,SAAS,aAAa,GAAG;AACjE,YAAQ,aAAa,IAAI,CAAC;AAAA,EAC5B;AACA,QAAM,eAAe,QAAQ,aAAa;AAC1C,MAAI,aAAc,cAAa,MAAM,IAAI;AAC3C;AAOO,SAAS,UAAU,MAA2B;AACnD,QAAM,UAAU,UAAU,IAAI;AAC9B,QAAM,SAAS,QAAQ,MAAM,KAAK,CAAC;AACnC,QAAM,eAAe,QAAQ,aAAa;AAC1C,MAAI,cAAc;AAChB,eAAW,SAAS,QAAQ;AAC1B,YAAM,WAAW,aAAa,MAAM,MAAM;AAC1C,UAAI,YAAY,MAAM,iBAAiB,QAAW;AAChD,cAAM,eAAe;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACA,QAAM,eAAe,QAAQ,aAAa;AAC1C,MAAI,cAAc;AAChB,eAAW,SAAS,QAAQ;AAC1B,YAAM,WAAW,aAAa,MAAM,MAAM;AAC1C,UAAI,YAAY,MAAM,WAAW,QAAW;AAC1C,cAAM,SAAS;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO,IAAI,CAAC,OAAO;AAAA,IACxB,GAAG;AAAA,IACH,QAAQ,EAAE,OAAO,MAAM;AAAA,IACvB,GAAI,EAAE,WAAW,SAAY,EAAE,QAAQ,EAAE,OAAO,MAAM,EAAE,IAAI,CAAC;AAAA,EAC/D,EAAE;AACJ;AA8BA,SAAS,cAAc,SAAsC;AAC3D,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,SAAS,UAAU,GAAG;AAC9D,YAAQ,UAAU,IAAI,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,EAClD;AACA,SAAO,QAAQ,UAAU;AAC3B;AAKO,SAAS,eAAe,QAAgB,MAAgB,QAAsB;AACnF,QAAM,SAAS,cAAc,UAAU,MAAM,CAAC;AAC9C,QAAM,WAAW,OAAO,MAAM,IAAI;AAClC,MAAI,aAAa,UAAa,aAAa,QAAQ;AACjD,UAAM,QAAQ,KAAK,KAAK,OAAO,CAAC,EAAE,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAC/D,UAAM,IAAI;AAAA,MACR,IAAI,KAAK,mCAAmC,QAAQ,QAAQ,MAAM;AAAA,IAEpE;AAAA,EACF;AACA,SAAO,MAAM,IAAI,IAAI;AACvB;AAGO,SAAS,kBACd,QACA,MACA,QACA,QACM;AACN,QAAM,SAAS,cAAc,UAAU,MAAM,CAAC;AAC9C,QAAM,WAAW,OAAO,SAAS,IAAI;AACrC,MAAI,aAAa,UAAa,SAAS,WAAW,QAAQ;AACxD,UAAM,IAAI;AAAA,MACR,eAAe,IAAI,qCAAqC,SAAS,MAAM,QAAQ,MAAM;AAAA,IACvF;AAAA,EACF;AACA,SAAO,SAAS,IAAI,IAAI,EAAE,QAAQ,OAAO;AAC3C;AAIO,SAAS,WACd,MACA,MACM;AACN,QAAM,UAAU,UAAU,IAAI;AAC9B,QAAM,SAAS,cAAc,OAAO;AACpC,UAAQ,IAAI,IAAI,EAAE,GAAG,MAAM,OAAO,OAAO,OAAO,UAAU,OAAO,SAAS;AAC5E;AAKO,SAAS,QAAQ,MAAoC;AAC1D,QAAM,UAAU,UAAU,IAAI;AAC9B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,SAAS,IAAI,EAAG,QAAO;AACjE,SAAO,QAAQ,IAAI;AACrB;;;AC7WO,IAAM,kBAAiC,uBAAO,IAAI,gCAAgC;AAiBzF,IAAM,WAA0B,uBAAO,IAAI,gCAAgC;AAE3E,SAAS,WAAsB;AAC7B,QAAM,IAAI;AACV,QAAM,WAAW,EAAE,QAAQ;AAC3B,MAAI,SAAU,QAAO;AACrB,QAAM,QAAmB,CAAC;AAC1B,IAAE,QAAQ,IAAI;AACd,SAAO;AACT;AAUO,SAAS,2BAA+C;AAC7D,SAAO,SAAS,EAAE,MAAM;AAC1B;AAGO,SAAS,+BAAqC;AACnD,WAAS,EAAE,SAAS;AACtB;AAUA,IAAM,mBAAkC,uBAAO,IAAI,gCAAgC;AAEnF,SAAS,cAAoD;AAC3D,SAAO;AACT;AAoBO,SAAS,kBAAkB,MAAsB;AACtD,cAAY,EAAE,gBAAgB,IAAI;AACpC;AAGO,SAAS,iBAAuC;AACrD,SAAO,YAAY,EAAE,gBAAgB;AACvC;AAGO,SAAS,qBAA2B;AACzC,SAAO,YAAY,EAAE,gBAAgB;AACvC;AAeO,SAAS,qBACd,WACA,gBACU;AACV,SAAO,aAAa,kBAAkB,eAAe,KAAK;AAC5D;AAYA,IAAM,yBAAyB;AAe/B,SAAS,kBAAkB,MAAc,SAAuB;AAC9D,QAAM,CAAC,KAAK,IAAI,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC9C,MAAI,UAAU,wBAAwB;AACpC,UAAM,IAAI;AAAA,MACR,GAAG,OAAO,iCAAiC,sBAAsB;AAAA,IAEnE;AAAA,EACF;AACF;AAaO,SAAS,WAAW,UAAkB,UAA6B,CAAC,GAAG;AAC5E,SAAO,SAA+D,MAAY;AAehF,sBAAkB,UAAU,gBAAgB,QAAQ,IAAI;AACxD,eAAW,SAAS,UAAU,IAAI,GAAG;AACnC;AAAA,QACE,GAAG,QAAQ,GAAG,MAAM,OAAO;AAAA,QAC3B,IAAI,MAAM,MAAM,KAAK,MAAM,OAAO,sBAAsB,QAAQ;AAAA,MAClE;AAAA,IACF;AAEA,UAAM,UAAU;AAChB,UAAM,OAAuB;AAAA,MAC3B,WAAW;AAAA,MACX;AAAA,MACA,GAAI,QAAQ,SAAS,SAAY,EAAE,aAAa,QAAQ,KAAK,IAAI,CAAC;AAAA,IACpE;AAEA,WAAO,eAAe,SAAS,iBAAiB;AAAA,MAC9C,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAGD,WAAO,eAAe,SAAS,aAAa;AAAA,MAC1C,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAGD,UAAM,MAAM,SAAS;AACrB,QAAI,CAAC,IAAI,SAAS,IAAI,EAAG,KAAI,KAAK,IAAI;AACtC,WAAO;AAAA,EACT;AACF;AAKO,SAAS,aAAa,OAAyB;AACpD,MAAI,OAAO,UAAU,eAAe,OAAO,UAAU,YAAY,UAAU,OAAO;AAChF,WAAO;AAAA,EACT;AACA,QAAM,UAAU;AAChB,SAAO,QAAQ,cAAc,gBAAgB,QAAQ,eAAe,MAAM;AAC5E;AAKO,SAAS,kBAAkB,MAA+B;AAC/D,MAAI,OAAO,SAAS,eAAe,OAAO,SAAS,YAAY,SAAS,OAAO;AAC7E,UAAM,IAAI,UAAU,yCAAyC;AAAA,EAC/D;AACA,QAAM,OAAQ,KAA2B,eAAe;AACxD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAcO,SAAS,yBAAyB,MAAe,MAAoB;AAC1E,QAAM,QAAS,KAA6B,UAAU;AACtD,MAAI,UAAU,EAAG;AACjB,QAAM,OAAQ,KAA2B,QAAQ;AACjD,QAAM,IAAI;AAAA,IACR,GAAG,IAAI,IAAI,IAAI,gCAAgC,KAAK,oBAC7C,IAAI,iNAEyD,IAAI;AAAA,EAG1E;AACF;;;ACtRO,IAAM,mBAAkC,uBAAO,IAAI,2BAA2B;AAgB9E,IAAM,gBAA+B,uBAAO,IAAI,8BAA8B;AAG9E,SAAS,iBAAmC,GAAS;AAC1D,EAAC,EAA8B,aAAa,IAAI;AAChD,SAAO;AACT;AAGO,SAAS,eAAe,GAAqB;AAClD,SAAO,OAAO,MAAM,YAAY,MAAM,QAAS,EAA8B,aAAa,MAAM;AAClG;AAUO,SAAS,YAAY,KAAgC;AAC1D,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,QAAM,IAAI;AACV,SACE,EAAE,gBAAgB,MAAM,QACxB,OAAO,EAAE,WAAW,YACpB,OAAO,EAAE,UAAU,YACnB,OAAO,EAAE,qBAAqB;AAElC;AAgBO,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEhB,CAAiB,gBAAgB,IAAI;AAAA,EAErC,YAAY,QAAgB,OAAe,kBAA0B,MAAgB;AACnF,UAAM,gBAAgB;AACtB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,mBAAmB;AACxB,QAAI,SAAS,QAAW;AACtB,WAAK,OAAO;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,WAML;AACA,UAAM,SAMF;AAAA,MACF,OAAO,KAAK;AAAA,MACZ,mBAAmB,KAAK;AAAA,MACxB,QAAQ,KAAK;AAAA,IACf;AACA,QAAI,WAAW;AACb,aAAO,aAAa;AAAA,IACtB;AACA,QAAI,KAAK,SAAS,QAAW;AAC3B,aAAO,OAAO,KAAK;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF;AASO,IAAM,WAAN,cAAuB,UAAU;AAAA,EACtC,YAAY,QAAgB,MAAc,aAAqB,MAAgB;AAC7E,UAAM,QAAQ,MAAM,aAAa,IAAI;AACrC,SAAK,OAAO;AAAA,EACd;AACF;AAKA,IAAe,iBAAf,cAAsC,UAAU;AAAA,EACpC,YACR,QACA,aACA,MACA,SACA,MACA,MACA;AACA,UAAM,QAAQ,QAAQ,aAAa,WAAW,eAAe,IAAI,GAAG,IAAI;AACxE,SAAK,OAAO;AAAA,EACd;AACF;AAIA,SAAS,eAAe,MAAsB;AAC5C,QAAM,SAAS,KAAK,QAAQ,sBAAsB,OAAO;AACzD,SAAO,OAAO,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,MAAM,CAAC,EAAE,YAAY;AACtE;AAQO,IAAM,aAAN,cAAyB,eAAe;AAAA,EAE7C,YAAY,MAAsB,SAAkB;AAClD,UAAM,KAAK,eAAe,cAAc,SAAS,QAAW,IAAI;AAAA,EAClE;AACF;AAGO,IAAM,eAAN,cAA2B,eAAe;AAAA,EAC/C,YAAY,SAAkB,MAAe,MAAgB;AAC3D,UAAM,KAAK,gBAAgB,gBAAgB,SAAS,MAAM,IAAI;AAAA,EAChE;AACF;AAGO,IAAM,YAAN,cAAwB,eAAe;AAAA,EAC5C,YAAY,SAAkB,MAAe,MAAgB;AAC3D,UAAM,KAAK,aAAa,aAAa,SAAS,MAAM,IAAI;AAAA,EAC1D;AACF;AAGO,IAAM,WAAN,cAAuB,eAAe;AAAA,EAC3C,YAAY,SAAkB,MAAe,MAAgB;AAC3D,UAAM,KAAK,aAAa,YAAY,SAAS,MAAM,IAAI;AAAA,EACzD;AACF;AAGO,IAAM,WAAN,cAAuB,eAAe;AAAA,EAC3C,YAAY,SAAkB,MAAe,MAAgB;AAC3D,UAAM,KAAK,YAAY,YAAY,SAAS,MAAM,IAAI;AAAA,EACxD;AACF;AAoCO,IAAM,kBAAN,cAA8B,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW5C,OAAO,GAAG,GAAkC;AAC1C,WACE,OAAO,MAAM,YACb,MAAM,QACL,EAAyB,SAAS,qBACnC,OAAQ,EAA+B,eAAe;AAAA,EAE1D;AAAA;AAAA;AAAA,EAIgB;AAAA,EAEhB,YAAY,YAAoB,SAAkB,MAAe,MAAgB;AAC/E,UAAM,WAAW,8BAA8B,QAAQ,oBAAoB,IAAI;AAC/E,SAAK,OAAO;AACZ,SAAK,aAAa;AAAA,EACpB;AACF;AA4BO,IAAM,kBAAN,cAA8B,eAAe;AAAA,EAElD,YAAY,MAA2B,SAAkB;AACvD,UAAM,KAAK,qBAAqB,mBAAmB,SAAS,QAAW,IAAI;AAAA,EAC7E;AACF;","names":[]}