@palbase/backend 25.1.0 → 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 +2401 -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-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-VDF2T4AS.js → chunk-OO7R25AI.js} +1213 -591
  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 +2339 -1006
  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 +33 -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 +401 -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
package/dist/db/index.cjs CHANGED
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -55,18 +56,149 @@ module.exports = __toCommonJS(db_exports);
55
56
  function qualifiedTableKey(schemaName, tableName) {
56
57
  return schemaName === "" || schemaName === "public" ? tableName : `${schemaName}.${tableName}`;
57
58
  }
59
+ __name(qualifiedTableKey, "qualifiedTableKey");
58
60
 
59
61
  // src/db/policy.ts
62
+ var PolicyExprRef = class _PolicyExprRef {
63
+ static {
64
+ __name(this, "PolicyExprRef");
65
+ }
66
+ expr;
67
+ constructor(expr) {
68
+ this.expr = expr;
69
+ }
70
+ bin(op, other) {
71
+ return new _PolicyExprRef({
72
+ kind: "binop",
73
+ op,
74
+ left: this.expr,
75
+ right: toExpr(other)
76
+ });
77
+ }
78
+ eq(other) {
79
+ return this.bin("eq", other);
80
+ }
81
+ neq(other) {
82
+ return this.bin("neq", other);
83
+ }
84
+ gt(other) {
85
+ return this.bin("gt", other);
86
+ }
87
+ gte(other) {
88
+ return this.bin("gte", other);
89
+ }
90
+ lt(other) {
91
+ return this.bin("lt", other);
92
+ }
93
+ lte(other) {
94
+ return this.bin("lte", other);
95
+ }
96
+ /**
97
+ * `IS NULL` / `IS NOT NULL` — `= NULL` SQL'de her zaman UNKNOWN'dır, o yüzden
98
+ * niyet ayrı bir düğümle yazılır. Partial index'in en sık koşulu
99
+ * (`WHERE deleted_at IS NULL`) tam olarak bu.
100
+ */
101
+ isNull(negated = false) {
102
+ return new _PolicyExprRef({
103
+ kind: "isNull",
104
+ expr: this.expr,
105
+ negated
106
+ });
107
+ }
108
+ and(...others) {
109
+ return new _PolicyExprRef({
110
+ kind: "and",
111
+ parts: [
112
+ this.expr,
113
+ ...others.map((o) => o.expr)
114
+ ]
115
+ });
116
+ }
117
+ or(...others) {
118
+ return new _PolicyExprRef({
119
+ kind: "or",
120
+ parts: [
121
+ this.expr,
122
+ ...others.map((o) => o.expr)
123
+ ]
124
+ });
125
+ }
126
+ not() {
127
+ return new _PolicyExprRef({
128
+ kind: "not",
129
+ expr: this.expr
130
+ });
131
+ }
132
+ };
133
+ function toExpr(v) {
134
+ return v instanceof PolicyExprRef ? v.expr : {
135
+ kind: "lit",
136
+ value: v
137
+ };
138
+ }
139
+ __name(toExpr, "toExpr");
140
+ function exprCtx(_columns, depth = 0, ownTable = "") {
141
+ const alias = `pb_e${depth}`;
142
+ return {
143
+ col: /* @__PURE__ */ __name((name) => new PolicyExprRef(depth === 0 ? {
144
+ kind: "col",
145
+ name
146
+ } : {
147
+ kind: "col",
148
+ name,
149
+ alias
150
+ }), "col"),
151
+ auth: {
152
+ uid: /* @__PURE__ */ __name(() => new PolicyExprRef({
153
+ kind: "authUid"
154
+ }), "uid")
155
+ },
156
+ lit: /* @__PURE__ */ __name((v) => new PolicyExprRef({
157
+ kind: "lit",
158
+ value: v
159
+ }), "lit"),
160
+ and: /* @__PURE__ */ __name((...parts) => new PolicyExprRef({
161
+ kind: "and",
162
+ parts: parts.map((p) => p.expr)
163
+ }), "and"),
164
+ or: /* @__PURE__ */ __name((...parts) => new PolicyExprRef({
165
+ kind: "or",
166
+ parts: parts.map((p) => p.expr)
167
+ }), "or"),
168
+ not: /* @__PURE__ */ __name((part) => new PolicyExprRef({
169
+ kind: "not",
170
+ expr: part.expr
171
+ }), "not"),
172
+ existsIn: /* @__PURE__ */ __name((table, predicate) => {
173
+ const meta = table[TABLE_META];
174
+ const inner = exprCtx(Object.keys(meta.columns), depth + 1, ownTable);
175
+ return new PolicyExprRef({
176
+ kind: "exists",
177
+ table: meta.name,
178
+ alias: `pb_e${depth + 1}`,
179
+ outer: ownTable,
180
+ predicate: predicate(inner).expr
181
+ });
182
+ }, "existsIn")
183
+ };
184
+ }
185
+ __name(exprCtx, "exprCtx");
60
186
  function quote(name) {
61
187
  return `"${name.replace(/"/g, '""')}"`;
62
188
  }
189
+ __name(quote, "quote");
63
190
  var PolicyBuilder = class {
191
+ static {
192
+ __name(this, "PolicyBuilder");
193
+ }
64
194
  _def;
65
195
  constructor(name) {
66
196
  this._def = {
67
197
  name,
68
198
  command: "all",
69
- roles: ["authenticated"],
199
+ roles: [
200
+ "authenticated"
201
+ ],
70
202
  using: null,
71
203
  withCheck: null,
72
204
  permissive: true
@@ -78,65 +210,78 @@ var PolicyBuilder = class {
78
210
  return this;
79
211
  }
80
212
  /**
81
- * Set the DB roles the policy applies to (the `TO` clause), replacing any
82
- * previously-set roles. Call with no arguments to target PUBLIC (all roles).
83
- *
84
- * @example
85
- * policy("p").to("authenticated")
86
- * policy("p").to("authenticated", "service_role")
87
- * policy("p").to() // PUBLIC
88
- */
213
+ * Set the DB roles the policy applies to (the `TO` clause), replacing any
214
+ * previously-set roles. Call with no arguments to target PUBLIC (all roles).
215
+ *
216
+ * @example
217
+ * policy("p").to("authenticated")
218
+ * policy("p").to("authenticated", "service_role")
219
+ * policy("p").to() // PUBLIC
220
+ */
89
221
  to(...roles) {
90
222
  this._def.roles = roles;
91
223
  return this;
92
224
  }
93
- /** Set the `USING (...)` row-visibility expression (raw SQL). */
94
- using(sqlExpr) {
95
- this._def.using = sqlExpr;
225
+ /**
226
+ * `USING (...)` satır görünürlüğü ifadesi.
227
+ *
228
+ * Tercih edilen biçim YAPI'dır (FR-022) — `policies` callback'inin verdiği
229
+ * bağlamla kurulur ve kolon adları derlemede doğrulanır:
230
+ *
231
+ * ```ts
232
+ * policies: (p) => [
233
+ * policy("owner_read").for("select").using(p.col("owner").eq(p.auth.uid())),
234
+ * ]
235
+ * ```
236
+ *
237
+ * Ham string KAÇIŞ KAPAĞI olarak kalır (FR-028): yapının ifade edemediği bir
238
+ * şey gerektiğinde yol kapanmaz. Ama o yolda kolon adı doğrulaması yoktur ve
239
+ * hata deploy anında Postgres'ten gelir.
240
+ */
241
+ using(expr) {
242
+ this._def.using = expr instanceof PolicyExprRef ? expr.expr : expr;
96
243
  return this;
97
244
  }
98
245
  /**
99
- * "Rows of THIS table whose owner the caller is a member of" — the membership
100
- * pattern, written so it cannot recurse.
101
- *
102
- * THE TRAP IT EXISTS FOR. Written by hand, membership policies point at each
103
- * other: `channels` is visible to members, so its policy reads
104
- * `channel_members`; `channel_members` is visible to members, so its policy
105
- * reads `channels`. Postgres refuses the pair at query time with `infinite
106
- * recursion detected in policy for relation ...`, and the error names the
107
- * relation but not the cycle. The way out is asymmetry — the MEMBERSHIP table
108
- * is protected by `user_id = auth.uid()` and nothing else, and every other
109
- * table subqueries INTO it. That shape was in the platform's own schema and
110
- * written down nowhere; a customer recovered it by reading that schema.
111
- *
112
- * `(select auth.uid())` rather than a bare call: the scalar subquery is
113
- * evaluated ONCE per statement instead of per row.
114
- *
115
- * @example
116
- * // channels: visible to members. The membership table gets the simple one.
117
- * policy("member_read").for("select").to("authenticated")
118
- * .memberOf("channel_members", "channel_id")
119
- * // → id IN (SELECT "channel_id" FROM "channel_members"
120
- * // WHERE "user_id" = (select auth.uid()))
121
- */
246
+ * "Rows of THIS table whose owner the caller is a member of" — the membership
247
+ * pattern, written so it cannot recurse.
248
+ *
249
+ * THE TRAP IT EXISTS FOR. Written by hand, membership policies point at each
250
+ * other: `channels` is visible to members, so its policy reads
251
+ * `channel_members`; `channel_members` is visible to members, so its policy
252
+ * reads `channels`. Postgres refuses the pair at query time with `infinite
253
+ * recursion detected in policy for relation ...`, and the error names the
254
+ * relation but not the cycle. The way out is asymmetry — the MEMBERSHIP table
255
+ * is protected by `user_id = auth.uid()` and nothing else, and every other
256
+ * table subqueries INTO it. That shape was in the platform's own schema and
257
+ * written down nowhere; a customer recovered it by reading that schema.
258
+ *
259
+ * `(select auth.uid())` rather than a bare call: the scalar subquery is
260
+ * evaluated ONCE per statement instead of per row.
261
+ *
262
+ * @example
263
+ * // channels: visible to members. The membership table gets the simple one.
264
+ * policy("member_read").for("select").to("authenticated")
265
+ * .memberOf("channel_members", "channel_id")
266
+ * // → id IN (SELECT "channel_id" FROM "channel_members"
267
+ * // WHERE "user_id" = (select auth.uid()))
268
+ */
122
269
  memberOf(membershipTable, foreignKey, options = {}) {
123
270
  if (this._def.using !== null) {
124
- throw new Error(
125
- `policy(${this._def.name}).memberOf(): this policy already has a using() expression. Write one or the other \u2014 memberOf IS the using expression.`
126
- );
271
+ 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.`);
127
272
  }
128
273
  const column = options.column ?? "id";
129
274
  const userColumn = options.userColumn ?? "user_id";
130
275
  this._def.using = `${quote(column)} IN (SELECT ${quote(foreignKey)} FROM ${quote(membershipTable)} WHERE ${quote(userColumn)} = (select auth.uid()))`;
131
276
  return this;
132
277
  }
133
- /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */
134
- withCheck(sqlExpr) {
135
- this._def.withCheck = sqlExpr;
278
+ /** `WITH CHECK (...)` yazma doğrulaması `using` ile aynı iki biçim. */
279
+ withCheck(expr) {
280
+ this._def.withCheck = expr instanceof PolicyExprRef ? expr.expr : expr;
136
281
  return this;
137
282
  }
138
283
  /** Set the policy mode: `"permissive"` (default, OR-combined) or
139
- * `"restrictive"` (AND-combined). */
284
+ * `"restrictive"` (AND-combined). */
140
285
  as(mode) {
141
286
  this._def.permissive = mode === "permissive";
142
287
  return this;
@@ -145,23 +290,93 @@ var PolicyBuilder = class {
145
290
  function policy(name) {
146
291
  return new PolicyBuilder(name);
147
292
  }
293
+ __name(policy, "policy");
148
294
 
149
295
  // src/db/schema.ts
296
+ var IndexBuilder = class {
297
+ static {
298
+ __name(this, "IndexBuilder");
299
+ }
300
+ _def;
301
+ constructor(name) {
302
+ if (name.trim() === "") {
303
+ throw new Error("index(ad): index'in ad\u0131 bo\u015F olamaz \u2014 Palbase index'leri ADA g\xF6re uzla\u015Ft\u0131r\u0131r.");
304
+ }
305
+ this._def = {
306
+ name
307
+ };
308
+ }
309
+ /** Index'in kolonları. SIRA KORUNUR — çok kolonlu bir index'in anlamı sırasıdır. */
310
+ on(...cols) {
311
+ this._def.columns = cols.map((c) => {
312
+ const e = c.expr;
313
+ if (e.kind !== "col") {
314
+ throw new Error(`index(${this._def.name}).on(): yaln\u0131z kolon referans\u0131 al\u0131r \u2014 ifade i\xE7in onExpression("\u2026") kullan\u0131n.`);
315
+ }
316
+ return e.name;
317
+ });
318
+ return this;
319
+ }
320
+ /**
321
+ * İfade index'i (`lower(email)`), kolon yerine.
322
+ *
323
+ * Metin VERBATIM emit ediliyor — `policy().using("…")` ile aynı güven duruşu.
324
+ * Tipli yapı bunu ifade edemiyor ve kaçış kapağını kapatmak, yazarı elle
325
+ * migration yazmaya iterdi.
326
+ */
327
+ onExpression(expr) {
328
+ this._def.expression = expr;
329
+ return this;
330
+ }
331
+ /** Partial index koşulu — politika ifade dilinin ta kendisi. */
332
+ where(expr) {
333
+ this._def.where = expr.expr;
334
+ return this;
335
+ }
336
+ /** Sıra. Tek yönlü index'te sıra genelde önemsizdir; ORDER BY ile eşleşen
337
+ * bir index arandığında değildir. */
338
+ desc() {
339
+ this._def.sort = "desc";
340
+ return this;
341
+ }
342
+ asc() {
343
+ this._def.sort = "asc";
344
+ return this;
345
+ }
346
+ /** NULL'ların yeri — `ORDER BY … NULLS LAST` ile eşleşmesi için. */
347
+ nulls(where) {
348
+ this._def.nulls = where;
349
+ return this;
350
+ }
351
+ /** Covering index (`INCLUDE`): index-only scan için taşınan ama
352
+ * ARANMAYAN kolonlar. */
353
+ include(cols) {
354
+ this._def.include = cols;
355
+ return this;
356
+ }
357
+ };
150
358
  function toPolicyDef(p) {
151
359
  return p instanceof PolicyBuilder ? p._def : p;
152
360
  }
361
+ __name(toPolicyDef, "toPolicyDef");
153
362
  var TABLE_META = /* @__PURE__ */ Symbol.for("palbase.table.meta");
154
363
  function defineTable(name, input) {
155
364
  if (name.trim() === "") {
156
365
  throw new Error("defineTable(name, \u2026): name must not be empty");
157
366
  }
158
- const policies = (input.policies ?? []).map(toPolicyDef);
367
+ const policies = (input.policies?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map(toPolicyDef);
159
368
  const rls = policies.length > 0 || input.rls !== false;
160
369
  const owned = {};
161
370
  for (const [colName, b] of Object.entries(input.columns)) {
162
371
  const builder = b;
163
372
  const clone = Object.create(Object.getPrototypeOf(builder));
164
- Object.defineProperty(clone, "_def", { value: { ...builder._def }, enumerable: true, writable: true });
373
+ Object.defineProperty(clone, "_def", {
374
+ value: {
375
+ ...builder._def
376
+ },
377
+ enumerable: true,
378
+ writable: true
379
+ });
165
380
  owned[colName] = clone;
166
381
  }
167
382
  const def = {
@@ -174,22 +389,20 @@ function defineTable(name, input) {
174
389
  if (input.unique !== void 0) def.unique = input.unique;
175
390
  if (input.raw !== void 0 && input.raw.length > 0) def.raw = input.raw.slice();
176
391
  if (input.checks !== void 0 && input.checks.length > 0) def.checks = input.checks.slice();
177
- if (input.indexes !== void 0 && input.indexes.length > 0) def.indexes = input.indexes.slice();
392
+ const declaredIndexes = (input.indexes?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map((i) => i instanceof IndexBuilder ? i._def : i);
393
+ if (declaredIndexes.length > 0) def.indexes = declaredIndexes;
394
+ if (input.appendOnly === true) def.appendOnly = true;
178
395
  if (input.search !== void 0) {
179
396
  const s = input.search;
180
397
  if (s.from !== void 0) {
181
398
  if (s.vector !== void 0) {
182
- throw new Error(
183
- `table ${name}: search beyan\u0131nda tek bi\xE7im kullan\u0131n \u2014 'from' (yeni) ile 'vector' (eski) birlikte olamaz`
184
- );
399
+ throw new Error(`table ${name}: search beyan\u0131nda tek bi\xE7im kullan\u0131n \u2014 'from' (yeni) ile 'vector' (eski) birlikte olamaz`);
185
400
  }
186
401
  if (s.from.length === 0) {
187
402
  throw new Error(`table ${name}: search.from bo\u015F olamaz`);
188
403
  }
189
404
  if (s.model === void 0) {
190
- throw new Error(
191
- `table ${name}: search.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin (BYO i\xE7in eski 'vector' bi\xE7imini kullan\u0131n)`
192
- );
405
+ 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)`);
193
406
  }
194
407
  if (Array.isArray(s.text) && s.text.length === 0) {
195
408
  throw new Error(`table ${name}: search.text bo\u015F dizi olamaz \u2014 FTS istemiyorsan text: false yaz\u0131n`);
@@ -199,14 +412,14 @@ function defineTable(name, input) {
199
412
  throw new Error(`table ${name}: text:${String(s.text)} yaln\u0131z yeni bi\xE7imde ('from' ile) ge\xE7erli`);
200
413
  }
201
414
  if (s.text === void 0 && s.vector === void 0) {
202
- throw new Error(
203
- `table ${name}: search beyan\u0131 bo\u015F \u2014 en az bir kol (text ya da vector) verin, yoksa alan\u0131 hi\xE7 yazmay\u0131n`
204
- );
415
+ 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`);
205
416
  }
206
417
  if (s.text !== void 0 && s.text.length === 0) {
207
418
  throw new Error(`table ${name}: search.text bo\u015F olamaz \u2014 FTS kolu istemiyorsan alan\u0131 hi\xE7 yazma`);
208
419
  }
209
- const legs = s.vector === void 0 ? [] : Array.isArray(s.vector) ? s.vector : [s.vector];
420
+ const legs = s.vector === void 0 ? [] : Array.isArray(s.vector) ? s.vector : [
421
+ s.vector
422
+ ];
210
423
  for (const leg of legs) {
211
424
  if (leg.model !== void 0 && (leg.from === void 0 || leg.from.length === 0)) {
212
425
  throw new Error(`table ${name}: search.vector.model beyan edildi ama 'from' yok \u2014 embed kayna\u011F\u0131 kolonlar zorunlu (C-2)`);
@@ -227,10 +440,16 @@ function defineTable(name, input) {
227
440
  for (const b of Object.values(owned)) {
228
441
  b._def.ownerTable = def;
229
442
  }
230
- const handle = { ...owned };
231
- Object.defineProperty(handle, TABLE_META, { value: def, enumerable: false });
443
+ const handle = {
444
+ ...owned
445
+ };
446
+ Object.defineProperty(handle, TABLE_META, {
447
+ value: def,
448
+ enumerable: false
449
+ });
232
450
  return handle;
233
451
  }
452
+ __name(defineTable, "defineTable");
234
453
  var declaringSchemaOf = /* @__PURE__ */ new WeakMap();
235
454
  function resolveReferences(tables, schemaName) {
236
455
  for (const table of Object.values(tables)) {
@@ -238,9 +457,7 @@ function resolveReferences(tables, schemaName) {
238
457
  const def = builder._def;
239
458
  if (def.selfRefColumn !== void 0) {
240
459
  if (!(def.selfRefColumn in table.columns)) {
241
- throw new Error(
242
- `table "${table.name}" column "${colName}": selfReferences("${def.selfRefColumn}") \u2014 no such column on this table`
243
- );
460
+ throw new Error(`table "${table.name}" column "${colName}": selfReferences("${def.selfRefColumn}") \u2014 no such column on this table`);
244
461
  }
245
462
  def.references = {
246
463
  table: qualifiedTableKey(schemaName, table.name),
@@ -252,23 +469,15 @@ function resolveReferences(tables, schemaName) {
252
469
  const target = def.referencesThunk();
253
470
  const owner = target?._def?.ownerTable;
254
471
  if (owner === void 0) {
255
- throw new Error(
256
- `table "${table.name}" column "${colName}": references(() => \u2026) must point at a column of a table declared with defineTable(...)`
257
- );
472
+ throw new Error(`table "${table.name}" column "${colName}": references(() => \u2026) must point at a column of a table declared with defineTable(...)`);
258
473
  }
259
- const targetColumn = Object.entries(owner.columns).find(
260
- ([, b]) => b._def === target._def
261
- )?.[0];
474
+ const targetColumn = Object.entries(owner.columns).find(([, b]) => b._def === target._def)?.[0];
262
475
  if (targetColumn === void 0) {
263
- throw new Error(
264
- `table "${table.name}" column "${colName}": the referenced column was not found on table "${owner.name}"`
265
- );
476
+ throw new Error(`table "${table.name}" column "${colName}": the referenced column was not found on table "${owner.name}"`);
266
477
  }
267
478
  const targetSchema = declaringSchemaOf.get(owner);
268
479
  if (targetSchema === void 0) {
269
- throw new Error(
270
- `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).`
271
- );
480
+ 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).`);
272
481
  }
273
482
  def.references = {
274
483
  table: qualifiedTableKey(targetSchema, owner.name),
@@ -277,11 +486,10 @@ function resolveReferences(tables, schemaName) {
277
486
  }
278
487
  }
279
488
  }
489
+ __name(resolveReferences, "resolveReferences");
280
490
  function defineSchema(name, input) {
281
491
  if (typeof name !== "string") {
282
- throw new Error(
283
- `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.`
284
- );
492
+ 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.`);
285
493
  }
286
494
  if (name.trim() === "") {
287
495
  throw new Error("defineSchema(name, \u2026): name must not be empty");
@@ -290,9 +498,7 @@ function defineSchema(name, input) {
290
498
  for (const handle of input.tables) {
291
499
  const table = handle[TABLE_META];
292
500
  if (tables[table.name] !== void 0) {
293
- throw new Error(
294
- `defineSchema("${name}"): two tables declare the name "${table.name}" \u2014 table names must be unique within a schema`
295
- );
501
+ throw new Error(`defineSchema("${name}"): two tables declare the name "${table.name}" \u2014 table names must be unique within a schema`);
296
502
  }
297
503
  tables[table.name] = table;
298
504
  declaringSchemaOf.set(table, name);
@@ -323,7 +529,9 @@ function defineSchema(name, input) {
323
529
  }
324
530
  }
325
531
  }
326
- const extensions = [...new Set(input.extensions ?? [])];
532
+ const extensions = [
533
+ ...new Set(input.extensions ?? [])
534
+ ];
327
535
  return {
328
536
  name,
329
537
  tables,
@@ -331,46 +539,39 @@ function defineSchema(name, input) {
331
539
  exposed: input.exposed ?? name === "public"
332
540
  };
333
541
  }
542
+ __name(defineSchema, "defineSchema");
334
543
 
335
544
  // src/db/extensions.ts
336
545
  var PALBASE_EXTENSIONS = [
337
546
  // Search & text
338
547
  "vector",
339
- // pgvector: AI embeddings + vector similarity search (semantic search / RAG).
340
548
  // NB: the Postgres extension is named "vector", not "pgvector" — declare "vector".
341
549
  "pg_trgm",
342
- // trigram fuzzy / typo-tolerant text search
343
550
  "unaccent",
344
- // accent-insensitive text search
345
551
  "citext",
346
- // case-insensitive text type
347
552
  // Geospatial / location
348
553
  "cube",
349
- // multi-dimensional cubes (dependency of earthdistance)
350
554
  "earthdistance",
351
- // great-circle distance (needs cube)
352
555
  // Data types & structures
353
556
  "hstore",
354
- // key/value pairs in a single column
355
557
  "ltree",
356
- // hierarchical tree-structured labels
357
558
  // Indexing & constraints
358
559
  "btree_gist",
359
- // GiST operator classes for scalar types — needed for EXCLUDE
360
560
  // constraints that mix "=" with a range/&& overlap (e.g. no-double-booking).
361
561
  // Scheduling
362
562
  // Crypto / ids (also installed by default; listable for explicitness)
363
563
  "pgcrypto",
364
- // cryptographic functions (hashing, encryption)
365
564
  "uuid-ossp"
366
- // UUID generation functions
367
565
  ];
368
566
  var EXTENSION_DEPENDENCIES = {
369
- earthdistance: ["cube"]
567
+ earthdistance: [
568
+ "cube"
569
+ ]
370
570
  };
371
571
  function isPalbaseExtension(name) {
372
572
  return PALBASE_EXTENSIONS.includes(name);
373
573
  }
574
+ __name(isPalbaseExtension, "isPalbaseExtension");
374
575
 
375
576
  // src/db/columns.ts
376
577
  function refuseOnVector(def, modifier) {
@@ -378,7 +579,11 @@ function refuseOnVector(def, modifier) {
378
579
  throw new Error(`vector column: .${modifier}() is not supported (FR-002 \u2014 allowed: nullable()/notNull())`);
379
580
  }
380
581
  }
582
+ __name(refuseOnVector, "refuseOnVector");
381
583
  var ColumnBuilder = class _ColumnBuilder {
584
+ static {
585
+ __name(this, "ColumnBuilder");
586
+ }
382
587
  _def;
383
588
  constructor(type, existingDef) {
384
589
  this._def = existingDef ?? {
@@ -422,52 +627,52 @@ var ColumnBuilder = class _ColumnBuilder {
422
627
  return new _ColumnBuilder(this._def.type, this._def);
423
628
  }
424
629
  /**
425
- * The DATABASE assigns this column's value — a trigger, a rule, an identity.
426
- *
427
- * The column becomes optional on INSERT (the author has nothing to send) while
428
- * the DDL stays free of a DEFAULT this schema would not honour. It is NOT
429
- * `default()`: that declares a value the schema promises to write.
430
- *
431
- * Naming: deliberately not `generated()`. Postgres has GENERATED columns and
432
- * they are a different thing; borrowing the word would send a reader — or a
433
- * model writing a schema — to the wrong feature.
434
- */
630
+ * The DATABASE assigns this column's value — a trigger, a rule, an identity.
631
+ *
632
+ * The column becomes optional on INSERT (the author has nothing to send) while
633
+ * the DDL stays free of a DEFAULT this schema would not honour. It is NOT
634
+ * `default()`: that declares a value the schema promises to write.
635
+ *
636
+ * Naming: deliberately not `generated()`. Postgres has GENERATED columns and
637
+ * they are a different thing; borrowing the word would send a reader — or a
638
+ * model writing a schema — to the wrong feature.
639
+ */
435
640
  dbAssigned() {
436
641
  this._def.dbAssigned = true;
437
642
  return new _ColumnBuilder(this._def.type, this._def);
438
643
  }
439
644
  /** Add a foreign key reference. */
440
645
  /**
441
- * Declares that this column used to be called `previous`.
442
- *
443
- * A schema diff sees one name gone and another present; it cannot know whether
444
- * you renamed a column or dropped one and added another, and the two are very
445
- * different — the second loses every value. Saying so here turns the plan into
446
- * `ALTER TABLE … RENAME COLUMN` instead.
447
- *
448
- * Once the rename has been applied the annotation is inert (the old name is no
449
- * longer there to rename), so it can be deleted at your leisure.
450
- */
646
+ * Declares that this column used to be called `previous`.
647
+ *
648
+ * A schema diff sees one name gone and another present; it cannot know whether
649
+ * you renamed a column or dropped one and added another, and the two are very
650
+ * different — the second loses every value. Saying so here turns the plan into
651
+ * `ALTER TABLE … RENAME COLUMN` instead.
652
+ *
653
+ * Once the rename has been applied the annotation is inert (the old name is no
654
+ * longer there to rename), so it can be deleted at your leisure.
655
+ */
451
656
  renamedFrom(previous) {
452
657
  this._def.renamedFrom = previous;
453
658
  return this;
454
659
  }
455
660
  /**
456
- * See {@link ColumnDef.ignored}.
457
- *
458
- * COPIES the def rather than mutating it. The constructor takes an existing
459
- * def BY REFERENCE, so every builder derived from another shares one object —
460
- * `const a = slug.unique()` leaves `a._def === slug._def`. An in-place
461
- * `ignored = true` therefore marks every column sharing that def, including
462
- * one another table actively reads, and the gate would let THAT column be
463
- * dropped. Measured before this copy existed.
464
- *
465
- * The aliasing is older than this method and other fields leak through it too.
466
- * The reason this one cannot wait: every other leak produces a VISIBLE schema
467
- * difference — the plan shows it, the DDL shows it. This one is invisible by
468
- * design (no DDL, no diff, no plan line), so its only effect is to disarm a
469
- * safety gate in silence.
470
- */
661
+ * See {@link ColumnDef.ignored}.
662
+ *
663
+ * COPIES the def rather than mutating it. The constructor takes an existing
664
+ * def BY REFERENCE, so every builder derived from another shares one object —
665
+ * `const a = slug.unique()` leaves `a._def === slug._def`. An in-place
666
+ * `ignored = true` therefore marks every column sharing that def, including
667
+ * one another table actively reads, and the gate would let THAT column be
668
+ * dropped. Measured before this copy existed.
669
+ *
670
+ * The aliasing is older than this method and other fields leak through it too.
671
+ * The reason this one cannot wait: every other leak produces a VISIBLE schema
672
+ * difference — the plan shows it, the DDL shows it. This one is invisible by
673
+ * design (no DDL, no diff, no plan line), so its only effect is to disarm a
674
+ * safety gate in silence.
675
+ */
471
676
  ignored() {
472
677
  return new _ColumnBuilder(this._def.type, {
473
678
  ...this._def,
@@ -475,47 +680,67 @@ var ColumnBuilder = class _ColumnBuilder {
475
680
  });
476
681
  }
477
682
  /**
478
- * Foreign key onto another table's column.
479
- *
480
- * The target is a THUNK, not a direct reference. In a cycle (`x → y`, `y → x`)
481
- * the second table does not exist yet when the first is built; a direct
482
- * reference makes TypeScript chase its own tail (TS7022 — measured, and making
483
- * the return type independent of the target does NOT help). The thunk is
484
- * invoked in `defineSchema`, where every binding exists and every table
485
- * already knows its name.
486
- *
487
- * In a cycle, ONE side needs an explicit return type:
488
- * `references((): AnyColumn => y.id)`. One side is enough — measured.
489
- * For a self-reference use `selfReferences(column)`: no thunk, no annotation.
490
- *
491
- * `as` names the FORWARD relation (`author_id` → `author` by default);
492
- * `reverseAs` names the REVERSE one on the parent, whose default is this
493
- * table's own name (`users.posts`). Two foreign keys from one table onto one
494
- * parent therefore need a `reverseAs` on at least one of them — the reverse
495
- * names would otherwise both be this table's name.
496
- */
683
+ * Foreign key onto another table's column.
684
+ *
685
+ * The target is a THUNK, not a direct reference. In a cycle (`x → y`, `y → x`)
686
+ * the second table does not exist yet when the first is built; a direct
687
+ * reference makes TypeScript chase its own tail (TS7022 — measured, and making
688
+ * the return type independent of the target does NOT help). The thunk is
689
+ * invoked in `defineSchema`, where every binding exists and every table
690
+ * already knows its name.
691
+ *
692
+ * In a cycle, ONE side needs an explicit return type:
693
+ * `references((): AnyColumn => y.id)`. One side is enough — measured.
694
+ * For a self-reference use `selfReferences(column)`: no thunk, no annotation.
695
+ *
696
+ * `as` names the FORWARD relation (`author_id` → `author` by default);
697
+ * `reverseAs` names the REVERSE one on the parent, whose default is this
698
+ * table's own name (`users.posts`). Two foreign keys from one table onto one
699
+ * parent therefore need a `reverseAs` on at least one of them — the reverse
700
+ * names would otherwise both be this table's name.
701
+ */
497
702
  references(target, opts) {
498
703
  refuseOnVector(this._def, "references");
499
704
  if (typeof target !== "function") {
500
- throw new Error(
501
- `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.`
502
- );
705
+ 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.`);
503
706
  }
504
707
  this._def.referencesThunk = target;
505
708
  if (opts?.as !== void 0) this._def.refAs = opts.as;
506
709
  if (opts?.reverseAs !== void 0) this._def.reverseAs = opts.reverseAs;
507
710
  if (opts?.onDelete !== void 0) this._def.onDeleteAction = opts.onDelete;
711
+ if (opts?.index === false) this._def.index = false;
712
+ return new _ColumnBuilder(this._def.type, this._def);
713
+ }
714
+ /**
715
+ * Bu kolon `increment()` / `decrement()` ile güncelleniyor (FR-049).
716
+ *
717
+ * Deploy kontrolcü kodunu OKUMAZ, o yüzden bildirimin söylemesi gerekiyor —
718
+ * ve söylediği anda plan bir şeyi görebiliyor: aynı kolon hem sayaç hem
719
+ * indeksliyse her güncelleme HOT'u kaybeder.
720
+ *
721
+ * ZİNCİR (D-028+D-030): HOT kaybı → ölü tuple → autovacuum yükü → ve
722
+ * autovacuum worker'ları KÜME GENELİNDE bir kaynak, yani bedeli başka
723
+ * kiracıların tabloları da öder.
724
+ *
725
+ * Sektörde çare "dokümana uyarı yaz"dır, çünkü index'i ekleyen kişi
726
+ * `increment()`'i yazan kişi değildir. Bu bildirimde ikisi de YAN YANA
727
+ * duruyor.
728
+ *
729
+ * Uyarı, HATA DEĞİL: sayaç kolonunu indekslemek bazen doğru karardır.
730
+ */
731
+ counter() {
732
+ this._def.counter = true;
508
733
  return new _ColumnBuilder(this._def.type, this._def);
509
734
  }
510
735
  /**
511
- * Foreign key onto THIS table (`parent_id → id`) — category trees, comment
512
- * replies, org charts.
513
- *
514
- * No thunk and no type annotation: the target table is the one being declared,
515
- * so there is nothing to defer and nothing for TypeScript to chase in a circle.
516
- * Drizzle forces an explicit `(): AnyPgColumn =>` here because its reference
517
- * always goes through a callback; measured, we do not need one.
518
- */
736
+ * Foreign key onto THIS table (`parent_id → id`) — category trees, comment
737
+ * replies, org charts.
738
+ *
739
+ * No thunk and no type annotation: the target table is the one being declared,
740
+ * so there is nothing to defer and nothing for TypeScript to chase in a circle.
741
+ * Drizzle forces an explicit `(): AnyPgColumn =>` here because its reference
742
+ * always goes through a callback; measured, we do not need one.
743
+ */
519
744
  selfReferences(column, opts) {
520
745
  refuseOnVector(this._def, "selfReferences");
521
746
  this._def.selfRefColumn = column;
@@ -535,23 +760,23 @@ var ColumnBuilder = class _ColumnBuilder {
535
760
  return new _ColumnBuilder(this._def.type, this._def);
536
761
  }
537
762
  /**
538
- * Declare how this column's value is projected in and out of the process.
539
- *
540
- * The DDL does not move: `numeric` stays `numeric`, and the driver still hands
541
- * back what Postgres sent. What changes is the type the row surface exposes —
542
- * it becomes `Target`:
543
- *
544
- * amount: numeric().transform<number>({ fromDb: Number, toDb: String })
545
- *
546
- * `numeric` surfacing as `string` is CORRECT (a JS number cannot hold
547
- * arbitrary precision), and that is exactly why this exists: application code
548
- * that does arithmetic on the column otherwise rewrites the same
549
- * `Number(row.amount)` / `String(x)` pair in every controller that touches it,
550
- * and each rewrite is a place the two directions can drift apart.
551
- *
552
- * A transform is a PROJECTION, never a constraint: it lives only in this
553
- * process, so it can neither validate nor migrate what is stored.
554
- */
763
+ * Declare how this column's value is projected in and out of the process.
764
+ *
765
+ * The DDL does not move: `numeric` stays `numeric`, and the driver still hands
766
+ * back what Postgres sent. What changes is the type the row surface exposes —
767
+ * it becomes `Target`:
768
+ *
769
+ * amount: numeric().transform<number>({ fromDb: Number, toDb: String })
770
+ *
771
+ * `numeric` surfacing as `string` is CORRECT (a JS number cannot hold
772
+ * arbitrary precision), and that is exactly why this exists: application code
773
+ * that does arithmetic on the column otherwise rewrites the same
774
+ * `Number(row.amount)` / `String(x)` pair in every controller that touches it,
775
+ * and each rewrite is a place the two directions can drift apart.
776
+ *
777
+ * A transform is a PROJECTION, never a constraint: it lives only in this
778
+ * process, so it can neither validate nor migrate what is stored.
779
+ */
555
780
  transform(fns) {
556
781
  this._def.transform = fns;
557
782
  return new _ColumnBuilder(this._def.type, this._def);
@@ -560,30 +785,40 @@ var ColumnBuilder = class _ColumnBuilder {
560
785
  function uuid() {
561
786
  return new ColumnBuilder("uuid");
562
787
  }
788
+ __name(uuid, "uuid");
563
789
  function text() {
564
790
  return new ColumnBuilder("text");
565
791
  }
792
+ __name(text, "text");
566
793
  function integer() {
567
794
  return new ColumnBuilder("integer");
568
795
  }
796
+ __name(integer, "integer");
569
797
  function bigint() {
570
798
  return new ColumnBuilder("bigint");
571
799
  }
800
+ __name(bigint, "bigint");
572
801
  function boolean() {
573
802
  return new ColumnBuilder("boolean");
574
803
  }
804
+ __name(boolean, "boolean");
575
805
  function timestamp() {
576
806
  return new ColumnBuilder("timestamp");
577
807
  }
808
+ __name(timestamp, "timestamp");
578
809
  function jsonb() {
579
810
  return new ColumnBuilder("jsonb");
580
811
  }
812
+ __name(jsonb, "jsonb");
581
813
  function enumType(name, values) {
582
814
  const builder = new ColumnBuilder("enum");
583
815
  builder._def.enumName = name;
584
- builder._def.enumValues = [...values];
816
+ builder._def.enumValues = [
817
+ ...values
818
+ ];
585
819
  return builder;
586
820
  }
821
+ __name(enumType, "enumType");
587
822
  function vector(dimensions) {
588
823
  if (!Number.isInteger(dimensions) || dimensions < 1 || dimensions > 2e3) {
589
824
  throw new Error(`vector(): dimensions must be an integer in [1, 2000], got ${String(dimensions)}`);
@@ -592,33 +827,53 @@ function vector(dimensions) {
592
827
  b._def.dimensions = dimensions;
593
828
  return b;
594
829
  }
830
+ __name(vector, "vector");
595
831
  function ownedByUser() {
596
832
  const b = new ColumnBuilder("text");
597
833
  b._def.nullable = false;
598
- b._def.references = { table: "auth.users", column: "id" };
834
+ b._def.references = {
835
+ table: "auth.users",
836
+ column: "id"
837
+ };
599
838
  b._def.onDeleteAction = "cascade";
600
839
  b._def.owns = true;
601
840
  return b;
602
841
  }
842
+ __name(ownedByUser, "ownedByUser");
603
843
  function userRef(opts) {
604
844
  const b = new ColumnBuilder("text");
605
- b._def.references = { table: "auth.users", column: "id" };
845
+ b._def.references = {
846
+ table: "auth.users",
847
+ column: "id"
848
+ };
606
849
  b._def.onDeleteAction = opts.onDelete;
607
850
  if (opts.as !== void 0) b._def.refAs = opts.as;
608
851
  return b;
609
852
  }
853
+ __name(userRef, "userRef");
610
854
  function installationRef(opts) {
611
855
  const b = new ColumnBuilder("text");
612
- b._def.references = { table: "auth.installations", column: "id" };
856
+ b._def.references = {
857
+ table: "auth.installations",
858
+ column: "id"
859
+ };
613
860
  b._def.onDeleteAction = opts.onDelete;
614
861
  if (opts.as !== void 0) b._def.refAs = opts.as;
615
862
  return b;
616
863
  }
864
+ __name(installationRef, "installationRef");
617
865
 
618
866
  // src/db/raw.ts
619
867
  function raw(name, up, opts) {
620
- return { name, up, ...opts?.down != null ? { down: opts.down } : {} };
868
+ return {
869
+ name,
870
+ up,
871
+ ...opts?.down != null ? {
872
+ down: opts.down
873
+ } : {}
874
+ };
621
875
  }
876
+ __name(raw, "raw");
622
877
 
623
878
  // src/db/embedding.ts
624
879
  var openai = {
@@ -627,23 +882,62 @@ var openai = {
627
882
  provider: "openai",
628
883
  model,
629
884
  apiKeyName: opts?.apiKeyName ?? "OPENAI_API_KEY",
630
- ...opts?.dimensions !== void 0 ? { dimensions: opts.dimensions } : {},
631
- ...opts?.baseURL !== void 0 ? { baseURL: opts.baseURL } : {}
885
+ ...opts?.dimensions !== void 0 ? {
886
+ dimensions: opts.dimensions
887
+ } : {},
888
+ ...opts?.baseURL !== void 0 ? {
889
+ baseURL: opts.baseURL
890
+ } : {}
632
891
  };
633
892
  },
634
893
  chat(model) {
635
- return { provider: "openai", model };
894
+ return {
895
+ provider: "openai",
896
+ model
897
+ };
636
898
  }
637
899
  };
638
900
 
901
+ // src/db/input-guards.ts
902
+ var REF_BRAND = /* @__PURE__ */ Symbol.for("palbase.db.ref");
903
+ function brandRef(v, kind) {
904
+ Object.defineProperty(v, REF_BRAND, {
905
+ value: kind,
906
+ enumerable: false
907
+ });
908
+ return v;
909
+ }
910
+ __name(brandRef, "brandRef");
911
+ function brandOf(v) {
912
+ if (typeof v !== "object" || v === null) return void 0;
913
+ return Object.hasOwn(v, REF_BRAND) ? v[REF_BRAND] : void 0;
914
+ }
915
+ __name(brandOf, "brandOf");
916
+ function isColRef(v) {
917
+ return brandOf(v) === "col" && typeof v.$col === "string";
918
+ }
919
+ __name(isColRef, "isColRef");
920
+ function isSqlFragment(v) {
921
+ if (brandOf(v) !== "sql") return false;
922
+ const f = v.$sql;
923
+ return f !== void 0 && Array.isArray(f.text) && Array.isArray(f.values);
924
+ }
925
+ __name(isSqlFragment, "isSqlFragment");
926
+
639
927
  // src/db/tx-plan.ts
640
928
  var TxRefError = class extends Error {
929
+ static {
930
+ __name(this, "TxRefError");
931
+ }
641
932
  constructor(message) {
642
933
  super(message);
643
934
  this.name = "TxRefError";
644
935
  }
645
936
  };
646
937
  var TxPlanError = class extends Error {
938
+ static {
939
+ __name(this, "TxPlanError");
940
+ }
647
941
  constructor(message) {
648
942
  super(message);
649
943
  this.name = "TxPlanError";
@@ -662,126 +956,193 @@ var TRAPPED_PROPS = [
662
956
  ];
663
957
  function trap(prop, what, hint) {
664
958
  const name = typeof prop === "symbol" ? prop.description ?? String(prop) : prop;
665
- throw new TxRefError(
666
- `${what} was used as a value (via \`${name}\`). Nothing in a transaction callback has run yet, so there is no value to read. ${hint}`
667
- );
959
+ throw new TxRefError(`${what} was used as a value (via \`${name}\`). Nothing in a transaction callback has run yet, so there is no value to read. ${hint}`);
668
960
  }
961
+ __name(trap, "trap");
669
962
  function now() {
670
- return makeExpr({ fn: "now" });
963
+ return makeExpr({
964
+ fn: "now"
965
+ });
671
966
  }
672
- function inc(by) {
673
- assertFiniteNumber(by, "inc");
674
- return makeExpr({ fn: "inc", by });
967
+ __name(now, "now");
968
+ function increment(by) {
969
+ assertAmount(by, "increment");
970
+ return makeExpr({
971
+ fn: "inc",
972
+ by
973
+ });
675
974
  }
676
- function dec(by) {
677
- assertFiniteNumber(by, "dec");
678
- return makeExpr({ fn: "dec", by });
975
+ __name(increment, "increment");
976
+ var inc = increment;
977
+ function decrement(by) {
978
+ assertAmount(by, "decrement");
979
+ return makeExpr({
980
+ fn: "dec",
981
+ by
982
+ });
679
983
  }
680
- function assertFiniteNumber(by, fn) {
681
- if (typeof by !== "number" || !Number.isFinite(by)) {
984
+ __name(decrement, "decrement");
985
+ var dec = decrement;
986
+ function assertAmount(by, fn) {
987
+ if (typeof by === "string") {
988
+ if (!/^-?\d+(\.\d+)?$/.test(by)) {
989
+ throw new TxPlanError(`${fn}() ondal\u0131k bir say\u0131 metni bekliyor, "${by}" ald\u0131 \u2014 kabul edilen bi\xE7im: "12", "-12", "12.50"`);
990
+ }
991
+ } else if (typeof by !== "number" || !Number.isFinite(by)) {
682
992
  throw new TxPlanError(`${fn}() needs a finite number, got ${String(by)}`);
683
993
  }
994
+ const negative = typeof by === "string" ? by.trimStart().startsWith("-") : by < 0;
995
+ if (negative) {
996
+ const other = fn === "increment" ? "decrement" : "increment";
997
+ throw new TxPlanError(`${fn}() negatif miktar almaz ("${String(by)}"). Ters y\xF6n i\xE7in ${other}() kullan\u0131n \u2014 i\u015Faretin miktarda saklanmas\u0131, y\xF6n\xFC okuyan hi\xE7bir kod taraf\u0131ndan g\xF6r\xFClmezdi.`);
998
+ }
684
999
  }
1000
+ __name(assertAmount, "assertAmount");
685
1001
  function makeExpr(expr) {
686
- return new Proxy(
687
- { [EXPR]: expr },
688
- {
689
- get(target, prop) {
690
- if (prop === EXPR) return target[EXPR];
691
- if (TRAPPED_PROPS.includes(prop)) {
692
- trap(prop, "A plan expression", "Write it into an operation instead.");
693
- }
694
- return void 0;
1002
+ return new Proxy({
1003
+ [EXPR]: expr
1004
+ }, {
1005
+ get(target, prop) {
1006
+ if (prop === EXPR) return target[EXPR];
1007
+ if (TRAPPED_PROPS.includes(prop)) {
1008
+ trap(prop, "A plan expression", "Write it into an operation instead.");
695
1009
  }
1010
+ return void 0;
696
1011
  }
697
- );
1012
+ });
698
1013
  }
1014
+ __name(makeExpr, "makeExpr");
699
1015
  function makeRef(op, field) {
700
- const target = { [REF]: { op, field } };
1016
+ const target = {
1017
+ [REF]: {
1018
+ op,
1019
+ field
1020
+ }
1021
+ };
701
1022
  return new Proxy(target, {
702
1023
  get(t, prop) {
703
1024
  if (prop === REF) return t[REF];
704
1025
  if (TRAPPED_PROPS.includes(prop)) {
705
- trap(
706
- prop,
707
- `\`${field}\` of a row this transaction has not written yet`,
708
- "Pass it to another operation in the same plan, or return it from the callback and read it after `transaction()` resolves."
709
- );
1026
+ trap(prop, `\`${field}\` of a row this transaction has not written yet`, "Pass it to another operation in the same plan, or return it from the callback and read it after `transaction()` resolves.");
710
1027
  }
711
1028
  return void 0;
712
1029
  }
713
1030
  });
714
1031
  }
1032
+ __name(makeRef, "makeRef");
715
1033
  function makeRowHandle(op) {
716
- const target = { [ROW]: op };
1034
+ const target = {
1035
+ [ROW]: op
1036
+ };
717
1037
  return new Proxy(target, {
718
1038
  get(t, prop) {
719
1039
  if (prop === ROW) return t[ROW];
720
1040
  if (TRAPPED_PROPS.includes(prop)) {
721
- trap(
722
- prop,
723
- "A row this transaction has not written yet",
724
- "Read one of its columns to reference it, or return the row from the callback and read it after `transaction()` resolves."
725
- );
1041
+ trap(prop, "A row this transaction has not written yet", "Read one of its columns to reference it, or return the row from the callback and read it after `transaction()` resolves.");
726
1042
  }
727
1043
  if (typeof prop === "symbol") return void 0;
728
1044
  return makeRef(op, prop);
729
1045
  }
730
1046
  });
731
1047
  }
1048
+ __name(makeRowHandle, "makeRowHandle");
732
1049
  function refDescriptor(v) {
733
1050
  if (typeof v !== "object" || v === null) return null;
734
1051
  const d = v[REF];
735
1052
  return isRefDescriptor(d) ? d : null;
736
1053
  }
1054
+ __name(refDescriptor, "refDescriptor");
737
1055
  function isRefDescriptor(d) {
738
1056
  return typeof d === "object" && d !== null && typeof d.op === "number" && typeof d.field === "string";
739
1057
  }
1058
+ __name(isRefDescriptor, "isRefDescriptor");
740
1059
  function rowOpIndex(v) {
741
1060
  if (typeof v !== "object" || v === null) return null;
742
1061
  const op = v[ROW];
743
1062
  return typeof op === "number" ? op : null;
744
1063
  }
1064
+ __name(rowOpIndex, "rowOpIndex");
745
1065
  function exprOf(v) {
746
1066
  if (typeof v !== "object" || v === null) return null;
747
1067
  const e = v[EXPR];
748
1068
  return typeof e === "object" && e !== null ? e : null;
749
1069
  }
1070
+ __name(exprOf, "exprOf");
750
1071
  function isRowsHandle(v) {
751
1072
  return typeof v === "object" && v !== null && v[ROWS] !== void 0;
752
1073
  }
1074
+ __name(isRowsHandle, "isRowsHandle");
753
1075
  function encodeValue(value, column, allowColumnExpr) {
754
1076
  const ref = refDescriptor(value);
755
- if (ref) return { $ref: { op: ref.op, field: ref.field } };
1077
+ if (ref) return brandRef({
1078
+ $ref: {
1079
+ op: ref.op,
1080
+ field: ref.field
1081
+ }
1082
+ }, "ref");
756
1083
  const expr = exprOf(value);
757
1084
  if (expr) {
758
1085
  if (expr.fn !== "now" && !allowColumnExpr) {
759
- throw new TxPlanError(
760
- `\`${column}\`: ${expr.fn}() reads the column's current value, so it is only valid in updateWhere(where, set).`
761
- );
1086
+ throw new TxPlanError(`\`${column}\`: ${expr.fn}() reads the column's current value, so it is only valid in updateWhere(where, set).`);
762
1087
  }
763
- return { $expr: expr };
1088
+ return {
1089
+ $expr: expr
1090
+ };
764
1091
  }
765
1092
  if (rowOpIndex(value) !== null) {
766
- throw new TxPlanError(
767
- `\`${column}\`: a row handle is not a value. Read the column you meant (e.g. \`row.id\`).`
768
- );
1093
+ throw new TxPlanError(`\`${column}\`: a row handle is not a value. Read the column you meant (e.g. \`row.id\`).`);
769
1094
  }
770
1095
  if (isRowsHandle(value)) {
771
- throw new TxPlanError(
772
- `\`${column}\`: an operation result is not a value. Declare an expectation first (\`.expectOne(err)\`) and read a column from the row.`
773
- );
1096
+ throw new TxPlanError(`\`${column}\`: an operation result is not a value. Declare an expectation first (\`.expectOne(err)\`) and read a column from the row.`);
774
1097
  }
775
1098
  assertNoNestedHandles(value, column);
776
1099
  return value;
777
1100
  }
1101
+ __name(encodeValue, "encodeValue");
1102
+ function encodeFilterValue(value, column) {
1103
+ const ref = refDescriptor(value);
1104
+ if (ref) return brandRef({
1105
+ $ref: {
1106
+ op: ref.op,
1107
+ field: ref.field
1108
+ }
1109
+ }, "ref");
1110
+ const expr = exprOf(value);
1111
+ if (expr) {
1112
+ throw new TxPlanError(`\`${column}\`: ${expr.fn}() bir YAZMA ifadesi, kar\u015F\u0131la\u015Ft\u0131rma de\u011Fil \u2014 filtrede kullan\u0131lamaz. Kolonu bir de\u011Ferle ya da col() ile kar\u015F\u0131la\u015Ft\u0131r\u0131n.`);
1113
+ }
1114
+ if (rowOpIndex(value) !== null) {
1115
+ throw new TxPlanError(`\`${column}\`: a row handle is not a value. Read the column you meant (e.g. \`row.id\`).`);
1116
+ }
1117
+ if (isRowsHandle(value)) {
1118
+ throw new TxPlanError(`\`${column}\`: an operation result is not a value. Declare an expectation first (\`.expectOne(err)\`) and read a column from the row.`);
1119
+ }
1120
+ if (Array.isArray(value)) return value.map((v) => encodeFilterValue(v, column));
1121
+ if (value !== null && typeof value === "object" && !(value instanceof Date) && !isColRef(value) && !isSqlFragment(value)) {
1122
+ const out = {};
1123
+ for (const [k, v] of Object.entries(value)) {
1124
+ out[k] = encodeFilterValue(v, column);
1125
+ }
1126
+ return out;
1127
+ }
1128
+ return value;
1129
+ }
1130
+ __name(encodeFilterValue, "encodeFilterValue");
1131
+ function encodeFilterMap(map) {
1132
+ const out = {};
1133
+ for (const key of Object.keys(map).sort()) {
1134
+ const value = map[key];
1135
+ if (value === void 0) continue;
1136
+ out[key] = encodeFilterValue(value, key);
1137
+ }
1138
+ return out;
1139
+ }
1140
+ __name(encodeFilterMap, "encodeFilterMap");
778
1141
  function assertNoNestedHandles(value, column) {
779
1142
  if (typeof value !== "object" || value === null) return;
780
1143
  if (value instanceof Date) return;
781
1144
  if (refDescriptor(value) || exprOf(value) || rowOpIndex(value) !== null || isRowsHandle(value)) {
782
- throw new TxPlanError(
783
- `\`${column}\`: a plan handle is nested inside a value. The server would store it as literal JSON, not resolve it. Put the reference directly in the column.`
784
- );
1145
+ throw new TxPlanError(`\`${column}\`: a plan handle is nested inside a value. The server would store it as literal JSON, not resolve it. Put the reference directly in the column.`);
785
1146
  }
786
1147
  if (Array.isArray(value)) {
787
1148
  for (const item of value) assertNoNestedHandles(item, column);
@@ -791,6 +1152,7 @@ function assertNoNestedHandles(value, column) {
791
1152
  assertNoNestedHandles(item, column);
792
1153
  }
793
1154
  }
1155
+ __name(assertNoNestedHandles, "assertNoNestedHandles");
794
1156
  function encodeMap(map, allowColumnExpr) {
795
1157
  const out = {};
796
1158
  for (const key of Object.keys(map).sort()) {
@@ -800,12 +1162,11 @@ function encodeMap(map, allowColumnExpr) {
800
1162
  }
801
1163
  return out;
802
1164
  }
1165
+ __name(encodeMap, "encodeMap");
803
1166
  var SKIPPED_OP = -1;
804
- var TxRowsImpl = class {
805
- constructor(builder, opIndex, what) {
806
- this.builder = builder;
807
- this.opIndex = opIndex;
808
- this.what = what;
1167
+ var TxRowsImpl = class TxRowsImpl2 {
1168
+ static {
1169
+ __name(this, "TxRowsImpl");
809
1170
  }
810
1171
  builder;
811
1172
  opIndex;
@@ -813,12 +1174,15 @@ var TxRowsImpl = class {
813
1174
  // Present so `isRowsHandle` recognises the object; never read for its value.
814
1175
  [ROWS] = true;
815
1176
  guarded = false;
1177
+ constructor(builder, opIndex, what) {
1178
+ this.builder = builder;
1179
+ this.opIndex = opIndex;
1180
+ this.what = what;
1181
+ }
816
1182
  // The type-level `await` guard made real: TS rejects `await rows` at compile
817
1183
  // time, and reaching this means someone called `.then(...)` by hand.
818
1184
  then() {
819
- throw new TxRefError(
820
- `${this.what} cannot be awaited: a transaction callback builds a plan, it does not run statements. Remove the \`await\`.`
821
- );
1185
+ throw new TxRefError(`${this.what} cannot be awaited: a transaction callback builds a plan, it does not run statements. Remove the \`await\`.`);
822
1186
  }
823
1187
  expectOne(error) {
824
1188
  this.declareGuard("one", 1, error);
@@ -839,14 +1203,10 @@ var TxRowsImpl = class {
839
1203
  }
840
1204
  declareGuard(kind, n, error) {
841
1205
  if (!(error instanceof Error)) {
842
- throw new TxPlanError(
843
- `${this.what}: an expectation needs the Error to throw when it does not hold (e.g. \`.expect\u2026(new Conflict("already accepted"))\`).`
844
- );
1206
+ throw new TxPlanError(`${this.what}: an expectation needs the Error to throw when it does not hold (e.g. \`.expect\u2026(new Conflict("already accepted"))\`).`);
845
1207
  }
846
1208
  if (this.guarded) {
847
- throw new TxPlanError(
848
- `${this.what} already has an expectation. One operation carries one expectation; declare the second one on its own operation.`
849
- );
1209
+ throw new TxPlanError(`${this.what} already has an expectation. One operation carries one expectation; declare the second one on its own operation.`);
850
1210
  }
851
1211
  this.guarded = true;
852
1212
  if (this.opIndex === SKIPPED_OP) return;
@@ -858,115 +1218,119 @@ function assertGuardCount(n, fn) {
858
1218
  throw new TxPlanError(`${fn}(n) needs a non-negative integer, got ${String(n)}`);
859
1219
  }
860
1220
  }
1221
+ __name(assertGuardCount, "assertGuardCount");
861
1222
  var MAX_OPS = 1e3;
862
1223
  var MAX_ROWS = 5e3;
863
1224
  var TxPlanBuilder = class {
1225
+ static {
1226
+ __name(this, "TxPlanBuilder");
1227
+ }
864
1228
  ops = [];
865
1229
  /** Errors handed to expectations, indexed by the `slot` the server echoes. */
866
1230
  slots = [];
867
1231
  /** The table surface handed to the callback. Untyped here; the public
868
- * `transaction()` signatures put the schema types on top. */
1232
+ * `transaction()` signatures put the schema types on top. */
869
1233
  table(name) {
870
1234
  return {
871
- insert: (values) => {
1235
+ insert: /* @__PURE__ */ __name((values) => {
872
1236
  const encoded = encodeMap(values, false);
873
1237
  if (Object.keys(encoded).length === 0) {
874
1238
  throw new TxPlanError(`${name}.insert() needs at least one column`);
875
1239
  }
876
- return this.push({ op: "insert", table: name, values: encoded }, `${name}.insert()`);
877
- },
878
- upsert: (values, options) => {
1240
+ return this.push({
1241
+ op: "insert",
1242
+ table: name,
1243
+ values: encoded
1244
+ }, `${name}.insert()`);
1245
+ }, "insert"),
1246
+ put: /* @__PURE__ */ __name((values, options) => {
879
1247
  const encoded = encodeMap(values, false);
880
1248
  if (Object.keys(encoded).length === 0) {
881
- throw new TxPlanError(`${name}.upsert() needs at least one column`);
1249
+ throw new TxPlanError(`${name}.put() needs at least one column`);
882
1250
  }
883
1251
  if (options.onConflict.length === 0) {
884
- throw new TxPlanError(`${name}.upsert() needs at least one onConflict column`);
1252
+ throw new TxPlanError(`${name}.put() needs at least one onConflict column`);
885
1253
  }
886
- return this.push(
887
- { op: "upsert", table: name, values: encoded, onConflict: options.onConflict },
888
- `${name}.upsert()`
889
- );
890
- },
891
- insertMany: (rows, opts) => {
1254
+ return this.push({
1255
+ op: "upsert",
1256
+ table: name,
1257
+ values: encoded,
1258
+ onConflict: options.onConflict
1259
+ }, `${name}.upsert()`);
1260
+ }, "put"),
1261
+ insertMany: /* @__PURE__ */ __name((rows, opts) => {
892
1262
  if (rows.length === 0) {
893
1263
  return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);
894
1264
  }
895
1265
  if (rows.length > MAX_ROWS) {
896
- throw new TxPlanError(
897
- `${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. Split the write across requests.`
898
- );
1266
+ throw new TxPlanError(`${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. Split the write across requests.`);
899
1267
  }
900
1268
  const encoded = rows.map((row) => encodeMap(row, false));
901
1269
  assertUniformRows(encoded, name);
902
1270
  if (opts !== void 0 && opts.onConflict.length === 0) {
903
- throw new TxPlanError(
904
- `${name}.insertMany() was given a conflict action with no onConflict columns. Postgres matches a collision on columns, so name them.`
905
- );
1271
+ throw new TxPlanError(`${name}.insertMany() was given a conflict action with no onConflict columns. Postgres matches a collision on columns, so name them.`);
906
1272
  }
907
- return this.push(
908
- {
909
- op: "insertMany",
910
- table: name,
911
- rows: encoded,
912
- // Omitted entirely when no options were given, so the op a plain
913
- // insertMany produces is byte-identical to the one it produced
914
- // before this option existed.
915
- ...opts !== void 0 ? { onConflict: opts.onConflict, action: opts.action ?? "ignore" } : {}
916
- },
917
- `${name}.insertMany()`
918
- );
919
- },
920
- updateWhere: (where, set) => {
921
- const encodedWhere = encodeMap(where, false);
1273
+ return this.push({
1274
+ op: "insertMany",
1275
+ table: name,
1276
+ rows: encoded,
1277
+ // Omitted entirely when no options were given, so the op a plain
1278
+ // insertMany produces is byte-identical to the one it produced
1279
+ // before this option existed.
1280
+ ...opts !== void 0 ? {
1281
+ onConflict: opts.onConflict,
1282
+ action: opts.action ?? "ignore"
1283
+ } : {}
1284
+ }, `${name}.insertMany()`);
1285
+ }, "insertMany"),
1286
+ updateWhere: /* @__PURE__ */ __name((where, set) => {
1287
+ const encodedWhere = encodeFilterMap(where);
922
1288
  const encodedSet = encodeMap(set, true);
923
1289
  if (Object.keys(encodedWhere).length === 0) {
924
- throw new TxPlanError(
925
- `${name}.updateWhere() needs a filter. An update with no filter rewrites the whole table.`
926
- );
1290
+ throw new TxPlanError(`${name}.updateWhere() needs a filter. An update with no filter rewrites the whole table.`);
927
1291
  }
928
1292
  if (Object.keys(encodedSet).length === 0) {
929
1293
  throw new TxPlanError(`${name}.updateWhere() needs at least one column to set`);
930
1294
  }
931
- return this.push(
932
- { op: "update", table: name, set: encodedSet, where: encodedWhere },
933
- `${name}.updateWhere()`
934
- );
935
- },
936
- deleteWhere: (where) => {
937
- const encodedWhere = encodeMap(where, false);
1295
+ return this.push({
1296
+ op: "update",
1297
+ table: name,
1298
+ set: encodedSet,
1299
+ where: encodedWhere
1300
+ }, `${name}.updateWhere()`);
1301
+ }, "updateWhere"),
1302
+ deleteWhere: /* @__PURE__ */ __name((where) => {
1303
+ const encodedWhere = encodeFilterMap(where);
938
1304
  if (Object.keys(encodedWhere).length === 0) {
939
- throw new TxPlanError(
940
- `${name}.deleteWhere() needs a filter. A delete with no filter empties the table.`
941
- );
1305
+ throw new TxPlanError(`${name}.deleteWhere() needs a filter. A delete with no filter empties the table.`);
942
1306
  }
943
- return this.push(
944
- { op: "delete", table: name, where: encodedWhere },
945
- `${name}.deleteWhere()`
946
- );
947
- },
948
- select: (where, options) => {
949
- const op = { op: "select", table: name };
950
- const encodedWhere = encodeMap(where ?? {}, false);
1307
+ return this.push({
1308
+ op: "delete",
1309
+ table: name,
1310
+ where: encodedWhere
1311
+ }, `${name}.deleteWhere()`);
1312
+ }, "deleteWhere"),
1313
+ select: /* @__PURE__ */ __name((where, options) => {
1314
+ const op = {
1315
+ op: "select",
1316
+ table: name
1317
+ };
1318
+ const encodedWhere = encodeFilterMap(where ?? {});
951
1319
  if (Object.keys(encodedWhere).length > 0) op.where = encodedWhere;
952
1320
  if (options?.limit !== void 0) {
953
1321
  if (!Number.isInteger(options.limit) || options.limit < 0) {
954
- throw new TxPlanError(
955
- `${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`
956
- );
1322
+ throw new TxPlanError(`${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`);
957
1323
  }
958
1324
  op.limit = options.limit;
959
1325
  }
960
1326
  if (options?.lock !== void 0) op.lock = options.lock;
961
1327
  return this.push(op, `${name}.select()`);
962
- }
1328
+ }, "select")
963
1329
  };
964
1330
  }
965
1331
  push(op, what) {
966
1332
  if (this.ops.length >= MAX_OPS) {
967
- throw new TxPlanError(
968
- `this transaction has ${MAX_OPS} operations, which is the limit. Use insertMany() for bulk writes, or split the work across requests.`
969
- );
1333
+ throw new TxPlanError(`this transaction has ${MAX_OPS} operations, which is the limit. Use insertMany() for bulk writes, or split the work across requests.`);
970
1334
  }
971
1335
  const index = this.ops.length;
972
1336
  this.ops.push(op);
@@ -978,14 +1342,20 @@ var TxPlanBuilder = class {
978
1342
  if (!op) throw new TxPlanError(`internal: expectation on unknown operation ${opIndex}`);
979
1343
  const slot = this.slots.length;
980
1344
  this.slots.push(error);
981
- op.guard = { kind, n, slot };
1345
+ op.guard = {
1346
+ kind,
1347
+ n,
1348
+ slot
1349
+ };
982
1350
  }
983
1351
  /** The serialisable plan. Empty when the callback described no writes. */
984
1352
  body() {
985
- return { ops: this.ops };
1353
+ return {
1354
+ ops: this.ops
1355
+ };
986
1356
  }
987
1357
  /** The error the server's `slot` selects, or `null` when it names one this
988
- * plan never declared (a server/client disagreement, not a tenant error). */
1358
+ * plan never declared (a server/client disagreement, not a tenant error). */
989
1359
  errorForSlot(slot) {
990
1360
  return this.slots[slot] ?? null;
991
1361
  }
@@ -998,29 +1368,24 @@ function assertUniformRows(rows, table) {
998
1368
  for (let i = 1; i < rows.length; i++) {
999
1369
  const got = Object.keys(rows[i]);
1000
1370
  if (got.join(",") !== wantKey) {
1001
- throw new TxPlanError(
1002
- `${table}.insertMany(): every row must set the same columns. Row 0 sets [${want.join(", ")}] but row ${i} sets [${got.join(", ")}]. (A property set to \`undefined\` counts as absent \u2014 use \`null\`.)`
1003
- );
1371
+ throw new TxPlanError(`${table}.insertMany(): every row must set the same columns. Row 0 sets [${want.join(", ")}] but row ${i} sets [${got.join(", ")}]. (A property set to \`undefined\` counts as absent \u2014 use \`null\`.)`);
1004
1372
  }
1005
1373
  }
1006
1374
  }
1375
+ __name(assertUniformRows, "assertUniformRows");
1007
1376
  function materializeResult(value, results) {
1008
1377
  const ref = refDescriptor(value);
1009
1378
  if (ref) {
1010
1379
  const row = rowOf(results, ref.op, `\`${ref.field}\``);
1011
1380
  if (!(ref.field in row)) {
1012
- throw new TxPlanError(
1013
- `the transaction's operation ${ref.op} returned no column \`${ref.field}\`.`
1014
- );
1381
+ throw new TxPlanError(`the transaction's operation ${ref.op} returned no column \`${ref.field}\`.`);
1015
1382
  }
1016
1383
  return row[ref.field];
1017
1384
  }
1018
1385
  const rowOp = rowOpIndex(value);
1019
1386
  if (rowOp !== null) return rowOf(results, rowOp, "a row");
1020
1387
  if (isRowsHandle(value)) {
1021
- throw new TxPlanError(
1022
- "an operation result cannot be returned from a transaction callback: its row count is not known until the plan runs. Declare an expectation (`.expectOne(err)`) and return the row, or a column of it."
1023
- );
1388
+ throw new TxPlanError("an operation result cannot be returned from a transaction callback: its row count is not known until the plan runs. Declare an expectation (`.expectOne(err)`) and return the row, or a column of it.");
1024
1389
  }
1025
1390
  if (Array.isArray(value)) return value.map((item) => materializeResult(item, results));
1026
1391
  if (isPlainObject(value)) {
@@ -1030,28 +1395,27 @@ function materializeResult(value, results) {
1030
1395
  }
1031
1396
  return value;
1032
1397
  }
1398
+ __name(materializeResult, "materializeResult");
1033
1399
  function rowOf(results, opIndex, what) {
1034
1400
  const result = results[opIndex];
1035
1401
  if (!result) {
1036
- throw new TxPlanError(
1037
- `the transaction returned no result for operation ${opIndex}, so ${what} cannot be read.`
1038
- );
1402
+ throw new TxPlanError(`the transaction returned no result for operation ${opIndex}, so ${what} cannot be read.`);
1039
1403
  }
1040
1404
  const row = result.rows[0];
1041
1405
  if (!row) {
1042
- throw new TxPlanError(
1043
- `the transaction's operation ${opIndex} returned no row, so ${what} cannot be read.`
1044
- );
1406
+ throw new TxPlanError(`the transaction's operation ${opIndex} returned no row, so ${what} cannot be read.`);
1045
1407
  }
1046
1408
  return row;
1047
1409
  }
1410
+ __name(rowOf, "rowOf");
1048
1411
  function isPlainObject(value) {
1049
1412
  if (typeof value !== "object" || value === null) return false;
1050
1413
  const proto = Object.getPrototypeOf(value);
1051
1414
  return proto === Object.prototype || proto === null;
1052
1415
  }
1053
- async function runTxPlan(transport, tables, builder, fn) {
1054
- const returned = fn({ tables });
1416
+ __name(isPlainObject, "isPlainObject");
1417
+ async function runTxPlan(transport, handle, builder, fn) {
1418
+ const returned = fn(handle);
1055
1419
  const body = builder.body();
1056
1420
  if (body.ops.length === 0) {
1057
1421
  return materializeResult(returned, []);
@@ -1064,6 +1428,7 @@ async function runTxPlan(transport, tables, builder, fn) {
1064
1428
  }
1065
1429
  return materializeResult(returned, response.results);
1066
1430
  }
1431
+ __name(runTxPlan, "runTxPlan");
1067
1432
  function translateRejection(err, builder) {
1068
1433
  if (typeof err !== "object" || err === null) return err;
1069
1434
  const rejection = err;
@@ -1072,25 +1437,72 @@ function translateRejection(err, builder) {
1072
1437
  }
1073
1438
  return builder.errorForSlot(rejection.slot) ?? err;
1074
1439
  }
1440
+ __name(translateRejection, "translateRejection");
1441
+
1442
+ // src/errors.ts
1443
+ var HTTP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("palbase.backend.httpError");
1444
+ var HttpError = class extends Error {
1445
+ static {
1446
+ __name(this, "HttpError");
1447
+ }
1448
+ status;
1449
+ error;
1450
+ errorDescription;
1451
+ data;
1452
+ /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */
1453
+ [HTTP_ERROR_BRAND] = true;
1454
+ constructor(status, error, errorDescription, data) {
1455
+ super(errorDescription);
1456
+ this.name = "HttpError";
1457
+ this.status = status;
1458
+ this.error = error;
1459
+ this.errorDescription = errorDescription;
1460
+ if (data !== void 0) {
1461
+ this.data = data;
1462
+ }
1463
+ }
1464
+ /**
1465
+ * Serialize to the standard Palbase error response format.
1466
+ * The `requestId` is injected by the runtime layer from the request context.
1467
+ * When called without arguments (e.g. JSON.stringify), request_id is omitted.
1468
+ * When `data` is set, it is appended as a strict-superset field.
1469
+ */
1470
+ toJSON(requestId) {
1471
+ const result = {
1472
+ error: this.error,
1473
+ error_description: this.errorDescription,
1474
+ status: this.status
1475
+ };
1476
+ if (requestId) {
1477
+ result.request_id = requestId;
1478
+ }
1479
+ if (this.data !== void 0) {
1480
+ result.data = this.data;
1481
+ }
1482
+ return result;
1483
+ }
1484
+ };
1075
1485
 
1076
1486
  // src/db/typed-db.ts
1077
1487
  function makeTypedTable(name, raw2) {
1078
1488
  return {
1079
- insert: (data) => raw2.insert(name, data),
1080
- upsert: (data, opts) => raw2.upsert(name, data, opts),
1081
- update: (id, data) => raw2.update(name, id, data),
1082
- delete: (id) => raw2.delete(name, id),
1083
- findById: (id) => raw2.findById(name, id),
1084
- findMany: (query, opts) => raw2.findMany(name, query, opts),
1085
- updateMany: (where, set) => raw2.updateMany(
1086
- name,
1087
- where,
1088
- set
1089
- ),
1090
- deleteMany: (where) => raw2.deleteMany(name, where),
1091
- count: (where) => raw2.count(name, where)
1489
+ insert: /* @__PURE__ */ __name((data) => raw2.insert(name, data), "insert"),
1490
+ put: /* @__PURE__ */ __name((q) => raw2.put(name, q.data, {
1491
+ onConflict: q.onConflict
1492
+ }), "put"),
1493
+ update: /* @__PURE__ */ __name((q) => raw2.update(name, q.where.id, q.set), "update"),
1494
+ delete: /* @__PURE__ */ __name((id) => raw2.delete(name, id), "delete"),
1495
+ findById: /* @__PURE__ */ __name((id) => raw2.findById(name, id), "findById"),
1496
+ findMany: /* @__PURE__ */ __name((q) => {
1497
+ const { where, ...opts } = q ?? {};
1498
+ return raw2.findMany(name, where, opts);
1499
+ }, "findMany"),
1500
+ updateMany: /* @__PURE__ */ __name((q) => raw2.updateMany(name, q.where, q.set), "updateMany"),
1501
+ deleteMany: /* @__PURE__ */ __name((q) => raw2.deleteMany(name, q.where), "deleteMany"),
1502
+ count: /* @__PURE__ */ __name((q) => raw2.count(name, q?.where), "count")
1092
1503
  };
1093
1504
  }
1505
+ __name(makeTypedTable, "makeTypedTable");
1094
1506
  function makeTypedDB(schema, raw2) {
1095
1507
  const tables = {};
1096
1508
  for (const key of Object.keys(schema.tables)) {
@@ -1108,16 +1520,14 @@ function makeTypedDB(schema, raw2) {
1108
1520
  const tableDef = schema.tables[key];
1109
1521
  if (tableDef !== void 0) planTables[key] = builder.table(tableDef.name);
1110
1522
  }
1111
- return runTxPlan(
1112
- raw2,
1113
- planTables,
1114
- builder,
1115
- fn
1116
- );
1523
+ return runTxPlan(raw2, {
1524
+ tables: planTables
1525
+ }, builder, fn);
1117
1526
  }
1118
1527
  };
1119
1528
  return result;
1120
1529
  }
1530
+ __name(makeTypedDB, "makeTypedDB");
1121
1531
  // Annotate the CommonJS export names for ESM import in node:
1122
1532
  0 && (module.exports = {
1123
1533
  EXTENSION_DEPENDENCIES,