@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,728 @@
1
+ import {
2
+ __name
3
+ } from "./chunk-VXPNPVAG.js";
4
+
5
+ // src/db/input-guards.ts
6
+ var REF_BRAND = /* @__PURE__ */ Symbol.for("palbase.db.ref");
7
+ function brandRef(v, kind) {
8
+ Object.defineProperty(v, REF_BRAND, {
9
+ value: kind,
10
+ enumerable: false
11
+ });
12
+ return v;
13
+ }
14
+ __name(brandRef, "brandRef");
15
+ function brandOf(v) {
16
+ if (typeof v !== "object" || v === null) return void 0;
17
+ return Object.hasOwn(v, REF_BRAND) ? v[REF_BRAND] : void 0;
18
+ }
19
+ __name(brandOf, "brandOf");
20
+ function looksLikeUnbrandedRef(v) {
21
+ if (typeof v !== "object" || v === null) return null;
22
+ if (brandOf(v) !== void 0) return null;
23
+ if (isColumnExpr(v)) return null;
24
+ const o = v;
25
+ if (typeof o.$col === "string") return "col";
26
+ if (o.$sql !== void 0 && typeof o.$sql === "object" && o.$sql !== null) return "sql";
27
+ if (o.$expr !== void 0 && typeof o.$expr === "object" && o.$expr !== null) return "expr";
28
+ return null;
29
+ }
30
+ __name(looksLikeUnbrandedRef, "looksLikeUnbrandedRef");
31
+ function isColRef(v) {
32
+ return brandOf(v) === "col" && typeof v.$col === "string";
33
+ }
34
+ __name(isColRef, "isColRef");
35
+ function isPlanRef(v) {
36
+ if (brandOf(v) !== "ref") return false;
37
+ const r = v.$ref;
38
+ return r !== void 0 && typeof r.op === "number" && typeof r.field === "string";
39
+ }
40
+ __name(isPlanRef, "isPlanRef");
41
+ function looksLikeUnbrandedPlanRef(v) {
42
+ if (typeof v !== "object" || v === null || brandOf(v) !== void 0) return false;
43
+ const r = v.$ref;
44
+ return r !== void 0 && typeof r === "object" && r !== null;
45
+ }
46
+ __name(looksLikeUnbrandedPlanRef, "looksLikeUnbrandedPlanRef");
47
+ function isSqlFragment(v) {
48
+ if (brandOf(v) !== "sql") return false;
49
+ const f = v.$sql;
50
+ return f !== void 0 && Array.isArray(f.text) && Array.isArray(f.values);
51
+ }
52
+ __name(isSqlFragment, "isSqlFragment");
53
+ var TX_EXPR = /* @__PURE__ */ Symbol.for("palbase.tx.expr");
54
+ function isNowExpr(v) {
55
+ if (!isColumnExpr(v)) return false;
56
+ try {
57
+ const e = v[TX_EXPR];
58
+ return typeof e === "object" && e !== null && e.fn === "now";
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+ __name(isNowExpr, "isNowExpr");
64
+ function isColumnExpr(v) {
65
+ if (typeof v !== "object" && typeof v !== "function") return false;
66
+ if (v === null) return false;
67
+ try {
68
+ return v[TX_EXPR] !== void 0;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+ __name(isColumnExpr, "isColumnExpr");
74
+ function assertNoExpressionHandles(caller, table, cols, data) {
75
+ for (const c of cols) {
76
+ const v = data[c];
77
+ if (isColumnExpr(v)) {
78
+ throw new Error(`${caller}(${table}): "${c}" bir ifade tutama\u011F\u0131 ald\u0131 (increment()/decrement()/now()). Bu yolda de\u011Fer beklenir. Saya\xE7 art\u0131\u015F\u0131 i\xE7in updateMany(where, { ${c}: increment(n) }) ya da $transaction i\xE7inde tx.tables.${table}.updateWhere(where, { ${c}: increment(n) }) kullan\u0131n.`);
79
+ }
80
+ if (isColRef(v)) {
81
+ throw new Error(`${caller}(${table}): "${c}" bir col() ald\u0131. Kolon referans\u0131 yaln\u0131z F\u0130LTREDE durabilir; bir kolonun de\u011Ferini ba\u015Fka bir kolona yazmak i\xE7in $query kullan\u0131n.`);
82
+ }
83
+ }
84
+ }
85
+ __name(assertNoExpressionHandles, "assertNoExpressionHandles");
86
+ var KNOWN_OPS = /* @__PURE__ */ new Set([
87
+ "gt",
88
+ "gte",
89
+ "lt",
90
+ "lte",
91
+ "neq",
92
+ "in",
93
+ // K1 metin operatörleri (FR-005) ve null testi (FR-006). Bu küme
94
+ // `fakeDatabase()` ile ORTAK kaynaktır: fake bir çağrıyı motorun reddettiği
95
+ // yerde kabul ederse, yazarın testi üretimde patlayan koda karşı yeşil verir.
96
+ "contains",
97
+ "icontains",
98
+ "startsWith",
99
+ "endsWith",
100
+ "isNull"
101
+ ]);
102
+ var REFUSED_OPS = {
103
+ eq: 'e\u015Fitlik \xC7IPLAK yaz\u0131l\u0131r: { <kolon>: <de\u011Fer> } (ya da kolon kar\u015F\u0131la\u015Ft\u0131rmas\u0131 i\xE7in { <kolon>: col("\u2026") })'
104
+ };
105
+ function assertUsableFilter(caller, table, where) {
106
+ const COMPOSITES = /* @__PURE__ */ new Set([
107
+ "OR",
108
+ "AND",
109
+ "NOT"
110
+ ]);
111
+ if (!where) return;
112
+ if (isSqlFragment(where)) return;
113
+ for (const [col, cond] of Object.entries(where)) {
114
+ if (COMPOSITES.has(col)) {
115
+ const branches = col === "NOT" ? [
116
+ cond
117
+ ] : cond;
118
+ if (!Array.isArray(branches) && col !== "NOT") {
119
+ throw new Error(`${caller}(${table}): where.${col} bir dizi olmal\u0131`);
120
+ }
121
+ for (const b of branches) {
122
+ if (b === null || typeof b !== "object") {
123
+ throw new Error(`${caller}(${table}): where.${col} dallar\u0131 filtre nesnesi olmal\u0131`);
124
+ }
125
+ assertUsableFilter(caller, table, b);
126
+ }
127
+ continue;
128
+ }
129
+ if (col === "has") {
130
+ if (cond === null || typeof cond !== "object" || Array.isArray(cond)) {
131
+ throw new Error(`${caller}(${table}): where.has bir ili\u015Fki haritas\u0131 olmal\u0131 ({ <ili\u015Fki>: { \u2026 } })`);
132
+ }
133
+ for (const [rel, inner] of Object.entries(cond)) {
134
+ if (inner === null || typeof inner !== "object" || Array.isArray(inner)) {
135
+ throw new Error(`${caller}(${table}): where.has.${rel} bir filtre nesnesi olmal\u0131`);
136
+ }
137
+ assertUsableFilter(caller, table, inner);
138
+ }
139
+ continue;
140
+ }
141
+ if (cond === void 0) {
142
+ throw new Error(`${caller}(${table}): where.${col} de\u011Feri undefined \u2014 bu bir filtre de\u011Feri de\u011Fil. Ba\u011Flan\u0131nca NULL olur ve '= NULL' hi\xE7bir sat\u0131ra uymaz, yani sorgu sessizce bo\u015F sonu\xE7 d\xF6nerdi. De\u011Fer yoksa anahtar\u0131 filtreye hi\xE7 koymay\u0131n.`);
143
+ }
144
+ if (cond === null || typeof cond !== "object" || Array.isArray(cond)) continue;
145
+ if (isColRef(cond)) continue;
146
+ if (isNowExpr(cond)) continue;
147
+ const entries = Object.entries(cond);
148
+ if (entries.length === 0) {
149
+ throw new Error(`${caller}(${table}): where.${col} bo\u015F bir operat\xF6r nesnesi ({}) \u2014 hi\xE7bir ko\u015Ful \xFCretmez, yani bu alan filtreden sessizce D\xDC\u015EERD\u0130. Ko\u015Ful kurulmayacaksa anahtar\u0131 filtreye hi\xE7 koymay\u0131n (D-21).`);
150
+ }
151
+ for (const [op, v] of entries) {
152
+ if (op === "in") {
153
+ if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmal\u0131`);
154
+ if (v.some((x) => x === void 0)) {
155
+ throw new Error(`${caller}(${table}): where.${col}.in listesinde undefined var \u2014 sessizce NULL'a ba\u011Flan\u0131r ve o eleman hi\xE7bir sat\u0131rla e\u015Fle\u015Fmez. Listeyi kurarken eleyin.`);
156
+ }
157
+ continue;
158
+ }
159
+ if (REFUSED_OPS[op] !== void 0) {
160
+ throw new Error(`${caller}(${table}): where.${col}.${op} bu filtre dilinde yok \u2014 ${REFUSED_OPS[op]}`);
161
+ }
162
+ if (!KNOWN_OPS.has(op)) {
163
+ throw new Error(`${caller}(${table}): where.${col} bilinmeyen operat\xF6r "${op}" (gt/gte/lt/lte/neq/in/contains/icontains/startsWith/endsWith/isNull)`);
164
+ }
165
+ if (v === void 0) {
166
+ throw new Error(`${caller}(${table}): where.${col}.${op} de\u011Feri undefined \u2014 kar\u015F\u0131la\u015Ft\u0131rman\u0131n sa\u011F taraf\u0131 NULL olur ve sonu\xE7 hi\xE7bir sat\u0131ra uymaz. Ko\u015Fulu kurmay\u0131n.`);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ __name(assertUsableFilter, "assertUsableFilter");
172
+ function assertUsableWriteValues(caller, table, cols, data) {
173
+ for (const c of cols) {
174
+ if (data[c] === void 0) {
175
+ throw new Error(`${caller}(${table}): "${c}" de\u011Feri undefined \u2014 bu bir yazma de\u011Feri de\u011Fil. Kolonu bo\u015Faltmak istiyorsan null yaz; kolonu de\u011Fi\u015Ftirmek istemiyorsan nesneye hi\xE7 koyma (bir eksik istek alan\u0131 sessizce NULL yaz\u0131yordu \u2014 FR-016).`);
176
+ }
177
+ }
178
+ }
179
+ __name(assertUsableWriteValues, "assertUsableWriteValues");
180
+
181
+ // src/db/tx-plan.ts
182
+ var TxRefError = class extends Error {
183
+ static {
184
+ __name(this, "TxRefError");
185
+ }
186
+ constructor(message) {
187
+ super(message);
188
+ this.name = "TxRefError";
189
+ }
190
+ };
191
+ var TxPlanError = class extends Error {
192
+ static {
193
+ __name(this, "TxPlanError");
194
+ }
195
+ constructor(message) {
196
+ super(message);
197
+ this.name = "TxPlanError";
198
+ }
199
+ };
200
+ var EXPR = /* @__PURE__ */ Symbol.for("palbase.tx.expr");
201
+ var REF = /* @__PURE__ */ Symbol.for("palbase.tx.ref");
202
+ var ROW = /* @__PURE__ */ Symbol.for("palbase.tx.row");
203
+ var ROWS = /* @__PURE__ */ Symbol.for("palbase.tx.rows");
204
+ var TRAPPED_PROPS = [
205
+ "then",
206
+ "valueOf",
207
+ "toString",
208
+ "toJSON",
209
+ Symbol.toPrimitive
210
+ ];
211
+ function trap(prop, what, hint) {
212
+ const name = typeof prop === "symbol" ? prop.description ?? String(prop) : prop;
213
+ 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}`);
214
+ }
215
+ __name(trap, "trap");
216
+ function now() {
217
+ return makeExpr({
218
+ fn: "now"
219
+ });
220
+ }
221
+ __name(now, "now");
222
+ function increment(by) {
223
+ assertAmount(by, "increment");
224
+ return makeExpr({
225
+ fn: "inc",
226
+ by
227
+ });
228
+ }
229
+ __name(increment, "increment");
230
+ var inc = increment;
231
+ function decrement(by) {
232
+ assertAmount(by, "decrement");
233
+ return makeExpr({
234
+ fn: "dec",
235
+ by
236
+ });
237
+ }
238
+ __name(decrement, "decrement");
239
+ var dec = decrement;
240
+ function assertAmount(by, fn) {
241
+ if (typeof by === "string") {
242
+ if (!/^-?\d+(\.\d+)?$/.test(by)) {
243
+ throw new TxPlanError(`${fn}() ondal\u0131k bir say\u0131 metni bekliyor, "${by}" ald\u0131 \u2014 kabul edilen bi\xE7im: "12", "-12", "12.50"`);
244
+ }
245
+ } else if (typeof by !== "number" || !Number.isFinite(by)) {
246
+ throw new TxPlanError(`${fn}() needs a finite number, got ${String(by)}`);
247
+ }
248
+ const negative = typeof by === "string" ? by.trimStart().startsWith("-") : by < 0;
249
+ if (negative) {
250
+ const other = fn === "increment" ? "decrement" : "increment";
251
+ 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.`);
252
+ }
253
+ }
254
+ __name(assertAmount, "assertAmount");
255
+ function columnExprOf(v) {
256
+ return exprOf(v);
257
+ }
258
+ __name(columnExprOf, "columnExprOf");
259
+ function makeExpr(expr) {
260
+ return new Proxy({
261
+ [EXPR]: expr
262
+ }, {
263
+ get(target, prop) {
264
+ if (prop === EXPR) return target[EXPR];
265
+ if (TRAPPED_PROPS.includes(prop)) {
266
+ trap(prop, "A plan expression", "Write it into an operation instead.");
267
+ }
268
+ return void 0;
269
+ }
270
+ });
271
+ }
272
+ __name(makeExpr, "makeExpr");
273
+ function makeRef(op, field) {
274
+ const target = {
275
+ [REF]: {
276
+ op,
277
+ field
278
+ }
279
+ };
280
+ return new Proxy(target, {
281
+ get(t, prop) {
282
+ if (prop === REF) return t[REF];
283
+ if (TRAPPED_PROPS.includes(prop)) {
284
+ 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.");
285
+ }
286
+ return void 0;
287
+ }
288
+ });
289
+ }
290
+ __name(makeRef, "makeRef");
291
+ function makeRowHandle(op) {
292
+ const target = {
293
+ [ROW]: op
294
+ };
295
+ return new Proxy(target, {
296
+ get(t, prop) {
297
+ if (prop === ROW) return t[ROW];
298
+ if (TRAPPED_PROPS.includes(prop)) {
299
+ 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.");
300
+ }
301
+ if (typeof prop === "symbol") return void 0;
302
+ return makeRef(op, prop);
303
+ }
304
+ });
305
+ }
306
+ __name(makeRowHandle, "makeRowHandle");
307
+ function refDescriptor(v) {
308
+ if (typeof v !== "object" || v === null) return null;
309
+ const d = v[REF];
310
+ return isRefDescriptor(d) ? d : null;
311
+ }
312
+ __name(refDescriptor, "refDescriptor");
313
+ function isRefDescriptor(d) {
314
+ return typeof d === "object" && d !== null && typeof d.op === "number" && typeof d.field === "string";
315
+ }
316
+ __name(isRefDescriptor, "isRefDescriptor");
317
+ function rowOpIndex(v) {
318
+ if (typeof v !== "object" || v === null) return null;
319
+ const op = v[ROW];
320
+ return typeof op === "number" ? op : null;
321
+ }
322
+ __name(rowOpIndex, "rowOpIndex");
323
+ function exprOf(v) {
324
+ if (typeof v !== "object" || v === null) return null;
325
+ const e = v[EXPR];
326
+ return typeof e === "object" && e !== null ? e : null;
327
+ }
328
+ __name(exprOf, "exprOf");
329
+ function isRowsHandle(v) {
330
+ return typeof v === "object" && v !== null && v[ROWS] !== void 0;
331
+ }
332
+ __name(isRowsHandle, "isRowsHandle");
333
+ function encodeValue(value, column, allowColumnExpr) {
334
+ const ref = refDescriptor(value);
335
+ if (ref) return brandRef({
336
+ $ref: {
337
+ op: ref.op,
338
+ field: ref.field
339
+ }
340
+ }, "ref");
341
+ if (isNowExpr(value)) return {
342
+ $expr: {
343
+ fn: "now"
344
+ }
345
+ };
346
+ const expr = exprOf(value);
347
+ if (expr) {
348
+ if (expr.fn !== "now" && !allowColumnExpr) {
349
+ throw new TxPlanError(`\`${column}\`: ${expr.fn}() reads the column's current value, so it is only valid in updateWhere(where, set).`);
350
+ }
351
+ return {
352
+ $expr: expr
353
+ };
354
+ }
355
+ if (rowOpIndex(value) !== null) {
356
+ throw new TxPlanError(`\`${column}\`: a row handle is not a value. Read the column you meant (e.g. \`row.id\`).`);
357
+ }
358
+ if (isRowsHandle(value)) {
359
+ throw new TxPlanError(`\`${column}\`: an operation result is not a value. Declare an expectation first (\`.expectOne(err)\`) and read a column from the row.`);
360
+ }
361
+ assertNoNestedHandles(value, column);
362
+ return value;
363
+ }
364
+ __name(encodeValue, "encodeValue");
365
+ function encodeFilterValue(value, column) {
366
+ const ref = refDescriptor(value);
367
+ if (ref) return brandRef({
368
+ $ref: {
369
+ op: ref.op,
370
+ field: ref.field
371
+ }
372
+ }, "ref");
373
+ const expr = exprOf(value);
374
+ if (expr) {
375
+ 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.`);
376
+ }
377
+ if (rowOpIndex(value) !== null) {
378
+ throw new TxPlanError(`\`${column}\`: a row handle is not a value. Read the column you meant (e.g. \`row.id\`).`);
379
+ }
380
+ if (isRowsHandle(value)) {
381
+ throw new TxPlanError(`\`${column}\`: an operation result is not a value. Declare an expectation first (\`.expectOne(err)\`) and read a column from the row.`);
382
+ }
383
+ if (Array.isArray(value)) return value.map((v) => encodeFilterValue(v, column));
384
+ if (value !== null && typeof value === "object" && !(value instanceof Date) && !isColRef(value) && !isSqlFragment(value)) {
385
+ const out = {};
386
+ for (const [k, v] of Object.entries(value)) {
387
+ out[k] = encodeFilterValue(v, column);
388
+ }
389
+ return out;
390
+ }
391
+ return value;
392
+ }
393
+ __name(encodeFilterValue, "encodeFilterValue");
394
+ function encodeFilterMap(map) {
395
+ const out = {};
396
+ for (const key of Object.keys(map).sort()) {
397
+ const value = map[key];
398
+ if (value === void 0) continue;
399
+ out[key] = encodeFilterValue(value, key);
400
+ }
401
+ return out;
402
+ }
403
+ __name(encodeFilterMap, "encodeFilterMap");
404
+ function assertNoNestedHandles(value, column) {
405
+ if (typeof value !== "object" || value === null) return;
406
+ if (value instanceof Date) return;
407
+ if (refDescriptor(value) || exprOf(value) || rowOpIndex(value) !== null || isRowsHandle(value)) {
408
+ 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.`);
409
+ }
410
+ if (Array.isArray(value)) {
411
+ for (const item of value) assertNoNestedHandles(item, column);
412
+ return;
413
+ }
414
+ for (const item of Object.values(value)) {
415
+ assertNoNestedHandles(item, column);
416
+ }
417
+ }
418
+ __name(assertNoNestedHandles, "assertNoNestedHandles");
419
+ function encodeMap(map, allowColumnExpr) {
420
+ const out = {};
421
+ for (const key of Object.keys(map).sort()) {
422
+ const value = map[key];
423
+ if (value === void 0) continue;
424
+ out[key] = encodeValue(value, key, allowColumnExpr);
425
+ }
426
+ return out;
427
+ }
428
+ __name(encodeMap, "encodeMap");
429
+ var SKIPPED_OP = -1;
430
+ var TxRowsImpl = class TxRowsImpl2 {
431
+ static {
432
+ __name(this, "TxRowsImpl");
433
+ }
434
+ builder;
435
+ opIndex;
436
+ what;
437
+ // Present so `isRowsHandle` recognises the object; never read for its value.
438
+ [ROWS] = true;
439
+ guarded = false;
440
+ constructor(builder, opIndex, what) {
441
+ this.builder = builder;
442
+ this.opIndex = opIndex;
443
+ this.what = what;
444
+ }
445
+ // The type-level `await` guard made real: TS rejects `await rows` at compile
446
+ // time, and reaching this means someone called `.then(...)` by hand.
447
+ then() {
448
+ throw new TxRefError(`${this.what} cannot be awaited: a transaction callback builds a plan, it does not run statements. Remove the \`await\`.`);
449
+ }
450
+ expectOne(error) {
451
+ this.declareGuard("one", 1, error);
452
+ if (this.opIndex === SKIPPED_OP) throw error;
453
+ return makeRowHandle(this.opIndex);
454
+ }
455
+ expectNone(error) {
456
+ this.declareGuard("none", 0, error);
457
+ }
458
+ expectAtLeast(n, error) {
459
+ assertGuardCount(n, "expectAtLeast");
460
+ this.declareGuard("atLeast", n, error);
461
+ if (this.opIndex === SKIPPED_OP && n > 0) throw error;
462
+ }
463
+ expectAtMost(n, error) {
464
+ assertGuardCount(n, "expectAtMost");
465
+ this.declareGuard("atMost", n, error);
466
+ }
467
+ declareGuard(kind, n, error) {
468
+ if (!(error instanceof Error)) {
469
+ 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"))\`).`);
470
+ }
471
+ if (this.guarded) {
472
+ throw new TxPlanError(`${this.what} already has an expectation. One operation carries one expectation; declare the second one on its own operation.`);
473
+ }
474
+ this.guarded = true;
475
+ if (this.opIndex === SKIPPED_OP) return;
476
+ this.builder.attachGuard(this.opIndex, kind, n, error);
477
+ }
478
+ };
479
+ function assertGuardCount(n, fn) {
480
+ if (!Number.isInteger(n) || n < 0) {
481
+ throw new TxPlanError(`${fn}(n) needs a non-negative integer, got ${String(n)}`);
482
+ }
483
+ }
484
+ __name(assertGuardCount, "assertGuardCount");
485
+ var MAX_OPS = 1e3;
486
+ var MAX_ROWS = 5e3;
487
+ var TxPlanBuilder = class {
488
+ static {
489
+ __name(this, "TxPlanBuilder");
490
+ }
491
+ ops = [];
492
+ /** Errors handed to expectations, indexed by the `slot` the server echoes. */
493
+ slots = [];
494
+ /** The table surface handed to the callback. Untyped here; the public
495
+ * `transaction()` signatures put the schema types on top. */
496
+ table(name) {
497
+ return {
498
+ insert: /* @__PURE__ */ __name((values) => {
499
+ const encoded = encodeMap(values, false);
500
+ if (Object.keys(encoded).length === 0) {
501
+ throw new TxPlanError(`${name}.insert() needs at least one column`);
502
+ }
503
+ return this.push({
504
+ op: "insert",
505
+ table: name,
506
+ values: encoded
507
+ }, `${name}.insert()`);
508
+ }, "insert"),
509
+ put: /* @__PURE__ */ __name((values, options) => {
510
+ const encoded = encodeMap(values, false);
511
+ if (Object.keys(encoded).length === 0) {
512
+ throw new TxPlanError(`${name}.put() needs at least one column`);
513
+ }
514
+ if (options.onConflict.length === 0) {
515
+ throw new TxPlanError(`${name}.put() needs at least one onConflict column`);
516
+ }
517
+ return this.push({
518
+ op: "upsert",
519
+ table: name,
520
+ values: encoded,
521
+ onConflict: options.onConflict
522
+ }, `${name}.upsert()`);
523
+ }, "put"),
524
+ insertMany: /* @__PURE__ */ __name((rows, opts) => {
525
+ if (rows.length === 0) {
526
+ return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);
527
+ }
528
+ if (rows.length > MAX_ROWS) {
529
+ throw new TxPlanError(`${name}.insertMany() has ${rows.length} rows; the limit is ${MAX_ROWS}. Split the write across requests.`);
530
+ }
531
+ const encoded = rows.map((row) => encodeMap(row, false));
532
+ assertUniformRows(encoded, name);
533
+ if (opts !== void 0 && opts.onConflict.length === 0) {
534
+ throw new TxPlanError(`${name}.insertMany() was given a conflict action with no onConflict columns. Postgres matches a collision on columns, so name them.`);
535
+ }
536
+ return this.push({
537
+ op: "insertMany",
538
+ table: name,
539
+ rows: encoded,
540
+ // Omitted entirely when no options were given, so the op a plain
541
+ // insertMany produces is byte-identical to the one it produced
542
+ // before this option existed.
543
+ ...opts !== void 0 ? {
544
+ onConflict: opts.onConflict,
545
+ action: opts.action ?? "ignore"
546
+ } : {}
547
+ }, `${name}.insertMany()`);
548
+ }, "insertMany"),
549
+ updateWhere: /* @__PURE__ */ __name((where, set) => {
550
+ const encodedWhere = encodeFilterMap(where);
551
+ const encodedSet = encodeMap(set, true);
552
+ if (Object.keys(encodedWhere).length === 0) {
553
+ throw new TxPlanError(`${name}.updateWhere() needs a filter. An update with no filter rewrites the whole table.`);
554
+ }
555
+ if (Object.keys(encodedSet).length === 0) {
556
+ throw new TxPlanError(`${name}.updateWhere() needs at least one column to set`);
557
+ }
558
+ return this.push({
559
+ op: "update",
560
+ table: name,
561
+ set: encodedSet,
562
+ where: encodedWhere
563
+ }, `${name}.updateWhere()`);
564
+ }, "updateWhere"),
565
+ deleteWhere: /* @__PURE__ */ __name((where) => {
566
+ const encodedWhere = encodeFilterMap(where);
567
+ if (Object.keys(encodedWhere).length === 0) {
568
+ throw new TxPlanError(`${name}.deleteWhere() needs a filter. A delete with no filter empties the table.`);
569
+ }
570
+ return this.push({
571
+ op: "delete",
572
+ table: name,
573
+ where: encodedWhere
574
+ }, `${name}.deleteWhere()`);
575
+ }, "deleteWhere"),
576
+ select: /* @__PURE__ */ __name((where, options) => {
577
+ const op = {
578
+ op: "select",
579
+ table: name
580
+ };
581
+ const encodedWhere = encodeFilterMap(where ?? {});
582
+ if (Object.keys(encodedWhere).length > 0) op.where = encodedWhere;
583
+ if (options?.limit !== void 0) {
584
+ if (!Number.isInteger(options.limit) || options.limit < 0) {
585
+ throw new TxPlanError(`${name}.select(): limit needs a non-negative integer, got ${String(options.limit)}`);
586
+ }
587
+ op.limit = options.limit;
588
+ }
589
+ if (options?.lock !== void 0) op.lock = options.lock;
590
+ return this.push(op, `${name}.select()`);
591
+ }, "select")
592
+ };
593
+ }
594
+ push(op, what) {
595
+ if (this.ops.length >= MAX_OPS) {
596
+ throw new TxPlanError(`this transaction has ${MAX_OPS} operations, which is the limit. Use insertMany() for bulk writes, or split the work across requests.`);
597
+ }
598
+ const index = this.ops.length;
599
+ this.ops.push(op);
600
+ return new TxRowsImpl(this, index, what);
601
+ }
602
+ /** Attach an expectation to an op and record its error in the slot table. */
603
+ attachGuard(opIndex, kind, n, error) {
604
+ const op = this.ops[opIndex];
605
+ if (!op) throw new TxPlanError(`internal: expectation on unknown operation ${opIndex}`);
606
+ const slot = this.slots.length;
607
+ this.slots.push(error);
608
+ op.guard = {
609
+ kind,
610
+ n,
611
+ slot
612
+ };
613
+ }
614
+ /** The serialisable plan. Empty when the callback described no writes. */
615
+ body() {
616
+ return {
617
+ ops: this.ops
618
+ };
619
+ }
620
+ /** The error the server's `slot` selects, or `null` when it names one this
621
+ * plan never declared (a server/client disagreement, not a tenant error). */
622
+ errorForSlot(slot) {
623
+ return this.slots[slot] ?? null;
624
+ }
625
+ };
626
+ function assertUniformRows(rows, table) {
627
+ const first = rows[0];
628
+ if (!first) return;
629
+ const want = Object.keys(first);
630
+ const wantKey = want.join(",");
631
+ for (let i = 1; i < rows.length; i++) {
632
+ const got = Object.keys(rows[i]);
633
+ if (got.join(",") !== wantKey) {
634
+ 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\`.)`);
635
+ }
636
+ }
637
+ }
638
+ __name(assertUniformRows, "assertUniformRows");
639
+ function materializeResult(value, results) {
640
+ const ref = refDescriptor(value);
641
+ if (ref) {
642
+ const row = rowOf(results, ref.op, `\`${ref.field}\``);
643
+ if (!(ref.field in row)) {
644
+ throw new TxPlanError(`the transaction's operation ${ref.op} returned no column \`${ref.field}\`.`);
645
+ }
646
+ return row[ref.field];
647
+ }
648
+ const rowOp = rowOpIndex(value);
649
+ if (rowOp !== null) return rowOf(results, rowOp, "a row");
650
+ if (isRowsHandle(value)) {
651
+ 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.");
652
+ }
653
+ if (Array.isArray(value)) return value.map((item) => materializeResult(item, results));
654
+ if (isPlainObject(value)) {
655
+ const out = {};
656
+ for (const [key, item] of Object.entries(value)) out[key] = materializeResult(item, results);
657
+ return out;
658
+ }
659
+ return value;
660
+ }
661
+ __name(materializeResult, "materializeResult");
662
+ function rowOf(results, opIndex, what) {
663
+ const result = results[opIndex];
664
+ if (!result) {
665
+ throw new TxPlanError(`the transaction returned no result for operation ${opIndex}, so ${what} cannot be read.`);
666
+ }
667
+ const row = result.rows[0];
668
+ if (!row) {
669
+ throw new TxPlanError(`the transaction's operation ${opIndex} returned no row, so ${what} cannot be read.`);
670
+ }
671
+ return row;
672
+ }
673
+ __name(rowOf, "rowOf");
674
+ function isPlainObject(value) {
675
+ if (typeof value !== "object" || value === null) return false;
676
+ const proto = Object.getPrototypeOf(value);
677
+ return proto === Object.prototype || proto === null;
678
+ }
679
+ __name(isPlainObject, "isPlainObject");
680
+ async function runTxPlan(transport, handle, builder, fn) {
681
+ const returned = fn(handle);
682
+ const body = builder.body();
683
+ if (body.ops.length === 0) {
684
+ return materializeResult(returned, []);
685
+ }
686
+ let response;
687
+ try {
688
+ response = await transport.txPlan(body);
689
+ } catch (err) {
690
+ throw translateRejection(err, builder);
691
+ }
692
+ return materializeResult(returned, response.results);
693
+ }
694
+ __name(runTxPlan, "runTxPlan");
695
+ function translateRejection(err, builder) {
696
+ if (typeof err !== "object" || err === null) return err;
697
+ const rejection = err;
698
+ if (rejection.error_code !== "tx_guard_failed" || typeof rejection.slot !== "number") {
699
+ return err;
700
+ }
701
+ return builder.errorForSlot(rejection.slot) ?? err;
702
+ }
703
+ __name(translateRejection, "translateRejection");
704
+
705
+ export {
706
+ brandRef,
707
+ looksLikeUnbrandedRef,
708
+ isColRef,
709
+ isPlanRef,
710
+ looksLikeUnbrandedPlanRef,
711
+ isSqlFragment,
712
+ isNowExpr,
713
+ isColumnExpr,
714
+ assertNoExpressionHandles,
715
+ assertUsableFilter,
716
+ assertUsableWriteValues,
717
+ TxRefError,
718
+ TxPlanError,
719
+ now,
720
+ increment,
721
+ inc,
722
+ decrement,
723
+ dec,
724
+ columnExprOf,
725
+ TxPlanBuilder,
726
+ runTxPlan
727
+ };
728
+ //# sourceMappingURL=chunk-JVZQCC77.js.map