@palbase/backend 24.1.1 → 24.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/palbase-backend.cjs +3 -2
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +1 -1
- package/dist/{chunk-LCL7TUAI.js → chunk-D5CQES25.js} +23 -1
- package/dist/chunk-D5CQES25.js.map +1 -0
- package/dist/{chunk-2A62DDVO.js → chunk-EIXCY4SS.js} +4 -3
- package/dist/{chunk-2A62DDVO.js.map → chunk-EIXCY4SS.js.map} +1 -1
- package/dist/db/index.cjs +22 -0
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/engine/index.cjs +3 -2
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +2 -2
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/{index-D4rts8T7.d.cts → index-BLAbr9ZH.d.cts} +30 -0
- package/dist/{index-ByBMibIJ.d.ts → index-BTMYod_l.d.ts} +30 -0
- package/dist/{index-DAwHMppB.d.cts → index-C-ALG22n.d.cts} +1 -1
- package/dist/{index-C0PMn5jl.d.ts → index-DEneI8Mn.d.ts} +1 -1
- package/dist/index.cjs +23 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/docs/llms-full.txt +72 -1
- package/docs/schema.md +72 -1
- package/package.json +1 -1
- package/dist/chunk-LCL7TUAI.js.map +0 -1
package/docs/llms-full.txt
CHANGED
|
@@ -1236,7 +1236,78 @@ export default defineSchema({
|
|
|
1236
1236
|
Chainable modifiers: `.primaryKey()`, `.notNull()` (default), `.nullable()`,
|
|
1237
1237
|
`.default(value)`, `.defaultRandom()` (uuid → `gen_random_uuid()`),
|
|
1238
1238
|
`.defaultNow()` (timestamp → `now()`), `.references(table, column)`,
|
|
1239
|
-
`.onDelete("cascade" | "set null" | "restrict" | "no action")`.
|
|
1239
|
+
`.onDelete("cascade" | "set null" | "restrict" | "no action")`, `.ignored()`.
|
|
1240
|
+
|
|
1241
|
+
## Removing a column
|
|
1242
|
+
|
|
1243
|
+
A deploy applies the schema while the PREVIOUS release is still answering requests, so
|
|
1244
|
+
dropping a column that release still names breaks it the instant the change lands. The
|
|
1245
|
+
gate therefore refuses the drop — and until now it refused every drop, with no way
|
|
1246
|
+
through: deleting the code that used the column changed nothing, because the gate never
|
|
1247
|
+
read your code.
|
|
1248
|
+
|
|
1249
|
+
`.ignored()` is how you tell it. The mark is a PROMISE about the release that carries
|
|
1250
|
+
it: **this release neither reads nor writes this column, and never names it in a filter,
|
|
1251
|
+
a sort or a SET.**
|
|
1252
|
+
|
|
1253
|
+
Removing a column is therefore two deploys:
|
|
1254
|
+
|
|
1255
|
+
```ts
|
|
1256
|
+
// 1. Mark it. The column stays; nothing breaks; no DDL is produced.
|
|
1257
|
+
export const schema = defineSchema({
|
|
1258
|
+
tables: { notes: { columns: { id: uuid().primaryKey(), old_body: text().ignored() } } },
|
|
1259
|
+
});
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
```ts
|
|
1263
|
+
// 2. Ship that. Then delete the column and ship again — this time the gate passes,
|
|
1264
|
+
// because the release now serving promised it does not name the column.
|
|
1265
|
+
export const schema = defineSchema({
|
|
1266
|
+
tables: { notes: { columns: { id: uuid().primaryKey() } } } },
|
|
1267
|
+
});
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
`palbase db plan` tells you which step you are on before you push. Locally,
|
|
1271
|
+
`palbase db apply` is not restricted — local is where you experiment, and there is no
|
|
1272
|
+
traffic to protect.
|
|
1273
|
+
|
|
1274
|
+
The word is `ignored` and not `deprecated` on purpose: deprecation is defined, in
|
|
1275
|
+
RFC 9745 and in the GraphQL spec alike, as changing NO behaviour. This changes what a
|
|
1276
|
+
deploy will accept.
|
|
1277
|
+
|
|
1278
|
+
**What the mark cannot do.** No static mark can PROVE your code does not name the
|
|
1279
|
+
column — that question is only answerable from traffic. `.ignored()` is your promise.
|
|
1280
|
+
What the gate adds is that it reads the promise from the release that is ACTUALLY
|
|
1281
|
+
SERVING, not from the file in front of you.
|
|
1282
|
+
|
|
1283
|
+
## Renaming an enum value
|
|
1284
|
+
|
|
1285
|
+
There is no `renamedFrom` for enum values, and the reason is measured rather than
|
|
1286
|
+
stylistic: on PostgreSQL 16, `ALTER TYPE … RENAME VALUE` is an **atomic cutover**. While
|
|
1287
|
+
the rename is uncommitted a writer using the OLD label succeeds and one using the NEW
|
|
1288
|
+
label fails; at commit that flips. The two names are never both valid, so there is no
|
|
1289
|
+
window in which a running release can be migrated across — the instant the rename
|
|
1290
|
+
commits, that release's writes fail with `invalid input value for enum`.
|
|
1291
|
+
|
|
1292
|
+
Add a value instead, and let the old one die:
|
|
1293
|
+
|
|
1294
|
+
```sql
|
|
1295
|
+
-- 1. Add the new label. This IS safe while the previous release serves.
|
|
1296
|
+
-- (Declare it in db/schema.ts; the rail emits ALTER TYPE … ADD VALUE.)
|
|
1297
|
+
-- 2. Move the data:
|
|
1298
|
+
UPDATE posts SET status = 'review' WHERE status = 'onay';
|
|
1299
|
+
-- 3. Stop naming the old value in the next release.
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
Postgres cannot delete an enum label, so `'onay'` stays — unused and harmless.
|
|
1303
|
+
|
|
1304
|
+
**One trap, measured.** A rename is followed automatically by everything Postgres stores
|
|
1305
|
+
as a parse tree: column defaults, enum-typed CHECKs, views, materialized-view
|
|
1306
|
+
definitions, partial-index predicates, RLS policies, partition bounds, generated columns.
|
|
1307
|
+
It is NOT followed by anything stored as TEXT. A constraint written
|
|
1308
|
+
`CHECK (status::text = 'onay')` keeps its text after a rename and now checks a label that
|
|
1309
|
+
no longer exists — a dead constraint, silently. Measured on PG16: an INSERT the check
|
|
1310
|
+
used to reject passed after the rename.
|
|
1240
1311
|
|
|
1241
1312
|
## Indexes
|
|
1242
1313
|
|
package/docs/schema.md
CHANGED
|
@@ -64,7 +64,78 @@ export default defineSchema({
|
|
|
64
64
|
Chainable modifiers: `.primaryKey()`, `.notNull()` (default), `.nullable()`,
|
|
65
65
|
`.default(value)`, `.defaultRandom()` (uuid → `gen_random_uuid()`),
|
|
66
66
|
`.defaultNow()` (timestamp → `now()`), `.references(table, column)`,
|
|
67
|
-
`.onDelete("cascade" | "set null" | "restrict" | "no action")`.
|
|
67
|
+
`.onDelete("cascade" | "set null" | "restrict" | "no action")`, `.ignored()`.
|
|
68
|
+
|
|
69
|
+
## Removing a column
|
|
70
|
+
|
|
71
|
+
A deploy applies the schema while the PREVIOUS release is still answering requests, so
|
|
72
|
+
dropping a column that release still names breaks it the instant the change lands. The
|
|
73
|
+
gate therefore refuses the drop — and until now it refused every drop, with no way
|
|
74
|
+
through: deleting the code that used the column changed nothing, because the gate never
|
|
75
|
+
read your code.
|
|
76
|
+
|
|
77
|
+
`.ignored()` is how you tell it. The mark is a PROMISE about the release that carries
|
|
78
|
+
it: **this release neither reads nor writes this column, and never names it in a filter,
|
|
79
|
+
a sort or a SET.**
|
|
80
|
+
|
|
81
|
+
Removing a column is therefore two deploys:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// 1. Mark it. The column stays; nothing breaks; no DDL is produced.
|
|
85
|
+
export const schema = defineSchema({
|
|
86
|
+
tables: { notes: { columns: { id: uuid().primaryKey(), old_body: text().ignored() } } },
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// 2. Ship that. Then delete the column and ship again — this time the gate passes,
|
|
92
|
+
// because the release now serving promised it does not name the column.
|
|
93
|
+
export const schema = defineSchema({
|
|
94
|
+
tables: { notes: { columns: { id: uuid().primaryKey() } } } },
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`palbase db plan` tells you which step you are on before you push. Locally,
|
|
99
|
+
`palbase db apply` is not restricted — local is where you experiment, and there is no
|
|
100
|
+
traffic to protect.
|
|
101
|
+
|
|
102
|
+
The word is `ignored` and not `deprecated` on purpose: deprecation is defined, in
|
|
103
|
+
RFC 9745 and in the GraphQL spec alike, as changing NO behaviour. This changes what a
|
|
104
|
+
deploy will accept.
|
|
105
|
+
|
|
106
|
+
**What the mark cannot do.** No static mark can PROVE your code does not name the
|
|
107
|
+
column — that question is only answerable from traffic. `.ignored()` is your promise.
|
|
108
|
+
What the gate adds is that it reads the promise from the release that is ACTUALLY
|
|
109
|
+
SERVING, not from the file in front of you.
|
|
110
|
+
|
|
111
|
+
## Renaming an enum value
|
|
112
|
+
|
|
113
|
+
There is no `renamedFrom` for enum values, and the reason is measured rather than
|
|
114
|
+
stylistic: on PostgreSQL 16, `ALTER TYPE … RENAME VALUE` is an **atomic cutover**. While
|
|
115
|
+
the rename is uncommitted a writer using the OLD label succeeds and one using the NEW
|
|
116
|
+
label fails; at commit that flips. The two names are never both valid, so there is no
|
|
117
|
+
window in which a running release can be migrated across — the instant the rename
|
|
118
|
+
commits, that release's writes fail with `invalid input value for enum`.
|
|
119
|
+
|
|
120
|
+
Add a value instead, and let the old one die:
|
|
121
|
+
|
|
122
|
+
```sql
|
|
123
|
+
-- 1. Add the new label. This IS safe while the previous release serves.
|
|
124
|
+
-- (Declare it in db/schema.ts; the rail emits ALTER TYPE … ADD VALUE.)
|
|
125
|
+
-- 2. Move the data:
|
|
126
|
+
UPDATE posts SET status = 'review' WHERE status = 'onay';
|
|
127
|
+
-- 3. Stop naming the old value in the next release.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Postgres cannot delete an enum label, so `'onay'` stays — unused and harmless.
|
|
131
|
+
|
|
132
|
+
**One trap, measured.** A rename is followed automatically by everything Postgres stores
|
|
133
|
+
as a parse tree: column defaults, enum-typed CHECKs, views, materialized-view
|
|
134
|
+
definitions, partial-index predicates, RLS policies, partition bounds, generated columns.
|
|
135
|
+
It is NOT followed by anything stored as TEXT. A constraint written
|
|
136
|
+
`CHECK (status::text = 'onay')` keeps its text after a rename and now checks a label that
|
|
137
|
+
no longer exists — a dead constraint, silently. Measured on PG16: an INSERT the check
|
|
138
|
+
used to reject passed after the rename.
|
|
68
139
|
|
|
69
140
|
## Indexes
|
|
70
141
|
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../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":["/**\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 { 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 `defineSchema({ tables: { <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 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 TablesFromInput<T extends Record<string, TableInput>> = {\n [K in keyof T]: TableDef<T[K][\"columns\"]>;\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 * Define a schema. The table NAME comes from the object key. Each table value\n * is `{ columns, rls?, policies? }`:\n *\n * export default defineSchema({\n * tables: {\n * 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 * });\n *\n * The returned value is\n * `{ tables: { todos: { name, columns, rls, policies } } }` — the exact shape\n * the runtime schema extractor parses. Per-column phantom types are preserved\n * so `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 */\nexport function defineSchema<T extends Record<string, TableInput>>(\n input: SchemaInput<T>,\n): SchemaDef<TablesFromInput<T>> {\n const tables = {} as TablesFromInput<T>;\n for (const name of Object.keys(input.tables) as (keyof T)[]) {\n const table = input.tables[name];\n // `noUncheckedIndexedAccess` widens the index access to `… | undefined`,\n // but `name` comes straight from `Object.keys(input.tables)`, so the entry\n // always exists. Guard to narrow without a cast.\n if (table === undefined) continue;\n const policies = (table.policies ?? []).map(toPolicyDef);\n // Fail closed. RLS is on unless the schema explicitly says `rls: false`, and\n // policies force it on regardless — a policy on a table without RLS enabled\n // is inert, so declaring both is a contradiction that resolves towards the\n // 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. Both cannot be true, and the\n // live proof settled which one was not: user B read user A's row in full\n // through the typed client, while the same request against a table declaring\n // `rls: true` returned 0 of 165 rows\n // (docs/superpowers/uat/2026-08-07-rls-fail-open-proof.md). With no policies\n // this is deny-all, so an unconsidered table now returns nothing instead of\n // returning everything to everyone.\n const rls = policies.length > 0 || table.rls !== false;\n const tableDef: TableDef<T[typeof name][\"columns\"]> = {\n name: name as string,\n columns: table.columns,\n rls,\n policies,\n };\n if (table.primaryKey !== undefined) tableDef.primaryKey = table.primaryKey;\n if (table.unique !== undefined) tableDef.unique = table.unique;\n if (table.raw !== undefined && table.raw.length > 0) tableDef.raw = table.raw.slice();\n if (table.checks !== undefined && table.checks.length > 0) tableDef.checks = table.checks.slice();\n if (table.indexes !== undefined && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();\n if (table.search !== undefined) {\n const s = table.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 ${String(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 ${String(name)}: search.from boş olamaz`);\n }\n if (s.model === undefined) {\n throw new Error(\n `table ${String(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 ${String(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 ${String(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 ${String(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 ${String(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 ${String(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 ${String(name)}: search.vector.from model'siz anlamsız — auto-embed için model verin`);\n }\n }\n }\n tableDef.search = s;\n }\n if (table.memory !== undefined) {\n if (table.memory.from.length === 0) {\n throw new Error(`table ${String(name)}: memory.from boş olamaz`);\n }\n tableDef.memory = table.memory;\n }\n tables[name] = tableDef;\n }\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 return { tables, extensions };\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 /**\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 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 references(table: string, column: string): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, 'references');\n this._def.references = { table, column };\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /**\n * Add a real DB-level foreign key to the built-in auth users\n * (`REFERENCES auth.users(id)`), so a column like `user_id` gets true\n * database cascade/integrity instead of app-layer-only. Sugar for\n * `.references(\"auth.users\", \"id\")`.\n *\n * `auth.users` lives in the SAME tenant database (palauth-owned), so this is\n * a genuine cross-schema integrity constraint scoped to THIS tenant's users.\n * The referenced `auth.users.id` is `text` (palauth ids are `usr_<uuid>`), so\n * the referencing column must be `text()` too.\n *\n * ON DELETE is REQUIRED here and may only be `cascade` or `set null`: an\n * account-erasure request must never be blocked by a lingering FK, so\n * `restrict` / `no action` are not accepted (they don't type-check). Example:\n * `text().notNull().referencesAuthUser(\"cascade\")`, or\n * `text().nullable().referencesAuthUser(\"set null\")`. The server\n * (validateAuthUserFK) enforces this — and the remaining rules the type can't\n * express (referencing column is text, `set null` needs a nullable column) —\n * as the real boundary; this signature is the compile-time DX mirror.\n */\n referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, \"referencesAuthUser\");\n this._def.references = { table: 'auth.users', column: 'id' };\n this._def.onDeleteAction = onDelete;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\n }\n\n /**\n * Add a real DB-level foreign key to the canonical, server-minted installation\n * anchor (`REFERENCES auth.installations(id)`) — the app-scoped verified-device\n * root (`ins_...`). Sugar for `.references(\"auth.installations\", \"id\")`.\n *\n * An installation is an APP INSTALL, not a user: this FK is NOT user ownership.\n * A user-owned row STILL needs its own `.referencesAuthUser(...)` FK so account\n * erasure removes it — an installation reference alone does not tie a row to a\n * user's deletion. Use this only for install-scoped state (device prefs, push\n * routing, …), alongside a separate auth-user FK where the row is user-owned.\n *\n * `auth.installations` lives in the SAME tenant DB (palauth-owned); its `id` is\n * `text` (`ins_<uuid>`), so the referencing column must be `text()` too. ON\n * DELETE is REQUIRED and may only be `cascade` or `set null` (same allowed set\n * as an auth-user FK): an installation revoke / orphan cleanup must never be\n * blocked by a lingering FK. The server (validateAuthAnchorFK) is the real\n * boundary; this signature is the compile-time DX mirror.\n */\n referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P, T> {\n refuseOnVector(this._def, \"referencesInstallation\");\n this._def.references = { table: 'auth.installations', column: 'id' };\n this._def.onDeleteAction = onDelete;\n return new ColumnBuilder<K, N, D, E, P, T>(this._def.type as K, this._def);\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 * 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, 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/** 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 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 * 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":["raw"]}
|