@palbase/backend 25.1.0 → 27.1.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 +2432 -1039
  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-BQN723PL.js +930 -0
  6. package/dist/chunk-BQN723PL.js.map +1 -0
  7. package/dist/chunk-CGNN2PUH.js +213 -0
  8. package/dist/chunk-CGNN2PUH.js.map +1 -0
  9. package/dist/{chunk-VDF2T4AS.js → chunk-EB3TUX5J.js} +1228 -591
  10. package/dist/chunk-EB3TUX5J.js.map +1 -0
  11. package/dist/chunk-JVZQCC77.js +728 -0
  12. package/dist/chunk-JVZQCC77.js.map +1 -0
  13. package/dist/chunk-OZKSM3JW.js +370 -0
  14. package/dist/chunk-OZKSM3JW.js.map +1 -0
  15. package/dist/{chunk-YOY5DFQS.js → chunk-TWX6JTGJ.js} +76 -34
  16. package/dist/{chunk-YOY5DFQS.js.map → chunk-TWX6JTGJ.js.map} +1 -1
  17. package/dist/{chunk-35PNTIRN.js → chunk-VVMJEVQP.js} +63 -162
  18. package/dist/chunk-VVMJEVQP.js.map +1 -0
  19. package/dist/{chunk-7D4SUZUM.js → chunk-VXPNPVAG.js} +3 -1
  20. package/dist/chunk-XABHGMUT.js +885 -0
  21. package/dist/chunk-XABHGMUT.js.map +1 -0
  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 +780 -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 +2366 -1002
  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-CUomTA3e.d.ts → index-CAKOgAlP.d.ts} +171 -296
  36. package/dist/index-CgE4sVhg.d.cts +4864 -0
  37. package/dist/{index-ClpDeSos.d.cts → index-H-0qv5d4.d.cts} +171 -296
  38. package/dist/index-V7QRh1wg.d.ts +4864 -0
  39. package/dist/index.cjs +2720 -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-4EI8aaFs.d.ts} +1 -1
  54. package/dist/{registry-CC0WBQq6.d.cts → registry-DHsPDY0_.d.cts} +1 -1
  55. package/dist/stack.cjs.map +1 -1
  56. package/dist/test/index.cjs +732 -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 +490 -124
  61. package/dist/test/index.js.map +1 -1
  62. package/docs/README.md +33 -18
  63. package/docs/auth.md +1 -1
  64. package/docs/background.md +2 -2
  65. package/docs/database.md +255 -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 +435 -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 -72
  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-CJSKYY76.js +0 -627
  89. package/dist/chunk-CJSKYY76.js.map +0 -1
  90. package/dist/chunk-CRQKCRGF.js +0 -276
  91. package/dist/chunk-CRQKCRGF.js.map +0 -1
  92. package/dist/chunk-G4R6BTLV.js +0 -662
  93. package/dist/chunk-G4R6BTLV.js.map +0 -1
  94. package/dist/chunk-VDF2T4AS.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 -76
  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,885 @@
1
+ import {
2
+ qualifiedTableKey
3
+ } from "./chunk-OZKSM3JW.js";
4
+ import {
5
+ __name
6
+ } from "./chunk-VXPNPVAG.js";
7
+
8
+ // src/db/schema.ts
9
+ var IndexBuilder = class {
10
+ static {
11
+ __name(this, "IndexBuilder");
12
+ }
13
+ _def;
14
+ constructor(name) {
15
+ if (name.trim() === "") {
16
+ throw new Error("index(ad): index'in ad\u0131 bo\u015F olamaz \u2014 Palbase index'leri ADA g\xF6re uzla\u015Ft\u0131r\u0131r.");
17
+ }
18
+ this._def = {
19
+ name
20
+ };
21
+ }
22
+ /** Index'in kolonları. SIRA KORUNUR — çok kolonlu bir index'in anlamı sırasıdır. */
23
+ on(...cols) {
24
+ this._def.columns = cols.map((c) => {
25
+ const e = c.expr;
26
+ if (e.kind !== "col") {
27
+ throw new Error(`index(${this._def.name}).on(): yaln\u0131z kolon referans\u0131 al\u0131r \u2014 ifade i\xE7in onExpression("\u2026") kullan\u0131n.`);
28
+ }
29
+ return e.name;
30
+ });
31
+ return this;
32
+ }
33
+ /**
34
+ * İfade index'i (`lower(email)`), kolon yerine.
35
+ *
36
+ * Metin VERBATIM emit ediliyor — `policy().using("…")` ile aynı güven duruşu.
37
+ * Tipli yapı bunu ifade edemiyor ve kaçış kapağını kapatmak, yazarı elle
38
+ * migration yazmaya iterdi.
39
+ */
40
+ onExpression(expr) {
41
+ this._def.expression = expr;
42
+ return this;
43
+ }
44
+ /** Partial index koşulu — politika ifade dilinin ta kendisi. */
45
+ where(expr) {
46
+ this._def.where = expr.expr;
47
+ return this;
48
+ }
49
+ /** Sıra. Tek yönlü index'te sıra genelde önemsizdir; ORDER BY ile eşleşen
50
+ * bir index arandığında değildir. */
51
+ desc() {
52
+ this._def.sort = "desc";
53
+ return this;
54
+ }
55
+ asc() {
56
+ this._def.sort = "asc";
57
+ return this;
58
+ }
59
+ /** NULL'ların yeri — `ORDER BY … NULLS LAST` ile eşleşmesi için. */
60
+ nulls(where) {
61
+ this._def.nulls = where;
62
+ return this;
63
+ }
64
+ /** Covering index (`INCLUDE`): index-only scan için taşınan ama
65
+ * ARANMAYAN kolonlar. */
66
+ include(cols) {
67
+ this._def.include = cols;
68
+ return this;
69
+ }
70
+ };
71
+ function index(name) {
72
+ return new IndexBuilder(name);
73
+ }
74
+ __name(index, "index");
75
+ function toPolicyDef(p) {
76
+ return p instanceof PolicyBuilder ? p._def : p;
77
+ }
78
+ __name(toPolicyDef, "toPolicyDef");
79
+ var TABLE_META = /* @__PURE__ */ Symbol.for("palbase.table.meta");
80
+ function defineTable(name, input) {
81
+ if (name.trim() === "") {
82
+ throw new Error("defineTable(name, \u2026): name must not be empty");
83
+ }
84
+ const policies = (input.policies?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map(toPolicyDef);
85
+ const rls = policies.length > 0 || input.rls !== false;
86
+ const owned = {};
87
+ for (const [colName, b] of Object.entries(input.columns)) {
88
+ const builder = b;
89
+ const clone = Object.create(Object.getPrototypeOf(builder));
90
+ Object.defineProperty(clone, "_def", {
91
+ value: {
92
+ ...builder._def
93
+ },
94
+ enumerable: true,
95
+ writable: true
96
+ });
97
+ owned[colName] = clone;
98
+ }
99
+ const def = {
100
+ name,
101
+ columns: owned,
102
+ rls,
103
+ policies
104
+ };
105
+ if (input.primaryKey !== void 0) def.primaryKey = input.primaryKey;
106
+ if (input.unique !== void 0) def.unique = input.unique;
107
+ if (input.raw !== void 0 && input.raw.length > 0) def.raw = input.raw.slice();
108
+ if (input.checks !== void 0 && input.checks.length > 0) def.checks = input.checks.slice();
109
+ const declaredIndexes = (input.indexes?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map((i) => i instanceof IndexBuilder ? i._def : i);
110
+ if (declaredIndexes.length > 0) def.indexes = declaredIndexes;
111
+ if (input.appendOnly === true) def.appendOnly = true;
112
+ if (input.search !== void 0) {
113
+ const s = input.search;
114
+ if (s.from !== void 0) {
115
+ if (s.vector !== void 0) {
116
+ throw new Error(`table ${name}: search beyan\u0131nda tek bi\xE7im kullan\u0131n \u2014 'from' (yeni) ile 'vector' (eski) birlikte olamaz`);
117
+ }
118
+ if (s.from.length === 0) {
119
+ throw new Error(`table ${name}: search.from bo\u015F olamaz`);
120
+ }
121
+ if (s.model === void 0) {
122
+ throw new Error(`table ${name}: search.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin (BYO i\xE7in eski 'vector' bi\xE7imini kullan\u0131n)`);
123
+ }
124
+ if (Array.isArray(s.text) && s.text.length === 0) {
125
+ throw new Error(`table ${name}: search.text bo\u015F dizi olamaz \u2014 FTS istemiyorsan text: false yaz\u0131n`);
126
+ }
127
+ } else {
128
+ if (typeof s.text === "boolean") {
129
+ throw new Error(`table ${name}: text:${String(s.text)} yaln\u0131z yeni bi\xE7imde ('from' ile) ge\xE7erli`);
130
+ }
131
+ if (s.text === void 0 && s.vector === void 0) {
132
+ throw new Error(`table ${name}: search beyan\u0131 bo\u015F \u2014 en az bir kol (text ya da vector) verin, yoksa alan\u0131 hi\xE7 yazmay\u0131n`);
133
+ }
134
+ if (s.text !== void 0 && s.text.length === 0) {
135
+ throw new Error(`table ${name}: search.text bo\u015F olamaz \u2014 FTS kolu istemiyorsan alan\u0131 hi\xE7 yazma`);
136
+ }
137
+ const legs = s.vector === void 0 ? [] : Array.isArray(s.vector) ? s.vector : [
138
+ s.vector
139
+ ];
140
+ for (const leg of legs) {
141
+ if (leg.model !== void 0 && (leg.from === void 0 || leg.from.length === 0)) {
142
+ throw new Error(`table ${name}: search.vector.model beyan edildi ama 'from' yok \u2014 embed kayna\u011F\u0131 kolonlar zorunlu (C-2)`);
143
+ }
144
+ if (leg.model === void 0 && leg.from !== void 0) {
145
+ throw new Error(`table ${name}: search.vector.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin`);
146
+ }
147
+ }
148
+ }
149
+ def.search = s;
150
+ }
151
+ if (input.memory !== void 0) {
152
+ if (input.memory.from.length === 0) {
153
+ throw new Error(`table ${name}: memory.from bo\u015F olamaz`);
154
+ }
155
+ def.memory = input.memory;
156
+ }
157
+ for (const b of Object.values(owned)) {
158
+ b._def.ownerTable = def;
159
+ }
160
+ const handle = {
161
+ ...owned
162
+ };
163
+ Object.defineProperty(handle, TABLE_META, {
164
+ value: def,
165
+ enumerable: false
166
+ });
167
+ return handle;
168
+ }
169
+ __name(defineTable, "defineTable");
170
+ var declaringSchemaOf = /* @__PURE__ */ new WeakMap();
171
+ function resolveReferences(tables, schemaName) {
172
+ for (const table of Object.values(tables)) {
173
+ for (const [colName, builder] of Object.entries(table.columns)) {
174
+ const def = builder._def;
175
+ if (def.selfRefColumn !== void 0) {
176
+ if (!(def.selfRefColumn in table.columns)) {
177
+ throw new Error(`table "${table.name}" column "${colName}": selfReferences("${def.selfRefColumn}") \u2014 no such column on this table`);
178
+ }
179
+ def.references = {
180
+ table: qualifiedTableKey(schemaName, table.name),
181
+ column: def.selfRefColumn
182
+ };
183
+ continue;
184
+ }
185
+ if (def.referencesThunk === void 0) continue;
186
+ const target = def.referencesThunk();
187
+ const owner = target?._def?.ownerTable;
188
+ if (owner === void 0) {
189
+ throw new Error(`table "${table.name}" column "${colName}": references(() => \u2026) must point at a column of a table declared with defineTable(...)`);
190
+ }
191
+ const targetColumn = Object.entries(owner.columns).find(([, b]) => b._def === target._def)?.[0];
192
+ if (targetColumn === void 0) {
193
+ throw new Error(`table "${table.name}" column "${colName}": the referenced column was not found on table "${owner.name}"`);
194
+ }
195
+ const targetSchema = declaringSchemaOf.get(owner);
196
+ if (targetSchema === void 0) {
197
+ throw new Error(`table "${table.name}" column "${colName}": references(() => \u2026) points at table "${owner.name}", which no defineSchema(...) has claimed yet \u2014 a foreign key cannot be written without its target's schema. Declare that table's schema first (one file per schema: db/public.ts, db/billing.ts \u2026, imported by this one).`);
198
+ }
199
+ def.references = {
200
+ table: qualifiedTableKey(targetSchema, owner.name),
201
+ column: targetColumn
202
+ };
203
+ }
204
+ }
205
+ }
206
+ __name(resolveReferences, "resolveReferences");
207
+ function defineSchema(name, input) {
208
+ if (typeof name !== "string") {
209
+ throw new Error(`defineSchema(...) takes the schema NAME first: defineSchema("public", { tables: [todos, lists] }). The one-argument form defineSchema({ tables: { \u2026 } }) is gone \u2014 a schema that does not say its own name cannot be told apart from another schema's table of the same name, which is what a cross-schema foreign key has to do. Migrate db/public.ts (one file per schema: db/public.ts, db/billing.ts \u2026): name the schema, and lift each table key onto the table itself with defineTable("todos", { columns: { \u2026 } }), then list the tables in the array.`);
210
+ }
211
+ if (name.trim() === "") {
212
+ throw new Error("defineSchema(name, \u2026): name must not be empty");
213
+ }
214
+ const tables = {};
215
+ for (const handle of input.tables) {
216
+ const table = handle[TABLE_META];
217
+ if (tables[table.name] !== void 0) {
218
+ throw new Error(`defineSchema("${name}"): two tables declare the name "${table.name}" \u2014 table names must be unique within a schema`);
219
+ }
220
+ tables[table.name] = table;
221
+ declaringSchemaOf.set(table, name);
222
+ }
223
+ resolveReferences(tables, name);
224
+ for (const [name2, def] of Object.entries(tables)) {
225
+ const m = def.memory;
226
+ if (m === void 0) continue;
227
+ const target = Object.values(tables).find((t) => t.name === m.into);
228
+ if (target === void 0) {
229
+ throw new Error(`table ${name2}: memory.into "${m.into}" \u015Femada declared de\u011Fil`);
230
+ }
231
+ const subject = m.subject ?? "owner";
232
+ if (!(subject in def.columns)) {
233
+ throw new Error(`table ${name2}: memory.subject "${subject}" kolonu kaynak tabloda yok`);
234
+ }
235
+ if (!(subject in target.columns)) {
236
+ throw new Error(`table ${name2}: memory.subject "${subject}" kolonu hedef "${m.into}" tablosunda yok`);
237
+ }
238
+ const factCol = target.columns["fact"];
239
+ const factDef = factCol !== void 0 && "_def" in factCol ? factCol._def : factCol;
240
+ if (factDef === void 0 || factDef.type !== "text") {
241
+ throw new Error(`table ${name2}: memory.into "${m.into}" tablosunda "fact" (text) kolonu zorunlu`);
242
+ }
243
+ for (const c of m.from) {
244
+ if (!(c in def.columns)) {
245
+ throw new Error(`table ${name2}: memory.from kolonu "${c}" kaynak tabloda yok`);
246
+ }
247
+ }
248
+ }
249
+ const extensions = [
250
+ ...new Set(input.extensions ?? [])
251
+ ];
252
+ return {
253
+ name,
254
+ tables,
255
+ extensions,
256
+ exposed: input.exposed ?? name === "public"
257
+ };
258
+ }
259
+ __name(defineSchema, "defineSchema");
260
+
261
+ // src/db/policy.ts
262
+ var PolicyExprRef = class _PolicyExprRef {
263
+ static {
264
+ __name(this, "PolicyExprRef");
265
+ }
266
+ expr;
267
+ constructor(expr) {
268
+ this.expr = expr;
269
+ }
270
+ bin(op, other) {
271
+ return new _PolicyExprRef({
272
+ kind: "binop",
273
+ op,
274
+ left: this.expr,
275
+ right: toExpr(other)
276
+ });
277
+ }
278
+ eq(other) {
279
+ return this.bin("eq", other);
280
+ }
281
+ neq(other) {
282
+ return this.bin("neq", other);
283
+ }
284
+ gt(other) {
285
+ return this.bin("gt", other);
286
+ }
287
+ gte(other) {
288
+ return this.bin("gte", other);
289
+ }
290
+ lt(other) {
291
+ return this.bin("lt", other);
292
+ }
293
+ lte(other) {
294
+ return this.bin("lte", other);
295
+ }
296
+ /**
297
+ * `IS NULL` / `IS NOT NULL` — `= NULL` SQL'de her zaman UNKNOWN'dır, o yüzden
298
+ * niyet ayrı bir düğümle yazılır. Partial index'in en sık koşulu
299
+ * (`WHERE deleted_at IS NULL`) tam olarak bu.
300
+ */
301
+ isNull(negated = false) {
302
+ return new _PolicyExprRef({
303
+ kind: "isNull",
304
+ expr: this.expr,
305
+ negated
306
+ });
307
+ }
308
+ and(...others) {
309
+ return new _PolicyExprRef({
310
+ kind: "and",
311
+ parts: [
312
+ this.expr,
313
+ ...others.map((o) => o.expr)
314
+ ]
315
+ });
316
+ }
317
+ or(...others) {
318
+ return new _PolicyExprRef({
319
+ kind: "or",
320
+ parts: [
321
+ this.expr,
322
+ ...others.map((o) => o.expr)
323
+ ]
324
+ });
325
+ }
326
+ not() {
327
+ return new _PolicyExprRef({
328
+ kind: "not",
329
+ expr: this.expr
330
+ });
331
+ }
332
+ };
333
+ function toExpr(v) {
334
+ return v instanceof PolicyExprRef ? v.expr : {
335
+ kind: "lit",
336
+ value: v
337
+ };
338
+ }
339
+ __name(toExpr, "toExpr");
340
+ function exprCtx(_columns, depth = 0, ownTable = "") {
341
+ const alias = `pb_e${depth}`;
342
+ return {
343
+ col: /* @__PURE__ */ __name((name) => new PolicyExprRef(depth === 0 ? {
344
+ kind: "col",
345
+ name
346
+ } : {
347
+ kind: "col",
348
+ name,
349
+ alias
350
+ }), "col"),
351
+ auth: {
352
+ uid: /* @__PURE__ */ __name(() => new PolicyExprRef({
353
+ kind: "authUid"
354
+ }), "uid")
355
+ },
356
+ lit: /* @__PURE__ */ __name((v) => new PolicyExprRef({
357
+ kind: "lit",
358
+ value: v
359
+ }), "lit"),
360
+ and: /* @__PURE__ */ __name((...parts) => new PolicyExprRef({
361
+ kind: "and",
362
+ parts: parts.map((p) => p.expr)
363
+ }), "and"),
364
+ or: /* @__PURE__ */ __name((...parts) => new PolicyExprRef({
365
+ kind: "or",
366
+ parts: parts.map((p) => p.expr)
367
+ }), "or"),
368
+ not: /* @__PURE__ */ __name((part) => new PolicyExprRef({
369
+ kind: "not",
370
+ expr: part.expr
371
+ }), "not"),
372
+ existsIn: /* @__PURE__ */ __name((table, predicate) => {
373
+ const meta = table[TABLE_META];
374
+ const inner = exprCtx(Object.keys(meta.columns), depth + 1, ownTable);
375
+ return new PolicyExprRef({
376
+ kind: "exists",
377
+ table: meta.name,
378
+ alias: `pb_e${depth + 1}`,
379
+ outer: ownTable,
380
+ predicate: predicate(inner).expr
381
+ });
382
+ }, "existsIn")
383
+ };
384
+ }
385
+ __name(exprCtx, "exprCtx");
386
+ function quote(name) {
387
+ return `"${name.replace(/"/g, '""')}"`;
388
+ }
389
+ __name(quote, "quote");
390
+ var PolicyBuilder = class {
391
+ static {
392
+ __name(this, "PolicyBuilder");
393
+ }
394
+ _def;
395
+ constructor(name) {
396
+ this._def = {
397
+ name,
398
+ command: "all",
399
+ roles: [
400
+ "authenticated"
401
+ ],
402
+ using: null,
403
+ withCheck: null,
404
+ permissive: true
405
+ };
406
+ }
407
+ /** Restrict the policy to a single SQL command (default `"all"`). */
408
+ for(command) {
409
+ this._def.command = command;
410
+ return this;
411
+ }
412
+ /**
413
+ * Set the DB roles the policy applies to (the `TO` clause), replacing any
414
+ * previously-set roles. Call with no arguments to target PUBLIC (all roles).
415
+ *
416
+ * @example
417
+ * policy("p").to("authenticated")
418
+ * policy("p").to("authenticated", "service_role")
419
+ * policy("p").to() // PUBLIC
420
+ */
421
+ to(...roles) {
422
+ this._def.roles = roles;
423
+ return this;
424
+ }
425
+ /**
426
+ * `USING (...)` satır görünürlüğü ifadesi.
427
+ *
428
+ * Tercih edilen biçim YAPI'dır (FR-022) — `policies` callback'inin verdiği
429
+ * bağlamla kurulur ve kolon adları derlemede doğrulanır:
430
+ *
431
+ * ```ts
432
+ * policies: (p) => [
433
+ * policy("owner_read").for("select").using(p.col("owner").eq(p.auth.uid())),
434
+ * ]
435
+ * ```
436
+ *
437
+ * Ham string KAÇIŞ KAPAĞI olarak kalır (FR-028): yapının ifade edemediği bir
438
+ * şey gerektiğinde yol kapanmaz. Ama o yolda kolon adı doğrulaması yoktur ve
439
+ * hata deploy anında Postgres'ten gelir.
440
+ */
441
+ using(expr) {
442
+ this._def.using = expr instanceof PolicyExprRef ? expr.expr : expr;
443
+ return this;
444
+ }
445
+ /**
446
+ * "Rows of THIS table whose owner the caller is a member of" — the membership
447
+ * pattern, written so it cannot recurse.
448
+ *
449
+ * THE TRAP IT EXISTS FOR. Written by hand, membership policies point at each
450
+ * other: `channels` is visible to members, so its policy reads
451
+ * `channel_members`; `channel_members` is visible to members, so its policy
452
+ * reads `channels`. Postgres refuses the pair at query time with `infinite
453
+ * recursion detected in policy for relation ...`, and the error names the
454
+ * relation but not the cycle. The way out is asymmetry — the MEMBERSHIP table
455
+ * is protected by `user_id = auth.uid()` and nothing else, and every other
456
+ * table subqueries INTO it. That shape was in the platform's own schema and
457
+ * written down nowhere; a customer recovered it by reading that schema.
458
+ *
459
+ * `(select auth.uid())` rather than a bare call: the scalar subquery is
460
+ * evaluated ONCE per statement instead of per row.
461
+ *
462
+ * @example
463
+ * // channels: visible to members. The membership table gets the simple one.
464
+ * policy("member_read").for("select").to("authenticated")
465
+ * .memberOf("channel_members", "channel_id")
466
+ * // → id IN (SELECT "channel_id" FROM "channel_members"
467
+ * // WHERE "user_id" = (select auth.uid()))
468
+ */
469
+ memberOf(membershipTable, foreignKey, options = {}) {
470
+ if (this._def.using !== null) {
471
+ throw new Error(`policy(${this._def.name}).memberOf(): this policy already has a using() expression. Write one or the other \u2014 memberOf IS the using expression.`);
472
+ }
473
+ const column = options.column ?? "id";
474
+ const userColumn = options.userColumn ?? "user_id";
475
+ this._def.using = `${quote(column)} IN (SELECT ${quote(foreignKey)} FROM ${quote(membershipTable)} WHERE ${quote(userColumn)} = (select auth.uid()))`;
476
+ return this;
477
+ }
478
+ /** `WITH CHECK (...)` yazma doğrulaması — `using` ile aynı iki biçim. */
479
+ withCheck(expr) {
480
+ this._def.withCheck = expr instanceof PolicyExprRef ? expr.expr : expr;
481
+ return this;
482
+ }
483
+ /** Set the policy mode: `"permissive"` (default, OR-combined) or
484
+ * `"restrictive"` (AND-combined). */
485
+ as(mode) {
486
+ this._def.permissive = mode === "permissive";
487
+ return this;
488
+ }
489
+ };
490
+ function policy(name) {
491
+ return new PolicyBuilder(name);
492
+ }
493
+ __name(policy, "policy");
494
+
495
+ // src/db/extensions.ts
496
+ var PALBASE_EXTENSIONS = [
497
+ // Search & text
498
+ "vector",
499
+ // NB: the Postgres extension is named "vector", not "pgvector" — declare "vector".
500
+ "pg_trgm",
501
+ "unaccent",
502
+ "citext",
503
+ // Geospatial / location
504
+ "cube",
505
+ "earthdistance",
506
+ // Data types & structures
507
+ "hstore",
508
+ "ltree",
509
+ // Indexing & constraints
510
+ "btree_gist",
511
+ // constraints that mix "=" with a range/&& overlap (e.g. no-double-booking).
512
+ // Scheduling
513
+ // Crypto / ids (also installed by default; listable for explicitness)
514
+ "pgcrypto",
515
+ "uuid-ossp"
516
+ ];
517
+ var EXTENSION_DEPENDENCIES = {
518
+ earthdistance: [
519
+ "cube"
520
+ ]
521
+ };
522
+ function isPalbaseExtension(name) {
523
+ return PALBASE_EXTENSIONS.includes(name);
524
+ }
525
+ __name(isPalbaseExtension, "isPalbaseExtension");
526
+
527
+ // src/db/columns.ts
528
+ function refuseOnVector(def, modifier) {
529
+ if (def.type === "vector") {
530
+ throw new Error(`vector column: .${modifier}() is not supported (FR-002 \u2014 allowed: nullable()/notNull())`);
531
+ }
532
+ }
533
+ __name(refuseOnVector, "refuseOnVector");
534
+ var ColumnBuilder = class _ColumnBuilder {
535
+ static {
536
+ __name(this, "ColumnBuilder");
537
+ }
538
+ _def;
539
+ constructor(type, existingDef) {
540
+ this._def = existingDef ?? {
541
+ type,
542
+ nullable: false,
543
+ primaryKey: false
544
+ };
545
+ }
546
+ /** Mark this column as the primary key. */
547
+ primaryKey() {
548
+ refuseOnVector(this._def, "primaryKey");
549
+ this._def.primaryKey = true;
550
+ return new _ColumnBuilder(this._def.type, this._def);
551
+ }
552
+ /** Mark this column as NOT NULL (default). */
553
+ notNull() {
554
+ this._def.nullable = false;
555
+ return new _ColumnBuilder(this._def.type, this._def);
556
+ }
557
+ /** Allow NULL values. */
558
+ nullable() {
559
+ this._def.nullable = true;
560
+ return new _ColumnBuilder(this._def.type, this._def);
561
+ }
562
+ /** Set a default value. */
563
+ default(value) {
564
+ refuseOnVector(this._def, "default");
565
+ this._def.defaultValue = value;
566
+ return new _ColumnBuilder(this._def.type, this._def);
567
+ }
568
+ /** UUID: generate a random default (gen_random_uuid()). */
569
+ defaultRandom() {
570
+ refuseOnVector(this._def, "defaultRandom");
571
+ this._def.defaultRandom = true;
572
+ return new _ColumnBuilder(this._def.type, this._def);
573
+ }
574
+ /** Timestamp: default to now(). */
575
+ defaultNow() {
576
+ refuseOnVector(this._def, "defaultNow");
577
+ this._def.defaultNow = true;
578
+ return new _ColumnBuilder(this._def.type, this._def);
579
+ }
580
+ /**
581
+ * The DATABASE assigns this column's value — a trigger, a rule, an identity.
582
+ *
583
+ * The column becomes optional on INSERT (the author has nothing to send) while
584
+ * the DDL stays free of a DEFAULT this schema would not honour. It is NOT
585
+ * `default()`: that declares a value the schema promises to write.
586
+ *
587
+ * Naming: deliberately not `generated()`. Postgres has GENERATED columns and
588
+ * they are a different thing; borrowing the word would send a reader — or a
589
+ * model writing a schema — to the wrong feature.
590
+ */
591
+ dbAssigned() {
592
+ this._def.dbAssigned = true;
593
+ return new _ColumnBuilder(this._def.type, this._def);
594
+ }
595
+ /** Add a foreign key reference. */
596
+ /**
597
+ * Declares that this column used to be called `previous`.
598
+ *
599
+ * A schema diff sees one name gone and another present; it cannot know whether
600
+ * you renamed a column or dropped one and added another, and the two are very
601
+ * different — the second loses every value. Saying so here turns the plan into
602
+ * `ALTER TABLE … RENAME COLUMN` instead.
603
+ *
604
+ * Once the rename has been applied the annotation is inert (the old name is no
605
+ * longer there to rename), so it can be deleted at your leisure.
606
+ */
607
+ renamedFrom(previous) {
608
+ this._def.renamedFrom = previous;
609
+ return this;
610
+ }
611
+ /**
612
+ * See {@link ColumnDef.ignored}.
613
+ *
614
+ * COPIES the def rather than mutating it. The constructor takes an existing
615
+ * def BY REFERENCE, so every builder derived from another shares one object —
616
+ * `const a = slug.unique()` leaves `a._def === slug._def`. An in-place
617
+ * `ignored = true` therefore marks every column sharing that def, including
618
+ * one another table actively reads, and the gate would let THAT column be
619
+ * dropped. Measured before this copy existed.
620
+ *
621
+ * The aliasing is older than this method and other fields leak through it too.
622
+ * The reason this one cannot wait: every other leak produces a VISIBLE schema
623
+ * difference — the plan shows it, the DDL shows it. This one is invisible by
624
+ * design (no DDL, no diff, no plan line), so its only effect is to disarm a
625
+ * safety gate in silence.
626
+ */
627
+ ignored() {
628
+ return new _ColumnBuilder(this._def.type, {
629
+ ...this._def,
630
+ ignored: true
631
+ });
632
+ }
633
+ /**
634
+ * Foreign key onto another table's column.
635
+ *
636
+ * The target is a THUNK, not a direct reference. In a cycle (`x → y`, `y → x`)
637
+ * the second table does not exist yet when the first is built; a direct
638
+ * reference makes TypeScript chase its own tail (TS7022 — measured, and making
639
+ * the return type independent of the target does NOT help). The thunk is
640
+ * invoked in `defineSchema`, where every binding exists and every table
641
+ * already knows its name.
642
+ *
643
+ * In a cycle, ONE side needs an explicit return type:
644
+ * `references((): AnyColumn => y.id)`. One side is enough — measured.
645
+ * For a self-reference use `selfReferences(column)`: no thunk, no annotation.
646
+ *
647
+ * `as` names the FORWARD relation (`author_id` → `author` by default);
648
+ * `reverseAs` names the REVERSE one on the parent, whose default is this
649
+ * table's own name (`users.posts`). Two foreign keys from one table onto one
650
+ * parent therefore need a `reverseAs` on at least one of them — the reverse
651
+ * names would otherwise both be this table's name.
652
+ */
653
+ references(target, opts) {
654
+ refuseOnVector(this._def, "references");
655
+ if (typeof target !== "function") {
656
+ throw new Error(`references(...) takes a callback: write references(() => otherTable.column). The two-string form references("table", "column") is gone \u2014 a string cannot be type-checked and cannot point at a table that does not exist yet.`);
657
+ }
658
+ this._def.referencesThunk = target;
659
+ if (opts?.as !== void 0) this._def.refAs = opts.as;
660
+ if (opts?.reverseAs !== void 0) this._def.reverseAs = opts.reverseAs;
661
+ if (opts?.onDelete !== void 0) this._def.onDeleteAction = opts.onDelete;
662
+ if (opts?.index === false) this._def.index = false;
663
+ return new _ColumnBuilder(this._def.type, this._def);
664
+ }
665
+ /**
666
+ * Bu kolon `increment()` / `decrement()` ile güncelleniyor (FR-049).
667
+ *
668
+ * Deploy kontrolcü kodunu OKUMAZ, o yüzden bildirimin söylemesi gerekiyor —
669
+ * ve söylediği anda plan bir şeyi görebiliyor: aynı kolon hem sayaç hem
670
+ * indeksliyse her güncelleme HOT'u kaybeder.
671
+ *
672
+ * ZİNCİR (D-028+D-030): HOT kaybı → ölü tuple → autovacuum yükü → ve
673
+ * autovacuum worker'ları KÜME GENELİNDE bir kaynak, yani bedeli başka
674
+ * kiracıların tabloları da öder.
675
+ *
676
+ * Sektörde çare "dokümana uyarı yaz"dır, çünkü index'i ekleyen kişi
677
+ * `increment()`'i yazan kişi değildir. Bu bildirimde ikisi de YAN YANA
678
+ * duruyor.
679
+ *
680
+ * Uyarı, HATA DEĞİL: sayaç kolonunu indekslemek bazen doğru karardır.
681
+ */
682
+ counter() {
683
+ this._def.counter = true;
684
+ return new _ColumnBuilder(this._def.type, this._def);
685
+ }
686
+ /**
687
+ * Foreign key onto THIS table (`parent_id → id`) — category trees, comment
688
+ * replies, org charts.
689
+ *
690
+ * No thunk and no type annotation: the target table is the one being declared,
691
+ * so there is nothing to defer and nothing for TypeScript to chase in a circle.
692
+ * Drizzle forces an explicit `(): AnyPgColumn =>` here because its reference
693
+ * always goes through a callback; measured, we do not need one.
694
+ */
695
+ selfReferences(column, opts) {
696
+ refuseOnVector(this._def, "selfReferences");
697
+ this._def.selfRefColumn = column;
698
+ if (opts?.as !== void 0) this._def.refAs = opts.as;
699
+ if (opts?.onDelete !== void 0) this._def.onDeleteAction = opts.onDelete;
700
+ return new _ColumnBuilder(this._def.type, this._def);
701
+ }
702
+ /** Set the ON DELETE action for a foreign key reference. */
703
+ onDelete(action) {
704
+ this._def.onDeleteAction = action;
705
+ return new _ColumnBuilder(this._def.type, this._def);
706
+ }
707
+ /** Add a single-column UNIQUE constraint. */
708
+ unique() {
709
+ refuseOnVector(this._def, "unique");
710
+ this._def.unique = true;
711
+ return new _ColumnBuilder(this._def.type, this._def);
712
+ }
713
+ /**
714
+ * Declare how this column's value is projected in and out of the process.
715
+ *
716
+ * The DDL does not move: `numeric` stays `numeric`, and the driver still hands
717
+ * back what Postgres sent. What changes is the type the row surface exposes —
718
+ * it becomes `Target`:
719
+ *
720
+ * amount: numeric().transform<number>({ fromDb: Number, toDb: String })
721
+ *
722
+ * `numeric` surfacing as `string` is CORRECT (a JS number cannot hold
723
+ * arbitrary precision), and that is exactly why this exists: application code
724
+ * that does arithmetic on the column otherwise rewrites the same
725
+ * `Number(row.amount)` / `String(x)` pair in every controller that touches it,
726
+ * and each rewrite is a place the two directions can drift apart.
727
+ *
728
+ * A transform is a PROJECTION, never a constraint: it lives only in this
729
+ * process, so it can neither validate nor migrate what is stored.
730
+ */
731
+ transform(fns) {
732
+ this._def.transform = fns;
733
+ return new _ColumnBuilder(this._def.type, this._def);
734
+ }
735
+ };
736
+ function uuid() {
737
+ return new ColumnBuilder("uuid");
738
+ }
739
+ __name(uuid, "uuid");
740
+ function text() {
741
+ return new ColumnBuilder("text");
742
+ }
743
+ __name(text, "text");
744
+ function integer() {
745
+ return new ColumnBuilder("integer");
746
+ }
747
+ __name(integer, "integer");
748
+ function bigint() {
749
+ return new ColumnBuilder("bigint");
750
+ }
751
+ __name(bigint, "bigint");
752
+ function numeric() {
753
+ return new ColumnBuilder("numeric");
754
+ }
755
+ __name(numeric, "numeric");
756
+ function boolean() {
757
+ return new ColumnBuilder("boolean");
758
+ }
759
+ __name(boolean, "boolean");
760
+ function timestamp() {
761
+ return new ColumnBuilder("timestamp");
762
+ }
763
+ __name(timestamp, "timestamp");
764
+ function jsonb() {
765
+ return new ColumnBuilder("jsonb");
766
+ }
767
+ __name(jsonb, "jsonb");
768
+ function enumType(name, values) {
769
+ const builder = new ColumnBuilder("enum");
770
+ builder._def.enumName = name;
771
+ builder._def.enumValues = [
772
+ ...values
773
+ ];
774
+ return builder;
775
+ }
776
+ __name(enumType, "enumType");
777
+ function vector(dimensions) {
778
+ if (!Number.isInteger(dimensions) || dimensions < 1 || dimensions > 2e3) {
779
+ throw new Error(`vector(): dimensions must be an integer in [1, 2000], got ${String(dimensions)}`);
780
+ }
781
+ const b = new ColumnBuilder("vector");
782
+ b._def.dimensions = dimensions;
783
+ return b;
784
+ }
785
+ __name(vector, "vector");
786
+ function ownedByUser() {
787
+ const b = new ColumnBuilder("text");
788
+ b._def.nullable = false;
789
+ b._def.references = {
790
+ table: "auth.users",
791
+ column: "id"
792
+ };
793
+ b._def.onDeleteAction = "cascade";
794
+ b._def.owns = true;
795
+ return b;
796
+ }
797
+ __name(ownedByUser, "ownedByUser");
798
+ function userRef(opts) {
799
+ const b = new ColumnBuilder("text");
800
+ b._def.references = {
801
+ table: "auth.users",
802
+ column: "id"
803
+ };
804
+ b._def.onDeleteAction = opts.onDelete;
805
+ if (opts.as !== void 0) b._def.refAs = opts.as;
806
+ return b;
807
+ }
808
+ __name(userRef, "userRef");
809
+ function installationRef(opts) {
810
+ const b = new ColumnBuilder("text");
811
+ b._def.references = {
812
+ table: "auth.installations",
813
+ column: "id"
814
+ };
815
+ b._def.onDeleteAction = opts.onDelete;
816
+ if (opts.as !== void 0) b._def.refAs = opts.as;
817
+ return b;
818
+ }
819
+ __name(installationRef, "installationRef");
820
+
821
+ // src/db/raw.ts
822
+ function raw(name, up, opts) {
823
+ return {
824
+ name,
825
+ up,
826
+ ...opts?.down != null ? {
827
+ down: opts.down
828
+ } : {}
829
+ };
830
+ }
831
+ __name(raw, "raw");
832
+
833
+ // src/db/embedding.ts
834
+ var openai = {
835
+ embedding(model, opts) {
836
+ return {
837
+ provider: "openai",
838
+ model,
839
+ apiKeyName: opts?.apiKeyName ?? "OPENAI_API_KEY",
840
+ ...opts?.dimensions !== void 0 ? {
841
+ dimensions: opts.dimensions
842
+ } : {},
843
+ ...opts?.baseURL !== void 0 ? {
844
+ baseURL: opts.baseURL
845
+ } : {}
846
+ };
847
+ },
848
+ chat(model) {
849
+ return {
850
+ provider: "openai",
851
+ model
852
+ };
853
+ }
854
+ };
855
+
856
+ export {
857
+ PolicyExprRef,
858
+ exprCtx,
859
+ PolicyBuilder,
860
+ policy,
861
+ IndexBuilder,
862
+ index,
863
+ TABLE_META,
864
+ defineTable,
865
+ defineSchema,
866
+ PALBASE_EXTENSIONS,
867
+ EXTENSION_DEPENDENCIES,
868
+ isPalbaseExtension,
869
+ uuid,
870
+ text,
871
+ integer,
872
+ bigint,
873
+ numeric,
874
+ boolean,
875
+ timestamp,
876
+ jsonb,
877
+ enumType,
878
+ vector,
879
+ ownedByUser,
880
+ userRef,
881
+ installationRef,
882
+ raw,
883
+ openai
884
+ };
885
+ //# sourceMappingURL=chunk-XABHGMUT.js.map