@palbase/backend 25.0.4 → 27.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/bin/palbase-backend.cjs +2622 -1012
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +87 -51
  4. package/dist/bin/palbase-backend.js.map +1 -1
  5. package/dist/chunk-CGNN2PUH.js +213 -0
  6. package/dist/chunk-CGNN2PUH.js.map +1 -0
  7. package/dist/chunk-DRZFQRJI.js +370 -0
  8. package/dist/chunk-DRZFQRJI.js.map +1 -0
  9. package/dist/chunk-GYK6QYS4.js +708 -0
  10. package/dist/chunk-GYK6QYS4.js.map +1 -0
  11. package/dist/chunk-I3C4PFIW.js +930 -0
  12. package/dist/chunk-I3C4PFIW.js.map +1 -0
  13. package/dist/{chunk-AILPKEK5.js → chunk-OO7R25AI.js} +1433 -563
  14. package/dist/chunk-OO7R25AI.js.map +1 -0
  15. package/dist/chunk-TS4U7NBD.js +885 -0
  16. package/dist/chunk-TS4U7NBD.js.map +1 -0
  17. package/dist/{chunk-YOY5DFQS.js → chunk-TWX6JTGJ.js} +76 -34
  18. package/dist/{chunk-YOY5DFQS.js.map → chunk-TWX6JTGJ.js.map} +1 -1
  19. package/dist/{chunk-35PNTIRN.js → chunk-VVMJEVQP.js} +63 -162
  20. package/dist/chunk-VVMJEVQP.js.map +1 -0
  21. package/dist/{chunk-7D4SUZUM.js → chunk-VXPNPVAG.js} +3 -1
  22. package/dist/db/env.cjs.map +1 -1
  23. package/dist/db/env.d.cts +2 -2
  24. package/dist/db/env.d.ts +2 -2
  25. package/dist/db/index.cjs +754 -344
  26. package/dist/db/index.cjs.map +1 -1
  27. package/dist/db/index.d.cts +2 -2
  28. package/dist/db/index.d.ts +2 -2
  29. package/dist/db/index.js +7 -4
  30. package/dist/engine/index.cjs +2562 -981
  31. package/dist/engine/index.cjs.map +1 -1
  32. package/dist/engine/index.d.cts +6 -6
  33. package/dist/engine/index.d.ts +6 -6
  34. package/dist/engine/index.js +7 -6
  35. package/dist/index-BrvvxSpn.d.ts +4844 -0
  36. package/dist/index-Bve7BBTL.d.cts +4844 -0
  37. package/dist/{index-CUomTA3e.d.ts → index-NuzRCuxe.d.ts} +171 -296
  38. package/dist/{index-ClpDeSos.d.cts → index-VtToZmUm.d.cts} +171 -296
  39. package/dist/index.cjs +2694 -1169
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +165 -19
  42. package/dist/index.d.ts +165 -19
  43. package/dist/index.js +738 -477
  44. package/dist/index.js.map +1 -1
  45. package/dist/module-Dl1KFVtc.d.cts +54 -0
  46. package/dist/module-Dl1KFVtc.d.ts +54 -0
  47. package/dist/openapi/index.cjs +1330 -484
  48. package/dist/openapi/index.cjs.map +1 -1
  49. package/dist/openapi/index.d.cts +4 -2
  50. package/dist/openapi/index.d.ts +4 -2
  51. package/dist/openapi/index.js +1264 -474
  52. package/dist/openapi/index.js.map +1 -1
  53. package/dist/{registry-dZZ5JKYg.d.ts → registry-B0eyOF9x.d.ts} +1 -1
  54. package/dist/{registry-CC0WBQq6.d.cts → registry-Bk9_rbNd.d.cts} +1 -1
  55. package/dist/stack.cjs.map +1 -1
  56. package/dist/test/index.cjs +705 -141
  57. package/dist/test/index.cjs.map +1 -1
  58. package/dist/test/index.d.cts +30 -4
  59. package/dist/test/index.d.ts +30 -4
  60. package/dist/test/index.js +472 -124
  61. package/dist/test/index.js.map +1 -1
  62. package/docs/README.md +34 -18
  63. package/docs/auth.md +1 -1
  64. package/docs/background.md +2 -2
  65. package/docs/database.md +221 -50
  66. package/docs/endpoints.md +3 -4
  67. package/docs/events.md +3 -3
  68. package/docs/getting-started.md +1 -1
  69. package/docs/llms-full.txt +402 -117
  70. package/docs/migrations.md +2 -2
  71. package/docs/schema.md +19 -10
  72. package/docs/services.md +116 -26
  73. package/package.json +8 -4
  74. package/stager/generics.js +205 -0
  75. package/stager/stage.js +39 -3
  76. package/template/AGENTS.md +110 -70
  77. package/template/db/public.ts +1 -1
  78. package/template/{controllers → modules/health}/health.controller.ts +1 -1
  79. package/template/modules/health/health.module.ts +24 -0
  80. package/template/modules/notes/note.service.test.ts +49 -0
  81. package/template/modules/notes/note.service.ts +108 -0
  82. package/template/{controllers → modules/notes}/notes.controller.ts +17 -11
  83. package/template/modules/notes/notes.module.ts +37 -0
  84. package/template/package.json +5 -3
  85. package/template/scripts/test.sh +33 -0
  86. package/template/tsconfig.json +29 -30
  87. package/dist/chunk-35PNTIRN.js.map +0 -1
  88. package/dist/chunk-AILPKEK5.js.map +0 -1
  89. package/dist/chunk-CJSKYY76.js +0 -627
  90. package/dist/chunk-CJSKYY76.js.map +0 -1
  91. package/dist/chunk-CRQKCRGF.js +0 -276
  92. package/dist/chunk-CRQKCRGF.js.map +0 -1
  93. package/dist/chunk-G4R6BTLV.js +0 -662
  94. package/dist/chunk-G4R6BTLV.js.map +0 -1
  95. package/dist/chunk-XABBC7JP.js +0 -55
  96. package/dist/chunk-XABBC7JP.js.map +0 -1
  97. package/dist/endpoint-CTEHhb7A.d.ts +0 -2386
  98. package/dist/endpoint-DYHMo6cC.d.cts +0 -2386
  99. package/dist/index-CW21M9Z3.d.ts +0 -1222
  100. package/dist/index-CmBK76nx.d.cts +0 -1222
  101. package/template/services/note.service.test.ts +0 -45
  102. package/template/services/note.service.ts +0 -74
  103. /package/dist/{chunk-7D4SUZUM.js.map → chunk-VXPNPVAG.js.map} +0 -0
  104. /package/template/{models/notes → modules/notes/dto}/create.ts +0 -0
@@ -0,0 +1,370 @@
1
+ import {
2
+ TxPlanBuilder,
3
+ brandRef,
4
+ runTxPlan
5
+ } from "./chunk-GYK6QYS4.js";
6
+ import {
7
+ isRetryable
8
+ } from "./chunk-CGNN2PUH.js";
9
+ import {
10
+ __name
11
+ } from "./chunk-VXPNPVAG.js";
12
+
13
+ // src/db/typed-db.ts
14
+ function makeTypedTable(name, raw) {
15
+ return {
16
+ insert: /* @__PURE__ */ __name((data) => raw.insert(name, data), "insert"),
17
+ put: /* @__PURE__ */ __name((q) => raw.put(name, q.data, {
18
+ onConflict: q.onConflict
19
+ }), "put"),
20
+ update: /* @__PURE__ */ __name((q) => raw.update(name, q.where.id, q.set), "update"),
21
+ delete: /* @__PURE__ */ __name((id) => raw.delete(name, id), "delete"),
22
+ findById: /* @__PURE__ */ __name((id) => raw.findById(name, id), "findById"),
23
+ findMany: /* @__PURE__ */ __name((q) => {
24
+ const { where, ...opts } = q ?? {};
25
+ return raw.findMany(name, where, opts);
26
+ }, "findMany"),
27
+ updateMany: /* @__PURE__ */ __name((q) => raw.updateMany(name, q.where, q.set), "updateMany"),
28
+ deleteMany: /* @__PURE__ */ __name((q) => raw.deleteMany(name, q.where), "deleteMany"),
29
+ count: /* @__PURE__ */ __name((q) => raw.count(name, q?.where), "count")
30
+ };
31
+ }
32
+ __name(makeTypedTable, "makeTypedTable");
33
+ function makeTypedDB(schema, raw) {
34
+ const tables = {};
35
+ for (const key of Object.keys(schema.tables)) {
36
+ const tableDef = schema.tables[key];
37
+ if (tableDef !== void 0) {
38
+ tables[key] = makeTypedTable(tableDef.name, raw);
39
+ }
40
+ }
41
+ const result = {
42
+ tables,
43
+ transaction(fn) {
44
+ const builder = new TxPlanBuilder();
45
+ const planTables = {};
46
+ for (const key of Object.keys(schema.tables)) {
47
+ const tableDef = schema.tables[key];
48
+ if (tableDef !== void 0) planTables[key] = builder.table(tableDef.name);
49
+ }
50
+ return runTxPlan(raw, {
51
+ tables: planTables
52
+ }, builder, fn);
53
+ }
54
+ };
55
+ return result;
56
+ }
57
+ __name(makeTypedDB, "makeTypedDB");
58
+ function col(name) {
59
+ return brandRef({
60
+ $col: name
61
+ }, "col");
62
+ }
63
+ __name(col, "col");
64
+ async function withRetry(fn, opts = {}) {
65
+ const budget = opts.retry ?? 0;
66
+ let attempt = 0;
67
+ for (; ; ) {
68
+ try {
69
+ return await fn();
70
+ } catch (e) {
71
+ if (attempt >= budget || !isRetryable(e)) throw e;
72
+ attempt += 1;
73
+ }
74
+ }
75
+ }
76
+ __name(withRetry, "withRetry");
77
+ function sqlFragment(strings, ...values) {
78
+ return brandRef({
79
+ $sql: {
80
+ text: [
81
+ ...strings
82
+ ],
83
+ values
84
+ }
85
+ }, "sql");
86
+ }
87
+ __name(sqlFragment, "sqlFragment");
88
+
89
+ // src/db/schema-json.ts
90
+ function defOf(column) {
91
+ return "_def" in column ? column._def : column;
92
+ }
93
+ __name(defOf, "defOf");
94
+ function columnToJSON(column) {
95
+ const def = defOf(column);
96
+ const out = {
97
+ type: def.type,
98
+ nullable: def.nullable,
99
+ primaryKey: def.primaryKey
100
+ };
101
+ if (def.defaultValue !== void 0) out.defaultValue = def.defaultValue;
102
+ if (def.defaultRandom === true) out.defaultRandom = true;
103
+ if (def.defaultNow === true) out.defaultNow = true;
104
+ if (def.renamedFrom !== void 0) out.renamedFrom = def.renamedFrom;
105
+ if (def.ignored === true) out.ignored = true;
106
+ if (def.owns === true) out.owns = true;
107
+ if (def.references !== void 0) {
108
+ out.references = {
109
+ table: def.references.table,
110
+ column: def.references.column
111
+ };
112
+ }
113
+ if (def.onDeleteAction !== void 0) out.onDeleteAction = def.onDeleteAction;
114
+ if (def.index === false) out.index = false;
115
+ if (def.counter === true) out.counter = true;
116
+ if (def.enumName !== void 0) out.enumName = def.enumName;
117
+ if (def.enumValues !== void 0) out.enumValues = [
118
+ ...def.enumValues
119
+ ];
120
+ if (def.unique === true) out.unique = true;
121
+ if (def.dimensions !== void 0) out.dimensions = def.dimensions;
122
+ return out;
123
+ }
124
+ __name(columnToJSON, "columnToJSON");
125
+ function policyToJSON(policy) {
126
+ return {
127
+ name: policy.name,
128
+ command: policy.command ?? "all",
129
+ roles: policy.roles ? [
130
+ ...policy.roles
131
+ ] : [],
132
+ // null rather than omitted: a policy with no USING clause is a different
133
+ // thing from one whose clause the emitter forgot, and Go reads the
134
+ // difference.
135
+ using: policy.using ?? null,
136
+ withCheck: policy.withCheck ?? null,
137
+ permissive: policy.permissive !== false
138
+ };
139
+ }
140
+ __name(policyToJSON, "policyToJSON");
141
+ function commonSearchFields(search, out) {
142
+ if (search.synonyms !== void 0 && Object.keys(search.synonyms).length > 0) {
143
+ out.synonyms = Object.fromEntries(Object.entries(search.synonyms).map(([word, alts]) => [
144
+ word,
145
+ [
146
+ ...alts
147
+ ]
148
+ ]));
149
+ }
150
+ if (search.validity === true) out.validity = true;
151
+ }
152
+ __name(commonSearchFields, "commonSearchFields");
153
+ function searchToJSON(search, vectorColumn) {
154
+ if (search.from !== void 0 && search.model !== void 0) {
155
+ const out2 = {};
156
+ const textCols = search.text === false ? void 0 : Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from;
157
+ if (textCols !== void 0) out2.text = {
158
+ columns: [
159
+ ...textCols
160
+ ]
161
+ };
162
+ const v = {
163
+ metric: search.metric ?? "cosine"
164
+ };
165
+ if (vectorColumn !== void 0) v.column = vectorColumn;
166
+ v.embed = {
167
+ provider: search.model.provider,
168
+ model: search.model.model,
169
+ from: [
170
+ ...search.from
171
+ ],
172
+ ...search.model.apiKeyName !== void 0 ? {
173
+ apiKeyName: search.model.apiKeyName
174
+ } : {},
175
+ ...search.model.dimensions !== void 0 ? {
176
+ dimensions: search.model.dimensions
177
+ } : {},
178
+ ...search.model.baseURL !== void 0 ? {
179
+ baseURL: search.model.baseURL
180
+ } : {}
181
+ };
182
+ if (search.staleness !== void 0) v.staleness = search.staleness;
183
+ if (vectorColumn === void 0) {
184
+ v.mode = "chunks";
185
+ if (search.chunks !== void 0) {
186
+ const c = {};
187
+ if (search.chunks.size !== void 0 && search.chunks.size > 0) c.sizeChars = search.chunks.size;
188
+ if (search.chunks.overlap !== void 0 && search.chunks.overlap > 0) c.overlapChars = search.chunks.overlap;
189
+ if (Object.keys(c).length > 0) v.chunks = c;
190
+ }
191
+ }
192
+ out2.vector = [
193
+ v
194
+ ];
195
+ commonSearchFields(search, out2);
196
+ return out2;
197
+ }
198
+ const out = {};
199
+ if (Array.isArray(search.text) && search.text.length > 0) out.text = {
200
+ columns: [
201
+ ...search.text
202
+ ]
203
+ };
204
+ const legs = search.vector === void 0 ? [] : Array.isArray(search.vector) ? search.vector : [
205
+ search.vector
206
+ ];
207
+ if (legs.length > 0) {
208
+ out.vector = legs.map((leg) => {
209
+ const v = {
210
+ metric: leg.metric ?? "cosine"
211
+ };
212
+ if (leg.column !== void 0) v.column = leg.column;
213
+ if (leg.staleness !== void 0) v.staleness = leg.staleness;
214
+ if (leg.model !== void 0) {
215
+ v.embed = {
216
+ provider: leg.model.provider,
217
+ model: leg.model.model,
218
+ from: [
219
+ ...leg.from ?? []
220
+ ],
221
+ ...leg.model.apiKeyName !== void 0 ? {
222
+ apiKeyName: leg.model.apiKeyName
223
+ } : {},
224
+ ...leg.model.dimensions !== void 0 ? {
225
+ dimensions: leg.model.dimensions
226
+ } : {},
227
+ ...leg.model.baseURL !== void 0 ? {
228
+ baseURL: leg.model.baseURL
229
+ } : {}
230
+ };
231
+ }
232
+ return v;
233
+ });
234
+ }
235
+ commonSearchFields(search, out);
236
+ return out;
237
+ }
238
+ __name(searchToJSON, "searchToJSON");
239
+ function memoryToJSON(m) {
240
+ return {
241
+ from: [
242
+ ...m.from
243
+ ],
244
+ into: m.into,
245
+ ...m.subject !== void 0 ? {
246
+ subject: m.subject
247
+ } : {},
248
+ extract: {
249
+ provider: m.extract.provider,
250
+ model: m.extract.model
251
+ }
252
+ };
253
+ }
254
+ __name(memoryToJSON, "memoryToJSON");
255
+ function tableToJSON(table, schemaName) {
256
+ const columns = {};
257
+ for (const [name, column] of Object.entries(table.columns)) {
258
+ columns[name] = columnToJSON(column);
259
+ }
260
+ const out = {
261
+ name: table.name,
262
+ schema: schemaName,
263
+ columns,
264
+ // Read, not re-derived. `defineSchema` already resolves the fail-closed
265
+ // default (RLS on unless the author wrote `rls: false`, and forced on by any
266
+ // policy), and a second copy of a SECURITY default is exactly the thing that
267
+ // drifts — the direction it drifted last time was "expose everything", and
268
+ // the live proof was one user reading another's rows.
269
+ rls: table.rls,
270
+ policies: (table.policies ?? []).map(policyToJSON)
271
+ };
272
+ if (table.primaryKey !== void 0 && table.primaryKey.length > 0) {
273
+ out.primaryKey = [
274
+ ...table.primaryKey
275
+ ];
276
+ }
277
+ if (table.unique !== void 0 && table.unique.length > 0) {
278
+ out.uniqueConstraints = table.unique.map((u) => ({
279
+ name: u.name,
280
+ columns: [
281
+ ...u.columns
282
+ ]
283
+ }));
284
+ }
285
+ if (table.raw !== void 0 && table.raw.length > 0) {
286
+ out.rawConstraints = table.raw.map((r) => ({
287
+ name: r.name,
288
+ up: r.up,
289
+ down: r.down ?? null
290
+ }));
291
+ }
292
+ if (table.checks !== void 0 && table.checks.length > 0) {
293
+ out.checks = table.checks.map((c) => ({
294
+ name: c.name,
295
+ expr: c.expr
296
+ }));
297
+ }
298
+ if (table.indexes !== void 0 && table.indexes.length > 0) {
299
+ out.indexes = table.indexes.map((i) => {
300
+ const ix = {
301
+ name: i.name,
302
+ columns: i.columns ? [
303
+ ...i.columns
304
+ ] : []
305
+ };
306
+ if (i.where !== void 0) ix.where = i.where;
307
+ if (i.expression !== void 0) ix.expression = i.expression;
308
+ if (i.sort !== void 0) ix.sort = i.sort;
309
+ if (i.nulls !== void 0) ix.nulls = i.nulls;
310
+ if (i.include !== void 0) ix.include = [
311
+ ...i.include
312
+ ];
313
+ return ix;
314
+ });
315
+ }
316
+ if (table.appendOnly === true) out.appendOnly = true;
317
+ if (table.search !== void 0) {
318
+ const vectorColumn = Object.entries(columns).find(([, c]) => c.dimensions !== void 0)?.[0];
319
+ const sj = searchToJSON(table.search, vectorColumn);
320
+ if (sj.text !== void 0 || sj.vector !== void 0) out.search = sj;
321
+ }
322
+ if (table.memory !== void 0) {
323
+ out.memory = memoryToJSON(table.memory);
324
+ }
325
+ return out;
326
+ }
327
+ __name(tableToJSON, "tableToJSON");
328
+ function qualifiedTableKey(schemaName, tableName) {
329
+ return schemaName === "" || schemaName === "public" ? tableName : `${schemaName}.${tableName}`;
330
+ }
331
+ __name(qualifiedTableKey, "qualifiedTableKey");
332
+ function toSchemaJSON(schemas) {
333
+ const tables = {};
334
+ const extensions = [];
335
+ const meta = [];
336
+ const seen = /* @__PURE__ */ new Set();
337
+ for (const schema of schemas) {
338
+ if (seen.has(schema.name)) {
339
+ throw new Error(`two schemas declare the name "${schema.name}" \u2014 schema names must be unique`);
340
+ }
341
+ seen.add(schema.name);
342
+ for (const table of Object.values(schema.tables)) {
343
+ const json = tableToJSON(table, schema.name);
344
+ tables[qualifiedTableKey(schema.name, json.name)] = json;
345
+ }
346
+ extensions.push(...schema.extensions ?? []);
347
+ meta.push({
348
+ name: schema.name,
349
+ exposed: schema.exposed
350
+ });
351
+ }
352
+ return {
353
+ tables,
354
+ extensions: [
355
+ ...new Set(extensions)
356
+ ],
357
+ schemas: meta
358
+ };
359
+ }
360
+ __name(toSchemaJSON, "toSchemaJSON");
361
+
362
+ export {
363
+ makeTypedDB,
364
+ col,
365
+ withRetry,
366
+ sqlFragment,
367
+ qualifiedTableKey,
368
+ toSchemaJSON
369
+ };
370
+ //# sourceMappingURL=chunk-DRZFQRJI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db/typed-db.ts","../src/db/schema-json.ts"],"sourcesContent":["/**\n * typed-db.ts — Task 2: TypedDB schema-derived insert/row shapes.\n *\n * Derives INSERT and full-row TypeScript types from a `defineSchema()` result\n * and wraps the untyped runtime `DBClient` with a typed facade.\n *\n * No value-any. No `as unknown as X`. The two narrow `as` casts in\n * `makeTypedTable` are safe because:\n * - `data as Record<string, unknown>`: InsertShape<T> maps string keys to\n * typed values; all value types are subsets of `unknown`, so the cast is\n * structurally sound.\n * - `result as RowShape<T>`: The runtime DBClient returns `Record<string,\n * unknown>` which is the erased form of the typed row; we're narrowing back\n * to the precise shape that the schema declared.\n * Both casts are narrowing only (not widening) and correctness is guaranteed\n * by the schema the caller provides.\n */\n\nimport type { ColValue, ColIsOptionalOnInsert, ColumnBuilder } from \"./columns.js\";\nimport type { TableDef, SchemaDef } from \"./schema.js\";\nimport type { Tables, Schemas, TableTypes } from \"./env.js\";\nimport type { DBClient, DBOps } from \"../endpoint.js\";\nimport type { RecoOps } from \"../runtime.js\";\nimport type { Materialized, TxPlanHandle, TxTable, TxColumnExpr, TxNow } from \"./tx-plan.js\";\nimport { TxPlanBuilder, runTxPlan } from \"./tx-plan.js\";\nimport { isColRef, brandRef } from \"./input-guards.js\";\nimport { isRetryable } from \"../errors.js\";\n\n// ---------------------------------------------------------------------------\n// Key discriminators — split a column map into required vs optional keys.\n// ---------------------------------------------------------------------------\n\n/** Keys of C whose columns are required on INSERT (not nullable, no default). */\ntype RequiredKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? never : K;\n}[keyof C];\n\n/** Keys of C whose columns are optional on INSERT (nullable or has a default). */\ntype OptionalKeys<C> = {\n [K in keyof C]: ColIsOptionalOnInsert<C[K]> extends true ? K : never;\n}[keyof C];\n\n// ---------------------------------------------------------------------------\n// Public shape types — exported so callers can reference them directly.\n// ---------------------------------------------------------------------------\n\n/**\n * The TypeScript type for an INSERT payload for table `T`.\n * - Required: columns that are NOT NULL and have no DB-level default.\n * - Optional: columns that are nullable or carry a default.\n *\n * When all columns are optional, `RequiredKeys<C>` resolves to `never` and\n * the first part becomes `{}`, which is a neutral element for `&`.\n */\nexport type InsertShape<T extends TableDef> = {\n [K in RequiredKeys<T[\"columns\"]>]: ColValue<T[\"columns\"][K]>;\n} & {\n [K in OptionalKeys<T[\"columns\"]>]?: ColValue<T[\"columns\"][K]>;\n};\n\n/**\n * The TypeScript type for a full row returned by the DB for table `T`.\n * Every column is present; nullable columns resolve to `T | null`.\n */\nexport type RowShape<T extends TableDef> = {\n [K in keyof T[\"columns\"]]: ColValue<T[\"columns\"][K]>;\n};\n\n// ---------------------------------------------------------------------------\n// TypedTable + TypedDB interfaces.\n// ---------------------------------------------------------------------------\n\n/** A typed table accessor that mirrors the runtime DBClient surface. */\nexport interface TypedTable<T extends TableDef> {\n insert(data: InsertShape<T>): Promise<RowShape<T>>;\n put(q: { data: InsertShape<T>; onConflict: readonly string[] }): Promise<RowShape<T>>;\n /** Update the row by id; resolves to the updated row, or `null` if no row\n * matched (absent or RLS-hidden) — an idempotent outcome, mirroring\n * `findById`. The runtime returns a null row rather than throwing. */\n update(q: { where: { id: string }; set: 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<K extends keyof RowShape<T> = keyof RowShape<T>>(\n q?: QueryInput<RowShape<T>, K>,\n ): Promise<Pick<RowShape<T>, K>[]>;\n /**\n * Update every matching row in one statement; an empty filter is refused.\n *\n * **0 satır dönmesi hata DEĞİL, başarı da değil** (FR-014): koşulu `where`'e\n * koyup dönen diziyi kontrol etmek, \"önce oku sonra yaz\"ın yarış koşulu\n * olmayan hâlidir.\n *\n * ```ts\n * const [row] = await Database.public.accounts.updateMany({\n * where: { id, balance: { gte: amount } },\n * set: { balance: decrement(amount) },\n * });\n * if (row === undefined) throw new Conflict(\"yetersiz bakiye\");\n * ```\n */\n updateMany(q: MutateInput<RowShape<T>, InsertShape<T>>): Promise<RowShape<T>[]>;\n /** Delete every matching row; resolves to how many. Empty filter refused. */\n deleteMany(q: { where: WhereFilter<RowShape<T>> | SqlFragment }): Promise<number>;\n /** How many rows match. An empty filter is legitimate: counting is a read. */\n count(q?: { where?: WhereFilter<RowShape<T>> | SqlFragment }): Promise<number>;\n}\n\n/** A typed DB facade covering all tables declared in schema `S`. */\nexport interface TypedDB<S extends SchemaDef> {\n tables: {\n [K in keyof S[\"tables\"]]: TypedTable<S[\"tables\"][K]>;\n };\n /** Run a transaction plan. See {@link EnvTypedDatabase.transaction}. */\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>>;\n}\n\n/** The plan-building handle a `TypedDB<S>` transaction callback receives: the\n * schema's tables, expressed as plan operations rather than awaited calls.\n *\n * YALNIZ `tables`, ve ÇALIŞMA ZAMANI DA yalnız onu veriyor.\n *\n * Bir süre runtime `{ tables, public }` döndürüyordu ama tip yalnız `tables`\n * söylüyordu: `tx.public.x` derlenmiyor, koşsaydı çalışacaktı — tipin çalışma\n * zamanından AZ söylemesi (gözcü M-8). Tipe `public` EKLEMEK yanlış düzeltmeydi\n * ve `check:api` onu adıyla reddetti: `TypedTx` dışa açık, ve zorunlu bir üye\n * eklemek onu İNŞA EDEN müşterinin kodunu kırar — \"the new shape demands more\n * than the recorded one\". Yalan runtime'dan kaldırılarak kapatıldı; ikisi artık\n * aynı şeyi söylüyor. `Database.$transaction`'ın `tx.public`'i ayrı bir yüzey\n * (`TxPlan`) ve orada tip de runtime da onu taşıyor. */\nexport type TypedTx<S extends SchemaDef> = TxPlanHandle<{\n [K in keyof S[\"tables\"]]: TxTable<RowShape<S[\"tables\"][K]>, InsertShape<S[\"tables\"][K]>>;\n}>;\n\n// ---------------------------------------------------------------------------\n// Runtime factory.\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a typed table accessor that delegates every call to `raw` using the\n * runtime table name string. Two narrow `as` casts bridge the mapped-type\n * shapes to/from `Record<string, unknown>` — see module-level doc comment.\n *\n * The `raw` param is typed `DBOps` (the six string-keyed ops) because this only\n * ever calls those — never `txPlan`, which builds its own operations rather than\n * delegating to these.\n */\nfunction makeTypedTable<T extends TableDef<Record<string, ColumnBuilder>>>(\n name: string,\n raw: DBOps,\n): TypedTable<T> {\n return {\n insert: (data: InsertShape<T>) =>\n raw.insert(name, data as Record<string, unknown>) as Promise<RowShape<T>>,\n\n put: (q: { data: InsertShape<T>; onConflict: readonly string[] }) =>\n raw.put(name, q.data as Record<string, unknown>, { onConflict: q.onConflict }) as Promise<RowShape<T>>,\n\n update: (q: { where: { id: string }; set: Partial<InsertShape<T>> }) =>\n raw.update(name, q.where.id, q.set as Record<string, unknown>) as Promise<RowShape<T> | null>,\n\n delete: (id: string) => raw.delete(name, id),\n\n findById: (id: string) =>\n raw.findById(name, id) as Promise<RowShape<T> | null>,\n\n findMany: (q?: QueryInput<RowShape<T>>) => {\n // `where` AYIKLANIR: kalan alanlar (orderBy/limit/offset) opts'a gider.\n // Tümünü opts diye geçirmek `where`'i tel üstünde İKİ KEZ gönderirdi.\n const { where, ...opts } = q ?? {};\n return raw.findMany(\n name,\n where as Record<string, unknown> | undefined,\n opts as Parameters<typeof raw.findMany>[2],\n ) as Promise<RowShape<T>[]>;\n },\n\n updateMany: (q: MutateInput<RowShape<T>, InsertShape<T>>) =>\n raw.updateMany(\n name,\n q.where as Record<string, unknown>,\n q.set as Record<string, unknown>,\n ) as Promise<RowShape<T>[]>,\n\n deleteMany: (q: { where: WhereFilter<RowShape<T>> | SqlFragment }) =>\n raw.deleteMany(name, q.where as Record<string, unknown>),\n\n count: (q?: { where?: WhereFilter<RowShape<T>> }) =>\n raw.count(name, q?.where as Record<string, unknown> | undefined),\n };\n}\n\n/**\n * Wraps a raw `DBClient` with the type-safe `TypedDB<S>` facade derived from\n * the provided schema. No behavior change for the direct ops — all calls\n * delegate to `raw` with the table name as a plain string.\n *\n * `transaction` does NOT delegate to a per-op client: the callback describes a\n * plan against a fresh {@link TxPlanBuilder}, and the whole plan travels in one\n * `raw.txPlan` call. The schema is used only for its table NAMES; the values\n * are typed by `S` at compile time and are plain strings at run time.\n *\n * The `as` casts are single structural narrowings from a dynamically-built\n * object to the precise mapped type (TS cannot infer the mapped-type result\n * through `Object.keys` iteration) — see the module-level doc comment.\n */\nexport function makeTypedDB<S extends SchemaDef>(\n schema: S,\n raw: DBClient,\n): TypedDB<S> {\n const tables = {} as Record<string, TypedTable<TableDef>>;\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) {\n tables[key] = makeTypedTable(tableDef.name, raw);\n }\n }\n\n const result = {\n tables,\n transaction<T>(\n fn: (tx: TypedTx<S>) => T extends Promise<unknown> ? never : T,\n ): Promise<Materialized<T>> {\n const builder = new TxPlanBuilder();\n const planTables: Record<string, unknown> = {};\n for (const key of Object.keys(schema.tables)) {\n const tableDef = schema.tables[key];\n if (tableDef !== undefined) planTables[key] = builder.table(tableDef.name);\n }\n // Two narrowings at the same seam: the plan tables are built by NAME, so\n // TS cannot see the mapped type through the loop, and the driver erases\n // the callback's return type (see runTxPlan's doc). Both are the erasure\n // this facade exists to undo.\n // `runTxPlan` artık TUTAMAĞIN TAMAMINI alıyor (şema yüzeyi dahil).\n //\n // Burada tutamak YALNIZ `tables` taşıyor, çünkü `TypedTx<S>` de yalnız\n // onu söylüyor. Bir ara `public`'i de veriyordu ve tip onu bilmiyordu —\n // çalışma zamanının tipten FAZLA sunması da bir yalan. `makeTypedDB` tek\n // şemalı bir cephe; çok şemalı yüzey `Database.$transaction`.\n return runTxPlan(\n raw,\n { tables: planTables } as TypedTx<S>,\n builder,\n fn,\n ) as Promise<Materialized<T>>;\n },\n };\n\n // Narrow cast: `result.tables` is structurally identical to\n // TypedDB<S>[\"tables\"] — each key maps to a TypedTable for the matching\n // TableDef. TS cannot infer the mapped-type result through Object.keys\n // iteration, so a single `as` bridges the gap.\n return result as TypedDB<S>;\n}\n\n// ---------------------------------------------------------------------------\n// Env-augmentation-driven typed surface — the typed-by-default `Database`.\n//\n// These types read the globally-augmented `Tables` interface from\n// `@palbase/backend/env` (filled by the generated `palbase-env.d.ts`). They\n// back `Database.public.<name>` so handler code is typed with no import and no\n// generic (C5). They DELIBERATELY do not reference `ColumnBuilder` — the env\n// `Tables` interface carries flat `row`/`insert` object types.\n// ---------------------------------------------------------------------------\n\n/** Bir where değeri: düz eşitlik YA DA operatör nesnesi (FR-016). */\n/**\n * Metin operatörleri YALNIZ metin kolonlarında görünür (FR-005).\n *\n * `contains` bir sayı kolonunda anlamsızdır ve onu tipte sunmak \"ifade edilemez\n * kıl\" ilkesinin tersidir: derleme anında yakalanabilecek bir hata çalışma\n * zamanına ertelenir. Koşullu tip ÖZYİNELEMESİZDİR (N-2).\n */\n/**\n * Bir KOLONA yapılan referans (FR-011) — karşılaştırmanın sağ tarafında değer\n * yerine durabilen tek şey.\n *\n * Şekli okunabilir (`{ $col: \"…\" }`) ama KİMLİĞİ şekli değil: nesne\n * `Symbol.for(\"palbase.db.ref\")` ile markalanır. Şekil tek başına yetseydi\n * güvenilmeyen bir istek gövdesi `{\"$col\":\"tenant_id\"}` gönderip kiracılık\n * predikatını `t.\"tenant_id\" = t.\"tenant_id\"` totolojisine çevirebilirdi —\n * ölçüldü (W2-A/C1). Marka enumerable olmadığı için JSON round-trip'i onu\n * düşürür; süreç içinde (transaction planı dahil) korunur.\n */\nexport type ColRef<N extends string = string> = { readonly $col: N };\n\nexport { isColRef };\n\n/**\n * `total > amount_paid` — bugün bunu yazmanın tek yolu ham SQL'e düşmekti,\n * çünkü sağ taraf bir DEĞER değil.\n *\n * Ad literal olarak yakalanır (`const N`), ve doğruluğu ÇAĞRIDA değil\n * KULLANIM YERİNDE kanıtlanır: filtre `WhereFilter<Row>` beklediği için\n * `ColRef<\"yok_boyle\">` oraya atanamaz. Yani `col()`'a satır tipini elle\n * vermek gerekmiyor, yanlış ad yine de derleme hatası (P5).\n *\n * Dönen nesne MARKALIDIR (`brandRef`): telden gelen `{\"$col\":\"x\"}` bir kolon\n * referansı SAYILMAZ, \"bilinmeyen operatör\" diye reddedilir. Gerekçe\n * `db/input-guards.ts`'te ölçümüyle birlikte yazılı.\n */\nexport function col<const N extends string>(name: N): ColRef<N> {\n return brandRef({ $col: name }, \"col\");\n}\n\n/** Bu satırın kolonlarından birine referans. `Row` bilinmiyorsa hiçbiri. */\n/**\n * Bir kolonun karşılaştırma AİLESİ — ve neden PG tipi değil de bu.\n *\n * ÖLÇÜLDÜ (gözcü, canlı pg16): TS tarafı PG tipini TAŞIMIYOR. `numeric`,\n * `bigint`, `text`, `uuid` ve `timestamp` hepsi `string`'e, `integer` `number`'a\n * düşüyor (`env-gen.ts:30-60`). Bu yüzden TS tipine kurulan HİÇBİR kural doğru\n * olamaz — kural ne olursa olsun bir taraf yanlışa düşer:\n *\n * { qty: { gt: col(\"amount\") } } integer ↔ numeric PG: GEÇERLİ\n * { total: { gt: col(\"note\") } } integer ↔ text PG: GEÇERSİZ\n *\n * İkisi de TS'te \"number ↔ string\". Ayırt edecek bilgi tipte YOK.\n *\n * YANLIŞ RET, YANLIŞ KABULDEN KÖTÜDÜR — ve tercih buna göre yapıldı. Yanlış bir\n * ret meşru bir sorguyu İFADE EDİLEMEZ kılar, yani yazarı `$query`'ye düşürür:\n * bu yüzeyin kapatmak için var olduğu şey. Yanlış bir kabul ise Postgres'in\n * GÜRÜLTÜLÜ hatasına çıkar (`operator does not exist: integer > text`) — kötü\n * ama sessiz değil.\n *\n * O yüzden aile ayrımı yalnız TS'in GERÇEKTEN ayırdığı yerlerde yapılıyor:\n * `boolean`, vektör dizisi ve `Date` kendi başlarına; metin ve sayı ise TEK\n * ailede, çünkü aralarındaki PG ayrımı tipte yok.\n *\n * KALICI ÇÖZÜM tipte değil ÜRETİMDE: `env-gen` kolon başına bir PG-tip markası\n * bassın (`string & { readonly __pg?: \"numeric\" }`). O zaman `numeric ↔ integer`\n * kabul, `numeric ↔ text` ret olur ve ikisi de DOĞRU olur. Defterde teklif.\n */\ntype PgFamily<V> = [NonNullable<V>] extends [boolean]\n ? \"bool\"\n : [NonNullable<V>] extends [readonly (number | string)[]]\n ? \"array\"\n : [NonNullable<V>] extends [Date]\n ? \"date\"\n : [NonNullable<V>] extends [string | number]\n ? \"scalar\"\n : \"opaque\";\n\n/** `Row`'un `V` ile karşılaştırılabilir kolonları — aynı aileden olanlar. */\ntype ColumnsComparableTo<Row, V> = {\n [K in keyof Row]-?: PgFamily<Row[K]> extends PgFamily<V> ? K : never;\n}[keyof Row];\n\n/**\n * Bu satırın kolonlarından birine referans. `Row` bilinmiyorsa hiçbiri.\n *\n * İKİNCİ PARAMETRE kolonun tipi. Verilmezse (`unknown`) KISIT YOKTUR — bu\n * `findMany`'nin `Row`'u bilmediği yolların ve jsonb kolonlarının hâli, ve\n * ikisinde de tipin söyleyebileceği bir şey yok.\n */\nexport type ColRefOf<Row, V = unknown> = [keyof Row] extends [never]\n ? never\n : [unknown] extends [V]\n ? ColRef<Extract<keyof Row, string>>\n : ColRef<Extract<ColumnsComparableTo<Row, V>, string>>;\n\n/**\n * Doğrulanmış, GÖMÜLEBİLİR bir SQL parçası (FR-018, FR-019).\n *\n * Wire şekli `{ $sql: { text, values } }`: `text` parçalar hâlinde tutulur ve\n * değerler ARADA durur, çünkü birleştirilmiş tek bir string'in içinden hangi\n * kısmın kullanıcı verisi olduğunu bir daha kimse çıkaramaz — enjeksiyonun\n * doğduğu yer tam olarak orasıdır.\n */\nexport type SqlFragment = {\n readonly $sql: { readonly text: readonly string[]; readonly values: readonly unknown[] };\n};\n\n/**\n * Retryable bir hatada işlemi yeniden dener (FR-037).\n *\n * D-016: retry'SIZ bir izolasyon yükseltmesi sunmak defect'tir — kullanıcıya\n * çalışmayan bir düğme vermektir. `SerializationFailure`'ın metni\n * *\"{ retry: n } verebilirsiniz\"* diyor; bu fonksiyon o düğmenin gerçekten\n * çalışan yarısı.\n *\n * VARSAYILAN SIFIR. Sessiz bir varsayılan retry, idempotent OLMAYAN bir işlemi\n * çağıranın haberi olmadan iki kez çalıştırırdı — bir para transferini iki kez.\n * Tekrar denemek çağıranın kararı.\n *\n * Yalnız `isRetryable(e)` olan hatalar tekrarlanır. Küme dar tutuluyor: `23505`\n * buraya girseydi tekrar denemek aynı cevabı verir ve döngü boşuna dönerdi.\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n opts: { retry?: number } = {},\n): Promise<T> {\n const budget = opts.retry ?? 0;\n let attempt = 0;\n for (;;) {\n try {\n return await fn();\n } catch (e) {\n // Bütçe bittiğinde SON hata fırlatılıyor, sarmalanmıyor: çağıranın\n // gördüğü şey Postgres'in söylediği şey olsun.\n if (attempt >= budget || !isRetryable(e)) throw e;\n attempt += 1;\n }\n }\n}\n\n/**\n * K3: sorgudan KAÇMAK için değil, sorgunun İÇİNE girmek için kaçış kapağı.\n *\n * ```ts\n * Database.public.notes.findMany({\n * where: sqlFragment`similarity(title, ${q}) > 0.3`,\n * orderBy: { column: \"created_at\", direction: \"desc\" },\n * limit: 20,\n * })\n * ```\n *\n * `select` / `orderBy` / `limit` / RLS aynen çalışmaya devam eder — \"yetmedi,\n * ham SQL'e geçeyim\" anının bugünkü maliyeti tam olarak bunları kaybetmekti.\n *\n * TANIMLAYICI GÖMME YÜZEYİ YOK (`.raw` / `.unsafe` / `.identifier`). Drizzle'ın\n * CVE-2026-39356'sı ve Knex'in CVE-2019-10757'si tam o kapakta doğdu.\n *\n * Ve kapak fonksiyonun ÜSTÜNDE olmakla bitmiyordu: parça MARKALI değilken\n * `{\"$sql\":{\"text\":[\"1=1 -- pwned\"],\"values\":[]}}` düz JSON'dan uydurulup\n * guard'ın tamamını atlıyordu (W2-B/C3, ölçüldü). Marka o kapağı wire ŞEKLİNE\n * de koyuyor — parça yalnız bu template tag'inden çıkabilir.\n */\nexport function sqlFragment(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): SqlFragment {\n return brandRef({ $sql: { text: [...strings], values } }, \"sql\");\n}\n\nexport type TextOps<V> = V extends string\n ? { contains?: string; icontains?: string; startsWith?: string; endsWith?: string }\n : Record<never, never>;\n\n/** Operatör gövdesi, kolon-referans tipi DIŞARIDAN verilmiş hâliyle.\n *\n * `C` bir parametre, çünkü `ColRefOf<Row, V>` aksi hâlde altı operatör\n * konumunda AYRI AYRI instantiate edilirdi — kolon başına altı mapped type.\n * Böyle kolon başına BİR tane (N-2). */\ntype WhereOpBody<V, C> = {\n gt?: V | C;\n gte?: V | C;\n lt?: V | C;\n lte?: V | C;\n neq?: V | C;\n in?: V[];\n /** `IS NULL` / `IS NOT NULL` (FR-006) — `= NULL` SQL'de her zaman UNKNOWN'dır. */\n isNull?: boolean;\n} & TextOps<V>;\n\nexport type WhereOp<V, Row = unknown> = WhereOpWith<V, ColRefOf<Row, V>>;\n\n/**\n * Operatör sözlüğü, kolon-referans/plan-tutamağı konumu DIŞARIDAN verilmiş.\n *\n * `export`, çünkü plan yüzeyi (`tx-plan.ts`) aynı sözlüğü `C = ColRefOf<…> |\n * Ref<…>` ile kuruyor: bir plan filtresi ÖNCEKİ bir işlemin sonucuna\n * bakabiliyor, `findMany` bakamıyor. Ref'i `V`'ye eklemek YANLIŞ olurdu —\n * `TextOps<V>` `V extends string` diye soruyor ve `string | Ref<string>` o\n * soruya HAYIR der, yani `contains`/`startsWith` sessizce KAYBOLURDU.\n */\nexport type WhereOpWith<V, C> = V | C | WhereOpBody<V, C>;\n\n/**\n * A filter over a row: every field optional, each one a plain value (equality)\n * or an operator object. THE filter language — `findMany`, `updateMany`,\n * `deleteMany` and `count` all take this one, because two spellings of a filter\n * is how the two come to disagree.\n */\nexport type WhereFilter<Row> = { [K in keyof Row]?: WhereOp<Row[K], Row> } & {\n /**\n * Boolean bileşimi (FR-007). Dallar aynı filtre dilidir — iki yazım olmaz.\n *\n * ÖZYİNELEME BURADA BAŞLIYOR ve N-2'nin izlediği şey tam olarak budur:\n * Kysely'nin TS7'de 9,8M instantiation üreten vakası derin generic\n * özyinelemeydi. Burada derinlik yazarın filtresi kadardır ve pratikte\n * bir-iki seviyedir; tip maliyeti T001'in tavanına karşı ölçülür.\n */\n OR?: WhereFilter<Row>[];\n AND?: WhereFilter<Row>[];\n NOT?: WhereFilter<Row>;\n};\n\n/**\n * Ordering and paging for a read.\n *\n * `column` is `keyof Row`, not `string`: a mistyped column name is a compile\n * error here rather than a runtime rejection three layers down. `offset`\n * without `limit` is refused by the engine — a page with no size is not a page.\n */\nexport type OrderBySpec<Row> = {\n column: Extract<keyof Row, string>;\n direction?: \"asc\" | \"desc\";\n /** NULL'ların yeri (FR-008). Verilmezse Postgres varsayılanı geçerlidir ve o\n * varsayılan YÖNE GÖRE DEĞİŞİR: ASC'de NULLS LAST, DESC'te NULLS FIRST. */\n nulls?: \"first\" | \"last\";\n};\n\ntype FindManyOpts<Row> = {\n /** Tek sıralama ya da SIRALI liste — sıra korunur (FR-008). */\n orderBy?: OrderBySpec<Row> | OrderBySpec<Row>[];\n limit?: number;\n offset?: number;\n};\n\n/**\n * Bir okumanın TEK parametresi (FR-004b).\n *\n * `where` bir ALAN, konumsal bir argüman değil. Kullanıcının kararı: \"deterministik\n * olması lazım, tek düzlem\" — aynı bilginin iki yere dağılması, alanlar çoğaldıkça\n * (select/include/orderBy) \"hangisi nereye\" sorusunu ezberlenecek bir şeye çevirir.\n * Prisma ve Drizzle de tek obje kullanıyor. Bedeli açık ve kabul edildi: en sık\n * kullanım uzuyor — `findMany({ where: { owner: uid } })`.\n *\n * ÖZYİNELEMESİZ kalmak zorunda (N-2): tip maliyeti şekilden değil özyineleme\n * derinliğinden geliyor (Kysely'nin TS7'de 9,8M instantiation vakası).\n */\n/**\n * `has` — İLİŞKİ ÜZERİNDEN SÜZME, JOIN'in ihtiyaç duyulmayan hâli.\n *\n * ```ts\n * Database.public.interests.findMany({\n * where: { has: { user_interests: { user_id: uid } } },\n * orderBy: [{ column: \"sort_order\" }, { column: \"name\" }],\n * })\n * ```\n * → `… WHERE t.\"id\" IN (SELECT r1.\"interest_id\" FROM \"user_interests\" r1\n * WHERE r1.\"user_id\" = $1)`\n *\n * İlişki ADLARI ve gittikleri kolonlar `palbase-env.d.ts`'in ZATEN bastığı\n * `relations` bloğundan geliyor — yabancı anahtarlardan türetiliyorlar, yazar\n * hiçbir kolon adı yazmıyor. O blok üretiliyordu ve HİÇBİR okuma onu\n * kullanmıyordu; `has` onun karşılığı.\n *\n * İç filtre AYNI dil: bir tablo ötesinde de `gt`, `icontains`, `OR`, ve iç içe\n * `has` yazılabiliyor.\n */\n/**\n * İlişkinin HEDEF TABLOSU — anahtar ŞEMA NİTELİKLİ gelir.\n *\n * `buildRelations` `to`'yu `qualifiedTableKey` ile yazıyor: public için düz ad\n * (`\"interests\"`), başka şema için noktalı (`\"billing.invoices\"`). `Tables`\n * yalnız public'i taşır, diğerleri `Schemas`'tadır — noktalı anahtarı doğrudan\n * `Tables`'ta aramak HER ZAMAN ıskalar ve iç filtre sessizce `Record<string,\n * unknown>`'a düşerdi: bilinmeyen kolon da, yanlış tip de derlenirdi (ölçüldü).\n */\ntype RelatedTable<To> = To extends `${infer S}.${infer T}`\n ? S extends keyof Schemas\n ? T extends keyof Schemas[S]\n ? Schemas[S][T]\n : never\n : never\n : To extends keyof Tables\n ? Tables[To]\n : never;\n\ntype RelatedRow<To> = RelatedTable<To> extends { row: infer R } ? R : Record<string, unknown>;\ntype RelatedRels<To> = RelatedTable<To> extends { relations: infer R } ? R : unknown;\n\n/**\n * İç içe `has` ÜÇ seviyeyle sınırlı.\n *\n * Üretilen `relations` bloğu ÇİFT YÖNLÜ: `customers.invoices` ile\n * `invoices.customer` birbirini gösteriyor, yani grafiğin kendisi döngülü.\n * Sınırsız açılım bu döngüyü sonsuz bir tipe çevirirdi — TypeScript'in\n * \"excessively deep\" hatası, yazılan sorgunun karmaşıklığından değil ŞEMANIN\n * şeklinden gelirdi. Üç seviye, ölçtüğümüz tüm gerçek sorguların üstünde.\n */\ntype HasDepth = 0 | 1 | 2 | 3;\ntype HasDec = [0, 0, 1, 2];\ntype HasNest<Rels, D extends HasDepth> = [keyof Rels] extends [never]\n ? unknown\n : D extends 0\n ? unknown\n : { has?: HasFilter<Rels, HasDec[D]> };\n\ntype HasFilter<Rels, D extends HasDepth = 3> = {\n [R in keyof Rels]?: Rels[R] extends { to: infer To }\n ? WhereFilter<RelatedRow<To>> & HasNest<RelatedRels<To>, D>\n : never;\n};\n\n/** İlişki bilgisi taşıyan bir tablo tipinin filtre yüzeyi. */\nexport type WhereWithRelations<Row, Rels> = WhereFilter<Row> & { has?: HasFilter<Rels> };\n\n/**\n * `has` dalı — SADECE `has`, satır filtresi olmadan.\n *\n * Plan yolunun filtre dili (`TxWhere`) düz op'unkiyle aynı değil: orada bir\n * alan ÖNCEKİ bir işlemin satırına referans (`Ref`) taşıyabiliyor. `has`'ı\n * plana taşımak için o dili kopyalamak gerekmiyor — kesişimle EKLENİYOR.\n * İlişki yoksa `unknown` dönüyor, çünkü `X & unknown = X`: dal yok olur ve\n * `has` fazla-alan denetimine takılır.\n */\nexport type HasOnly<Rels> = [unknown] extends [Rels]\n ? unknown\n : [keyof Rels] extends [never]\n ? unknown\n : { has?: HasFilter<Rels> };\n\n/**\n * `has` dalı NE ZAMAN var olur.\n *\n * İlişkisi OLMAYAN bir tabloda `has` hiç yazılamamalı. `HasFilter<{}>` boş bir\n * nesne tipidir ve boş nesne tipi HER nesneyi kabul eder — yani dalı koşulsuz\n * eklemek, ilişkisiz bir tabloda `has: { neyse_ne: {} }`'yi SESSİZCE geçirirdi\n * (ölçüldü: kapı yeşil, çalışma anında \"böyle bir ilişki yok\" hatası).\n */\ntype HasBranch<Row, Rels> = [unknown] extends [Rels]\n ? never\n : [keyof Rels] extends [never]\n ? never\n : WhereWithRelations<Row, Rels>;\n\nexport type QueryInput<Row, K extends keyof Row = keyof Row, Rels = unknown> = {\n /**\n * Filtre — ya tipli filtre dili ya da bir `sqlFragment` (FR-018). İkisi de\n * AYNI alandır: kademe atlamak bir parametre değişikliği, ayrı bir çağrı\n * yolu değil (P1).\n */\n where?: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;\n /**\n * Projeksiyon (FR-009): yalnız bu kolonlar çekilir ve DÖNÜŞ TİPİ buna daralır.\n *\n * Tip `Pick<Row, K>` ile TÜRETİLİR, üretilmez: `select` kombinasyonları için\n * tip basmak, üretilen `.d.ts`'i kombinatoryal olarak şişirirdi (N-1: tablo\n * başına ≤ 25 satır).\n */\n select?: readonly K[];\n} & FindManyOpts<Row>;\n\n/** Bir yazmanın TEK parametresi: neyi (`where`) neye çevirdiğin (`set`). */\nexport type MutateInput<Row, Insert, Rels = unknown> = {\n where: WhereFilter<Row> | SqlFragment | HasBranch<Row, Rels>;\n set: SetShape<Insert>;\n};\n\n/**\n * `set`'e yazılabilen değer (FR-012): kolonun kendi tipi ya da — sayısal\n * kolonlarda — kolonun ŞU ANKİ değerini okuyan bir ifade.\n *\n * `increment()` metin ya da boolean kolonda YOK: \"kolona ekle\"nin orada bir\n * anlamı olmadığı için ifade edilemez kılınıyor (P5 — anlatmak değil, ifade\n * edilemez kılmak). `numeric` kolonlar TypeScript'te `string` taşır, o yüzden\n * string de sayısal sayılır; ayrımı burada yapamayız, ama D-007 zaten miktarın\n * JS `number`'a hiç uğramamasını istiyor.\n */\nexport type SetValue<V> =\n | V\n | (NonNullable<V> extends number | string ? TxColumnExpr : never)\n // `now()` doğrudan yolda da geçerli: motor onu `SET col = now()` diye\n // derliyor (plan yolunun her zaman yaptığı gibi). Tipte yasaklamak, çalışan\n // bir çağrıyı ifade edilemez kılardı — P5'in tersi.\n | (NonNullable<V> extends Date ? TxNow : never);\n\n/** Bir update'in `set`'i: insert şeklinin herhangi bir alt kümesi, ifadelerle. */\nexport type SetShape<Insert> = { [K in keyof Insert]?: SetValue<Insert[K]> };\n\n/** search() parametreleri, satır tipiyle koşullanmış (FR-013). `offset` BİLEREK yok (UD-013). */\nexport interface SearchParamsTyped<T extends TableTypes> {\n /** Metin sorgusu: FTS kolunu besler; embed beyanlıysa sorgu vektörü de bundan üretilir. */\n query?: string;\n /** Hazır sorgu vektörü — verilirse embed çağrısı olmaz (FR-025). */\n vector?: number[];\n /** `findMany`'nin filtre dili — İKİNCİ tip argümanıyla, yoksa `Row` sessizce\n * `unknown`'a düşer ve `col()` burada ifade edilemez olurdu. Motor `search`\n * için aynı `compileWhereBare`'i kullanıyor; yetenek orada (gözcü I7). */\n where?: { [K in keyof T[\"row\"]]?: WhereOp<T[\"row\"][K], T[\"row\"]> };\n /** default 20, tavan 100 (engine uygular). */\n limit?: number;\n /** Birden çok vektör kolonunda hedef seçimi (model geçişi, FR-013/using). */\n using?: string;\n mode?: \"hybrid\" | \"text\" | \"vector\";\n /** Nihai (RRF-sonrası) skor alt eşiği — süzme LIMIT'ten önce uygulanır (FR-001). */\n minScore?: number;\n /** Chunk-modunda satır başına en iyi blok sayısı (1..10, vars. 3; FR-015). */\n blocksPerRow?: number;\n /** Tazelik çürümesi: nihai skor RRF-sonrası exp(-ln(2)*yaş/halfLife) ile çarpılır;\n * field bir timestamp kolonu, halfLife \"90s\" | \"15m\" | \"12h\" | \"30d\" biçiminde (FR-004). */\n recency?: { field: Extract<keyof T[\"row\"], string>; halfLife: string };\n /** Satır-modunda FTS eşleşme vurgusu: sonuç satırına `_highlight` ekler;\n * chunk-modda no-op — bloklar zaten eşleşen kesittir (FR-025). */\n highlight?: boolean;\n /** Validity'li tabloda zaman penceresi: varsayılan yalnız güncel versiyon;\n * \"all\" tüm versiyonlar; {asOf} o anda geçerli olan (FR-029). */\n validity?: \"all\" | { asOf: string };\n /** Alan-boost (FR-030): skor * (1 + w·x/(1+x)) — sayısal kolonla sınırlı\n * çarpan, dış servissiz; bileşim RRF → boost → recency → minScore. */\n boost?: { field: Extract<keyof T[\"row\"], string>; weight: number };\n}\n\n/**\n * `facets()` dönüşü (FR-027, FR-058): kolon adı → o kolonun top-20 değeri ve\n * sayacı.\n *\n * Bu tip bir zamanlar `search()` dönüş DİZİSİNİN üstünde taşınıyordu; dizi-üstü\n * özellik `JSON.stringify`'da kayboluyor, yani bir kontrolcü onu döndürmeye\n * çalıştığında yanıt gövdesinde hiç görünmüyordu. Sayaçlar artık BAĞIMSIZ\n * dönüşle geliyor ve tip de o dönüşü adlandırıyor.\n */\nexport type SearchFacets = Record<string, { value: string | null; count: number }[]>;\n\n/** similar()/recommend() taşıyıcı opsiyonları (T018, FR-022): search'ün\n * paramlarından query/vector/mode düşer — hedef vektörü metodun kendisi\n * DB'den kurar; facets/highlight de düşer (T020) — engine bu ikisini\n * similar/recommend'e geçirmez, tip vaadi gerçekle aynı kalır. */\nexport type SimilarParamsTyped<T extends TableTypes> = Omit<\n SearchParamsTyped<T>,\n \"query\" | \"vector\" | \"mode\" | \"facets\" | \"highlight\"\n>;\n\n/** recommend() parametreleri (T018, FR-023). */\nexport type RecommendParamsTyped<T extends TableTypes> = SimilarParamsTyped<T> & {\n /** Kaynak beğeniler — hedef vektör bunların DB-içi avg'ı; boş olamaz. */\n positive: string[];\n /** İtilen örnekler — hedef pos.v + (pos.v - neg.v) ile yönlenir. */\n negative?: string[];\n};\n\n/**\n * Tablonun ilişki bloğu — env `Tables` girdisinden.\n *\n * TEK yerde türetiliyor ve HER op'a aynısı veriliyor: `has` yalnız `findMany`'de\n * olsaydı, \"aynı filtre dili her op'ta\" sözü ilk `deleteMany`'de kırılırdı.\n */\ntype RelsOf<T> = T extends { relations: infer R } ? R : unknown;\n\n/** Temel tablo erişimcisi — search'süz beş op. */\nexport interface EnvTypedTableBase<T extends TableTypes> {\n insert(data: T[\"insert\"]): Promise<T[\"row\"]>;\n /**\n * Bir idempotency anahtarını sahiplen (FR-033).\n *\n * ```ts\n * const { inserted, row } = await Database.public.payments.claim(\n * { idem_key: req.headers[\"idempotency-key\"] },\n * { amount, user_id },\n * );\n * if (!inserted) return row; // aynı istek ikinci kez geldi\n * ```\n *\n * `inserted: false` bir HATA DEĞİL: dönen satır ilk çağrının satırıdır.\n * İlk argüman satırı BULAN alanlar, ikincisi yalnız yazılanlar — ikinci çağrı\n * farklı bir yük gönderse bile satır anahtarla bulunur.\n */\n claim(\n unique: Partial<T[\"insert\"]>,\n extra?: Partial<T[\"insert\"]>,\n ): Promise<{ inserted: boolean; row: T[\"row\"] }>;\n /**\n * Satırı yaz; `onConflict` kolonlarında çakışırsa ÜZERİNE yaz (FR-034).\n *\n * ```ts\n * await Database.public.settings.put({\n * data: { user_id, theme: \"dark\" },\n * onConflict: [\"user_id\"],\n * });\n * ```\n *\n * `onConflict` kolonları benzersiz bir kısıt ya da index taşımalı — Postgres\n * onlarla eşleştirir — ve güncellemeden dışlanırlar, çünkü eşleşen şey onlar.\n *\n * **`upsert`'ün yerine geldi ve adı bilerek değişti.** `upsert` tek isim\n * altında iki niyet taşıyordu: \"yoksa ekle varsa güncelle\" (bu) ve \"idempotent\n * yaz\" (artık {@link EnvTypedTableBase.claim}). İkincisi için ÖLÇÜLMÜŞ biçimde\n * yanlıştı: `DO UPDATE` ikinci çağrının verisiyle birincininkini EZİYOR\n * (10.00 → 999.00 ölçüldü). İki niyeti tek isimde tutmak, yanlış olanı\n * seçmeyi kolay yapıyordu.\n */\n put(q: {\n data: T[\"insert\"];\n onConflict: readonly Extract<keyof T[\"row\"], string>[];\n }): Promise<T[\"row\"]>;\n /** Update the row by id; resolves to the updated row, or `null` if no row\n * matched (absent or RLS-hidden) — an idempotent outcome, mirroring\n * `findById`. The runtime returns a null row rather than throwing. */\n update(q: { where: { id: string }; set: 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<K extends keyof T[\"row\"] = keyof T[\"row\"]>(\n q?: QueryInput<T[\"row\"], K, RelsOf<T>>,\n ): Promise<Pick<T[\"row\"], K>[]>;\n /**\n * Update every matching row in one statement; an empty filter is refused.\n *\n * **0 satır dönmesi hata DEĞİL, başarı da değil** (FR-014): koşulu `where`'e\n * koyup dönen diziyi kontrol etmek, \"önce oku sonra yaz\"ın yarış koşulu\n * olmayan hâlidir.\n *\n * ```ts\n * const [row] = await Database.public.accounts.updateMany({\n * where: { id, balance: { gte: amount } },\n * set: { balance: decrement(amount) },\n * });\n * if (row === undefined) throw new Conflict(\"yetersiz bakiye\");\n * ```\n */\n updateMany(q: MutateInput<T[\"row\"], T[\"insert\"], RelsOf<T>>): Promise<T[\"row\"][]>;\n /** Delete every matching row; resolves to how many. Empty filter refused. */\n deleteMany(q: { where: WhereFilter<T[\"row\"]> | SqlFragment | HasBranch<T[\"row\"], RelsOf<T>> }): Promise<number>;\n /** How many rows match. An empty filter is legitimate: counting is a read. */\n count(q?: { where?: WhereFilter<T[\"row\"]> | SqlFragment | HasBranch<T[\"row\"], RelsOf<T>> }): Promise<number>;\n /** Validity'li tabloda satırın yeni versiyonu (FR-029, C-9): eski satır\n * kapanır (valid_to/superseded_by), yenisi TEK savepoint'te eklenir; dönüş\n * yeni satır. Validity beyanı olmayan tabloda adlandırılmış çalışma-zamanı\n * hatası — tip düzeyinde ayrım env `Tables` bayrağı taşımadığından yapılamaz. */\n supersede(id: string, row: T[\"insert\"]): Promise<T[\"row\"]>;\n}\n\n/** Tablo erişimcisi: env girdisi `searchable: true` taşıyorsa (vector kolonu ya da\n * search beyanı — env-gen üretir) `search()` üyesi VARDIR; yoksa üye hiç yoktur ve\n * çağrı derleme hatasıdır (FR-013). Yapısal koşul TableTypes'ı genişletmeden çalışır. */\n/**\n * `appendOnly` tabloda YAYIMLANMAYAN üyeler (FR-031).\n *\n * Altısı da ayrı ayrı: biri unutulursa append-only sözü o üye üzerinden sessizce\n * delinir. `insert` ve okuma üyeleri kalır — düzeltme SİLMEKLE değil, telafi\n * kaydı EKLEMEKLE yapılır (FR-032).\n */\ntype AppendOnlyForbidden = \"update\" | \"updateMany\" | \"delete\" | \"deleteMany\" | \"put\" | \"supersede\";\n\nexport type EnvTypedTable<T extends TableTypes> = (T extends { appendOnly: true }\n ? Omit<EnvTypedTableBase<T>, AppendOnlyForbidden>\n : EnvTypedTableBase<T>) &\n (T extends { searchable: true }\n ? {\n search(\n params: SearchParamsTyped<T>,\n ): Promise<Array<T[\"row\"] & { _score: number; _highlight?: string }>>;\n /** \"Bu satıra benzeyenler\" (FR-022): hedef vektör DB'den okunur,\n * kaynak satır sonuçta yoktur; id yoksa adlandırılmış hata. */\n similar(id: string, params?: SimilarParamsTyped<T>): Promise<Array<T[\"row\"] & { _score: number }>>;\n /** D-021: sayaçlar bağımsız dönüşle — search'ün dizi-üstü _facets'i\n * JSON.stringify'da kaybolur; ciddi sözleşme budur. */\n facets(params: { facets: Array<keyof T[\"row\"] & string>; where?: Partial<T[\"row\"]>; validity?: \"all\" | { asOf: string } }): Promise<SearchFacets>;\n /** positive/negative beğenilerden öneri (FR-023): hedef vektör DB-içi\n * avg CTE'leriyle; kaynak id'ler sonuçta yoktur. */\n recommend(params: RecommendParamsTyped<T>): Promise<Array<T[\"row\"] & { _score: number }>>;\n }\n : Record<never, never>);\n\n/** The `tables` map exposed on `Database`/`tx`, keyed by the env `Tables`\n * interface. When no schema is declared `Tables` is empty, so `tables` is an\n * empty object — accessing `.tables.foo` is then a compile error (no member). */\nexport type EnvTables = {\n [K in keyof Tables]: EnvTypedTable<Tables[K]>;\n};\n\n/**\n * The project's NON-public schemas, keyed by schema name, each exposing its own\n * `tables` map — the shape `Database.schema(\"billing\")` returns.\n *\n * The intermediate `tables` is there for the reason {@link EnvTables} sits under\n * `.tables`: a schema's table names must not share a namespace with anything the\n * accessor itself might grow.\n *\n * Empty by default. The generated `palbase-env.d.ts` augments `Schemas` with one\n * member per declared schema other than `public`, so a project that declares\n * none has `keyof Schemas = never` and every `schema(...)` call is a compile\n * error rather than a runtime surprise.\n */\n/**\n * @deprecated ARTIK VAR OLMAYAN BİR ŞEKLİ tarif ediyor. Bu tip her şemayı\n * `{ tables: … }` altında gösteriyor; yüzey FR-001 ile `Database.<şema>.<tablo>`\n * oldu ve `.tables` ara katmanı KALKTI. Güncel şekil: {@link EnvSchemaSurface}.\n *\n * Kaldırılmadı çünkü dışa açık bir tip ve kaldırmak SEKİZİNCİ bir kırıcı olurdu;\n * ama bir tip, çalışma zamanının ÜRETMEDİĞİ bir şekli tarif ediyorsa yalan\n * söylüyor demektir — `const x: EnvSchemas[\"billing\"] = Database.billing`\n * açıklanamayan bir derleme hatası verir. Bir sonraki kırıcı sürümde silinmeli\n * (defter D-18).\n *\n * Bu tipi ÜRETEN iki fonksiyon (`makeTablesAccessor`, `makeSchemaAccessor`)\n * ölçüldü: hiçbir yerden çağrılmıyorlardı ve silindiler. Canlı yol\n * `makeTypedSurface`'ın proxy'si.\n */\nexport type EnvSchemas = {\n [S in keyof Schemas]: {\n tables: {\n [T in keyof Schemas[S]]: EnvTypedTable<Extract<Schemas[S][T], TableTypes>>;\n };\n };\n};\n\n/** The project's tables as PLAN operations, keyed by the env `Tables`\n * interface. The transaction twin of {@link EnvTables}. */\n/** `appendOnly` bir tabloda transaction planının da kaybettiği üyeler. Doğrudan\n * yüzeyin `AppendOnlyForbidden`'ının plan-yolu ikizi; adlar farklı çünkü plan\n * yüzeyinin üye adları farklı. */\ntype TxAppendOnlyForbidden = \"put\" | \"updateWhere\" | \"deleteWhere\";\n\n/**\n * Plan yüzeyi de `appendOnly`'yi UYGULUYOR — ve uygulamıyor olması bir kusurdu.\n *\n * `EnvTypedTable` altı üyeyi Omit ediyordu, ama `TxTables` hiçbirini: yani\n * `tx.tables.entries.updateWhere(…)` ve `.put(…)` DERLENİYORDU. Tip bir şeyi\n * \"ifade edilemez\" ilan edip ikinci bir kapıda ifade edilebilir bırakırsa,\n * ilan yalandır (doğrulayıcı gözcü, FR-031).\n *\n * Motor da aynı üçünü adıyla reddediyor — tip atlanınca susmaması için.\n */\nexport type TxTables = {\n [K in keyof Tables]: Tables[K] extends { appendOnly: true }\n ? Omit<TxTable<Tables[K][\"row\"], Tables[K][\"insert\"], RelsOf<Tables[K]>>, TxAppendOnlyForbidden>\n : TxTable<Tables[K][\"row\"], Tables[K][\"insert\"], RelsOf<Tables[K]>>;\n};\n\n/** Bir şemanın tabloları PLAN operasyonları olarak — `TxTables`'ın public\n * DIŞI şemalar için ikizi. */\ntype TxTablesOf<S> = {\n [T in keyof S]: Extract<S[T], TableTypes> extends { appendOnly: true }\n ? Omit<\n TxTable<\n Extract<S[T], TableTypes>[\"row\"],\n Extract<S[T], TableTypes>[\"insert\"],\n RelsOf<Extract<S[T], TableTypes>>\n >,\n TxAppendOnlyForbidden\n >\n : TxTable<\n Extract<S[T], TableTypes>[\"row\"],\n Extract<S[T], TableTypes>[\"insert\"],\n RelsOf<Extract<S[T], TableTypes>>\n >;\n};\n\n/**\n * Plan tutamağının şema yüzeyi — `EnvSchemaSurface`'ın BİREBİR ikizi.\n *\n * NEDEN AYNI ŞEKİL: `Database.billing.invoices` yazılabiliyorken\n * `tx.billing.invoices` yazılamıyordu, yani `billing` şemasındaki iki tabloyu\n * TEK ATOMİK PLANDA yazmak imkânsızdı — yazar `$query`'ye düşüyor, tipi ve RLS\n * yardımını kaybediyordu. Bu yüzeyin kapatmak için var olduğu düşüşün ta\n * kendisi, ve GOAL'ün \"ciddi ölçekli fintech\" yarısının tam ortasında\n * (nihai inceleme I-6).\n */\nexport type TxSchemaSurface = { public: TxTables } & {\n [S in keyof Schemas]: TxTablesOf<Schemas[S]>;\n};\n\n/**\n * The handle a `Database.$transaction(…)` callback receives.\n *\n * Tables only — no `query`, no `findById`, no `asService`. A read whose value\n * the plan does not write belongs outside the transaction, where it costs one\n * round trip and is an ordinary value you can branch on.\n *\n * `tx.public.x` ve `tx.<şema>.x`, `Database` ile aynı şekil. `tx.tables.x`\n * public'in TAKMA ADI olarak duruyor: bu run'ın göç notu onu öğretiyor ve her\n * mevcut çağrı onu kullanıyor — kaldırmak sekizinci bir kırıcı olurdu ve\n * hiçbir şey kazandırmazdı.\n */\nexport type TxPlan = TxPlanHandle<TxTables> & TxSchemaSurface;\n\n/**\n * The RLS-bypass sibling returned by `Database.$asService()`. Same typed surface\n * as {@link EnvTypedDatabase} — `tables`, the raw string ops, and a typed\n * `transaction` — but it does NOT re-expose `asService` (no double-bypass).\n * Every op it performs runs as the `service_role` (BYPASSRLS).\n */\nexport type EnvServiceDatabase = EnvSchemaSurface & {\n /** Ham SQL. Generic verilmezse `unknown[]` döner (FR-021). */\n $query: DBClient[\"query\"];\n $insert: DBClient[\"insert\"];\n $update: DBClient[\"update\"];\n $delete: DBClient[\"delete\"];\n $findById: DBClient[\"findById\"];\n $findMany: DBClient[\"findMany\"];\n $put: DBClient[\"put\"];\n $updateMany: DBClient[\"updateMany\"];\n $deleteMany: DBClient[\"deleteMany\"];\n $count: DBClient[\"count\"];\n $search: DBClient[\"search\"];\n $similar: RecoOps[\"similar\"];\n $recommend: RecoOps[\"recommend\"];\n $facets: DBClient[\"facets\"];\n $supersede: DBClient[\"supersede\"];\n $claim: DBClient[\"claim\"];\n $lockRows: DBClient[\"lockRows\"];\n $advisoryXactLock: DBClient[\"advisoryXactLock\"];\n $attempt: DBClient[\"attempt\"];\n /** Bkz. {@link EnvTypedDatabase.$transaction}. */\n /**\n * `opts.retry` verilirse, `SerializationFailure` / `DeadlockDetected`\n * alındığında plan BAŞTAN kurulup yeniden çalıştırılır (FR-037).\n * Varsayılan 0 — sessiz bir retry, idempotent olmayan bir işlemi çağıranın\n * haberi olmadan iki kez çalıştırırdı.\n */\n $transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n opts?: { retry?: number },\n ): Promise<Materialized<T>>;\n }\n\n/**\n * The typed-by-default Database surface: the raw string-keyed `DBClient` ops\n * PLUS a `tables` map typed against the project's generated `palbase-env.d.ts`,\n * a `transaction` that runs a whole plan in one request, and `asService()` for\n * the explicit RLS-bypass sibling.\n *\n * The low-level `txPlan` op is deliberately NOT re-exposed here: `transaction`\n * is the surface, and a hand-built plan would bypass the ref/guard machinery\n * that makes one safe to write.\n */\nexport type EnvSchemaSurface = { public: EnvTables } & {\n [S in keyof Schemas]: {\n [T in keyof Schemas[S]]: EnvTypedTable<Extract<Schemas[S][T], TableTypes>>;\n };\n};\n\n/**\n * `$` öneki, sistem üyelerini kullanıcı adlarından AYIRAN şeydir (FR-002/003).\n *\n * `Database` altında on beşten fazla string-anahtarlı op var ve çoğu son derece\n * makul bir tablo adı — `transaction` bir fintech şemasında neredeyse kaçınılmaz.\n * Şema doğrulayıcısı bir tablo/şema adının `$` ile başlamasına izin vermediği\n * için (`^[a-zA-Z_][a-zA-Z0-9_]*`), önek çakışmayı MATEMATİKSEL olarak imkânsız\n * kılar: bir isim ya `$`'la başlar (sistem) ya başlamaz (kullanıcı).\n */\nexport type DollarOps<T> = { [K in keyof T as `$${string & K}`]: T[K] };\n\n// NOT: `EnvTypedDatabase` bu yardımcıyı KULLANMIYOR, üyelerini AÇIKÇA yazıyor.\n// Sebep ölçüldü: `database.test.ts`'in sayımı TypeScript checker'ıyla yürüyor ve\n// her property'nin declaration'ını arıyor; mapped type ile yeniden adlandırılan\n// property'ler SYNTHETIC'tir, declaration taşımaz, dolayısıyla sayımda GÖRÜNMEZ.\n// Görünmeyen bir yüzey denetlenemez — o testin varlık sebebi de bu. Yardımcı,\n// runtime tarafındaki `satisfies` kontrolü için duruyor.\n\n/**\n * Projenin veri yüzeyi: `Database.<şema>.<tablo>` + `$` önekli sistem üyeleri.\n *\n * Bugünkü `tables` ve `schema(\"x\")` ikilisinin yerine geçer (FR-001). İki yol\n * tek yola iner: `public` de diğer şemalar gibi adıyla anılır, ara katman yoktur.\n *\n * @example\n * await Database.public.notes.findMany({ where: { owner: uid } });\n * await Database.billing.invoices.findMany({ where: { paid: false } });\n * await Database.$transaction((tx) => { … });\n */\nexport type EnvTypedDatabase = EnvSchemaSurface & {\n /** Ham SQL. Generic verilmezse `unknown[]` döner (FR-021). */\n $query: DBClient[\"query\"];\n $insert: DBClient[\"insert\"];\n $update: DBClient[\"update\"];\n $delete: DBClient[\"delete\"];\n $findById: DBClient[\"findById\"];\n $findMany: DBClient[\"findMany\"];\n $put: DBClient[\"put\"];\n $updateMany: DBClient[\"updateMany\"];\n $deleteMany: DBClient[\"deleteMany\"];\n $count: DBClient[\"count\"];\n $search: DBClient[\"search\"];\n $similar: RecoOps[\"similar\"];\n $recommend: RecoOps[\"recommend\"];\n $facets: DBClient[\"facets\"];\n $supersede: DBClient[\"supersede\"];\n $claim: DBClient[\"claim\"];\n $lockRows: DBClient[\"lockRows\"];\n $advisoryXactLock: DBClient[\"advisoryXactLock\"];\n $attempt: DBClient[\"attempt\"];\n /** RLS'i bypass eden kardeş yüzey. Kendisi `$asService` TAŞIMAZ — çift bypass yok. */\n $asService(): EnvServiceDatabase;\n /**\n * Bir transaction çalıştırır. Callback işlemleri TARİF eder; tarifin tamamı\n * tek istekte gider ve broker onu tek bir transaction içinde koşturur.\n * Callback SENKRONDUR: döndüğünde hiçbir şey çalışmamıştır.\n */\n /**\n * `opts.retry` verilirse, `SerializationFailure` / `DeadlockDetected`\n * alındığında plan BAŞTAN kurulup yeniden çalıştırılır (FR-037).\n * Varsayılan 0 — sessiz bir retry, idempotent olmayan bir işlemi çağıranın\n * haberi olmadan iki kez çalıştırırdı.\n */\n $transaction<T>(\n fn: (tx: TxPlan) => T extends Promise<unknown> ? never : T,\n opts?: { retry?: number },\n ): Promise<Materialized<T>>;\n }\n","// The wire shape of a declared schema — what the deploy reads.\n//\n// `defineSchema(...)` produces a value full of builders and phantom types, which\n// is the right shape for authoring and the wrong shape for anything outside this\n// process. The deploy is Go: it introspects the live database, diffs it against\n// the declaration, and applies the difference. So the declaration has to leave\n// TypeScript as data, and this file is where that happens.\n//\n// It lives in the SDK because the SDK owns the DSL. The alternative — a script\n// beside the deploy that reaches into `._def` — is a second reading of a private\n// shape, and it drifts the moment a column gains a property: the DSL keeps\n// working, the emitter silently omits it, and the database is missing something\n// nobody can see in the source.\n//\n// The field names below are a CONTRACT with Go's `schema.SchemaJSON`. Renaming\n// one here without renaming it there produces a declaration that parses to\n// something emptier than it was — the failure mode being a column, a policy, or\n// a whole table that quietly never gets created.\n// Politika ifadesinin tel şekli `policy.ts`'te TEK kez bildiriliyor. İki kopya\n// olsaydı biri `exists` düğümünü alır, diğeri almaz ve fark ancak Go tarafı\n// bilmediği bir `kind` gördüğünde ortaya çıkardı.\nimport type { PolicyExpr as PolicyExprJSON } from \"./policy.js\";\nexport type { PolicyExpr as PolicyExprJSON } from \"./policy.js\";\nimport type { ColumnBuilder, ColumnDef } from \"./columns.js\";\nimport type { PolicyDef } from \"./policy.js\";\nimport type { MemoryDecl, SchemaDef, SearchDecl, TableDef } from \"./schema.js\";\n\n/** One column, flattened. Mirrors Go's `schema.ColumnJSON`. */\nexport interface ColumnJSON {\n type: string;\n nullable: boolean;\n primaryKey: boolean;\n defaultValue?: unknown;\n defaultRandom?: boolean;\n defaultNow?: boolean;\n renamedFrom?: string;\n /** See Go's `schema.ColumnJSON.Ignored` — the contraction gate's only signal. */\n ignored?: boolean;\n owns?: boolean;\n references?: { table: string; column: string };\n onDeleteAction?: string;\n /** FR-044: türev FK index'i kapatılmışsa `false`. Bildirilmemişse alan YOK. */\n index?: boolean;\n /** FR-049: kolon increment() ile güncelleniyorsa `true`. Aksi hâlde alan YOK. */\n counter?: boolean;\n enumName?: string;\n enumValues?: string[];\n unique?: boolean;\n dimensions?: number;\n}\n\n/** One RLS policy. Mirrors Go's `schema.PolicyJSON`. */\nexport interface PolicyJSON {\n name: string;\n command: string;\n roles: string[];\n /**\n * `USING (...)` — ham string (kaçış kapağı, FR-028) ya da YAPI (FR-022).\n *\n * Go tarafı ikisini de okur: string olan verbatim emit edilir, yapı olan\n * `generator.go`'da SQL'e çevrilir (C-6). Yapı hâli InitPlan sarmalamasını\n * ve `TO <rol>` daraltmasını GÜVENLE yapılabilir kılan şey — string üstünde\n * regex'le denemek yorum içindeki bir `auth.uid()`'yi de sarmalardı.\n */\n using: string | PolicyExprJSON | null;\n withCheck: string | PolicyExprJSON | null;\n permissive: boolean;\n}\n\n\n/** One table. Mirrors Go's `schema.TableJSON`. */\nexport interface TableJSON {\n /**\n * The schema this table lives in. `public` unless declared otherwise.\n *\n * The table carries it because the diff iterates over KEYS but passes the\n * VALUE around: a bare name inside a qualified key space writes the migration\n * into the wrong schema, silently.\n */\n schema: string;\n name: string;\n columns: Record<string, ColumnJSON>;\n rls: boolean;\n policies: PolicyJSON[];\n primaryKey?: string[];\n uniqueConstraints?: { name: string; columns: string[] }[];\n rawConstraints?: { name: string; up: string; down: string | null }[];\n checks?: { name: string; expr: string }[];\n indexes?: IndexJSON[];\n /**\n * appendOnly (FR-030): tablo yalnız INSERT kabul eder. Sıfır değerde OMIT —\n * bildirmeyen tablolar wire'da bayt-aynı kalır.\n */\n appendOnly?: boolean;\n search?: SearchJSON;\n memory?: MemoryJSON;\n}\n\n/**\n * Bir index'in wire şekli — Go'nun `IndexJSON`'ıyla ALAN-ADI SÖZLEŞMESİ.\n *\n * `name` + `columns` bugünkü hâl; kalanı FR-041…043'ün taşıyıcısı. Hepsi sıfır\n * değerde OMIT edilir: bildirmeyen bir index wire'da eskisiyle bayt-aynı kalır,\n * yoksa dokunulmamış her şema diff'te değişmiş görünür ve her deploy churn üretir.\n */\nexport interface IndexJSON {\n name: string;\n columns: string[];\n /** Partial index koşulu (FR-042) — filtre şekli `WhereFilter` ile aynı. */\n where?: unknown;\n /** İfade index'i (FR-043), ör. `lower(email)`. `columns` ile birlikte kullanılmaz. */\n expression?: string;\n /** Kolon sırası (FR-043). */\n sort?: \"asc\" | \"desc\";\n /** NULL sırası (FR-043). */\n nulls?: \"first\" | \"last\";\n /** Covering index — `INCLUDE (...)` (FR-043). */\n include?: string[];\n}\n\n/** C-11 wire şekli — Go'nun MemoryJSON'ıyla alan-adı sözleşmesi (D-019).\n * Beyansız tablolarda alan OMIT — eski şemalar bayt-aynı (NFR-B1). */\nexport interface MemoryJSON {\n from: string[];\n into: string;\n subject?: string;\n extract: { provider: string; model: string };\n}\n\n/** A whole declaration. Mirrors Go's `schema.SchemaJSON`. */\nexport interface SchemaJSON {\n tables: Record<string, TableJSON>;\n extensions: string[];\n /**\n * Every declared schema, with its HTTP reachability.\n *\n * The flag has nowhere else to live: `/v1/db` must know which schemas are\n * reachable, and introspection must know which schemas the project DECLARED —\n * a live database also contains internal module schemas that are none of the\n * diff's business.\n */\n schemas: SchemaMetaJSON[];\n}\n\nexport interface SchemaMetaJSON {\n name: string;\n exposed: boolean;\n}\n\n/** The definition behind a column, whichever side of the builder it arrives on. */\nfunction defOf(column: ColumnBuilder | ColumnDef): ColumnDef {\n return \"_def\" in column ? column._def : column;\n}\n\nfunction columnToJSON(column: ColumnBuilder | ColumnDef): ColumnJSON {\n const def = defOf(column);\n const out: ColumnJSON = {\n type: def.type,\n nullable: def.nullable,\n primaryKey: def.primaryKey,\n };\n // Every optional field is omitted rather than emitted as undefined: Go\n // distinguishes \"absent\" from \"present and empty\" on several of these, and a\n // `defaultValue: null` is a real default that says NULL.\n if (def.defaultValue !== undefined) out.defaultValue = def.defaultValue;\n if (def.defaultRandom === true) out.defaultRandom = true;\n if (def.defaultNow === true) out.defaultNow = true;\n if (def.renamedFrom !== undefined) out.renamedFrom = def.renamedFrom;\n // Go'daki schema.ColumnJSON'un aynası. `omitempty` karşılığı: yalnız TRUE ise yazılır,\n // böylece işaretsiz bir şemanın JSON'u bu alandan önceki hâliyle byte-eş kalır.\n if (def.ignored === true) out.ignored = true;\n // OWNERSHIP HAS TO CROSS THE WIRE, because the gate that enforces it is on the\n // other side. `ownedByUser()` sets `owns` on the column, and Go's\n // `validateOwnership` reads `ColumnJSON.Owns` to refuse a table that declares\n // two owners — but nothing was carrying the flag between them.\n //\n // Measured on the live cluster: a table with TWO `ownedByUser()` columns\n // pushed clean and both foreign keys landed on `auth.users` ON DELETE CASCADE.\n // The rule existed in the DSL and in the generator; the wire in between said\n // nothing, so the generator saw ZERO ownership columns and had nothing to\n // refuse. A flag with a reader and no writer is a dead wire.\n if (def.owns === true) out.owns = true;\n if (def.references !== undefined) {\n out.references = { table: def.references.table, column: def.references.column };\n }\n if (def.onDeleteAction !== undefined) out.onDeleteAction = def.onDeleteAction;\n // Yalnız `false` taşınıyor: \"bildirilmedi\" ile \"açık\" aynı şey ve wire'a\n // yazmak bildirmeyen her kolonu diff'te değişmiş gösterirdi.\n if (def.index === false) out.index = false;\n if (def.counter === true) out.counter = true;\n if (def.enumName !== undefined) out.enumName = def.enumName;\n if (def.enumValues !== undefined) out.enumValues = [...def.enumValues];\n if (def.unique === true) out.unique = true;\n if (def.dimensions !== undefined) out.dimensions = def.dimensions;\n return out;\n}\n\nfunction policyToJSON(policy: PolicyDef): PolicyJSON {\n return {\n name: policy.name,\n command: policy.command ?? \"all\",\n roles: policy.roles ? [...policy.roles] : [],\n // null rather than omitted: a policy with no USING clause is a different\n // thing from one whose clause the emitter forgot, and Go reads the\n // difference.\n using: policy.using ?? null,\n withCheck: policy.withCheck ?? null,\n permissive: policy.permissive !== false,\n };\n}\n\n/** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).\n * `mode`/`chunks` yalnız yeni-biçim chunk-modunda emit edilir (D-010);\n * satır-modu ve eski biçim bayt-aynı kalır (NFR-B1). */\nexport interface SearchJSON {\n text?: { columns: string[] };\n vector?: {\n column?: string;\n metric: string;\n embed?: { provider: string; model: string; from: string[]; apiKeyName?: string; dimensions?: number; baseURL?: string };\n staleness?: \"null\" | \"keep\";\n mode?: \"row\" | \"chunks\";\n chunks?: { sizeChars?: number; overlapChars?: number };\n }[];\n /** FR-026: sorgu-yeniden-yazımı haritası — beyan yoksa OMIT (NFR-B1). */\n synonyms?: Record<string, string[]>;\n /** C-1: sonuç yeniden-sıralama beyanı — beyan yoksa OMIT. */\n /** FR-029: geçerlilik türevleri — beyan yoksa OMIT. */\n validity?: boolean;\n}\n\n/** T020 (C-1): iki biçimin de üst-düzey ortak alanları — beyan yoksa OMIT,\n * boş synonyms haritası da OMIT (NFR-B1 baytları kımıldamaz). */\nfunction commonSearchFields(search: SearchDecl, out: SearchJSON): void {\n if (search.synonyms !== undefined && Object.keys(search.synonyms).length > 0) {\n out.synonyms = Object.fromEntries(\n Object.entries(search.synonyms).map(([word, alts]) => [word, [...alts]]),\n );\n }\n if (search.validity === true) out.validity = true;\n}\n\n/** Beyanı normalize eder: vector her zaman DİZİ, metric her zaman dolu (vars. cosine),\n * authoring'deki `from`/`model` wire'da `embed` altında toplanır. Alan yoksa OMIT —\n * search'süz şema bayt-aynı kalır (NFR-006). */\nfunction searchToJSON(search: SearchDecl, vectorColumn: string | undefined): SearchJSON {\n if (search.from !== undefined && search.model !== undefined) {\n // YENİ biçim (D-007): from tek listedir — FTS'i de embed'i de besler.\n // Mod ŞEMADAN türer (D-010): tabloda vector kolonu varsa satır-modu\n // (column yazılır, mode OMIT — eski davranışla aynı wire), yoksa\n // chunk-modu (mode:\"chunks\", column yok — vektörler türev tabloda).\n const out: SearchJSON = {};\n const textCols =\n search.text === false ? undefined : Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from;\n if (textCols !== undefined) out.text = { columns: [...textCols] };\n const v: NonNullable<SearchJSON[\"vector\"]>[number] = { metric: search.metric ?? \"cosine\" };\n if (vectorColumn !== undefined) v.column = vectorColumn;\n v.embed = {\n provider: search.model.provider,\n model: search.model.model,\n from: [...search.from],\n ...(search.model.apiKeyName !== undefined ? { apiKeyName: search.model.apiKeyName } : {}),\n ...(search.model.dimensions !== undefined ? { dimensions: search.model.dimensions } : {}),\n ...(search.model.baseURL !== undefined ? { baseURL: search.model.baseURL } : {}),\n };\n if (search.staleness !== undefined) v.staleness = search.staleness;\n if (vectorColumn === undefined) {\n v.mode = \"chunks\";\n if (search.chunks !== undefined) {\n const c: NonNullable<typeof v.chunks> = {};\n if (search.chunks.size !== undefined && search.chunks.size > 0) c.sizeChars = search.chunks.size;\n if (search.chunks.overlap !== undefined && search.chunks.overlap > 0) c.overlapChars = search.chunks.overlap;\n if (Object.keys(c).length > 0) v.chunks = c;\n }\n }\n out.vector = [v];\n commonSearchFields(search, out);\n return out;\n }\n const out: SearchJSON = {};\n // Eski biçimde text yalnız dizi olabilir (boolean'ı defineSchema zaten\n // reddediyor); Array.isArray hem tipi daraltır hem o sözleşmeyi belgeler.\n if (Array.isArray(search.text) && search.text.length > 0) out.text = { columns: [...search.text] };\n const legs = search.vector === undefined ? []\n : Array.isArray(search.vector) ? search.vector : [search.vector];\n if (legs.length > 0) {\n out.vector = legs.map((leg) => {\n const v: NonNullable<SearchJSON[\"vector\"]>[number] = { metric: leg.metric ?? \"cosine\" };\n if (leg.column !== undefined) v.column = leg.column;\n if (leg.staleness !== undefined) v.staleness = leg.staleness;\n if (leg.model !== undefined) {\n v.embed = {\n provider: leg.model.provider,\n model: leg.model.model,\n from: [...(leg.from ?? [])],\n ...(leg.model.apiKeyName !== undefined ? { apiKeyName: leg.model.apiKeyName } : {}),\n ...(leg.model.dimensions !== undefined ? { dimensions: leg.model.dimensions } : {}),\n ...(leg.model.baseURL !== undefined ? { baseURL: leg.model.baseURL } : {}),\n };\n }\n return v;\n });\n }\n commonSearchFields(search, out);\n return out;\n}\n\nfunction memoryToJSON(m: MemoryDecl): MemoryJSON {\n return {\n from: [...m.from],\n into: m.into,\n ...(m.subject !== undefined ? { subject: m.subject } : {}),\n extract: { provider: m.extract.provider, model: m.extract.model },\n };\n}\n\nfunction tableToJSON(table: TableDef, schemaName: string): TableJSON {\n const columns: Record<string, ColumnJSON> = {};\n for (const [name, column] of Object.entries(table.columns)) {\n columns[name] = columnToJSON(column);\n }\n\n const out: TableJSON = {\n name: table.name,\n schema: schemaName,\n columns,\n // Read, not re-derived. `defineSchema` already resolves the fail-closed\n // default (RLS on unless the author wrote `rls: false`, and forced on by any\n // policy), and a second copy of a SECURITY default is exactly the thing that\n // drifts — the direction it drifted last time was \"expose everything\", and\n // the live proof was one user reading another's rows.\n rls: table.rls,\n policies: (table.policies ?? []).map(policyToJSON),\n };\n\n if (table.primaryKey !== undefined && table.primaryKey.length > 0) {\n out.primaryKey = [...table.primaryKey];\n }\n if (table.unique !== undefined && table.unique.length > 0) {\n out.uniqueConstraints = table.unique.map((u) => ({ name: u.name, columns: [...u.columns] }));\n }\n if (table.raw !== undefined && table.raw.length > 0) {\n out.rawConstraints = table.raw.map((r) => ({\n name: r.name,\n up: r.up,\n down: r.down ?? null,\n }));\n }\n if (table.checks !== undefined && table.checks.length > 0) {\n out.checks = table.checks.map((c) => ({ name: c.name, expr: c.expr }));\n }\n if (table.indexes !== undefined && table.indexes.length > 0) {\n out.indexes = table.indexes.map((i) => {\n // `columns` expression-index'te YOKTUR (ikisi birbirinin alternatifi).\n // Boş dizi ile taşınır: Go tarafı `expression` doluysa onu kullanır.\n const ix: IndexJSON = { name: i.name, columns: i.columns ? [...i.columns] : [] };\n if (i.where !== undefined) ix.where = i.where;\n if (i.expression !== undefined) ix.expression = i.expression;\n if (i.sort !== undefined) ix.sort = i.sort;\n if (i.nulls !== undefined) ix.nulls = i.nulls;\n if (i.include !== undefined) ix.include = [...i.include];\n return ix;\n });\n }\n // Sıfır değerde YAZILMAZ: `appendOnly: false` ile \"bildirilmemiş\" wire'da\n // ayırt edilemez olmalı, yoksa her eski şema diff'te değişmiş görünür.\n if (table.appendOnly === true) out.appendOnly = true;\n if (table.search !== undefined) {\n // D-010 mod kararının tek girdisi: tabloda dimensions'lı (vector) kolon\n // adı. Birden çoksa ilkini yazmak YANLIŞ olurdu — o durum eski biçimin\n // işidir ve yeni biçim + çoklu vector kolonu apply'da reddedilir.\n const vectorColumn = Object.entries(columns).find(([, c]) => c.dimensions !== undefined)?.[0];\n const sj = searchToJSON(table.search, vectorColumn);\n if (sj.text !== undefined || sj.vector !== undefined) out.search = sj;\n }\n if (table.memory !== undefined) {\n out.memory = memoryToJSON(table.memory);\n }\n return out;\n}\n\n/**\n * The key a table answers to in `SchemaJSON.tables`.\n *\n * A public table is BARE, anything else is schema-qualified. This is not a new\n * convention: `RefJSON.Table` already carries `auth.users`, and introspection\n * already returns a public referent bare and a non-public one qualified. Adding\n * a second key space would make two interpreters of the same database.\n */\nexport function qualifiedTableKey(schemaName: string, tableName: string): string {\n // An ABSENT schema means public, exactly as Go's `isPublicSchema` says. This\n // branch used to be missing here and present in the engine's private copy, so\n // the two writers of one rule answered DIFFERENTLY for `\"\"`: one qualified it\n // into a schema literally named the empty string, the other left it bare.\n return schemaName === \"\" || schemaName === \"public\" ? tableName : `${schemaName}.${tableName}`;\n}\n\n/**\n * Serialize declared schemas into the JSON the deploy applies.\n *\n * Takes every schema the project declares — one file per schema — because a\n * cross-schema foreign key can only be checked when both ends are in hand.\n */\nexport function toSchemaJSON(schemas: readonly SchemaDef[]): SchemaJSON {\n const tables: Record<string, TableJSON> = {};\n const extensions: string[] = [];\n const meta: SchemaMetaJSON[] = [];\n const seen = new Set<string>();\n for (const schema of schemas) {\n if (seen.has(schema.name)) {\n throw new Error(`two schemas declare the name \"${schema.name}\" — schema names must be unique`);\n }\n seen.add(schema.name);\n for (const table of Object.values(schema.tables)) {\n const json = tableToJSON(table, schema.name);\n tables[qualifiedTableKey(schema.name, json.name)] = json;\n }\n extensions.push(...(schema.extensions ?? []));\n // The schema list travels because the flag has nowhere else to live: without\n // it /v1/db cannot know which schemas are reachable over HTTP, and nothing\n // downstream can read the DECLARED schema set that introspection needs.\n meta.push({ name: schema.name, exposed: schema.exposed });\n }\n return { tables, extensions: [...new Set(extensions)], schemas: meta };\n}\n"],"mappings":"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","names":["makeTypedTable","name","raw","insert","data","put","q","onConflict","update","where","id","set","delete","findById","findMany","opts","updateMany","deleteMany","count","makeTypedDB","schema","tables","key","Object","keys","tableDef","undefined","result","transaction","fn","builder","TxPlanBuilder","planTables","table","runTxPlan","col","name","brandRef","$col","withRetry","fn","opts","budget","retry","attempt","e","isRetryable","sqlFragment","strings","values","$sql","text","defOf","column","_def","columnToJSON","def","out","type","nullable","primaryKey","defaultValue","undefined","defaultRandom","defaultNow","renamedFrom","ignored","owns","references","table","onDeleteAction","index","counter","enumName","enumValues","unique","dimensions","policyToJSON","policy","name","command","roles","using","withCheck","permissive","commonSearchFields","search","synonyms","Object","keys","length","fromEntries","entries","map","word","alts","validity","searchToJSON","vectorColumn","from","model","textCols","text","Array","isArray","columns","v","metric","embed","provider","apiKeyName","baseURL","staleness","mode","chunks","c","size","sizeChars","overlap","overlapChars","vector","legs","leg","memoryToJSON","m","into","subject","extract","tableToJSON","schemaName","schema","rls","policies","uniqueConstraints","u","raw","rawConstraints","r","up","down","checks","expr","indexes","i","ix","where","expression","sort","nulls","include","appendOnly","find","sj","memory","qualifiedTableKey","tableName","toSchemaJSON","schemas","tables","extensions","meta","seen","Set","has","Error","add","values","json","push","exposed"]}