@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
@@ -1,27 +1,46 @@
1
1
  import {
2
2
  __requestALS,
3
3
  __runStartHooks,
4
- __runWithRuntime
5
- } from "./chunk-CRQKCRGF.js";
4
+ __runWithRuntime,
5
+ assertNoOrphanEntryPoints,
6
+ buildContainer,
7
+ buildRelations
8
+ } from "./chunk-I3C4PFIW.js";
6
9
  import {
10
+ qualifiedTableKey
11
+ } from "./chunk-DRZFQRJI.js";
12
+ import {
13
+ assertNoExpressionHandles,
7
14
  assertUsableFilter,
8
- assertUsableWriteValues
9
- } from "./chunk-XABBC7JP.js";
15
+ assertUsableWriteValues,
16
+ columnExprOf,
17
+ isColRef,
18
+ isPlanRef,
19
+ isSqlFragment,
20
+ looksLikeUnbrandedPlanRef,
21
+ looksLikeUnbrandedRef
22
+ } from "./chunk-GYK6QYS4.js";
10
23
  import {
11
- qualifiedTableKey
12
- } from "./chunk-CJSKYY76.js";
24
+ getRoutes,
25
+ resolveEffectiveAuth
26
+ } from "./chunk-VVMJEVQP.js";
13
27
  import {
28
+ DeadlockDetected,
29
+ SerializationFailure,
14
30
  UniqueViolation,
15
- assertZeroArgConstructor,
16
- getRoutes,
17
31
  isEngineRaised,
18
32
  isHttpError,
19
- markEngineRaised,
20
- resolveEffectiveAuth
21
- } from "./chunk-35PNTIRN.js";
33
+ markEngineRaised
34
+ } from "./chunk-CGNN2PUH.js";
35
+ import {
36
+ __name
37
+ } from "./chunk-VXPNPVAG.js";
22
38
 
23
39
  // src/engine/config.ts
24
40
  var BootRefused = class extends Error {
41
+ static {
42
+ __name(this, "BootRefused");
43
+ }
25
44
  missing;
26
45
  constructor(missing, message) {
27
46
  super(message);
@@ -30,18 +49,21 @@ var BootRefused = class extends Error {
30
49
  }
31
50
  };
32
51
  var MANDATORY = [
33
- { key: "DATABASE_URL", what: "the stack's Postgres (Database module)" },
34
- { key: "AUTH_JWKS_URL", what: "where this stack publishes its token signing keys (Auth module)" }
52
+ {
53
+ key: "DATABASE_URL",
54
+ what: "the stack's Postgres (Database module)"
55
+ },
56
+ {
57
+ key: "AUTH_JWKS_URL",
58
+ what: "where this stack publishes its token signing keys (Auth module)"
59
+ }
35
60
  ];
36
61
  function loadConfig(env) {
37
62
  const missing = MANDATORY.filter((m) => !env[m.key]?.trim()).map((m) => m.key);
38
63
  if (missing.length > 0) {
39
64
  const detail = MANDATORY.filter((m) => missing.includes(m.key)).map((m) => ` ${m.key.padEnd(16)}${m.what}`).join("\n");
40
- throw new BootRefused(
41
- missing,
42
- `boot refused: mandatory module not configured \u2014 missing ${missing.join(", ")}.
43
- ${detail}`
44
- );
65
+ throw new BootRefused(missing, `boot refused: mandatory module not configured \u2014 missing ${missing.join(", ")}.
66
+ ${detail}`);
45
67
  }
46
68
  const port = Number(env.PORT ?? 3e3);
47
69
  if (!Number.isInteger(port) || port < 0 || port > 65535) {
@@ -75,6 +97,7 @@ ${detail}`
75
97
  poolMax
76
98
  };
77
99
  }
100
+ __name(loadConfig, "loadConfig");
78
101
 
79
102
  // src/engine/auth.ts
80
103
  function b64urlToBytes(s) {
@@ -85,7 +108,11 @@ function b64urlToBytes(s) {
85
108
  for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
86
109
  return out;
87
110
  }
111
+ __name(b64urlToBytes, "b64urlToBytes");
88
112
  var AuthVerifier = class {
113
+ static {
114
+ __name(this, "AuthVerifier");
115
+ }
89
116
  keys = /* @__PURE__ */ new Map();
90
117
  fetchedAt = 0;
91
118
  inflight = null;
@@ -111,16 +138,18 @@ var AuthVerifier = class {
111
138
  for (const jwk of body.keys ?? []) {
112
139
  if (jwk.kty !== "EC" || jwk.crv !== "P-256") continue;
113
140
  try {
114
- next.set(
115
- jwk.kid,
116
- await crypto.subtle.importKey(
117
- "jwk",
118
- { kty: "EC", crv: jwk.crv, x: jwk.x, y: jwk.y, ext: true },
119
- { name: "ECDSA", namedCurve: "P-256" },
120
- true,
121
- ["verify"]
122
- )
123
- );
141
+ next.set(jwk.kid, await crypto.subtle.importKey("jwk", {
142
+ kty: "EC",
143
+ crv: jwk.crv,
144
+ x: jwk.x,
145
+ y: jwk.y,
146
+ ext: true
147
+ }, {
148
+ name: "ECDSA",
149
+ namedCurve: "P-256"
150
+ }, true, [
151
+ "verify"
152
+ ]));
124
153
  } catch {
125
154
  }
126
155
  }
@@ -140,12 +169,12 @@ var AuthVerifier = class {
140
169
  return this.keys.get(kid) ?? null;
141
170
  }
142
171
  /**
143
- * Verify an `Authorization` header value.
144
- *
145
- * @returns the verified claims, or `null` for absent / malformed / expired /
146
- * wrong-issuer / bad-signature. One `null` for every failure on purpose:
147
- * the caller answers 401 either way, and a detailed reason is an oracle.
148
- */
172
+ * Verify an `Authorization` header value.
173
+ *
174
+ * @returns the verified claims, or `null` for absent / malformed / expired /
175
+ * wrong-issuer / bad-signature. One `null` for every failure on purpose:
176
+ * the caller answers 401 either way, and a detailed reason is an oracle.
177
+ */
149
178
  async verify(authorization) {
150
179
  if (!authorization || !authorization.startsWith("Bearer ")) return null;
151
180
  const parts = authorization.slice(7).trim().split(".");
@@ -167,12 +196,10 @@ var AuthVerifier = class {
167
196
  if (!key) return null;
168
197
  let ok = false;
169
198
  try {
170
- ok = await crypto.subtle.verify(
171
- { name: "ECDSA", hash: "SHA-256" },
172
- key,
173
- b64urlToBytes(sig),
174
- new TextEncoder().encode(`${h}.${p}`)
175
- );
199
+ ok = await crypto.subtle.verify({
200
+ name: "ECDSA",
201
+ hash: "SHA-256"
202
+ }, key, b64urlToBytes(sig), new TextEncoder().encode(`${h}.${p}`));
176
203
  } catch {
177
204
  return null;
178
205
  }
@@ -184,9 +211,18 @@ var AuthVerifier = class {
184
211
  };
185
212
  function effectiveAuth(routeAuth, controllerAuth) {
186
213
  const spec = routeAuth !== void 0 ? routeAuth : controllerAuth;
187
- if (spec === false) return { required: false, verifiedEmail: false };
188
- if (spec === true || spec === void 0 || spec === null) return { required: true, verifiedEmail: false };
189
- if (typeof spec !== "object") return { required: true, verifiedEmail: false };
214
+ if (spec === false) return {
215
+ required: false,
216
+ verifiedEmail: false
217
+ };
218
+ if (spec === true || spec === void 0 || spec === null) return {
219
+ required: true,
220
+ verifiedEmail: false
221
+ };
222
+ if (typeof spec !== "object") return {
223
+ required: true,
224
+ verifiedEmail: false
225
+ };
190
226
  const o = spec;
191
227
  const role = typeof o.role === "string" && o.role.trim() !== "" ? o.role.trim() : void 0;
192
228
  return {
@@ -195,23 +231,27 @@ function effectiveAuth(routeAuth, controllerAuth) {
195
231
  verifiedEmail: o.verifiedEmail === true
196
232
  };
197
233
  }
234
+ __name(effectiveAuth, "effectiveAuth");
198
235
 
199
236
  // src/engine/ratelimit.ts
200
237
  var RateLimiter = class {
238
+ static {
239
+ __name(this, "RateLimiter");
240
+ }
241
+ maxKeys;
242
+ buckets = /* @__PURE__ */ new Map();
201
243
  /** Bound on distinct keys held, so an attacker cycling identities cannot
202
- * grow this map without limit. On overflow the oldest windows are dropped —
203
- * forgiving, consistent with the restart behaviour above. */
244
+ * grow this map without limit. On overflow the oldest windows are dropped —
245
+ * forgiving, consistent with the restart behaviour above. */
204
246
  constructor(maxKeys = 1e5) {
205
247
  this.maxKeys = maxKeys;
206
248
  }
207
- maxKeys;
208
- buckets = /* @__PURE__ */ new Map();
209
249
  /**
210
- * Identify the caller: the signed-in user when the route resolved one,
211
- * otherwise the address the edge forwarded. Callers the edge did not
212
- * identify share one bucket — deliberately conservative, since the
213
- * alternative is a limit anyone resets by omitting a header.
214
- */
250
+ * Identify the caller: the signed-in user when the route resolved one,
251
+ * otherwise the address the edge forwarded. Callers the edge did not
252
+ * identify share one bucket — deliberately conservative, since the
253
+ * alternative is a limit anyone resets by omitting a header.
254
+ */
215
255
  static key(routeId, userId, headers) {
216
256
  if (userId) return `${routeId}\0u:${userId}`;
217
257
  const fwd = headers.get("x-forwarded-for");
@@ -219,16 +259,19 @@ var RateLimiter = class {
219
259
  return `${routeId}\0a:${addr || "anonymous"}`;
220
260
  }
221
261
  /**
222
- * @returns `null` when the request may proceed, or the number of seconds to
223
- * wait (never 0 — a caller told to wait 0 comes straight back to the same
224
- * refusal).
225
- */
262
+ * @returns `null` when the request may proceed, or the number of seconds to
263
+ * wait (never 0 — a caller told to wait 0 comes straight back to the same
264
+ * refusal).
265
+ */
226
266
  check(rule, key, now) {
227
267
  if (!rule || !(rule.max > 0) || !(rule.window > 0)) return null;
228
268
  const bucket = this.buckets.get(key);
229
269
  if (!bucket || now >= bucket.resetAt) {
230
270
  if (this.buckets.size >= this.maxKeys) this.evict(now);
231
- this.buckets.set(key, { count: 1, resetAt: now + rule.window * 1e3 });
271
+ this.buckets.set(key, {
272
+ count: 1,
273
+ resetAt: now + rule.window * 1e3
274
+ });
232
275
  return null;
233
276
  }
234
277
  if (bucket.count < rule.max) {
@@ -238,7 +281,7 @@ var RateLimiter = class {
238
281
  return Math.max(1, Math.ceil((bucket.resetAt - now) / 1e3));
239
282
  }
240
283
  /** Drop expired windows; if none are expired, drop the earliest-resetting
241
- * quarter so the map cannot wedge at the ceiling. */
284
+ * quarter so the map cannot wedge at the ceiling. */
242
285
  evict(now) {
243
286
  let dropped = 0;
244
287
  for (const [k, b] of this.buckets) {
@@ -248,7 +291,9 @@ var RateLimiter = class {
248
291
  }
249
292
  }
250
293
  if (dropped > 0) return;
251
- const byReset = [...this.buckets.entries()].sort((a, b) => a[1].resetAt - b[1].resetAt);
294
+ const byReset = [
295
+ ...this.buckets.entries()
296
+ ].sort((a, b) => a[1].resetAt - b[1].resetAt);
252
297
  for (let i = 0; i < Math.ceil(byReset.length / 4); i++) {
253
298
  const victim = byReset[i];
254
299
  if (victim) this.buckets.delete(victim[0]);
@@ -266,7 +311,7 @@ function makeMemoryCache(opts = {}) {
266
311
  const now = opts.now ?? (() => Date.now());
267
312
  const store = /* @__PURE__ */ new Map();
268
313
  const inflight = /* @__PURE__ */ new Map();
269
- const live = (key) => {
314
+ const live = /* @__PURE__ */ __name((key) => {
270
315
  const e = store.get(key);
271
316
  if (!e) return void 0;
272
317
  if (e.expiresAt !== 0 && e.expiresAt <= now()) {
@@ -274,8 +319,8 @@ function makeMemoryCache(opts = {}) {
274
319
  return void 0;
275
320
  }
276
321
  return e;
277
- };
278
- const evict = () => {
322
+ }, "live");
323
+ const evict = /* @__PURE__ */ __name(() => {
279
324
  const t = now();
280
325
  let dropped = 0;
281
326
  for (const [k, e] of store) {
@@ -285,18 +330,21 @@ function makeMemoryCache(opts = {}) {
285
330
  }
286
331
  }
287
332
  if (dropped > 0) return;
288
- const order = [...store.entries()].sort(
289
- (a, b) => (a[1].expiresAt || Infinity) - (b[1].expiresAt || Infinity)
290
- );
333
+ const order = [
334
+ ...store.entries()
335
+ ].sort((a, b) => (a[1].expiresAt || Infinity) - (b[1].expiresAt || Infinity));
291
336
  for (let i = 0; i < Math.ceil(order.length / 4); i++) {
292
337
  const victim = order[i];
293
338
  if (victim) store.delete(victim[0]);
294
339
  }
295
- };
296
- const set = async (key, value, ttl) => {
340
+ }, "evict");
341
+ const set = /* @__PURE__ */ __name(async (key, value, ttl) => {
297
342
  if (store.size >= maxEntries && !store.has(key)) evict();
298
- store.set(key, { value, expiresAt: ttl && ttl > 0 ? now() + ttl * 1e3 : 0 });
299
- };
343
+ store.set(key, {
344
+ value,
345
+ expiresAt: ttl && ttl > 0 ? now() + ttl * 1e3 : 0
346
+ });
347
+ }, "set");
300
348
  return {
301
349
  async get(key) {
302
350
  const e = live(key);
@@ -309,7 +357,10 @@ function makeMemoryCache(opts = {}) {
309
357
  async incr(key) {
310
358
  const e = live(key);
311
359
  const next = (typeof e?.value === "number" ? e.value : 0) + 1;
312
- store.set(key, { value: next, expiresAt: e?.expiresAt ?? 0 });
360
+ store.set(key, {
361
+ value: next,
362
+ expiresAt: e?.expiresAt ?? 0
363
+ });
313
364
  return next;
314
365
  },
315
366
  async getOrSet(key, ttl, fn) {
@@ -331,34 +382,45 @@ function makeMemoryCache(opts = {}) {
331
382
  }
332
383
  };
333
384
  }
385
+ __name(makeMemoryCache, "makeMemoryCache");
334
386
 
335
387
  // src/engine/db.ts
336
388
  function quoteIdent(name) {
337
389
  return `"${name.replace(/"/g, '""')}"`;
338
390
  }
391
+ __name(quoteIdent, "quoteIdent");
339
392
  function quoteTable(key) {
340
393
  const dot = key.indexOf(".");
341
394
  if (dot === -1) return quoteIdent(key);
342
395
  return `${quoteIdent(key.slice(0, dot))}.${quoteIdent(key.slice(dot + 1))}`;
343
396
  }
397
+ __name(quoteTable, "quoteTable");
344
398
  function encodePgArray(value) {
345
- const element = (x) => {
399
+ const element = /* @__PURE__ */ __name((x) => {
346
400
  if (x === null || x === void 0) return "NULL";
347
401
  if (Array.isArray(x)) return encodePgArray(x);
348
402
  return `"${String(x).replace(/(["\\])/g, "\\$1")}"`;
349
- };
403
+ }, "element");
350
404
  return `{${value.map(element).join(",")}}`;
351
405
  }
406
+ __name(encodePgArray, "encodePgArray");
352
407
  var BIND_SQL = "select set_config('role',$1,true), set_config('search_path','public',true), set_config('request.jwt.claims',$2,true)";
353
408
  function createLazyTransaction(sql, role, claimsJson, options = {}) {
354
409
  const { lockTimeout } = options;
355
410
  const bindSql = lockTimeout ? `${BIND_SQL}, set_config('lock_timeout',$3,true)` : BIND_SQL;
356
- const bindParams = lockTimeout ? [role, claimsJson, lockTimeout] : [role, claimsJson];
411
+ const bindParams = lockTimeout ? [
412
+ role,
413
+ claimsJson,
414
+ lockTimeout
415
+ ] : [
416
+ role,
417
+ claimsJson
418
+ ];
357
419
  let opening = null;
358
420
  let release = null;
359
421
  let fail = null;
360
422
  let settled = null;
361
- const ensure = () => {
423
+ const ensure = /* @__PURE__ */ __name(() => {
362
424
  if (opening) return opening;
363
425
  opening = new Promise((resolveTx2, rejectTx) => {
364
426
  const parked = new Promise((res, rej) => {
@@ -375,7 +437,7 @@ function createLazyTransaction(sql, role, claimsJson, options = {}) {
375
437
  });
376
438
  });
377
439
  return opening;
378
- };
440
+ }, "ensure");
379
441
  return {
380
442
  ensure,
381
443
  get opened() {
@@ -393,24 +455,29 @@ function createLazyTransaction(sql, role, claimsJson, options = {}) {
393
455
  }
394
456
  };
395
457
  }
396
- var resolveTx = async (tx) => typeof tx.ensure === "function" ? await tx.ensure() : tx;
458
+ __name(createLazyTransaction, "createLazyTransaction");
459
+ var resolveTx = /* @__PURE__ */ __name(async (tx) => typeof tx.ensure === "function" ? await tx.ensure() : tx, "resolveTx");
397
460
  function asWireValue(value) {
398
461
  if (value instanceof Date) return value.toISOString();
399
462
  if (Array.isArray(value)) return value.map(asWireValue);
400
463
  return value;
401
464
  }
465
+ __name(asWireValue, "asWireValue");
402
466
  function asWireRow(row) {
403
467
  if (row === null || typeof row !== "object") return row;
404
468
  const out = {};
405
469
  for (const [key, value] of Object.entries(row)) out[key] = asWireValue(value);
406
470
  return out;
407
471
  }
472
+ __name(asWireRow, "asWireRow");
408
473
  function asWireRows(rows) {
409
474
  return rows.map((row) => asWireRow(row));
410
475
  }
476
+ __name(asWireRows, "asWireRows");
411
477
  function toVectorLiteral(v) {
412
478
  return `[${v.join(",")}]`;
413
479
  }
480
+ __name(toVectorLiteral, "toVectorLiteral");
414
481
  function vectorColumnsOf(schema, table) {
415
482
  const out = /* @__PURE__ */ new Set();
416
483
  const def = tableDefOf(table, schema);
@@ -422,9 +489,11 @@ function vectorColumnsOf(schema, table) {
422
489
  }
423
490
  return out;
424
491
  }
492
+ __name(vectorColumnsOf, "vectorColumnsOf");
425
493
  function tableDefOf(key, schema = currentSchema) {
426
494
  return schema.tables?.[key] ?? null;
427
495
  }
496
+ __name(tableDefOf, "tableDefOf");
428
497
  function reviveVectors(row, vectorCols) {
429
498
  if (row === null || typeof row !== "object" || vectorCols.size === 0) return row;
430
499
  const out = row;
@@ -434,6 +503,7 @@ function reviveVectors(row, vectorCols) {
434
503
  }
435
504
  return row;
436
505
  }
506
+ __name(reviveVectors, "reviveVectors");
437
507
  function transformsOf(schema, table) {
438
508
  const out = /* @__PURE__ */ new Map();
439
509
  const def = tableDefOf(table, schema);
@@ -448,6 +518,7 @@ function transformsOf(schema, table) {
448
518
  }
449
519
  return out;
450
520
  }
521
+ __name(transformsOf, "transformsOf");
451
522
  function applyFromDb(row, transforms) {
452
523
  if (transforms.size === 0) return row;
453
524
  for (const [col, t] of transforms) {
@@ -458,17 +529,21 @@ function applyFromDb(row, transforms) {
458
529
  }
459
530
  return row;
460
531
  }
532
+ __name(applyFromDb, "applyFromDb");
461
533
  function asTableRow(table, row) {
462
534
  const revived = reviveVectors(asWireRow(row), vectorColumnsOf(currentSchema, table));
463
535
  return applyFromDb(revived, transformsOf(currentSchema, table));
464
536
  }
537
+ __name(asTableRow, "asTableRow");
465
538
  function asTableRows(table, rows) {
466
539
  const vectorCols = vectorColumnsOf(currentSchema, table);
467
540
  const transforms = transformsOf(currentSchema, table);
468
541
  return rows.map((row) => applyFromDb(reviveVectors(asWireRow(row), vectorCols), transforms));
469
542
  }
543
+ __name(asTableRows, "asTableRows");
470
544
  function asBindParams(table, cols, data, caller) {
471
545
  assertUsableWriteValues(caller, table, cols, data);
546
+ assertNoExpressionHandles(caller, table, cols, data);
472
547
  const vectorCols = vectorColumnsOf(currentSchema, table);
473
548
  const transforms = transformsOf(currentSchema, table);
474
549
  return cols.map((c) => {
@@ -479,6 +554,7 @@ function asBindParams(table, cols, data, caller) {
479
554
  return v;
480
555
  });
481
556
  }
557
+ __name(asBindParams, "asBindParams");
482
558
  var SELECTIVITY_EXACT_THRESHOLD = 1e4;
483
559
  var METRIC_OPERATOR = {
484
560
  cosine: "<=>",
@@ -489,27 +565,33 @@ function searchConfigFor(table) {
489
565
  const t = tableDefOf(table);
490
566
  if (!t) return null;
491
567
  const columns = t.columns ?? {};
492
- const defOf = (c) => c !== null && typeof c === "object" && "_def" in c ? c._def : c ?? {};
568
+ const defOf = /* @__PURE__ */ __name((c) => c !== null && typeof c === "object" && "_def" in c ? c._def : c ?? {}, "defOf");
493
569
  const cols = Object.keys(columns);
494
570
  const vectorCols = cols.filter((c) => defOf(columns[c]).type === "vector");
495
- const defOfFull = (c) => c !== null && typeof c === "object" && "_def" in c ? c._def : c ?? {};
571
+ const defOfFull = /* @__PURE__ */ __name((c) => c !== null && typeof c === "object" && "_def" in c ? c._def : c ?? {}, "defOfFull");
496
572
  const pkCols = cols.filter((c) => defOfFull(columns[c]).primaryKey === true);
497
573
  const pk = pkCols.length === 1 ? pkCols[0] : cols.includes("id") ? "id" : null;
498
574
  if (pk === null) {
499
- throw new Error(
500
- `search(${table}): tek-kolon primary key bulunamad\u0131 \u2014 arama s\u0131ralamas\u0131 ve sat\u0131r birle\u015Fimi PK ister (FR-020)`
501
- );
575
+ throw new Error(`search(${table}): tek-kolon primary key bulunamad\u0131 \u2014 arama s\u0131ralamas\u0131 ve sat\u0131r birle\u015Fimi PK ister (FR-020)`);
502
576
  }
503
577
  const search = t.search;
504
- const synonyms = search?.synonyms !== void 0 && Object.keys(search.synonyms).length > 0 ? { synonyms: search.synonyms } : {};
505
- const validity = search?.validity === true ? { validity: true } : {};
578
+ const synonyms = search?.synonyms !== void 0 && Object.keys(search.synonyms).length > 0 ? {
579
+ synonyms: search.synonyms
580
+ } : {};
581
+ const validity = search?.validity === true ? {
582
+ validity: true
583
+ } : {};
506
584
  if (search?.from !== void 0 && search.model !== void 0) {
507
585
  const m = search.model;
508
586
  const embed = {
509
587
  model: m.model,
510
588
  apiKeyName: m.apiKeyName ?? "OPENAI_API_KEY",
511
- ...m.baseURL !== void 0 ? { baseURL: m.baseURL } : {},
512
- ...m.dimensions !== void 0 ? { dimensions: m.dimensions } : {}
589
+ ...m.baseURL !== void 0 ? {
590
+ baseURL: m.baseURL
591
+ } : {},
592
+ ...m.dimensions !== void 0 ? {
593
+ dimensions: m.dimensions
594
+ } : {}
513
595
  };
514
596
  const metric = search.metric ?? "cosine";
515
597
  const ftsOn = search.text !== false;
@@ -520,7 +602,13 @@ function searchConfigFor(table) {
520
602
  cols,
521
603
  colSet: new Set(cols),
522
604
  ftsCols: ftsColsNew,
523
- legs: [{ column: vectorCols[0], metric, embed }],
605
+ legs: [
606
+ {
607
+ column: vectorCols[0],
608
+ metric,
609
+ embed
610
+ }
611
+ ],
524
612
  ...synonyms,
525
613
  ...validity
526
614
  };
@@ -531,13 +619,20 @@ function searchConfigFor(table) {
531
619
  colSet: new Set(cols),
532
620
  ftsCols: ftsColsNew,
533
621
  legs: [],
534
- chunk: { table: `${table}__palbase_chunks`, metric, embed, fts: ftsOn },
622
+ chunk: {
623
+ table: `${table}__palbase_chunks`,
624
+ metric,
625
+ embed,
626
+ fts: ftsOn
627
+ },
535
628
  ...synonyms,
536
629
  ...validity
537
630
  };
538
631
  }
539
632
  const ftsCols = (Array.isArray(search?.text) ? search.text : void 0) ?? [];
540
- const rawLegs = search?.vector === void 0 ? [] : Array.isArray(search.vector) ? search.vector : [search.vector];
633
+ const rawLegs = search?.vector === void 0 ? [] : Array.isArray(search.vector) ? search.vector : [
634
+ search.vector
635
+ ];
541
636
  let legs;
542
637
  if (rawLegs.length > 0) {
543
638
  legs = rawLegs.map((leg) => {
@@ -550,35 +645,57 @@ function searchConfigFor(table) {
550
645
  return {
551
646
  column,
552
647
  metric: l.metric ?? "cosine",
553
- ...model !== void 0 ? { embed: {
554
- model: model.model,
555
- apiKeyName: model.apiKeyName ?? "OPENAI_API_KEY",
556
- ...model.baseURL !== void 0 ? { baseURL: model.baseURL } : {},
557
- ...model.dimensions !== void 0 ? { dimensions: model.dimensions } : {}
558
- } } : {}
648
+ ...model !== void 0 ? {
649
+ embed: {
650
+ model: model.model,
651
+ apiKeyName: model.apiKeyName ?? "OPENAI_API_KEY",
652
+ ...model.baseURL !== void 0 ? {
653
+ baseURL: model.baseURL
654
+ } : {},
655
+ ...model.dimensions !== void 0 ? {
656
+ dimensions: model.dimensions
657
+ } : {}
658
+ }
659
+ } : {}
559
660
  };
560
661
  });
561
662
  } else {
562
- legs = vectorCols.map((column) => ({ column, metric: "cosine" }));
663
+ legs = vectorCols.map((column) => ({
664
+ column,
665
+ metric: "cosine"
666
+ }));
563
667
  }
564
668
  if (ftsCols.length === 0 && legs.length === 0) return null;
565
- return { pk, cols, colSet: new Set(cols), ftsCols, legs, ...synonyms, ...validity };
669
+ return {
670
+ pk,
671
+ cols,
672
+ colSet: new Set(cols),
673
+ ftsCols,
674
+ legs,
675
+ ...synonyms,
676
+ ...validity
677
+ };
566
678
  }
679
+ __name(searchConfigFor, "searchConfigFor");
567
680
  function pickLeg(table, legs, using) {
568
681
  if (legs.length === 0) return null;
569
682
  if (using !== void 0) {
570
683
  const hit = legs.find((l) => l.column === using);
571
684
  if (!hit) {
572
- throw new Error(
573
- `search(${table}): using "${using}" bir vekt\xF6r kolunu adlam\u0131yor \u2014 mevcut: ${legs.map((l) => l.column).join(", ")}`
574
- );
685
+ throw new Error(`search(${table}): using "${using}" bir vekt\xF6r kolunu adlam\u0131yor \u2014 mevcut: ${legs.map((l) => l.column).join(", ")}`);
575
686
  }
576
687
  return hit;
577
688
  }
578
689
  if (legs.length === 1) return legs[0];
579
690
  throw new Error(`search(${table}): birden \xE7ok vekt\xF6r kolu var \u2014 'using' ile se\xE7in (FR-013) \u2014 salt metin ar\u0131yorsan mode:"text" kullan`);
580
691
  }
581
- var HALF_LIFE_UNIT_SECONDS = { s: 1, m: 60, h: 3600, d: 86400 };
692
+ __name(pickLeg, "pickLeg");
693
+ var HALF_LIFE_UNIT_SECONDS = {
694
+ s: 1,
695
+ m: 60,
696
+ h: 3600,
697
+ d: 86400
698
+ };
582
699
  function parseHalfLife(s) {
583
700
  const m = /^(\d+)(s|m|h|d)$/.exec(s);
584
701
  const sec = m === null ? 0 : Number(m[1]) * HALF_LIFE_UNIT_SECONDS[m[2]];
@@ -587,10 +704,20 @@ function parseHalfLife(s) {
587
704
  }
588
705
  return sec;
589
706
  }
590
- var WHERE_OPS = { gt: ">", gte: ">=", lt: "<", lte: "<=", neq: "<>" };
707
+ __name(parseHalfLife, "parseHalfLife");
708
+ var WHERE_OPS = {
709
+ gt: ">",
710
+ gte: ">=",
711
+ lt: "<",
712
+ lte: "<=",
713
+ neq: "<>"
714
+ };
591
715
  function ftsExprOf(ftsCols) {
592
- return [...ftsCols].sort().map((c) => `coalesce(t.${quoteIdent(c)},'')`).join(" || ' ' || ");
716
+ return [
717
+ ...ftsCols
718
+ ].sort().map((c) => `coalesce(t.${quoteIdent(c)},'')`).join(" || ' ' || ");
593
719
  }
720
+ __name(ftsExprOf, "ftsExprOf");
594
721
  function expandSynonyms(query, map) {
595
722
  const lower = {};
596
723
  for (const [word, alts] of Object.entries(map)) lower[word.toLowerCase()] = alts;
@@ -603,9 +730,10 @@ function expandSynonyms(query, map) {
603
730
  }).join("");
604
731
  }).join("");
605
732
  }
606
- var searchLogger = (evt, fields) => {
733
+ __name(expandSynonyms, "expandSynonyms");
734
+ var searchLogger = /* @__PURE__ */ __name((evt, fields) => {
607
735
  console.log(evt, JSON.stringify(fields));
608
- };
736
+ }, "searchLogger");
609
737
  function logNoResults(table, query, mode, n) {
610
738
  if (n === 0) {
611
739
  searchLogger?.("palbase.search.no_results", {
@@ -615,26 +743,29 @@ function logNoResults(table, query, mode, n) {
615
743
  });
616
744
  }
617
745
  }
746
+ __name(logNoResults, "logNoResults");
618
747
  async function fetchFacets(live, table, colSet, facets, where, extraWhere = () => "") {
619
748
  const bind = [];
620
- const add = (v) => {
749
+ const add = /* @__PURE__ */ __name((v) => {
621
750
  bind.push(v);
622
751
  return `$${bind.length}`;
623
- };
752
+ }, "add");
624
753
  const whereSql = compileWhere(table, colSet, where, add) + extraWhere(add);
625
- const parts = facets.map(
626
- (col) => `(SELECT '${col.replace(/'/g, "''")}' AS f, t.${quoteIdent(col)}::text AS v, count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql} GROUP BY 2 ORDER BY 3 DESC LIMIT 20)`
627
- );
754
+ const parts = facets.map((col) => `(SELECT '${col.replace(/'/g, "''")}' AS f, t.${quoteIdent(col)}::text AS v, count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql} GROUP BY 2 ORDER BY 3 DESC LIMIT 20)`);
628
755
  const rows = await live.unsafe(parts.join(" UNION ALL "), bind);
629
756
  const out = {};
630
757
  for (const col of facets) out[col] = [];
631
758
  for (const r of rows) {
632
759
  if (typeof r.f === "string" && out[r.f] !== void 0) {
633
- out[r.f].push({ value: r.v ?? null, count: Number(r.n) });
760
+ out[r.f].push({
761
+ value: r.v ?? null,
762
+ count: Number(r.n)
763
+ });
634
764
  }
635
765
  }
636
766
  return out;
637
767
  }
768
+ __name(fetchFacets, "fetchFacets");
638
769
  function validitySql(v, add) {
639
770
  if (v === "all") return "";
640
771
  if (v !== void 0) {
@@ -643,26 +774,96 @@ function validitySql(v, add) {
643
774
  }
644
775
  return ` AND t."valid_to" IS NULL`;
645
776
  }
777
+ __name(validitySql, "validitySql");
646
778
  function excludeSql(pk, ids, add) {
647
779
  if (ids.length === 0) return "";
648
780
  if (ids.length === 1) return ` AND t.${quoteIdent(pk)} <> ${add(ids[0])}`;
649
781
  return ` AND t.${quoteIdent(pk)}::text <> ALL(ARRAY[${ids.map((x) => add(x)).join(", ")}])`;
650
782
  }
783
+ __name(excludeSql, "excludeSql");
784
+ function primaryKeyOf(table) {
785
+ const t = tableDefOf(table);
786
+ const columns = t?.columns ?? {};
787
+ const cols = Object.keys(columns);
788
+ if (cols.length === 0) return null;
789
+ const declared = t?.primaryKey;
790
+ if (Array.isArray(declared)) {
791
+ if (declared.length !== 1) return null;
792
+ const only = declared[0];
793
+ return typeof only === "string" && cols.includes(only) ? only : null;
794
+ }
795
+ const pkOf = /* @__PURE__ */ __name((c) => {
796
+ if (c === null || typeof c !== "object") return false;
797
+ const rec = c;
798
+ const def = "_def" in rec ? rec._def : rec;
799
+ return def !== null && typeof def === "object" && def.primaryKey === true;
800
+ }, "pkOf");
801
+ const pks = cols.filter((c) => pkOf(columns[c]));
802
+ return pks.length === 1 ? pks[0] : null;
803
+ }
804
+ __name(primaryKeyOf, "primaryKeyOf");
805
+ function isSinglePkEquality(where, pk) {
806
+ if (pk === null) return false;
807
+ const keys = Object.keys(where);
808
+ if (keys.length !== 1 || keys[0] !== pk) return false;
809
+ const v = where[pk];
810
+ return v !== null && (typeof v !== "object" || Array.isArray(v));
811
+ }
812
+ __name(isSinglePkEquality, "isSinglePkEquality");
813
+ function assertNotAppendOnly(caller, table) {
814
+ const def = tableDefOf(table);
815
+ if (def?.appendOnly !== true) return;
816
+ throw new Error(`${caller}(${table}): "${table}" append-only \u2014 sat\u0131r g\xFCncellenemez ya da silinemez. D\xFCzeltme i\xE7in TELAF\u0130 KAYDI ekleyin: insert("${table}", { \u2026 }) ile ters i\u015Fareti ta\u015F\u0131yan yeni bir sat\u0131r yaz\u0131n; ge\xE7mi\u015F oldu\u011Fu gibi kals\u0131n diye tablo b\xF6yle bildirilmi\u015F (appendOnly: true).`);
817
+ }
818
+ __name(assertNotAppendOnly, "assertNotAppendOnly");
651
819
  function schemaColumns(table) {
652
820
  const t = tableDefOf(table);
653
821
  const cols = t?.columns ? Object.keys(t.columns) : [];
654
822
  return cols.length > 0 ? new Set(cols) : null;
655
823
  }
824
+ __name(schemaColumns, "schemaColumns");
825
+ function colRefSql(table, known, ref, caller, alias = "t") {
826
+ const name = ref.$col;
827
+ const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);
828
+ if (known !== null ? !known.has(name) : !shapeOK) {
829
+ throw new Error(`${caller}(${table}): col("${name}") tabloda yok (FR-011)`);
830
+ }
831
+ return `${alias}.${quoteIdent(name)}`;
832
+ }
833
+ __name(colRefSql, "colRefSql");
834
+ function selectClause(table, known, select) {
835
+ if (select !== void 0 && select.length === 0) {
836
+ throw new Error(`findMany(${table}): select bo\u015F bir liste ald\u0131 \u2014 bu "hepsini ver" DE\u011E\u0130L, "hi\xE7birini saymad\u0131m" demek. Projeksiyon istemiyorsan\u0131z anahtar\u0131 hi\xE7 koymay\u0131n; istiyorsan\u0131z en az bir kolon ad\u0131 verin.`);
837
+ }
838
+ if (select === void 0) return "*";
839
+ return select.map((col) => {
840
+ const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);
841
+ if (known !== null ? !known.has(col) : !shapeOK) {
842
+ throw new Error(`findMany(${table}): select kolonu "${col}" tabloda yok`);
843
+ }
844
+ return `t.${quoteIdent(col)}`;
845
+ }).join(", ");
846
+ }
847
+ __name(selectClause, "selectClause");
656
848
  function orderClause(table, known, orderBy) {
657
849
  if (!orderBy) return "";
658
- const col = orderBy.column;
659
- const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);
660
- if (known !== null ? !known.has(col) : !shapeOK) {
661
- throw new Error(`findMany(${table}): orderBy kolonu "${col}" tabloda yok`);
662
- }
663
- const dir = orderBy.direction === "desc" ? "DESC" : "ASC";
664
- return ` ORDER BY ${quoteIdent(col)} ${dir}`;
850
+ const items = Array.isArray(orderBy) ? orderBy : [
851
+ orderBy
852
+ ];
853
+ if (items.length === 0) return "";
854
+ const rendered = items.map((o) => {
855
+ const col = o.column;
856
+ const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);
857
+ if (known !== null ? !known.has(col) : !shapeOK) {
858
+ throw new Error(`findMany(${table}): orderBy kolonu "${col}" tabloda yok`);
859
+ }
860
+ const dir = o.direction === "desc" ? "DESC" : "ASC";
861
+ const nulls = o.nulls === "first" ? " NULLS FIRST" : o.nulls === "last" ? " NULLS LAST" : "";
862
+ return `${quoteIdent(col)} ${dir}${nulls}`;
863
+ });
864
+ return ` ORDER BY ${rendered.join(", ")}`;
665
865
  }
866
+ __name(orderClause, "orderClause");
666
867
  function limitClause(limit) {
667
868
  if (limit === void 0) return "";
668
869
  if (!Number.isInteger(limit) || limit < 0) {
@@ -670,46 +871,118 @@ function limitClause(limit) {
670
871
  }
671
872
  return ` LIMIT ${limit}`;
672
873
  }
874
+ __name(limitClause, "limitClause");
673
875
  function offsetClause(offset, limit) {
674
876
  if (offset === void 0) return "";
675
877
  if (!Number.isInteger(offset) || offset < 0) {
676
- throw new Error(
677
- `findMany: offset bir negatif olmayan tam say\u0131 olmal\u0131 (geldi: ${String(offset)})`
678
- );
878
+ throw new Error(`findMany: offset bir negatif olmayan tam say\u0131 olmal\u0131 (geldi: ${String(offset)})`);
679
879
  }
680
880
  if (limit === void 0) {
681
- throw new Error(
682
- "findMany: offset yaln\u0131z limit ile birlikte verilir \u2014 limitsiz offset bir sayfa de\u011Fil, s\u0131n\u0131rs\u0131z bir kuyru\u011Fun kayd\u0131r\u0131lm\u0131\u015F\u0131d\u0131r"
683
- );
881
+ throw new Error("findMany: offset yaln\u0131z limit ile birlikte verilir \u2014 limitsiz offset bir sayfa de\u011Fil, s\u0131n\u0131rs\u0131z bir kuyru\u011Fun kayd\u0131r\u0131lm\u0131\u015F\u0131d\u0131r");
684
882
  }
685
883
  return ` OFFSET ${offset}`;
686
884
  }
687
- function compileWhere(table, colSet, where, add, caller = "search") {
885
+ __name(offsetClause, "offsetClause");
886
+ function compileWhereBare(table, colSet, where, add, caller = "search", alias = "t", depth = 0) {
688
887
  const parts = [];
689
888
  const transforms = transformsOf(currentSchema, table);
690
- const bindFor = (col) => {
889
+ const bindFor = /* @__PURE__ */ __name((col) => {
691
890
  const t = transforms.get(col);
692
891
  return t?.toDb === void 0 ? add : (v) => add(v === null || v === void 0 ? v : t.toDb(v));
693
- };
892
+ }, "bindFor");
694
893
  assertUsableFilter(caller, table, where);
894
+ if (isSqlFragment(where)) {
895
+ const { text, values } = where.$sql;
896
+ if (text.length !== values.length + 1) {
897
+ throw new Error(`${caller}(${table}): sqlFragment par\xE7alar\u0131 bozuk (${text.length} metin, ${values.length} de\u011Fer) \u2014 bunu \xFCreten tek \u015Fey template tag'i, elle kurulmu\u015F bir nesne de\u011Fil`);
898
+ }
899
+ let out = text[0] ?? "";
900
+ for (let i = 0; i < values.length; i++) out += `${add(values[i])}${text[i + 1] ?? ""}`;
901
+ return `(${out})`;
902
+ }
695
903
  for (const [col, cond] of Object.entries(where)) {
904
+ if (col === "OR" || col === "AND") {
905
+ const branches = cond;
906
+ if (branches.length === 0) {
907
+ parts.push(col === "OR" ? "false" : "true");
908
+ continue;
909
+ }
910
+ const compiled = branches.map((b) => `(${compileWhereBare(table, colSet, b, add, caller, alias, depth)})`);
911
+ parts.push(`(${compiled.join(col === "OR" ? " OR " : " AND ")})`);
912
+ continue;
913
+ }
914
+ if (col === "has") {
915
+ const rels = currentRelations.get(table) ?? [];
916
+ for (const [relName, inner] of Object.entries(cond)) {
917
+ const rel = rels.find((r) => r.name === relName);
918
+ if (rel === void 0) {
919
+ const known = rels.map((r) => r.name).sort();
920
+ throw new Error(`${caller}(${table}): has.${relName} diye bir ili\u015Fki yok${known.length > 0 ? ` (bilinenler: ${known.join(", ")})` : " \u2014 bu tablonun hi\xE7 ili\u015Fkisi yok"}. \u0130li\u015Fkiler yabanc\u0131 anahtarlardan T\xDCRET\u0130L\u0130R; ad\u0131n\u0131 de\u011Fi\u015Ftirmek i\xE7in references(..., { as, reverseAs }).`);
921
+ }
922
+ const ourCol = rel.kind === "many" ? primaryKeyOf(table) : rel.via;
923
+ const theirCol = rel.kind === "many" ? rel.via : primaryKeyOf(rel.to);
924
+ if (ourCol === null || theirCol === null) {
925
+ const missing = ourCol === null ? table : rel.to;
926
+ throw new Error(`${caller}(${table}): has.${relName} kurulam\u0131yor \u2014 "${missing}" tablosunun tek kolonlu bir primary key'i yok. Korelasyon bir anahtar ister; \xE7ok kolonlu anahtarda ili\u015Fki \xFCzerinden s\xFCzmek yerine sqlFragment ile yaz\u0131n.`);
927
+ }
928
+ const sub = `r${depth + 1}`;
929
+ const innerSql = compileWhereBare(rel.to, schemaColumns(rel.to), inner ?? {}, add, caller, sub, depth + 1);
930
+ parts.push(`${alias}.${quoteIdent(ourCol)} IN (SELECT ${sub}.${quoteIdent(theirCol)} FROM ${quoteTable(rel.to)} ${sub}${innerSql === "" ? "" : ` WHERE ${innerSql}`})`);
931
+ }
932
+ continue;
933
+ }
934
+ if (col === "NOT") {
935
+ parts.push(`NOT (${compileWhereBare(table, colSet, cond, add, caller, alias, depth)})`);
936
+ continue;
937
+ }
696
938
  if (colSet !== null && !colSet.has(col)) {
697
939
  throw new Error(`${caller}(${table}): where kolonu "${col}" tabloda yok (FR-016)`);
698
940
  }
699
- const q = `t.${quoteIdent(col)}`;
941
+ const q = `${alias}.${quoteIdent(col)}`;
700
942
  const bind = bindFor(col);
943
+ if (isColRef(cond)) {
944
+ parts.push(`${q} = ${colRefSql(table, colSet, cond, caller, alias)}`);
945
+ continue;
946
+ }
701
947
  if (cond !== null && typeof cond === "object" && !Array.isArray(cond)) {
702
948
  for (const [op, v] of Object.entries(cond)) {
949
+ if (op === "contains" || op === "icontains" || op === "startsWith" || op === "endsWith") {
950
+ if (typeof v !== "string") {
951
+ throw new Error(`${caller}(${table}): where.${col}.${op} bir string olmal\u0131`);
952
+ }
953
+ const lit = v.replace(/([\\%_])/g, "\\$1");
954
+ const pattern = op === "startsWith" ? `${lit}%` : op === "endsWith" ? `%${lit}` : `%${lit}%`;
955
+ parts.push(`${q} ${op === "icontains" ? "ILIKE" : "LIKE"} ${bind(pattern)}`);
956
+ continue;
957
+ }
958
+ if (op === "isNull") {
959
+ if (typeof v !== "boolean") {
960
+ throw new Error(`${caller}(${table}): where.${col}.isNull bir boolean olmal\u0131`);
961
+ }
962
+ parts.push(`${q} IS ${v ? "NULL" : "NOT NULL"}`);
963
+ continue;
964
+ }
703
965
  if (op === "in") {
704
966
  if (!Array.isArray(v)) throw new Error(`${caller}(${table}): where.${col}.in bir dizi olmal\u0131`);
967
+ if (v.some(isColRef)) {
968
+ throw new Error(`${caller}(${table}): where.${col}.in col() ile kullan\u0131lamaz \u2014 kolon kar\u015F\u0131la\u015Ft\u0131rmas\u0131 i\xE7in \xE7\u0131plak bi\xE7imi ({ ${col}: col("\u2026") }) ya da gt/gte/lt/lte/neq kullan\u0131n`);
969
+ }
705
970
  if (v.length === 0) {
706
971
  parts.push("false");
707
972
  continue;
708
973
  }
709
974
  parts.push(`${q} IN (${v.map((x) => bind(x)).join(", ")})`);
975
+ } else if (isColRef(v)) {
976
+ if (!(op in WHERE_OPS)) {
977
+ throw new Error(`${caller}(${table}): where.${col}.${op} col() ile kullan\u0131lamaz \u2014 e\u015Fitlik i\xE7in \xE7\u0131plak bi\xE7imi kullan\u0131n: { ${col}: col("\u2026") }`);
978
+ }
979
+ parts.push(`${q} ${WHERE_OPS[op]} ${colRefSql(table, colSet, v, caller, alias)}`);
980
+ } else if (looksLikeUnbrandedRef(v) !== null) {
981
+ const kind = looksLikeUnbrandedRef(v);
982
+ throw new Error(`${caller}(${table}): where.${col}.${op} bir ${kind === "col" ? "col()" : "sqlFragment"} TAKL\u0130D\u0130 ald\u0131 \u2014 bu nesne bu s\xFCre\xE7te ${kind === "col" ? "col()" : "sqlFragment"} ile \xFCretilmemi\u015F. \u0130stek g\xF6vdesinden gelen bir filtre i\u015Faret\xE7i TA\u015EIYAMAZ; kolon kar\u015F\u0131la\u015Ft\u0131rmas\u0131n\u0131 kendi kodunuzda ${kind === "col" ? 'col("kolon_ad\u0131")' : "sqlFragment`\u2026`"} ile kurun.`);
710
983
  } else if (op in WHERE_OPS) {
711
- if (v === null && (op === "neq" || op === "eq")) {
712
- parts.push(`${q} IS ${op === "neq" ? "NOT " : ""}NULL`);
984
+ if (v === null && op === "neq") {
985
+ parts.push(`${q} IS NOT NULL`);
713
986
  continue;
714
987
  }
715
988
  parts.push(`${q} ${WHERE_OPS[op]} ${bind(v)}`);
@@ -723,8 +996,14 @@ function compileWhere(table, colSet, where, add, caller = "search") {
723
996
  parts.push(`${q} = ${bind(cond)}`);
724
997
  }
725
998
  }
726
- return parts.length === 0 ? "" : ` AND ${parts.join(" AND ")}`;
999
+ return parts.join(" AND ");
1000
+ }
1001
+ __name(compileWhereBare, "compileWhereBare");
1002
+ function compileWhere(table, colSet, where, add, caller = "search") {
1003
+ const bare = compileWhereBare(table, colSet, where, add, caller);
1004
+ return bare === "" ? "" : ` AND ${bare}`;
727
1005
  }
1006
+ __name(compileWhere, "compileWhere");
728
1007
  function onConflictTail(cols, conflict, action) {
729
1008
  const target = `ON CONFLICT (${conflict.map(quoteIdent).join(", ")})`;
730
1009
  if (action === "ignore") return `${target} DO NOTHING`;
@@ -732,26 +1011,22 @@ function onConflictTail(cols, conflict, action) {
732
1011
  const sets = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
733
1012
  return sets.length ? `${target} DO UPDATE SET ${sets.join(", ")}` : `${target} DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
734
1013
  }
1014
+ __name(onConflictTail, "onConflictTail");
735
1015
  var cachedVectorSchema = null;
736
1016
  var cachedTrgmSchema = null;
737
1017
  async function trgmSchemaOf(live) {
738
1018
  if (cachedTrgmSchema !== null) return cachedTrgmSchema;
739
- const rows = await live.unsafe(
740
- "select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'pg_trgm'"
741
- );
1019
+ const rows = await live.unsafe("select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'pg_trgm'");
742
1020
  cachedTrgmSchema = rows?.[0]?.nspname ?? "public";
743
1021
  return cachedTrgmSchema;
744
1022
  }
1023
+ __name(trgmSchemaOf, "trgmSchemaOf");
745
1024
  async function vectorSchemaWithGuc(runner) {
746
1025
  if (cachedVectorSchema !== null) {
747
- await runner.unsafe(
748
- "select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true)"
749
- );
1026
+ await runner.unsafe("select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true)");
750
1027
  return cachedVectorSchema;
751
1028
  }
752
- const rows = await runner.unsafe(
753
- "select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true), (select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'vector') as nspname"
754
- );
1029
+ const rows = await runner.unsafe("select set_config('hnsw.iterative_scan','relaxed_order',true), set_config('hnsw.max_scan_tuples','200000',true), set_config('hnsw.ef_search','200',true), (select n.nspname from pg_extension e join pg_namespace n on n.oid = e.extnamespace where e.extname = 'vector') as nspname");
755
1030
  const name = rows?.[0]?.nspname;
756
1031
  if (typeof name !== "string" || name === "") {
757
1032
  throw new Error("pgvector extension kurulu de\u011Fil \u2014 vector aramas\u0131 \xE7al\u0131\u015Famaz (extensions beyan\u0131 deploy'dan ge\xE7ti mi?)");
@@ -759,11 +1034,13 @@ async function vectorSchemaWithGuc(runner) {
759
1034
  cachedVectorSchema = name;
760
1035
  return name;
761
1036
  }
1037
+ __name(vectorSchemaWithGuc, "vectorSchemaWithGuc");
762
1038
  var secretReader = null;
763
1039
  function setSecretReader(fn) {
764
1040
  secretReader = fn;
765
1041
  }
766
- var embedFetch = (url, init) => fetch(url, init);
1042
+ __name(setSecretReader, "setSecretReader");
1043
+ var embedFetch = /* @__PURE__ */ __name((url, init) => fetch(url, init), "embedFetch");
767
1044
  async function embedQuery(embed, text) {
768
1045
  if (secretReader === null) {
769
1046
  throw new Error(`query embed: secret reader ba\u011Flanmam\u0131\u015F \u2014 ${embed.apiKeyName} okunam\u0131yor`);
@@ -778,11 +1055,18 @@ async function embedQuery(embed, text) {
778
1055
  try {
779
1056
  const res = await embedFetch(url, {
780
1057
  method: "POST",
781
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
1058
+ headers: {
1059
+ "Content-Type": "application/json",
1060
+ Authorization: `Bearer ${key}`
1061
+ },
782
1062
  body: JSON.stringify({
783
1063
  model: embed.model,
784
- input: [text],
785
- ...embed.dimensions !== void 0 ? { dimensions: embed.dimensions } : {}
1064
+ input: [
1065
+ text
1066
+ ],
1067
+ ...embed.dimensions !== void 0 ? {
1068
+ dimensions: embed.dimensions
1069
+ } : {}
786
1070
  }),
787
1071
  signal: controller.signal
788
1072
  });
@@ -799,9 +1083,13 @@ async function embedQuery(embed, text) {
799
1083
  clearTimeout(timer);
800
1084
  }
801
1085
  }
1086
+ __name(embedQuery, "embedQuery");
802
1087
  function createOps(tx) {
803
- const at = () => resolveTx(tx);
1088
+ const at = /* @__PURE__ */ __name(() => resolveTx(tx), "at");
804
1089
  const ops = {
1090
+ // Generic dönüş, çağıranın İDDİASIDIR (FR-021). Motor her zaman satır objeleri
1091
+ // üretir; `T` onlara bir ad vermekten ibarettir ve verilmezse `unknown` kalır —
1092
+ // yani "bilmiyorum", ki ham SQL için doğru cevap odur.
805
1093
  async query(sql, params = []) {
806
1094
  const bound = params.map((p) => Array.isArray(p) ? encodePgArray(p) : p);
807
1095
  return asWireRows(await (await at()).unsafe(sql, bound));
@@ -814,27 +1102,141 @@ function createOps(tx) {
814
1102
  const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "insert"));
815
1103
  const inserted = rows[0];
816
1104
  if (!inserted) {
817
- throw new Error(
818
- `insert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`
819
- );
1105
+ throw new Error(`insert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`);
820
1106
  }
821
1107
  return asTableRow(table, inserted);
822
1108
  },
823
1109
  /**
824
- * INSERT the row, or UPDATE it when it collides on `onConflict`.
825
- *
826
- * WHY IT IS AN OPERATION rather than a recipe. "Try the insert, catch the
827
- * unique violation, update instead" does not work here: a request runs in ONE
828
- * Postgres transaction, so the failed insert aborts it and every later
829
- * statement answers `current transaction is aborted`. A tenant measured that
830
- * as 7 of 8 concurrent requests returning 500, gave up on upsert, and had a
831
- * trigger create the row instead a workaround that needs a new trigger for
832
- * every table with a unique row.
833
- *
834
- * The conflict columns are excluded from the SET list: they are what MATCHED,
835
- * so writing them back is at best a no-op and at worst a surprise.
836
- */
837
- async upsert(table, data, opts) {
1110
+ * Bir ADI kilitle satırı değil (FR-054).
1111
+ *
1112
+ * "Aynı anda tek bir fatura kapanışı koşsun" gibi, kilitlenecek satırı
1113
+ * OLMAYAN işler için. Anahtar bir metin; Postgres 64-bit tamsayı istediği
1114
+ * için `hashtextextended` ile hash'leniyor ve metin SQL'e hiç GİRMİYOR.
1115
+ *
1116
+ * YALNIZ transaction kapsamlı aile (`pg_advisory_xact_lock`). Oturum
1117
+ * kapsamlı sürüm bırakıldığı yerde KALIR: bağlantı havuza döner, kilit
1118
+ * üstünde kalır ve bir sonraki isteği — hiç bitmeyecek şekilde — bekletir.
1119
+ * Transaction kapsamlısı commit/rollback'te Postgres tarafından bırakılır,
1120
+ * yani unutulması imkânsız.
1121
+ */
1122
+ async advisoryXactLock(key) {
1123
+ await (await at()).unsafe("select pg_advisory_xact_lock(hashtextextended($1, 0))", [
1124
+ key
1125
+ ]);
1126
+ },
1127
+ /**
1128
+ * Bu satırları KİLİTLE, ve sırayı KATMAN koysun (FR-035).
1129
+ *
1130
+ * D-017: katman sıralamayı değil, **sıralamayı mümkün kılan primitifi**
1131
+ * verir. Uygulama dokunacağı kümeyi önden bildirir; sırayı burası koyar.
1132
+ * Çağıranın verdiği sıraya güvenmek, iki çağıranın aynı iki satıra ters
1133
+ * sırayla girmesi demektir — ve deadlock'un bedeli ucuz değil:
1134
+ * `deadlock_timeout` varsayılanı **1 saniye**, yani kaybeden işlem bir
1135
+ * saniye bekledikten sonra hata alır.
1136
+ *
1137
+ * `FOR NO KEY UPDATE`, `updateMany`'nin CTE'siyle AYNI kilit modu: iki
1138
+ * yazma yolunun tek bir sırası ve tek bir modu olmak zorunda, yoksa biri
1139
+ * diğerini bekletir.
1140
+ */
1141
+ async lockRows(table, ids) {
1142
+ const unique = [
1143
+ ...new Set(ids)
1144
+ ].sort();
1145
+ if (unique.length === 0) {
1146
+ return;
1147
+ }
1148
+ const pk = primaryKeyOf(table);
1149
+ if (pk === null) {
1150
+ throw new Error(`lockRows(${table}): tek-kolon primary key bulunamad\u0131 \u2014 kilit s\u0131ras\u0131 bir anahtar ister (FR-035).`);
1151
+ }
1152
+ const params = [];
1153
+ const add = /* @__PURE__ */ __name((v) => {
1154
+ params.push(v);
1155
+ return `$${params.length}`;
1156
+ }, "add");
1157
+ const list = unique.map((id) => add(id)).join(", ");
1158
+ await (await at()).unsafe(`SELECT t.${quoteIdent(pk)} FROM ${quoteTable(table)} t WHERE t.${quoteIdent(pk)} IN (${list}) ORDER BY t.${quoteIdent(pk)} FOR NO KEY UPDATE`, params);
1159
+ },
1160
+ /**
1161
+ * Bir idempotency anahtarını SAHİPLEN (FR-033).
1162
+ *
1163
+ * `{ inserted: true, row }` → bu çağrı yazdı.
1164
+ * `{ inserted: false, row }` → başkası önce yazdı; dönen satır ONUN satırı.
1165
+ *
1166
+ * ÖLÇÜLDÜ (pg16, spec Research Appendix) — üç dalın üçü de farklı davranıyor:
1167
+ *
1168
+ * plain INSERT ikinci oturum 2121 ms BLOKLANIR, sonra 23505 alır;
1169
+ * birincinin satırı korunur ← istenen
1170
+ * ON CONFLICT DO UPDATE ikincinin verisi birincininkini EZER
1171
+ * ON CONFLICT DO NOTHING `INSERT 0 0` — sessiz; çağıran ne olduğunu bilemez
1172
+ *
1173
+ * Bu yüzden `ON CONFLICT` KULLANILMIYOR. Ödeme yolunda "ikinci çağrı
1174
+ * birincinin sonucunu görsün" idempotency'nin tanımıdır; ezmek ya da
1175
+ * susmak ikisi de yanlış cevap.
1176
+ *
1177
+ * INSERT bir SAVEPOINT içinde koşuyor: başarısız bir INSERT transaction'ı
1178
+ * ABORT eder (25P02) ve savepoint olmadan yakalama işe yaramaz — hata
1179
+ * yakalanır ama sonraki SELECT de "current transaction is aborted" alır.
1180
+ */
1181
+ async claim(table, unique, extra = {}) {
1182
+ const keyCols = Object.keys(unique);
1183
+ if (keyCols.length === 0) {
1184
+ throw new Error(`claim(${table}): benzersiz alan verilmedi. claim, bir anahtar\u0131 sahiplenmektir; anahtar yoksa sahiplenecek bir \u015Fey de yok \u2014 insert(${table}, \u2026) kullan\u0131n.`);
1185
+ }
1186
+ assertUsableWriteValues("claim", table, keyCols, unique);
1187
+ const data = {
1188
+ ...unique,
1189
+ ...extra
1190
+ };
1191
+ const cols = Object.keys(data);
1192
+ const live = await at();
1193
+ try {
1194
+ return await live.savepoint(async (sp) => {
1195
+ const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
1196
+ const rows = await sp.unsafe(`INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`, asBindParams(table, cols, data, "claim"));
1197
+ if (!rows[0]) {
1198
+ throw new Error(`claim(${table}): INSERT sat\u0131r d\xF6nd\xFCrmedi \u2014 yazma reddedildi (b\xFCy\xFCk olas\u0131l\u0131kla bir RLS policy'si).`);
1199
+ }
1200
+ return {
1201
+ inserted: true,
1202
+ row: asTableRow(table, rows[0])
1203
+ };
1204
+ });
1205
+ } catch (e) {
1206
+ if (!isUniqueViolation(e)) throw e;
1207
+ const params = [];
1208
+ const add = /* @__PURE__ */ __name((v) => {
1209
+ params.push(v);
1210
+ return `$${params.length}`;
1211
+ }, "add");
1212
+ const where = keyCols.map((c) => `t.${quoteIdent(c)} = ${add(unique[c])}`).join(" AND ");
1213
+ const found = await (await at()).unsafe(`SELECT * FROM ${quoteTable(table)} t WHERE ${where} LIMIT 1`, params);
1214
+ if (!found[0]) {
1215
+ const named = constraintOf(e);
1216
+ throw new Error(`claim(${table}): benzersizlik ihlali${named ? ` (${named})` : ""} yakaland\u0131 ama ${keyCols.join(", ")} ile sat\u0131r bulunamad\u0131. Ya ihlal BA\u015EKA bir unique k\u0131s\u0131ttan geliyor \u2014 o zaman claim() bu \xE7a\u011Fr\u0131 i\xE7in yanl\u0131\u015F ara\xE7 \u2014 ya da sat\u0131r var ve bir RLS policy'si onu bu \xE7a\u011F\u0131randan gizliyor.`);
1217
+ }
1218
+ return {
1219
+ inserted: false,
1220
+ row: asTableRow(table, found[0])
1221
+ };
1222
+ }
1223
+ },
1224
+ /**
1225
+ * INSERT the row, or UPDATE it when it collides on `onConflict`.
1226
+ *
1227
+ * WHY IT IS AN OPERATION rather than a recipe. "Try the insert, catch the
1228
+ * unique violation, update instead" does not work here: a request runs in ONE
1229
+ * Postgres transaction, so the failed insert aborts it and every later
1230
+ * statement answers `current transaction is aborted`. A tenant measured that
1231
+ * as 7 of 8 concurrent requests returning 500, gave up on upsert, and had a
1232
+ * trigger create the row instead — a workaround that needs a new trigger for
1233
+ * every table with a unique row.
1234
+ *
1235
+ * The conflict columns are excluded from the SET list: they are what MATCHED,
1236
+ * so writing them back is at best a no-op and at worst a surprise.
1237
+ */
1238
+ async put(table, data, opts) {
1239
+ assertNotAppendOnly("put", table);
838
1240
  const conflict = opts.onConflict;
839
1241
  if (conflict.length === 0) {
840
1242
  throw new Error(`upsert into ${table}: onConflict en az bir kolon ad\u0131 ister`);
@@ -845,33 +1247,29 @@ function createOps(tx) {
845
1247
  const ph = cols.map((_, i) => `$${i + 1}`).join(", ");
846
1248
  const insertSql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${ph}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) WHERE "valid_to" IS NULL DO NOTHING RETURNING *`;
847
1249
  const live = await at();
848
- const bindData = asBindParams(table, cols, data, "upsert");
1250
+ const bindData = asBindParams(table, cols, data, "put");
849
1251
  const first = await live.unsafe(insertSql, bindData);
850
1252
  if (first[0]) return asTableRow(table, first[0]);
851
1253
  const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(" AND ");
852
1254
  const condBind = conflict.map((c) => data[c]);
853
- const cur = await live.unsafe(
854
- `SELECT * FROM ${quoteTable(table)} WHERE ${condSql} AND "valid_to" IS NULL`,
855
- condBind
856
- );
1255
+ const cur = await live.unsafe(`SELECT * FROM ${quoteTable(table)} WHERE ${condSql} AND "valid_to" IS NULL`, condBind);
857
1256
  const old = cur[0];
858
1257
  if (old === void 0) {
859
1258
  throw new Error(`upsert into ${table}: e\u015Fzamanl\u0131 supersede yar\u0131\u015F\u0131 \u2014 ge\xE7erli sat\u0131r bulunamad\u0131, iste\u011Fi yineleyin (D-020)`);
860
1259
  }
861
1260
  const pk = Object.keys(old).includes("id") ? "id" : Object.keys(old)[0];
862
- await live.unsafe(
863
- `UPDATE ${quoteTable(table)} SET "valid_to" = now() WHERE ${quoteIdent(pk)} = $1 AND "valid_to" IS NULL`,
864
- [old[pk]]
865
- );
1261
+ await live.unsafe(`UPDATE ${quoteTable(table)} SET "valid_to" = now() WHERE ${quoteIdent(pk)} = $1 AND "valid_to" IS NULL`, [
1262
+ old[pk]
1263
+ ]);
866
1264
  const second = await live.unsafe(insertSql, bindData);
867
1265
  if (!second[0]) {
868
1266
  throw new Error(`upsert into ${table}: e\u015Fzamanl\u0131 supersede yar\u0131\u015F\u0131 \u2014 yeni sat\u0131r a\xE7\u0131lamad\u0131, iste\u011Fi yineleyin (D-020)`);
869
1267
  }
870
1268
  const fresh = second[0];
871
- await live.unsafe(
872
- `UPDATE ${quoteTable(table)} SET "superseded_by" = $2 WHERE ${quoteIdent(pk)} = $1`,
873
- [old[pk], fresh[pk]]
874
- );
1269
+ await live.unsafe(`UPDATE ${quoteTable(table)} SET "superseded_by" = $2 WHERE ${quoteIdent(pk)} = $1`, [
1270
+ old[pk],
1271
+ fresh[pk]
1272
+ ]);
875
1273
  return asTableRow(table, second[0]);
876
1274
  }
877
1275
  const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
@@ -879,50 +1277,54 @@ function createOps(tx) {
879
1277
  const assignments = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
880
1278
  const action = assignments.length ? `DO UPDATE SET ${assignments.join(", ")}` : `DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
881
1279
  const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) ${action} RETURNING *`;
882
- const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "upsert"));
1280
+ const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "put"));
883
1281
  const row = rows[0];
884
1282
  if (!row) {
885
- throw new Error(
886
- `upsert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`
887
- );
1283
+ throw new Error(`upsert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`);
888
1284
  }
889
1285
  return asTableRow(table, row);
890
1286
  },
891
1287
  async update(table, id, data) {
1288
+ assertNotAppendOnly("update", table);
892
1289
  const cols = Object.keys(data);
893
1290
  if (cols.length === 0) return ops.findById(table, id);
894
1291
  const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(", ");
895
1292
  const sql = `UPDATE ${quoteTable(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;
896
- const rows = await (await at()).unsafe(sql, [...asBindParams(table, cols, data, "update"), id]);
1293
+ const rows = await (await at()).unsafe(sql, [
1294
+ ...asBindParams(table, cols, data, "update"),
1295
+ id
1296
+ ]);
897
1297
  return rows[0] ? asTableRow(table, rows[0]) : null;
898
1298
  },
899
1299
  async delete(table, id) {
900
- await (await at()).unsafe(`DELETE FROM ${quoteTable(table)} WHERE id = $1`, [id]);
1300
+ assertNotAppendOnly("delete", table);
1301
+ await (await at()).unsafe(`DELETE FROM ${quoteTable(table)} WHERE id = $1`, [
1302
+ id
1303
+ ]);
901
1304
  },
902
1305
  /**
903
- * Update every row the filter matches, in ONE statement.
904
- *
905
- * The capability was already here and only reachable from inside a
906
- * transaction plan (`tx.tables.x.updateWhere`, since 11.0.0). Outside it the
907
- * only door was `update(id, …)`, so "mark every unapproved row in this
908
- * household" was an N+1 loop or hand-written SQL — and hand-written SQL is
909
- * where the typed surface and RLS both stop helping.
910
- *
911
- * The filter language is `findMany`'s, compiled by the same `compileWhere`:
912
- * one filter language, or the two spellings drift.
913
- *
914
- * AN EMPTY FILTER IS REFUSED. `UPDATE … WHERE true` is a whole-table write,
915
- * and the shape that produces it by accident — a filter object built from
916
- * request input that happened to come back empty — is exactly the shape that
917
- * should not silently succeed. Callers who mean every row say so with a
918
- * predicate that is true for every row.
919
- */
1306
+ * Update every row the filter matches, in ONE statement.
1307
+ *
1308
+ * The capability was already here and only reachable from inside a
1309
+ * transaction plan (`tx.tables.x.updateWhere`, since 11.0.0). Outside it the
1310
+ * only door was `update(id, …)`, so "mark every unapproved row in this
1311
+ * household" was an N+1 loop or hand-written SQL — and hand-written SQL is
1312
+ * where the typed surface and RLS both stop helping.
1313
+ *
1314
+ * The filter language is `findMany`'s, compiled by the same `compileWhere`:
1315
+ * one filter language, or the two spellings drift.
1316
+ *
1317
+ * AN EMPTY FILTER IS REFUSED. `UPDATE … WHERE true` is a whole-table write,
1318
+ * and the shape that produces it by accident — a filter object built from
1319
+ * request input that happened to come back empty — is exactly the shape that
1320
+ * should not silently succeed. Callers who mean every row say so with a
1321
+ * predicate that is true for every row.
1322
+ */
920
1323
  async updateMany(table, where, set) {
1324
+ assertNotAppendOnly("updateMany", table);
921
1325
  const cols = Object.keys(set);
922
1326
  if (cols.length === 0) {
923
- throw new Error(
924
- `updateMany(${table}): nothing to set. An update with no columns is not a no-op worth pretending happened \u2014 pass the columns to write.`
925
- );
1327
+ throw new Error(`updateMany(${table}): nothing to set. An update with no columns is not a no-op worth pretending happened \u2014 pass the columns to write.`);
926
1328
  }
927
1329
  const known = schemaColumns(table);
928
1330
  if (known !== null) {
@@ -933,27 +1335,43 @@ function createOps(tx) {
933
1335
  }
934
1336
  }
935
1337
  const params = [];
936
- const add = (v) => {
1338
+ const add = /* @__PURE__ */ __name((v) => {
937
1339
  params.push(v);
938
1340
  return `$${params.length}`;
939
- };
940
- const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set, "updateMany")[0])}`).join(", ");
1341
+ }, "add");
1342
+ const assignments = cols.map((c) => {
1343
+ const expr = columnExprOf(set[c]);
1344
+ if (expr !== null && expr.fn === "now") {
1345
+ return `${quoteIdent(c)} = now()`;
1346
+ }
1347
+ if (expr !== null) {
1348
+ const operator = expr.fn === "inc" ? "+" : "-";
1349
+ const t = transformsOf(currentSchema, table).get(c);
1350
+ const amount = t?.toDb === void 0 || expr.by === null || expr.by === void 0 ? expr.by : t.toDb(expr.by);
1351
+ return `${quoteIdent(c)} = ${quoteIdent(c)} ${operator} ${add(amount)}`;
1352
+ }
1353
+ return `${quoteIdent(c)} = ${add(asBindParams(table, [
1354
+ c
1355
+ ], set, "updateMany")[0])}`;
1356
+ }).join(", ");
941
1357
  const whereSql = compileWhere(table, known, where, add, "updateMany");
942
1358
  assertHasPredicate(whereSql, "updateMany", table);
943
- const sql = `UPDATE ${quoteTable(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;
1359
+ const pk = primaryKeyOf(table);
1360
+ const sql = isSinglePkEquality(where, pk) || pk === null ? `UPDATE ${quoteTable(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *` : `WITH locked AS (SELECT t.${quoteIdent(pk)} FROM ${quoteTable(table)} t WHERE true${whereSql} ORDER BY t.${quoteIdent(pk)} FOR NO KEY UPDATE) UPDATE ${quoteTable(table)} AS t SET ${assignments} FROM locked WHERE t.${quoteIdent(pk)} = locked.${quoteIdent(pk)} RETURNING t.*`;
944
1361
  return asTableRows(table, await (await at()).unsafe(sql, params));
945
1362
  },
946
1363
  /**
947
- * Delete every row the filter matches, in ONE statement; resolves to how
948
- * many went. Same filter language, same empty-filter refusal as
949
- * {@link updateMany} — and here the accident is worse.
950
- */
1364
+ * Delete every row the filter matches, in ONE statement; resolves to how
1365
+ * many went. Same filter language, same empty-filter refusal as
1366
+ * {@link updateMany} — and here the accident is worse.
1367
+ */
951
1368
  async deleteMany(table, where) {
1369
+ assertNotAppendOnly("deleteMany", table);
952
1370
  const params = [];
953
- const add = (v) => {
1371
+ const add = /* @__PURE__ */ __name((v) => {
954
1372
  params.push(v);
955
1373
  return `$${params.length}`;
956
- };
1374
+ }, "add");
957
1375
  const known = schemaColumns(table);
958
1376
  const whereSql = compileWhere(table, known, where, add, "deleteMany");
959
1377
  assertHasPredicate(whereSql, "deleteMany", table);
@@ -962,20 +1380,20 @@ function createOps(tx) {
962
1380
  return rows.length;
963
1381
  },
964
1382
  /**
965
- * How many rows match — the half of pagination `limit`/`offset` cannot
966
- * supply. Without it a page count is either a guess or "fetch everything and
967
- * read .length", and the second one is the scale risk this surface exists to
968
- * remove.
969
- *
970
- * An empty filter is legitimate HERE: counting a whole table is a read, and
971
- * reads do not destroy anything.
972
- */
1383
+ * How many rows match — the half of pagination `limit`/`offset` cannot
1384
+ * supply. Without it a page count is either a guess or "fetch everything and
1385
+ * read .length", and the second one is the scale risk this surface exists to
1386
+ * remove.
1387
+ *
1388
+ * An empty filter is legitimate HERE: counting a whole table is a read, and
1389
+ * reads do not destroy anything.
1390
+ */
973
1391
  async count(table, where = {}) {
974
1392
  const params = [];
975
- const add = (v) => {
1393
+ const add = /* @__PURE__ */ __name((v) => {
976
1394
  params.push(v);
977
1395
  return `$${params.length}`;
978
- };
1396
+ }, "add");
979
1397
  const known = schemaColumns(table);
980
1398
  const whereSql = compileWhere(table, known, where, add, "count");
981
1399
  const sql = `SELECT count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql}`;
@@ -983,33 +1401,33 @@ function createOps(tx) {
983
1401
  return Number(rows[0]?.n ?? 0);
984
1402
  },
985
1403
  async findById(table, id) {
986
- const rows = await (await at()).unsafe(
987
- `SELECT * FROM ${quoteTable(table)} WHERE id = $1`,
988
- [id]
989
- );
1404
+ const rows = await (await at()).unsafe(`SELECT * FROM ${quoteTable(table)} WHERE id = $1`, [
1405
+ id
1406
+ ]);
990
1407
  return rows[0] ? asTableRow(table, rows[0]) : null;
991
1408
  },
992
1409
  async findMany(table, query = {}, opts = {}) {
993
1410
  const params = [];
994
- const add = (v) => {
1411
+ const add = /* @__PURE__ */ __name((v) => {
995
1412
  params.push(v);
996
1413
  return `$${params.length}`;
997
- };
1414
+ }, "add");
998
1415
  const known = schemaColumns(table);
999
1416
  const whereSql = compileWhere(table, known, query, add, "findMany");
1000
1417
  const order = orderClause(table, known, opts.orderBy);
1001
1418
  const limit = limitClause(opts.limit);
1002
1419
  const offset = offsetClause(opts.offset, opts.limit);
1003
- const sql = `SELECT * FROM ${quoteTable(table)} t WHERE true${whereSql}${order}${limit}${offset}`;
1420
+ const cols = selectClause(table, known, opts.select);
1421
+ const sql = `SELECT ${cols} FROM ${quoteTable(table)} t WHERE true${whereSql}${order}${limit}${offset}`;
1004
1422
  return asTableRows(table, await (await at()).unsafe(sql, params));
1005
1423
  },
1006
1424
  /**
1007
- * Tek-SQL hibrit arama (FR-014): iki kol CTE + FULL OUTER JOIN + RRF
1008
- * (1/(50+rank), CLAIM-N4). Operatör şema-nitelikli (C-10, M-1); GUC
1009
- * hnsw.iterative_scan=relaxed_order aynı tx'te set_config ile (CLAIM-N3 —
1010
- * RLS/filtre altında LIMIT-altı dönüş açığını kapatır). Sorgu-anı embed
1011
- * T024'te gelir; o zamana dek vector kolu yalnız params.vector ile koşar.
1012
- */
1425
+ * Tek-SQL hibrit arama (FR-014): iki kol CTE + FULL OUTER JOIN + RRF
1426
+ * (1/(50+rank), CLAIM-N4). Operatör şema-nitelikli (C-10, M-1); GUC
1427
+ * hnsw.iterative_scan=relaxed_order aynı tx'te set_config ile (CLAIM-N3 —
1428
+ * RLS/filtre altında LIMIT-altı dönüş açığını kapatır). Sorgu-anı embed
1429
+ * T024'te gelir; o zamana dek vector kolu yalnız params.vector ile koşar.
1430
+ */
1013
1431
  async search(table, params = {}) {
1014
1432
  const cfg = searchConfigFor(table);
1015
1433
  if (!cfg) {
@@ -1017,18 +1435,12 @@ function createOps(tx) {
1017
1435
  }
1018
1436
  const excl = params.__excludeIds ?? [];
1019
1437
  if (params.facets !== void 0) {
1020
- for (const col of params.facets) {
1021
- if (!cfg.colSet.has(col)) {
1022
- throw new Error(`search(${table}): facets kolonu "${col}" tabloda yok (FR-027)`);
1023
- }
1024
- }
1438
+ throw new Error(`search(${table}): facets art\u0131k search'\xFCn parametresi de\u011Fil \u2014 saya\xE7lar dizi \xFCst\xFCnde ta\u015F\u0131n\u0131nca JSON.stringify onlar\u0131 d\xFC\u015F\xFCr\xFCyordu (FR-058). Ba\u011F\u0131ms\u0131z \xE7a\u011F\u0131r\u0131n: facets({ facets: [...], where })`);
1025
1439
  }
1026
1440
  if (params.validity !== void 0 && cfg.validity !== true) {
1027
- throw new Error(
1028
- `search(${table}): validity parametresi verildi ama tablo validity beyan\u0131 ta\u015F\u0131m\u0131yor (FR-029)`
1029
- );
1441
+ throw new Error(`search(${table}): validity parametresi verildi ama tablo validity beyan\u0131 ta\u015F\u0131m\u0131yor (FR-029)`);
1030
1442
  }
1031
- const validityFor = (adder) => cfg.validity === true ? validitySql(params.validity, adder) : "";
1443
+ const validityFor = /* @__PURE__ */ __name((adder) => cfg.validity === true ? validitySql(params.validity, adder) : "", "validityFor");
1032
1444
  const rawLimit = params.limit ?? 20;
1033
1445
  if (typeof rawLimit !== "number" || !Number.isFinite(rawLimit)) {
1034
1446
  throw new Error(`search(${table}): limit sonlu bir say\u0131 olmal\u0131, ${String(rawLimit)} verildi (FR-013)`);
@@ -1074,15 +1486,13 @@ function createOps(tx) {
1074
1486
  }
1075
1487
  }
1076
1488
  if (!wantTextC && qvC === null) {
1077
- throw new Error(
1078
- `search(${table}): ko\u015Fulabilir kol yok \u2014 metin i\xE7in 'query' (FTS beyan\u0131 gerekir), semantik i\xE7in 'vector' verin (FR-015)`
1079
- );
1489
+ throw new Error(`search(${table}): ko\u015Fulabilir kol yok \u2014 metin i\xE7in 'query' (FTS beyan\u0131 gerekir), semantik i\xE7in 'vector' verin (FR-015)`);
1080
1490
  }
1081
1491
  const bindC = [];
1082
- const addC = (v) => {
1492
+ const addC = /* @__PURE__ */ __name((v) => {
1083
1493
  bindC.push(v);
1084
1494
  return `$${bindC.length}`;
1085
- };
1495
+ }, "addC");
1086
1496
  const userWhereC = compileWhere(table, cfg.colSet, params.where ?? {}, addC);
1087
1497
  const whereC = userWhereC + excludeSql(cfg.pk, excl, addC) + validityFor(addC);
1088
1498
  const parentJoinC = ` JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = c.${pidQ} WHERE true${whereC} AND `;
@@ -1096,10 +1506,7 @@ function createOps(tx) {
1096
1506
  const op = METRIC_OPERATOR[ck.metric] ?? METRIC_OPERATOR.cosine;
1097
1507
  let exactOrderC = "";
1098
1508
  if (userWhereC !== "") {
1099
- const probeRows = await liveC.unsafe(
1100
- `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(ck.table)} c${parentJoinC}c.embedding IS NOT NULL LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,
1101
- bindC.slice()
1102
- );
1509
+ const probeRows = await liveC.unsafe(`SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(ck.table)} c${parentJoinC}c.embedding IS NOT NULL LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`, bindC.slice());
1103
1510
  const n = probeRows?.[0]?.n;
1104
1511
  if (typeof n === "number" && n <= SELECTIVITY_EXACT_THRESHOLD) {
1105
1512
  exactOrderC = " + 0.0";
@@ -1119,7 +1526,7 @@ function createOps(tx) {
1119
1526
  const msC = params.minScore === void 0 ? "" : addC(params.minScore);
1120
1527
  const colListC = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(", ");
1121
1528
  const scoreC = scoreMul === "" ? "g._score" : `(g._score)${scoreMul}`;
1122
- const assembleC = (kwIn, withKwn) => {
1529
+ const assembleC = /* @__PURE__ */ __name((kwIn, withKwn) => {
1123
1530
  const kwnCol = withKwn ? `, (SELECT count(*) FROM kw)::int AS _kwn` : "";
1124
1531
  let fusedSrc;
1125
1532
  if (semC !== "" && kwIn !== "") {
@@ -1131,7 +1538,7 @@ function createOps(tx) {
1131
1538
  }
1132
1539
  const inner = `${fusedSrc}, ranked AS (SELECT f.pid, f.chunk_seq, f.cscore, ROW_NUMBER() OVER (PARTITION BY f.pid ORDER BY f.cscore DESC, f.chunk_seq) AS rn FROM fused f), grouped AS (SELECT r.pid, MAX(r.cscore) AS _score, json_agg(json_build_object('content', c.content, 'score', r.cscore, 'chunkSeq', r.chunk_seq, 'charStart', c.char_start) ORDER BY r.cscore DESC, r.chunk_seq) FILTER (WHERE r.rn <= ${bpr}) AS blocks FROM ranked r JOIN ${quoteTable(ck.table)} c ON c.${pidQ} = r.pid AND c.chunk_seq = r.chunk_seq GROUP BY r.pid) SELECT ${colListC}, ${scoreC}::float8 AS _score, g.blocks AS blocks${kwnCol} FROM grouped g JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = g.pid`;
1133
1540
  return msC === "" ? `SELECT * FROM (${inner}) q ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}` : `SELECT * FROM (${inner}) q WHERE q._score >= ${msC} ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;
1134
- };
1541
+ }, "assembleC");
1135
1542
  let rowsC = await liveC.unsafe(assembleC(kwC, kwC !== ""), bindC);
1136
1543
  if (wantTextC && kwC !== "" && (rowsC.length === 0 || rowsC[0]._kwn === 0)) {
1137
1544
  const tsch = await trgmSchemaOf(liveC);
@@ -1141,12 +1548,10 @@ function createOps(tx) {
1141
1548
  rowsC = await liveC.unsafe(assembleC(trgmKwC, false), retryBindC);
1142
1549
  }
1143
1550
  for (const r of rowsC) delete r._kwn;
1144
- const outC = asTableRows(table, rowsC).map((r) => ({ ...r, blocks: r.blocks ?? [] }));
1145
- if (params.facets !== void 0 && params.facets.length > 0) {
1146
- Object.assign(outC, {
1147
- _facets: await fetchFacets(liveC, table, cfg.colSet, params.facets, params.where ?? {}, validityFor)
1148
- });
1149
- }
1551
+ const outC = asTableRows(table, rowsC).map((r) => ({
1552
+ ...r,
1553
+ blocks: r.blocks ?? []
1554
+ }));
1150
1555
  logNoResults(table, params.query, params.mode, outC.length);
1151
1556
  return outC;
1152
1557
  }
@@ -1165,15 +1570,13 @@ function createOps(tx) {
1165
1570
  }
1166
1571
  const wantVector = leg !== null && qv !== null;
1167
1572
  if (!wantText && !wantVector) {
1168
- throw new Error(
1169
- `search(${table}): ko\u015Fulabilir kol yok \u2014 metin i\xE7in 'query' (FTS beyan\u0131 gerekir), semantik i\xE7in 'vector' verin (FR-015)`
1170
- );
1573
+ throw new Error(`search(${table}): ko\u015Fulabilir kol yok \u2014 metin i\xE7in 'query' (FTS beyan\u0131 gerekir), semantik i\xE7in 'vector' verin (FR-015)`);
1171
1574
  }
1172
1575
  const bind = [];
1173
- const add = (v) => {
1576
+ const add = /* @__PURE__ */ __name((v) => {
1174
1577
  bind.push(v);
1175
1578
  return `$${bind.length}`;
1176
- };
1579
+ }, "add");
1177
1580
  const userWhere = compileWhere(table, cfg.colSet, params.where ?? {}, add);
1178
1581
  const whereSql = userWhere + excludeSql(cfg.pk, excl, add) + validityFor(add);
1179
1582
  const live = await at();
@@ -1185,10 +1588,7 @@ function createOps(tx) {
1185
1588
  const op = METRIC_OPERATOR[leg.metric] ?? METRIC_OPERATOR.cosine;
1186
1589
  let exactOrder = "";
1187
1590
  if (userWhere !== "") {
1188
- const probeRows = await live.unsafe(
1189
- `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,
1190
- bind.slice()
1191
- );
1591
+ const probeRows = await live.unsafe(`SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`, bind.slice());
1192
1592
  const n = probeRows?.[0]?.n;
1193
1593
  if (typeof n === "number" && n <= SELECTIVITY_EXACT_THRESHOLD) {
1194
1594
  exactOrder = " + 0.0";
@@ -1209,7 +1609,7 @@ function createOps(tx) {
1209
1609
  const colList = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(", ");
1210
1610
  const msP = params.minScore === void 0 ? "" : add(params.minScore);
1211
1611
  const hlCol = params.highlight === true && wantText ? `, ts_headline('simple', ${ftsExprOf(cfg.ftsCols)}, websearch_to_tsquery('simple', ${qpRef})) AS _highlight` : "";
1212
- const assemble = (kwIn, withKwn) => {
1612
+ const assemble = /* @__PURE__ */ __name((kwIn, withKwn) => {
1213
1613
  const kwnCol = withKwn ? `, (SELECT count(*) FROM kw)::int AS _kwn` : "";
1214
1614
  let inner;
1215
1615
  let orderScore;
@@ -1226,7 +1626,7 @@ function createOps(tx) {
1226
1626
  orderScore = "_score";
1227
1627
  }
1228
1628
  return msP === "" ? `${inner} ORDER BY ${orderScore} DESC, t.${quoteIdent(cfg.pk)} LIMIT ${limit}` : `SELECT * FROM (${inner}) q WHERE q._score >= ${msP} ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;
1229
- };
1629
+ }, "assemble");
1230
1630
  let rows = await live.unsafe(assemble(kwSql, kwSql !== ""), bind);
1231
1631
  if (wantText && kwSql !== "" && (rows.length === 0 || rows[0]._kwn === 0)) {
1232
1632
  const tsch = await trgmSchemaOf(live);
@@ -1237,28 +1637,26 @@ function createOps(tx) {
1237
1637
  rows = await live.unsafe(assemble(trgmKw, false), retryBind);
1238
1638
  }
1239
1639
  for (const r of rows) delete r._kwn;
1240
- const out = asTableRows(table, rows).map((r) => ({ ...r, blocks: [] }));
1241
- if (params.facets !== void 0 && params.facets.length > 0) {
1242
- Object.assign(out, {
1243
- _facets: await fetchFacets(live, table, cfg.colSet, params.facets, params.where ?? {}, validityFor)
1244
- });
1245
- }
1640
+ const out = asTableRows(table, rows).map((r) => ({
1641
+ ...r,
1642
+ blocks: []
1643
+ }));
1246
1644
  logNoResults(table, params.query, params.mode, out.length);
1247
1645
  return out;
1248
1646
  },
1249
1647
  /**
1250
- * similar (T018, FR-022): "bu satıra benzeyenler". Hedef vektör DB'den
1251
- * okunur — satır-modu satırın kendi kolonu, chunk-modu parent chunk'larının
1252
- * şema-nitelikli avg'ı — ve ana arama search'ün vector yoluyla koşar;
1253
- * kaynak satır sonuçtan düşer. İKİ tur BİLİNÇLİ (plan T018): target-CTE'li
1254
- * tek SQL'de "id yok" ile "0 komşu" ayrılamazdı; +1 küçük turla id-yokluğu
1255
- * adlandırılmış hataya çevrilir. Sonuç şekli search ile aynı (FR-015).
1256
- */
1648
+ * similar (T018, FR-022): "bu satıra benzeyenler". Hedef vektör DB'den
1649
+ * okunur — satır-modu satırın kendi kolonu, chunk-modu parent chunk'larının
1650
+ * şema-nitelikli avg'ı — ve ana arama search'ün vector yoluyla koşar;
1651
+ * kaynak satır sonuçtan düşer. İKİ tur BİLİNÇLİ (plan T018): target-CTE'li
1652
+ * tek SQL'de "id yok" ile "0 komşu" ayrılamazdı; +1 küçük turla id-yokluğu
1653
+ * adlandırılmış hataya çevrilir. Sonuç şekli search ile aynı (FR-015).
1654
+ */
1257
1655
  /** D-021 (FR-027 DX): sayaçlar BAĞIMSIZ op'la — search'ün dizi-üstü
1258
- * `_facets` özelliği JSON.stringify'da kaybolur (dizi özelliği), tenant
1259
- * yanıtına koyunca sessizce yok olurdu. Ayrı dönüş ciddi bir sözleşmedir;
1260
- * search'teki alan geriye-uyum için DURUR. where + validity default'u
1261
- * sayaçlara da uygulanır (sayaç, kullanıcının gördüğü kümeyi anlatır). */
1656
+ * `_facets` özelliği JSON.stringify'da kaybolur (dizi özelliği), tenant
1657
+ * yanıtına koyunca sessizce yok olurdu. Ayrı dönüş ciddi bir sözleşmedir;
1658
+ * search'teki alan geriye-uyum için DURUR. where + validity default'u
1659
+ * sayaçlara da uygulanır (sayaç, kullanıcının gördüğü kümeyi anlatır). */
1262
1660
  async facets(table, params) {
1263
1661
  const cfg = searchConfigFor(table);
1264
1662
  if (!cfg) {
@@ -1282,20 +1680,18 @@ function createOps(tx) {
1282
1680
  let v;
1283
1681
  if (cfg.chunk !== void 0) {
1284
1682
  const sch = await vectorSchemaWithGuc(live);
1285
- const rows = await live.unsafe(
1286
- `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteTable(cfg.chunk.table)} c WHERE c.${quoteIdent(`parent_${cfg.pk}`)} = $1 AND c.embedding IS NOT NULL`,
1287
- [id]
1288
- );
1683
+ const rows = await live.unsafe(`SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteTable(cfg.chunk.table)} c WHERE c.${quoteIdent(`parent_${cfg.pk}`)} = $1 AND c.embedding IS NOT NULL`, [
1684
+ id
1685
+ ]);
1289
1686
  v = rows?.[0]?.v;
1290
1687
  } else {
1291
1688
  const leg = pickLeg(table, cfg.legs, opts.using);
1292
1689
  if (leg === null) {
1293
1690
  throw new Error(`similar(${table}): tabloda vekt\xF6r kolonu yok \u2014 benzerlik semantik vekt\xF6r ister (FR-022)`);
1294
1691
  }
1295
- const rows = await live.unsafe(
1296
- `SELECT t.${quoteIdent(leg.column)} AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} = $1`,
1297
- [id]
1298
- );
1692
+ const rows = await live.unsafe(`SELECT t.${quoteIdent(leg.column)} AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} = $1`, [
1693
+ id
1694
+ ]);
1299
1695
  v = rows?.[0]?.v;
1300
1696
  }
1301
1697
  if (typeof v !== "string") {
@@ -1312,18 +1708,20 @@ function createOps(tx) {
1312
1708
  blocksPerRow: opts.blocksPerRow,
1313
1709
  validity: opts.validity,
1314
1710
  boost: opts.boost,
1315
- __excludeIds: [id]
1711
+ __excludeIds: [
1712
+ id
1713
+ ]
1316
1714
  };
1317
1715
  return ops.search(table, p);
1318
1716
  },
1319
1717
  /**
1320
- * recommend (T018, FR-023): positive/negative id kümelerinden öneri.
1321
- * Hedef vektör DB-İÇİ CTE'lerle türer: pos = avg(embedding of positives),
1322
- * negative varsa hedef = pos.v + (pos.v - neg.v) — pgvector avg agregası
1323
- * ve +/- operatörleri ŞEMA-NİTELİKLİ (M-1: search_path'e güvenilmez).
1324
- * Vektör matematiği istemciye inmez; bulunamayan positive/negative
1325
- * adlandırılmış hatadır ve kaynak id'ler sonuçtan düşer.
1326
- */
1718
+ * recommend (T018, FR-023): positive/negative id kümelerinden öneri.
1719
+ * Hedef vektör DB-İÇİ CTE'lerle türer: pos = avg(embedding of positives),
1720
+ * negative varsa hedef = pos.v + (pos.v - neg.v) — pgvector avg agregası
1721
+ * ve +/- operatörleri ŞEMA-NİTELİKLİ (M-1: search_path'e güvenilmez).
1722
+ * Vektör matematiği istemciye inmez; bulunamayan positive/negative
1723
+ * adlandırılmış hatadır ve kaynak id'ler sonuçtan düşer.
1724
+ */
1327
1725
  async recommend(table, opts) {
1328
1726
  const positive = opts?.positive;
1329
1727
  if (!Array.isArray(positive) || positive.length === 0) {
@@ -1344,14 +1742,14 @@ function createOps(tx) {
1344
1742
  const live = await at();
1345
1743
  const sch = await vectorSchemaWithGuc(live);
1346
1744
  const bind = [];
1347
- const add = (x) => {
1745
+ const add = /* @__PURE__ */ __name((x) => {
1348
1746
  bind.push(x);
1349
1747
  return `$${bind.length}`;
1350
- };
1351
- const avgSel = (ids) => {
1748
+ }, "add");
1749
+ const avgSel = /* @__PURE__ */ __name((ids) => {
1352
1750
  const inList = ids.map((x) => add(x)).join(", ");
1353
1751
  return cfg.chunk !== void 0 ? `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteTable(cfg.chunk.table)} c WHERE c.${quoteIdent(`parent_${cfg.pk}`)} IN (${inList}) AND c.embedding IS NOT NULL` : `SELECT ${quoteIdent(sch)}.avg(t.${quoteIdent(leg.column)}) AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} IN (${inList}) AND t.${quoteIdent(leg.column)} IS NOT NULL`;
1354
- };
1752
+ }, "avgSel");
1355
1753
  const targetSql = negative.length === 0 ? `WITH pos AS (${avgSel(positive)}) SELECT pos.v AS v, (pos.v IS NULL) AS pos_missing FROM pos` : `WITH pos AS (${avgSel(positive)}), neg AS (${avgSel(negative)}) SELECT (pos.v OPERATOR(${quoteIdent(sch)}.+) (pos.v OPERATOR(${quoteIdent(sch)}.-) neg.v)) AS v, (pos.v IS NULL) AS pos_missing, (neg.v IS NULL) AS neg_missing FROM pos, neg`;
1356
1754
  const rows = await live.unsafe(targetSql, bind);
1357
1755
  const r0 = rows?.[0];
@@ -1375,21 +1773,25 @@ function createOps(tx) {
1375
1773
  blocksPerRow: opts.blocksPerRow,
1376
1774
  validity: opts.validity,
1377
1775
  boost: opts.boost,
1378
- __excludeIds: [...positive, ...negative]
1776
+ __excludeIds: [
1777
+ ...positive,
1778
+ ...negative
1779
+ ]
1379
1780
  };
1380
1781
  return ops.search(table, p);
1381
1782
  },
1382
1783
  /**
1383
- * supersede (T021, FR-029, C-9): validity'li tabloda satırın YENİ
1384
- * versiyonunu TEK savepoint'te yazar — eski satır kapatılır
1385
- * (valid_to = now(), superseded_by = yeni pk), yeni satır eklenir, dönüş
1386
- * yeni satırdır. Yeni pk CLIENT'ta üretilir (row'da verilmemişse
1387
- * randomUUID — declared şemaların uuid().defaultRandom() standardı) ki
1388
- * kapatma UPDATE'i INSERT'ten ÖNCE koşabilsin: 0 satır = zaten superseded
1389
- * ya da yok → INSERT hiç denenmez; INSERT hatası ise savepoint'le
1390
- * kapatmayı da geri sarar — yarım supersede diye bir durum yoktur.
1391
- */
1784
+ * supersede (T021, FR-029, C-9): validity'li tabloda satırın YENİ
1785
+ * versiyonunu TEK savepoint'te yazar — eski satır kapatılır
1786
+ * (valid_to = now(), superseded_by = yeni pk), yeni satır eklenir, dönüş
1787
+ * yeni satırdır. Yeni pk CLIENT'ta üretilir (row'da verilmemişse
1788
+ * randomUUID — declared şemaların uuid().defaultRandom() standardı) ki
1789
+ * kapatma UPDATE'i INSERT'ten ÖNCE koşabilsin: 0 satır = zaten superseded
1790
+ * ya da yok → INSERT hiç denenmez; INSERT hatası ise savepoint'le
1791
+ * kapatmayı da geri sarar — yarım supersede diye bir durum yoktur.
1792
+ */
1392
1793
  async supersede(table, id, row) {
1794
+ assertNotAppendOnly("supersede", table);
1393
1795
  const cfg = searchConfigFor(table);
1394
1796
  if (cfg === null || cfg.validity !== true) {
1395
1797
  throw new Error(`supersede(${table}): tablo validity beyan\u0131 ta\u015F\u0131m\u0131yor (FR-029)`);
@@ -1397,24 +1799,22 @@ function createOps(tx) {
1397
1799
  const live = await at();
1398
1800
  return live.savepoint(async (sp) => {
1399
1801
  const newId = row[cfg.pk] ?? crypto.randomUUID();
1400
- const closed = await sp.unsafe(
1401
- `UPDATE ${quoteTable(table)} SET "valid_to" = now(), "superseded_by" = $1 WHERE ${quoteIdent(cfg.pk)} = $2 AND "valid_to" IS NULL RETURNING ${quoteIdent(cfg.pk)}`,
1402
- [newId, id]
1403
- );
1802
+ const closed = await sp.unsafe(`UPDATE ${quoteTable(table)} SET "valid_to" = now(), "superseded_by" = $1 WHERE ${quoteIdent(cfg.pk)} = $2 AND "valid_to" IS NULL RETURNING ${quoteIdent(cfg.pk)}`, [
1803
+ newId,
1804
+ id
1805
+ ]);
1404
1806
  if (closed.length === 0) {
1405
1807
  throw new Error(`supersede(${table}): id "${String(id)}" zaten superseded ya da yok (FR-029)`);
1406
1808
  }
1407
- const data = { ...row, [cfg.pk]: newId };
1809
+ const data = {
1810
+ ...row,
1811
+ [cfg.pk]: newId
1812
+ };
1408
1813
  const cols = Object.keys(data);
1409
1814
  const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
1410
- const rows = await sp.unsafe(
1411
- `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`,
1412
- asBindParams(table, cols, data, "supersede")
1413
- );
1815
+ const rows = await sp.unsafe(`INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`, asBindParams(table, cols, data, "supersede"));
1414
1816
  if (!rows[0]) {
1415
- throw new Error(
1416
- `supersede(${table}): INSERT sat\u0131r d\xF6nd\xFCrmedi \u2014 yazma reddedildi (b\xFCy\xFCk olas\u0131l\u0131kla bir RLS policy'si)`
1417
- );
1817
+ throw new Error(`supersede(${table}): INSERT sat\u0131r d\xF6nd\xFCrmedi \u2014 yazma reddedildi (b\xFCy\xFCk olas\u0131l\u0131kla bir RLS policy'si)`);
1418
1818
  }
1419
1819
  return asTableRow(table, rows[0]);
1420
1820
  });
@@ -1425,61 +1825,68 @@ function createOps(tx) {
1425
1825
  return live.savepoint(async (sp) => cb(withTables(createOps(sp), currentSchema)));
1426
1826
  },
1427
1827
  /**
1428
- * Run `fn` against a handle bound to a SAVEPOINT, so a failure inside it
1429
- * rolls back only what that handle wrote and the request can keep writing.
1430
- *
1431
- * WHY THE HANDLE IS AN ARGUMENT. The obvious shape — `attempt(async () => {
1432
- * ... Database.insert(...) ... })`, with no parameter — would have to point
1433
- * the ambient `Database` at the savepoint for the duration, and a request is
1434
- * concurrent with itself: `Promise.all([Database.insert(a),
1435
- * Database.attempt(...)])` would put `a` inside the savepoint and roll it
1436
- * back with it. Silent data loss, and the same interleaving this file already
1437
- * refuses for `asService()`. Passing the handle makes the boundary something
1438
- * you can see in the code that crosses it.
1439
- *
1440
- * Postgres, not us: the savepoint is released on success and rolled back on
1441
- * failure by the driver, so an aborted statement inside `fn` does not poison
1442
- * the surrounding transaction.
1443
- */
1828
+ * Run `fn` against a handle bound to a SAVEPOINT, so a failure inside it
1829
+ * rolls back only what that handle wrote and the request can keep writing.
1830
+ *
1831
+ * WHY THE HANDLE IS AN ARGUMENT. The obvious shape — `attempt(async () => {
1832
+ * ... Database.$insert(...) ... })`, with no parameter — would have to point
1833
+ * the ambient `Database` at the savepoint for the duration, and a request is
1834
+ * concurrent with itself: `Promise.all([Database.$insert(a),
1835
+ * Database.$attempt(...)])` would put `a` inside the savepoint and roll it
1836
+ * back with it. Silent data loss, and the same interleaving this file already
1837
+ * refuses for `asService()`. Passing the handle makes the boundary something
1838
+ * you can see in the code that crosses it.
1839
+ *
1840
+ * Postgres, not us: the savepoint is released on success and rolled back on
1841
+ * failure by the driver, so an aborted statement inside `fn` does not poison
1842
+ * the surrounding transaction.
1843
+ */
1444
1844
  async attempt(fn) {
1445
1845
  const live = await at();
1446
1846
  return live.savepoint(async (sp) => fn(withTables(createOps(sp), currentSchema)));
1447
1847
  },
1448
1848
  /**
1449
- * Execute a whole transaction plan — what `Database.transaction(fn)` builds.
1450
- *
1451
- * WHY IT RUNS HERE. The platform used to carry a complete implementation
1452
- * of this at `/internal-api/db/tx`, for tenant code that ran in an isolate
1453
- * with no connection of its own. Running the plan there means running it on
1454
- * a DIFFERENT connection: a transaction would not see the uncommitted
1455
- * writes of the request that started it, and the two would hold separate
1456
- * RLS bindings of the same identity. In this stack the tenant's code and
1457
- * the connection share a process, so the plan runs on the request's own
1458
- * transaction inside one SAVEPOINT — and that surface was removed on
1459
- * 2026-08-15, once this was the last thing that could have called it.
1460
- *
1461
- * Until 2026-08-15 it ran NOWHERE: `runTxPlan` called `transport.txPlan` and
1462
- * nothing here implemented it, so a live handler answered
1463
- * "transport.txPlan is not a function" while every test that covered
1464
- * transactions passed against a mock that did implement it.
1465
- */
1849
+ * Execute a whole transaction plan — what `Database.$transaction(fn)` builds.
1850
+ *
1851
+ * WHY IT RUNS HERE. The platform used to carry a complete implementation
1852
+ * of this at `/internal-api/db/tx`, for tenant code that ran in an isolate
1853
+ * with no connection of its own. Running the plan there means running it on
1854
+ * a DIFFERENT connection: a transaction would not see the uncommitted
1855
+ * writes of the request that started it, and the two would hold separate
1856
+ * RLS bindings of the same identity. In this stack the tenant's code and
1857
+ * the connection share a process, so the plan runs on the request's own
1858
+ * transaction inside one SAVEPOINT — and that surface was removed on
1859
+ * 2026-08-15, once this was the last thing that could have called it.
1860
+ *
1861
+ * Until 2026-08-15 it ran NOWHERE: `runTxPlan` called `transport.txPlan` and
1862
+ * nothing here implemented it, so a live handler answered
1863
+ * "transport.txPlan is not a function" while every test that covered
1864
+ * transactions passed against a mock that did implement it.
1865
+ */
1466
1866
  async txPlan(plan) {
1467
1867
  const live = await at();
1468
1868
  return live.savepoint(async (sp) => {
1469
1869
  const results = [];
1470
1870
  for (const op of plan.ops) {
1471
1871
  const rows = asTableRows(op.table, await runPlanOp(sp, op, results));
1472
- const result = { rows, rows_affected: rows.length };
1872
+ const result = {
1873
+ rows,
1874
+ rows_affected: rows.length
1875
+ };
1473
1876
  results.push(result);
1474
1877
  assertGuard(op, result);
1475
1878
  }
1476
- return { results };
1879
+ return {
1880
+ results
1881
+ };
1477
1882
  });
1478
1883
  }
1479
1884
  };
1480
1885
  return ops;
1481
1886
  }
1887
+ __name(createOps, "createOps");
1482
1888
  var currentSchema = {};
1889
+ var currentRelations = /* @__PURE__ */ new Map();
1483
1890
  function setSchema(schemas) {
1484
1891
  cachedVectorSchema = null;
1485
1892
  cachedTrgmSchema = null;
@@ -1492,22 +1899,52 @@ function setSchema(schemas) {
1492
1899
  tables[qualifiedTableKey(schemaName, table.name ?? key)] = table;
1493
1900
  }
1494
1901
  }
1495
- currentSchema = { tables };
1902
+ currentSchema = {
1903
+ tables
1904
+ };
1905
+ currentRelations = buildRelations(schemas.map((entry) => {
1906
+ const mod = entry;
1907
+ const def = (mod && "default" in mod ? mod.default : mod) ?? {};
1908
+ const tables2 = {};
1909
+ for (const [key, t] of Object.entries(def.tables ?? {})) {
1910
+ const table = t ?? {};
1911
+ const columns = {};
1912
+ for (const [cname, c] of Object.entries(table.columns ?? {})) {
1913
+ const cd = c ?? {};
1914
+ columns[cname] = "_def" in cd ? cd : {
1915
+ ...cd,
1916
+ _def: cd
1917
+ };
1918
+ }
1919
+ tables2[key] = {
1920
+ ...table,
1921
+ name: table.name ?? key,
1922
+ columns
1923
+ };
1924
+ }
1925
+ return {
1926
+ name: def.name ?? "public",
1927
+ tables: tables2
1928
+ };
1929
+ }));
1496
1930
  }
1931
+ __name(setSchema, "setSchema");
1497
1932
  function withTables(ops, schema = currentSchema) {
1498
- const bind = (key) => ({
1499
- insert: (data) => ops.insert(key, data),
1500
- update: (id, data) => ops.update(key, id, data),
1501
- delete: (id) => ops.delete(key, id),
1502
- findById: (id) => ops.findById(key, id),
1503
- findMany: (query, opts) => ops.findMany(key, query ?? {}, opts),
1504
- upsert: (data, opts) => ops.upsert(key, data, opts)
1505
- });
1933
+ const bind = /* @__PURE__ */ __name((key) => ({
1934
+ insert: /* @__PURE__ */ __name((data) => ops.insert(key, data), "insert"),
1935
+ update: /* @__PURE__ */ __name((id, data) => ops.update(key, id, data), "update"),
1936
+ delete: /* @__PURE__ */ __name((id) => ops.delete(key, id), "delete"),
1937
+ findById: /* @__PURE__ */ __name((id) => ops.findById(key, id), "findById"),
1938
+ findMany: /* @__PURE__ */ __name((query, opts) => ops.findMany(key, query ?? {}, opts), "findMany"),
1939
+ put: /* @__PURE__ */ __name((q) => ops.put(key, q.data, {
1940
+ onConflict: q.onConflict
1941
+ }), "put")
1942
+ }), "bind");
1506
1943
  const tables = {};
1507
1944
  for (const key of Object.keys(schema.tables ?? {})) {
1508
1945
  if (!key.includes(".")) tables[key] = bind(key);
1509
1946
  }
1510
- const schemaOf = (name) => {
1947
+ const schemaOf = /* @__PURE__ */ __name((name) => {
1511
1948
  const out = {};
1512
1949
  const prefix = `${name}.`;
1513
1950
  for (const key of Object.keys(schema.tables ?? {})) {
@@ -1517,25 +1954,31 @@ function withTables(ops, schema = currentSchema) {
1517
1954
  out[key.slice(prefix.length)] = bind(key);
1518
1955
  }
1519
1956
  }
1520
- return { tables: out };
1521
- };
1957
+ return {
1958
+ tables: out
1959
+ };
1960
+ }, "schemaOf");
1522
1961
  const base = /* @__PURE__ */ Object.create(null);
1523
- return Object.assign(base, ops, { tables, schema: schemaOf });
1962
+ return Object.assign(base, ops, {
1963
+ tables,
1964
+ schema: schemaOf
1965
+ });
1524
1966
  }
1967
+ __name(withTables, "withTables");
1525
1968
  var SERVICE_LOCK_TIMEOUT = "5s";
1526
1969
  function isAbortedTransaction(e) {
1527
1970
  const message = String(e?.message ?? "");
1528
1971
  return sqlstateOf(e) === "25P02" || /current transaction is aborted/i.test(message);
1529
1972
  }
1973
+ __name(isAbortedTransaction, "isAbortedTransaction");
1530
1974
  function assertHasPredicate(whereSql, op, table) {
1531
1975
  if (whereSql.trim().length > 0) return;
1532
- throw new Error(
1533
- `${op}(${table}): the filter compiled to no condition, so this would have written EVERY row. An empty filter \u2014 or an operator object with no operators in it, like { col: {} } \u2014 is refused. Name a condition.`
1534
- );
1976
+ throw new Error(`${op}(${table}): the filter compiled to no condition, so this would have written EVERY row. An empty filter \u2014 or an operator object with no operators in it, like { col: {} } \u2014 is refused. Name a condition.`);
1535
1977
  }
1978
+ __name(assertHasPredicate, "assertHasPredicate");
1536
1979
  function sqlstateOf(e) {
1537
1980
  const err = e;
1538
- const isState = (v) => typeof v === "string" && /^[0-9A-Z]{5}$/.test(v);
1981
+ const isState = /* @__PURE__ */ __name((v) => typeof v === "string" && /^[0-9A-Z]{5}$/.test(v), "isState");
1539
1982
  if (isState(err?.code)) return err.code;
1540
1983
  if (isState(err?.errno)) return err.errno;
1541
1984
  if (typeof err?.errno === "number") {
@@ -1544,46 +1987,48 @@ function sqlstateOf(e) {
1544
1987
  }
1545
1988
  return void 0;
1546
1989
  }
1990
+ __name(sqlstateOf, "sqlstateOf");
1547
1991
  function isForeignKeyViolation(e) {
1548
1992
  return sqlstateOf(e) === "23503";
1549
1993
  }
1994
+ __name(isForeignKeyViolation, "isForeignKeyViolation");
1550
1995
  function isUniqueViolation(e) {
1551
- return sqlstateOf(e) === "23505";
1996
+ return sqlstateOf(e) === "23505" || UniqueViolation.is(e);
1552
1997
  }
1998
+ __name(isUniqueViolation, "isUniqueViolation");
1553
1999
  function constraintOf(e) {
1554
2000
  const named = e?.constraint;
1555
2001
  if (typeof named === "string" && named.length > 0) return named;
1556
2002
  const message = String(e?.message ?? "");
1557
2003
  return /violates unique constraint "([^"]+)"/.exec(message)?.[1] ?? "";
1558
2004
  }
2005
+ __name(constraintOf, "constraintOf");
1559
2006
  function isLockTimeout(e) {
1560
2007
  const message = String(e?.message ?? "");
1561
2008
  return sqlstateOf(e) === "55P03" || /lock timeout/i.test(message);
1562
2009
  }
2010
+ __name(isLockTimeout, "isLockTimeout");
1563
2011
  function diagnosingDriver(sql, surface = "service") {
1564
- const original = (e) => String(e?.message ?? e);
1565
- const explain = (e) => {
2012
+ const original = /* @__PURE__ */ __name((e) => String(e?.message ?? e), "original");
2013
+ const explain = /* @__PURE__ */ __name((e) => {
1566
2014
  if (isAbortedTransaction(e)) {
1567
- return new Error(
1568
- `This request cannot write any more: an earlier write in it failed, and a request runs in ONE Postgres transaction, so every statement after the failure is refused. Nothing here is retryable in place. Wrap a write you expect to fail in \`Database.attempt(async (tx) => \u2026)\` \u2014 it takes a SAVEPOINT, so only that write rolls back \u2014 or use \`Database.tables.<t>.upsert(data, { onConflict: [...] })\` when the failure you were bracing for is a duplicate row. (${original(e)})`
1569
- );
2015
+ return new Error(`This request cannot write any more: an earlier write in it failed, and a request runs in ONE Postgres transaction, so every statement after the failure is refused. Nothing here is retryable in place. Wrap a write you expect to fail in \`Database.$attempt(async (tx) => \u2026)\` \u2014 it takes a SAVEPOINT, so only that write rolls back \u2014 or use \`Database.public.<t>.upsert(data, { onConflict: [...] })\` when the failure you were bracing for is a duplicate row. (${original(e)})`);
1570
2016
  }
1571
2017
  if (isUniqueViolation(e)) {
1572
2018
  return markEngineRaised(new UniqueViolation(constraintOf(e)));
1573
2019
  }
2020
+ const state = sqlstateOf(e);
2021
+ if (state === "40001") return markEngineRaised(new SerializationFailure(state));
2022
+ if (state === "40P01") return markEngineRaised(new DeadlockDetected(state));
1574
2023
  if (surface === "service" && isForeignKeyViolation(e)) {
1575
- return new Error(
1576
- `Database.asService() hit a foreign key with nothing to point at. It runs in its OWN transaction on its OWN connection, so a row this request wrote through \`Database.*\` is not visible to it until the request commits \u2014 and the request cannot commit until the handler returns. If the row it needs is one this request just created, do both writes on ONE surface. (${original(e)})`
1577
- );
2024
+ return new Error(`Database.$asService() hit a foreign key with nothing to point at. It runs in its OWN transaction on its OWN connection, so a row this request wrote through \`Database.*\` is not visible to it until the request commits \u2014 and the request cannot commit until the handler returns. If the row it needs is one this request just created, do both writes on ONE surface. (${original(e)})`);
1578
2025
  }
1579
2026
  if (isLockTimeout(e)) {
1580
- return new Error(
1581
- `Database.asService() waited too long for a row lock. It runs in its OWN transaction, so a row this request already wrote through Database.* is locked against it until the request commits \u2014 a wait that cannot end. Do that row's work on one surface or the other. (${original(e)})`
1582
- );
2027
+ return new Error(`Database.$asService() waited too long for a row lock. It runs in its OWN transaction, so a row this request already wrote through Database.* is locked against it until the request commits \u2014 a wait that cannot end. Do that row's work on one surface or the other. (${original(e)})`);
1583
2028
  }
1584
2029
  return e;
1585
- };
1586
- const wrapTx = (tx) => ({
2030
+ }, "explain");
2031
+ const wrapTx = /* @__PURE__ */ __name((tx) => ({
1587
2032
  async unsafe(text, params) {
1588
2033
  try {
1589
2034
  return await tx.unsafe(text, params);
@@ -1594,30 +2039,30 @@ function diagnosingDriver(sql, surface = "service") {
1594
2039
  savepoint(cb) {
1595
2040
  return tx.savepoint((sp) => cb(wrapTx(sp)));
1596
2041
  }
1597
- });
2042
+ }), "wrapTx");
1598
2043
  return {
1599
- unsafe: (text, params) => sql.unsafe(text, params),
1600
- begin: (cb) => sql.begin((tx) => cb(wrapTx(tx)))
2044
+ unsafe: /* @__PURE__ */ __name((text, params) => sql.unsafe(text, params), "unsafe"),
2045
+ begin: /* @__PURE__ */ __name((cb) => sql.begin((tx) => cb(wrapTx(tx))), "begin")
1601
2046
  };
1602
2047
  }
2048
+ __name(diagnosingDriver, "diagnosingDriver");
1603
2049
  function createRequestDatabase(sql, identity) {
1604
2050
  const tx = createLazyTransaction(diagnosingDriver(sql, "user"), identity.role, identity.claimsJson);
1605
2051
  let serviceTx = null;
1606
2052
  let serviceClient = null;
1607
- const asService = () => {
2053
+ const asService = /* @__PURE__ */ __name(() => {
1608
2054
  if (serviceClient === null) {
1609
- serviceTx = createLazyTransaction(
1610
- diagnosingDriver(sql, "service"),
1611
- identity.serviceRole,
1612
- identity.claimsJson,
1613
- { lockTimeout: SERVICE_LOCK_TIMEOUT }
1614
- );
2055
+ serviceTx = createLazyTransaction(diagnosingDriver(sql, "service"), identity.serviceRole, identity.claimsJson, {
2056
+ lockTimeout: SERVICE_LOCK_TIMEOUT
2057
+ });
1615
2058
  serviceClient = withTables(createOps(serviceTx));
1616
2059
  }
1617
2060
  return serviceClient;
1618
- };
2061
+ }, "asService");
1619
2062
  return {
1620
- client: Object.assign(withTables(createOps(tx)), { asService }),
2063
+ client: Object.assign(withTables(createOps(tx)), {
2064
+ asService
2065
+ }),
1621
2066
  async commit() {
1622
2067
  await tx.commit();
1623
2068
  await serviceTx?.commit();
@@ -1628,7 +2073,11 @@ function createRequestDatabase(sql, identity) {
1628
2073
  }
1629
2074
  };
1630
2075
  }
1631
- var Args = class {
2076
+ __name(createRequestDatabase, "createRequestDatabase");
2077
+ var Args = class Args2 {
2078
+ static {
2079
+ __name(this, "Args");
2080
+ }
1632
2081
  values = [];
1633
2082
  bind(value) {
1634
2083
  this.values.push(value);
@@ -1636,17 +2085,37 @@ var Args = class {
1636
2085
  }
1637
2086
  };
1638
2087
  function isRef(v) {
1639
- return typeof v === "object" && v !== null && "$ref" in v;
2088
+ return isPlanRef(v);
1640
2089
  }
2090
+ __name(isRef, "isRef");
2091
+ function refUnresolvedMessage(ref, results) {
2092
+ if (ref.op < 0 || ref.op >= results.length) {
2093
+ return `transaction plan: referans ${ref.op} numaral\u0131 i\u015Fleme bak\u0131yor ama planda ${results.length} i\u015Flem var (0\u2026${results.length - 1}). Referans yaln\u0131z KEND\u0130NDEN \xD6NCEK\u0130 bir i\u015Flemin sat\u0131r\u0131na bakabilir.`;
2094
+ }
2095
+ const row = results[ref.op]?.rows[0];
2096
+ if (!row) {
2097
+ return `transaction plan: ${ref.op} numaral\u0131 i\u015Flem H\u0130\xC7 SATIR d\xF6nd\xFCrmedi, o y\xFCzden "${ref.field}" okunam\u0131yor. Bir referans okunacak sat\u0131r\u0131n var oldu\u011Funu garanti etmez \u2014 \xF6nce beklentiyi bildirin (\`.expectOne(err)\`).`;
2098
+ }
2099
+ return `transaction plan: ${ref.op} numaral\u0131 i\u015Flemin sat\u0131r\u0131nda "${ref.field}" kolonu yok (d\xF6nen kolonlar: ${Object.keys(row).join(", ")}).`;
2100
+ }
2101
+ __name(refUnresolvedMessage, "refUnresolvedMessage");
2102
+ function refuseUnbrandedRef(v, where) {
2103
+ if (looksLikeUnbrandedPlanRef(v)) {
2104
+ throw new Error(`${where}: bir plan referans\u0131 TAKL\u0130D\u0130 ald\u0131 ({ $ref: \u2026 }) \u2014 bu nesne bu plan\u0131n builder'\u0131 taraf\u0131ndan \xFCretilmemi\u015F. Referans yaln\u0131z kendi kodunuzda, \xF6nceki bir i\u015Flemin sat\u0131r\u0131ndan okunarak kurulur (\xF6r. insert(...).expectOne(err).id); istek g\xF6vdesinden gelen bir filtre referans TA\u015EIYAMAZ.`);
2105
+ }
2106
+ }
2107
+ __name(refuseUnbrandedRef, "refuseUnbrandedRef");
1641
2108
  function isExpr(v) {
1642
2109
  return typeof v === "object" && v !== null && "$expr" in v;
1643
2110
  }
2111
+ __name(isExpr, "isExpr");
1644
2112
  function renderValue(value, column, args, results, vectorCols, transforms) {
2113
+ refuseUnbrandedRef(value, `transaction plan (${column})`);
1645
2114
  if (isRef(value)) {
1646
2115
  const source = results[value.$ref.op];
1647
2116
  const row = source?.rows[0];
1648
2117
  if (!row || !(value.$ref.field in row)) {
1649
- throw Object.assign(new Error(`op ${value.$ref.op} has no column "${value.$ref.field}" to reference`), {
2118
+ throw Object.assign(new Error(refUnresolvedMessage(value.$ref, results)), {
1650
2119
  error_code: "tx_ref_unresolved"
1651
2120
  });
1652
2121
  }
@@ -1660,16 +2129,50 @@ function renderValue(value, column, args, results, vectorCols, transforms) {
1660
2129
  }
1661
2130
  return bindMaybeVector(args, column, vectorCols, value, transforms);
1662
2131
  }
1663
- function renderWhere(where, args, results) {
1664
- const cols = Object.keys(where ?? {});
1665
- if (cols.length === 0) return "";
1666
- const terms = cols.map((c) => {
1667
- const v = where[c];
1668
- if (v === null) return `${quoteIdent(c)} IS NULL`;
1669
- return `${quoteIdent(c)} = ${renderValue(v, c, args, results)}`;
1670
- });
1671
- return ` WHERE ${terms.join(" AND ")}`;
2132
+ __name(renderValue, "renderValue");
2133
+ function resolveRefsDeep(value, results) {
2134
+ refuseUnbrandedRef(value, "transaction plan filtresi");
2135
+ if (isRef(value)) {
2136
+ const source = results[value.$ref.op];
2137
+ const row = source?.rows[0];
2138
+ if (!row || !(value.$ref.field in row)) {
2139
+ throw Object.assign(new Error(refUnresolvedMessage(value.$ref, results)), {
2140
+ error_code: "tx_ref_unresolved"
2141
+ });
2142
+ }
2143
+ return row[value.$ref.field];
2144
+ }
2145
+ if (Array.isArray(value)) return value.map((v) => resolveRefsDeep(v, results));
2146
+ if (value !== null && typeof value === "object" && !isColRef(value) && !isSqlFragment(value) && !isExpr(value) && !(value instanceof Date)) {
2147
+ const out = {};
2148
+ for (const [k, v] of Object.entries(value)) {
2149
+ out[k] = resolveRefsDeep(v, results);
2150
+ }
2151
+ return out;
2152
+ }
2153
+ return value;
2154
+ }
2155
+ __name(resolveRefsDeep, "resolveRefsDeep");
2156
+ function renderWhere(table, where, args, results) {
2157
+ return planWhere(table, where, args, results).sql;
2158
+ }
2159
+ __name(renderWhere, "renderWhere");
2160
+ function planWhere(table, where, args, results) {
2161
+ if (where === void 0 || Object.keys(where).length === 0) {
2162
+ return {
2163
+ sql: "",
2164
+ resolved: {}
2165
+ };
2166
+ }
2167
+ const resolved = resolveRefsDeep(where, results);
2168
+ const known = schemaColumns(table);
2169
+ const bare = compileWhereBare(table, known, resolved, (v) => args.bind(v), "transaction plan");
2170
+ return {
2171
+ sql: bare === "" ? "" : ` AND ${bare}`,
2172
+ resolved
2173
+ };
1672
2174
  }
2175
+ __name(planWhere, "planWhere");
1673
2176
  function bindMaybeVector(args, column, vectorCols, value, transforms) {
1674
2177
  if (column !== void 0 && vectorCols?.has(column) && Array.isArray(value)) {
1675
2178
  return args.bind(toVectorLiteral(value));
@@ -1680,11 +2183,12 @@ function bindMaybeVector(args, column, vectorCols, value, transforms) {
1680
2183
  }
1681
2184
  return args.bind(value);
1682
2185
  }
2186
+ __name(bindMaybeVector, "bindMaybeVector");
1683
2187
  async function runPlanOp(sp, op, results) {
1684
2188
  const opVectorCols = vectorColumnsOf(currentSchema, op.table);
1685
2189
  const opTransforms = transformsOf(currentSchema, op.table);
1686
2190
  const args = new Args();
1687
- const table = quoteIdent(op.table);
2191
+ const table = quoteTable(op.table);
1688
2192
  let sql;
1689
2193
  switch (op.op) {
1690
2194
  case "insert": {
@@ -1694,6 +2198,7 @@ async function runPlanOp(sp, op, results) {
1694
2198
  break;
1695
2199
  }
1696
2200
  case "upsert": {
2201
+ assertNotAppendOnly("put", op.table);
1697
2202
  const cols = Object.keys(op.values ?? {});
1698
2203
  const conflict = op.onConflict ?? [];
1699
2204
  if (cols.length === 0 || conflict.length === 0) {
@@ -1701,9 +2206,7 @@ async function runPlanOp(sp, op, results) {
1701
2206
  error_code: "tx_bad_upsert"
1702
2207
  });
1703
2208
  }
1704
- const rendered = cols.map(
1705
- (c) => renderValue(op.values[c], c, args, results, opVectorCols, opTransforms)
1706
- );
2209
+ const rendered = cols.map((c) => renderValue(op.values[c], c, args, results, opVectorCols, opTransforms));
1707
2210
  sql = `INSERT INTO ${table} (${cols.map(quoteIdent).join(", ")}) VALUES (${rendered.join(", ")}) ${onConflictTail(cols, conflict, "update")} RETURNING *`;
1708
2211
  break;
1709
2212
  }
@@ -1711,31 +2214,44 @@ async function runPlanOp(sp, op, results) {
1711
2214
  const rows = op.rows ?? [];
1712
2215
  if (rows.length === 0 || !rows[0]) return [];
1713
2216
  const cols = Object.keys(rows[0]);
1714
- const tuples = rows.map(
1715
- (r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols, opTransforms)).join(", ")})`
1716
- );
2217
+ const tuples = rows.map((r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols, opTransforms)).join(", ")})`);
1717
2218
  const conflictCols = op.onConflict ?? [];
1718
2219
  const tail = op.action !== void 0 && conflictCols.length > 0 ? ` ${onConflictTail(cols, conflictCols, op.action)}` : "";
1719
2220
  sql = `INSERT INTO ${table} (${cols.map(quoteIdent).join(", ")}) VALUES ${tuples.join(", ")}${tail} RETURNING *`;
1720
2221
  break;
1721
2222
  }
1722
2223
  case "update": {
2224
+ assertNotAppendOnly("updateWhere", op.table);
1723
2225
  const cols = Object.keys(op.set ?? {});
1724
2226
  if (cols.length === 0) throw new Error(`update ${op.table}: nothing to set`);
1725
- const assignments = cols.map(
1726
- (c) => `${quoteIdent(c)} = ${renderValue(op.set[c], c, args, results, opVectorCols, opTransforms)}`
1727
- );
1728
- sql = `UPDATE ${table} SET ${assignments.join(", ")}${renderWhere(op.where, args, results)} RETURNING *`;
2227
+ const knownSet = schemaColumns(op.table);
2228
+ for (const c of cols) {
2229
+ if (knownSet !== null && !knownSet.has(c)) {
2230
+ throw new Error(`transaction plan (${op.table}): set kolonu "${c}" tabloda yok`);
2231
+ }
2232
+ }
2233
+ const assignments = cols.map((c) => `${quoteIdent(c)} = ${renderValue(op.set[c], c, args, results, opVectorCols, opTransforms)}`);
2234
+ const planned = planWhere(op.table, op.where, args, results);
2235
+ const planPk = primaryKeyOf(op.table);
2236
+ sql = isSinglePkEquality(planned.resolved, planPk) || planPk === null ? `UPDATE ${table} AS t SET ${assignments.join(", ")} WHERE true${planned.sql} RETURNING t.*` : `WITH locked AS (SELECT t.${quoteIdent(planPk)} FROM ${table} t WHERE true${planned.sql} ORDER BY t.${quoteIdent(planPk)} FOR NO KEY UPDATE) UPDATE ${table} AS t SET ${assignments.join(", ")} FROM locked WHERE t.${quoteIdent(planPk)} = locked.${quoteIdent(planPk)} RETURNING t.*`;
1729
2237
  break;
1730
2238
  }
1731
2239
  case "delete": {
1732
- sql = `DELETE FROM ${table}${renderWhere(op.where, args, results)} RETURNING *`;
2240
+ assertNotAppendOnly("deleteWhere", op.table);
2241
+ sql = `DELETE FROM ${table} AS t WHERE true${renderWhere(op.table, op.where, args, results)} RETURNING t.*`;
1733
2242
  break;
1734
2243
  }
1735
2244
  case "select": {
1736
- const limit = op.limit !== void 0 ? ` LIMIT ${Number(op.limit)}` : "";
2245
+ let limit = "";
2246
+ if (op.limit !== void 0) {
2247
+ const n = Number(op.limit);
2248
+ if (!Number.isInteger(n) || n < 0) {
2249
+ throw new Error(`transaction plan (${op.table}): limit bir tam say\u0131 olmal\u0131, "${String(op.limit)}" al\u0131nd\u0131`);
2250
+ }
2251
+ limit = ` LIMIT ${n}`;
2252
+ }
1737
2253
  const lock = op.lock === "update" ? " FOR UPDATE" : "";
1738
- sql = `SELECT * FROM ${table}${renderWhere(op.where, args, results)}${limit}${lock}`;
2254
+ sql = `SELECT t.* FROM ${table} t WHERE true${renderWhere(op.table, op.where, args, results)}${limit}${lock}`;
1739
2255
  break;
1740
2256
  }
1741
2257
  default:
@@ -1743,6 +2259,7 @@ async function runPlanOp(sp, op, results) {
1743
2259
  }
1744
2260
  return await sp.unsafe(sql, args.values);
1745
2261
  }
2262
+ __name(runPlanOp, "runPlanOp");
1746
2263
  function assertGuard(op, result) {
1747
2264
  const guard = op.guard;
1748
2265
  if (!guard) return;
@@ -1754,6 +2271,7 @@ function assertGuard(op, result) {
1754
2271
  slot: guard.slot
1755
2272
  });
1756
2273
  }
2274
+ __name(assertGuard, "assertGuard");
1757
2275
 
1758
2276
  // src/engine/router.ts
1759
2277
  var ROOM_META = /* @__PURE__ */ Symbol.for("palbase.backend.room");
@@ -1761,7 +2279,8 @@ var CONTROLLER_META = /* @__PURE__ */ Symbol.for("palbase.backend.controllerMeta
1761
2279
  function toSegments(path) {
1762
2280
  return path.split("/").filter(Boolean).map((s) => s.startsWith("{") && s.endsWith("}") ? `:${s.slice(1, -1)}` : s);
1763
2281
  }
1764
- function buildRouteTable(controllers) {
2282
+ __name(toSegments, "toSegments");
2283
+ function buildRouteTable(controllers, container) {
1765
2284
  const table = [];
1766
2285
  for (const Ctrl of controllers) {
1767
2286
  if (Ctrl[ROOM_META] !== void 0) continue;
@@ -1771,12 +2290,9 @@ function buildRouteTable(controllers) {
1771
2290
  const routes = getRoutes(Ctrl);
1772
2291
  if (routes.length === 0) {
1773
2292
  const name = Ctrl.name ?? "<anonymous>";
1774
- throw new Error(
1775
- `controller ${name} collected zero routes. Either it declares no @Get/@Post/\u2026 , or its decorator metadata was erased at build time \u2014 check that the bundle was compiled with experimentalDecorators enabled.`
1776
- );
2293
+ throw new Error(`controller ${name} collected zero routes. Either it declares no @Get/@Post/\u2026 , or its decorator metadata was erased at build time \u2014 check that the bundle was compiled with experimentalDecorators enabled.`);
1777
2294
  }
1778
- assertZeroArgConstructor(Ctrl, "controller");
1779
- const instance = new ctor();
2295
+ const instance = container.get(Ctrl);
1780
2296
  for (const r of routes) {
1781
2297
  const full = `${basePath}${r.subpath ?? ""}` || "/";
1782
2298
  table.push({
@@ -1794,6 +2310,7 @@ function buildRouteTable(controllers) {
1794
2310
  }
1795
2311
  return table;
1796
2312
  }
2313
+ __name(buildRouteTable, "buildRouteTable");
1797
2314
  function matchRoute(table, method, pathname) {
1798
2315
  const parts = pathname.split("/").filter(Boolean);
1799
2316
  for (const entry of table) {
@@ -1814,10 +2331,14 @@ function matchRoute(table, method, pathname) {
1814
2331
  break;
1815
2332
  }
1816
2333
  }
1817
- if (ok) return { entry, params };
2334
+ if (ok) return {
2335
+ entry,
2336
+ params
2337
+ };
1818
2338
  }
1819
2339
  return null;
1820
2340
  }
2341
+ __name(matchRoute, "matchRoute");
1821
2342
 
1822
2343
  // src/engine/attest.ts
1823
2344
  var HEADER_DEVICE_ID = "x-palbase-device-id";
@@ -1836,10 +2357,12 @@ async function bodyDigest(body) {
1836
2357
  const buf = await crypto.subtle.digest("SHA-256", bytes);
1837
2358
  return btoa(String.fromCharCode(...new Uint8Array(buf)));
1838
2359
  }
2360
+ __name(bodyDigest, "bodyDigest");
1839
2361
  function readCapable(req) {
1840
2362
  const v = req.headers.get(HEADER_CAPABLE);
1841
2363
  return v === "yes" || v === "no" ? v : "unknown";
1842
2364
  }
2365
+ __name(readCapable, "readCapable");
1843
2366
  function createAttestGate(deps) {
1844
2367
  const doFetch = deps.fetchImpl ?? fetch;
1845
2368
  const ttl = deps.policyTtlMs ?? DEFAULT_POLICY_TTL_MS;
@@ -1850,7 +2373,9 @@ function createAttestGate(deps) {
1850
2373
  if (Date.now() - cachedAt < ttl) return cachedMode;
1851
2374
  try {
1852
2375
  const res = await doFetch(`${deps.moduleBaseUrl}/admin/attest/devices/attest-policy`, {
1853
- headers: { apikey: deps.serviceRoleKey },
2376
+ headers: {
2377
+ apikey: deps.serviceRoleKey
2378
+ },
1854
2379
  signal: AbortSignal.timeout(policyTimeoutMs)
1855
2380
  });
1856
2381
  if (!res.ok) throw new Error(`attest-policy ${res.status}`);
@@ -1861,10 +2386,17 @@ function createAttestGate(deps) {
1861
2386
  }
1862
2387
  return cachedMode;
1863
2388
  }
1864
- return async function gate(req, body, _ctx) {
2389
+ __name(mode, "mode");
2390
+ return /* @__PURE__ */ __name(async function gate(req, body, _ctx) {
1865
2391
  const m = await mode();
1866
2392
  if (m === "off") {
1867
- return { outcome: "pass", reason: "", device: null, observation: null, nextChallenge: null };
2393
+ return {
2394
+ outcome: "pass",
2395
+ reason: "",
2396
+ device: null,
2397
+ observation: null,
2398
+ nextChallenge: null
2399
+ };
1868
2400
  }
1869
2401
  const deviceId = req.headers.get(HEADER_DEVICE_ID) ?? "";
1870
2402
  const payload = req.headers.get(HEADER_PAYLOAD) ?? "";
@@ -1877,14 +2409,23 @@ function createAttestGate(deps) {
1877
2409
  };
1878
2410
  if (m === "monitor") {
1879
2411
  observation.attested = hasEvidence;
1880
- return { outcome: "pass", reason: "", device: null, observation, nextChallenge: null };
2412
+ return {
2413
+ outcome: "pass",
2414
+ reason: "",
2415
+ device: null,
2416
+ observation,
2417
+ nextChallenge: null
2418
+ };
1881
2419
  }
1882
2420
  const url = new URL(req.url);
1883
2421
  let verdict;
1884
2422
  try {
1885
2423
  const res = await doFetch(`${deps.moduleBaseUrl}/admin/attest/devices/assert`, {
1886
2424
  method: "POST",
1887
- headers: { apikey: deps.serviceRoleKey, "content-type": "application/json" },
2425
+ headers: {
2426
+ apikey: deps.serviceRoleKey,
2427
+ "content-type": "application/json"
2428
+ },
1888
2429
  // A HUNG palauth must not become a hung tenant. Without this, a
1889
2430
  // process that accepts the connection and never answers holds every
1890
2431
  // request open until the client gives up — the gate would take the
@@ -1945,8 +2486,9 @@ function createAttestGate(deps) {
1945
2486
  observation,
1946
2487
  nextChallenge: verdict.next_challenge || null
1947
2488
  };
1948
- };
2489
+ }, "gate");
1949
2490
  }
2491
+ __name(createAttestGate, "createAttestGate");
1950
2492
  function createObservationSink(deps) {
1951
2493
  const doFetch = deps.fetchImpl ?? fetch;
1952
2494
  const maxBatch = deps.maxBatch ?? 1e3;
@@ -1958,7 +2500,12 @@ function createObservationSink(deps) {
1958
2500
  }, intervalMs);
1959
2501
  timer.unref?.();
1960
2502
  function bucketsOf(batch) {
1961
- const counts = { capable: 0, incapable: 0, unknown: 0, no_sdk: 0 };
2503
+ const counts = {
2504
+ capable: 0,
2505
+ incapable: 0,
2506
+ unknown: 0,
2507
+ no_sdk: 0
2508
+ };
1962
2509
  for (const o of batch) {
1963
2510
  if (o.attested || o.capable === "yes") counts.capable += 1;
1964
2511
  else if (o.capable === "no") counts.incapable += 1;
@@ -1967,6 +2514,7 @@ function createObservationSink(deps) {
1967
2514
  }
1968
2515
  return counts;
1969
2516
  }
2517
+ __name(bucketsOf, "bucketsOf");
1970
2518
  async function flush() {
1971
2519
  if (buffer.length === 0) return;
1972
2520
  const batch = buffer;
@@ -1975,7 +2523,10 @@ function createObservationSink(deps) {
1975
2523
  try {
1976
2524
  await doFetch(`${deps.moduleBaseUrl}/admin/attest/devices/observations`, {
1977
2525
  method: "POST",
1978
- headers: { apikey: deps.serviceRoleKey, "content-type": "application/json" },
2526
+ headers: {
2527
+ apikey: deps.serviceRoleKey,
2528
+ "content-type": "application/json"
2529
+ },
1979
2530
  body: JSON.stringify(bucketsOf(batch))
1980
2531
  });
1981
2532
  } catch {
@@ -1983,6 +2534,7 @@ function createObservationSink(deps) {
1983
2534
  })();
1984
2535
  await inFlight;
1985
2536
  }
2537
+ __name(flush, "flush");
1986
2538
  return {
1987
2539
  record(o) {
1988
2540
  buffer.push(o);
@@ -1994,6 +2546,7 @@ function createObservationSink(deps) {
1994
2546
  }
1995
2547
  };
1996
2548
  }
2549
+ __name(createObservationSink, "createObservationSink");
1997
2550
 
1998
2551
  // src/engine/upload.ts
1999
2552
  var AUTHORIZE_PATH = "/__palbase/upload/authorize";
@@ -2001,10 +2554,12 @@ var SIGNATURE_HEADER = "x-palbase-upload-signature";
2001
2554
  function renderPath(template, tokens) {
2002
2555
  return template.replaceAll("{userId}", sanitizeSegment(tokens.userId ?? "anonymous")).replaceAll("{uploadId}", sanitizeSegment(tokens.uploadId)).replaceAll("{filename}", sanitizeSegment(tokens.filename ?? "file"));
2003
2556
  }
2557
+ __name(renderPath, "renderPath");
2004
2558
  function sanitizeSegment(raw) {
2005
2559
  const cleaned = raw.replace(/[\x00-\x1F\x7F]/g, "").replace(/[/\\]/g, "-").replace(/\.{2,}/g, ".").replace(/^\.+/, "").trim();
2006
2560
  return cleaned === "" ? "file" : cleaned.slice(0, 200);
2007
2561
  }
2562
+ __name(sanitizeSegment, "sanitizeSegment");
2008
2563
  function grantFor(entry, ctx, bucketLimits) {
2009
2564
  const cfg = entry?.meta?.options?.uploadConfig;
2010
2565
  if (!cfg) return null;
@@ -2020,12 +2575,16 @@ function grantFor(entry, ctx, bucketLimits) {
2020
2575
  ownerUid: ctx.userId ?? null
2021
2576
  };
2022
2577
  }
2578
+ __name(grantFor, "grantFor");
2023
2579
  var CompletionLedger = class {
2024
- constructor(capacity = 1024) {
2025
- this.capacity = capacity;
2580
+ static {
2581
+ __name(this, "CompletionLedger");
2026
2582
  }
2027
2583
  capacity;
2028
2584
  seen = /* @__PURE__ */ new Map();
2585
+ constructor(capacity = 1024) {
2586
+ this.capacity = capacity;
2587
+ }
2029
2588
  recall(uploadId) {
2030
2589
  return this.seen.get(uploadId);
2031
2590
  }
@@ -2050,6 +2609,7 @@ function verifySignature(presented, expected) {
2050
2609
  }
2051
2610
  return diff === 0;
2052
2611
  }
2612
+ __name(verifySignature, "verifySignature");
2053
2613
 
2054
2614
  // src/engine/sse.ts
2055
2615
  var SSE_CONTENT_TYPE = "text/event-stream";
@@ -2058,12 +2618,16 @@ function encodeFrame(value) {
2058
2618
 
2059
2619
  `;
2060
2620
  }
2621
+ __name(encodeFrame, "encodeFrame");
2061
2622
  function encodeErrorFrame(requestId) {
2062
2623
  return `event: error
2063
- data: ${JSON.stringify({ requestId })}
2624
+ data: ${JSON.stringify({
2625
+ requestId
2626
+ })}
2064
2627
 
2065
2628
  `;
2066
2629
  }
2630
+ __name(encodeErrorFrame, "encodeErrorFrame");
2067
2631
  function makeSseWriter(opts) {
2068
2632
  let begun = false;
2069
2633
  let chain = Promise.resolve();
@@ -2085,6 +2649,7 @@ function makeSseWriter(opts) {
2085
2649
  }
2086
2650
  };
2087
2651
  }
2652
+ __name(makeSseWriter, "makeSseWriter");
2088
2653
 
2089
2654
  // src/engine/fence.ts
2090
2655
  var SECRET_ENV = [
@@ -2105,8 +2670,12 @@ function scrubSecrets(env) {
2105
2670
  removed.push(name);
2106
2671
  }
2107
2672
  for (const name of Object.keys(env)) if (name.startsWith("PALBASE_VAR_")) kept.push(name);
2108
- return { removed, kept };
2673
+ return {
2674
+ removed,
2675
+ kept
2676
+ };
2109
2677
  }
2678
+ __name(scrubSecrets, "scrubSecrets");
2110
2679
  function hostAllowed(host, allow) {
2111
2680
  const h = host.toLowerCase();
2112
2681
  for (const raw of allow) {
@@ -2119,40 +2688,49 @@ function hostAllowed(host, allow) {
2119
2688
  }
2120
2689
  return false;
2121
2690
  }
2691
+ __name(hostAllowed, "hostAllowed");
2122
2692
  function installEgressFence(policy) {
2123
2693
  const original = globalThis.fetch.bind(globalThis);
2124
2694
  const declared = policy.allow.length > 0;
2125
2695
  const platform = (policy.alwaysAllow ?? []).map((h) => h.toLowerCase()).filter(Boolean);
2126
2696
  if (!declared && policy.whenUndeclared === "allow") return original;
2127
- const fenced = async (input, init) => {
2697
+ const fenced = /* @__PURE__ */ __name(async (input, init) => {
2128
2698
  const url = typeof input === "string" ? new URL(input) : input instanceof URL ? input : new URL(input.url);
2129
2699
  if (platform.includes(url.hostname.toLowerCase())) return original(input, init);
2130
2700
  if (!declared || !hostAllowed(url.hostname, policy.allow)) {
2131
- throw new Error(
2132
- `egress denied: ${url.hostname} is not in this backend's declared allowlist. Add it to config/egress.ts and deploy.`
2133
- );
2701
+ throw new Error(`egress denied: ${url.hostname} is not in this backend's declared allowlist. Add it to config/egress.ts and deploy.`);
2134
2702
  }
2135
2703
  if (policy.timeoutMs > 0) {
2136
2704
  const controller = new AbortController();
2137
2705
  const timer = setTimeout(() => controller.abort(), policy.timeoutMs);
2138
2706
  try {
2139
- return await original(input, { ...init, signal: init?.signal ?? controller.signal });
2707
+ return await original(input, {
2708
+ ...init,
2709
+ signal: init?.signal ?? controller.signal
2710
+ });
2140
2711
  } finally {
2141
2712
  clearTimeout(timer);
2142
2713
  }
2143
2714
  }
2144
2715
  return original(input, init);
2145
- };
2716
+ }, "fenced");
2146
2717
  globalThis.fetch = fenced;
2147
2718
  return original;
2148
2719
  }
2720
+ __name(installEgressFence, "installEgressFence");
2149
2721
 
2150
2722
  // src/engine/index.ts
2151
2723
  var MAX_BODY_BYTES = 10 * 1024 * 1024;
2152
- var JSON_HEADERS = { "content-type": "application/json" };
2724
+ var JSON_HEADERS = {
2725
+ "content-type": "application/json"
2726
+ };
2153
2727
  function fieldErrors(err) {
2154
- return err.issues.map((i) => ({ field: i.path.join("."), message: i.message }));
2728
+ return err.issues.map((i) => ({
2729
+ field: i.path.join("."),
2730
+ message: i.message
2731
+ }));
2155
2732
  }
2733
+ __name(fieldErrors, "fieldErrors");
2156
2734
  function headersFor(raw, schema) {
2157
2735
  const shape = schema.shape;
2158
2736
  if (typeof shape !== "object" || shape === null) return raw;
@@ -2162,53 +2740,84 @@ function headersFor(raw, schema) {
2162
2740
  if (lower === declared) continue;
2163
2741
  const value = raw[lower];
2164
2742
  if (value === void 0) continue;
2165
- aliased ??= { ...raw };
2743
+ aliased ??= {
2744
+ ...raw
2745
+ };
2166
2746
  aliased[declared] = value;
2167
2747
  }
2168
2748
  return aliased ?? raw;
2169
2749
  }
2750
+ __name(headersFor, "headersFor");
2170
2751
  function envelope(error, description, status, requestId, extra) {
2171
- return new Response(
2172
- JSON.stringify({ error, error_description: description, status, request_id: requestId, ...extra }),
2173
- { status, headers: JSON_HEADERS }
2174
- );
2752
+ return new Response(JSON.stringify({
2753
+ error,
2754
+ error_description: description,
2755
+ status,
2756
+ request_id: requestId,
2757
+ ...extra
2758
+ }), {
2759
+ status,
2760
+ headers: JSON_HEADERS
2761
+ });
2175
2762
  }
2763
+ __name(envelope, "envelope");
2176
2764
  function unavailable(name) {
2177
- throw new Error(
2178
- `${name} is unavailable. Either this backend was started without module clients (set MODULE_BASE_URL and the API keys so the engine can reach the module surface), or ${name} is not one of the modules this backend provides.`
2179
- );
2765
+ throw new Error(`${name} is unavailable. Either this backend was started without module clients (set MODULE_BASE_URL and the API keys so the engine can reach the module surface), or ${name} is not one of the modules this backend provides.`);
2180
2766
  }
2767
+ __name(unavailable, "unavailable");
2181
2768
  function stubModule(name) {
2182
- return new Proxy(
2183
- {},
2184
- {
2185
- get: () => unavailable(name),
2186
- apply: () => unavailable(name)
2187
- }
2188
- );
2769
+ return new Proxy({}, {
2770
+ get: /* @__PURE__ */ __name(() => unavailable(name), "get"),
2771
+ apply: /* @__PURE__ */ __name(() => unavailable(name), "apply")
2772
+ });
2189
2773
  }
2774
+ __name(stubModule, "stubModule");
2190
2775
  async function defaultSqlDriver(config) {
2191
2776
  const g = globalThis;
2192
2777
  if (!g.Bun?.SQL) {
2193
- throw new BootRefused(
2194
- [],
2195
- "boot refused: no SQL driver. Running outside Bun means the driver must be supplied \u2014 pass `sql` to createApp()."
2196
- );
2778
+ throw new BootRefused([], "boot refused: no SQL driver. Running outside Bun means the driver must be supplied \u2014 pass `sql` to createApp().");
2197
2779
  }
2198
- return new g.Bun.SQL({ url: config.databaseUrl, max: config.poolMax });
2780
+ return new g.Bun.SQL({
2781
+ url: config.databaseUrl,
2782
+ max: config.poolMax
2783
+ });
2199
2784
  }
2200
- var AUTHOR_ANSWERED = /* @__PURE__ */ new Set([400, 401, 403, 404, 409, 429]);
2785
+ __name(defaultSqlDriver, "defaultSqlDriver");
2786
+ var AUTHOR_ANSWERED = /* @__PURE__ */ new Set([
2787
+ 400,
2788
+ 401,
2789
+ 403,
2790
+ 404,
2791
+ 409,
2792
+ 429
2793
+ ]);
2201
2794
  async function createApp(opts) {
2202
2795
  const { config, controllers } = opts;
2203
- setSchema(opts.schemas ?? []);
2204
- setSecretReader(opts.secretReader ?? null);
2205
- const routes = buildRouteTable(controllers);
2796
+ const container = buildContainer();
2797
+ let released = false;
2798
+ const liveContainer = {
2799
+ get(t) {
2800
+ if (released) {
2801
+ throw new Error("this app has shut down \u2014 its container no longer resolves. A class resolved here would hold a closed database pool.");
2802
+ }
2803
+ return container.get(t);
2804
+ },
2805
+ owned: container.owned,
2806
+ pressure: container.pressure
2807
+ };
2808
+ assertNoOrphanEntryPoints(controllers, container.owned);
2809
+ const routes = buildRouteTable(controllers, liveContainer);
2206
2810
  if (routes.length === 0) {
2207
2811
  throw new BootRefused([], "boot refused: zero endpoints collected \u2014 nothing would answer.");
2208
2812
  }
2209
2813
  const sql = opts.sql ?? await defaultSqlDriver(config);
2210
2814
  await sql.unsafe("select 1");
2211
- const auth = new AuthVerifier({ jwksUrl: config.authJwksUrl, issuer: config.authIssuer });
2815
+ setSchema(opts.schemas ?? []);
2816
+ setSecretReader(opts.secretReader ?? null);
2817
+ const auth = new AuthVerifier({
2818
+ jwksUrl: config.authJwksUrl,
2819
+ issuer: config.authIssuer
2820
+ });
2212
2821
  const attestGate = createAttestGate({
2213
2822
  moduleBaseUrl: config.moduleBaseUrl,
2214
2823
  serviceRoleKey: config.serviceRoleKey
@@ -2242,6 +2851,7 @@ async function createApp(opts) {
2242
2851
  Secrets: modules.Secrets ?? stubModule("Secrets")
2243
2852
  };
2244
2853
  }
2854
+ __name(buildServices, "buildServices");
2245
2855
  async function runInServiceScope(fn) {
2246
2856
  const db = createRequestDatabase(sql, {
2247
2857
  role: config.dbRole,
@@ -2257,6 +2867,7 @@ async function createApp(opts) {
2257
2867
  throw err;
2258
2868
  }
2259
2869
  }
2870
+ __name(runInServiceScope, "runInServiceScope");
2260
2871
  async function handleAuthorize(req, requestId) {
2261
2872
  if (uploadSecret === "" || !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? "", uploadSecret)) {
2262
2873
  return envelope("unauthorized", "This endpoint is not callable directly", 401, requestId);
@@ -2280,15 +2891,14 @@ async function createApp(opts) {
2280
2891
  filename: body.filename
2281
2892
  });
2282
2893
  if (!grant) {
2283
- return envelope(
2284
- "not_an_upload_route",
2285
- `${body.method ?? "POST"} ${body.path} does not declare @Upload`,
2286
- 400,
2287
- requestId
2288
- );
2894
+ return envelope("not_an_upload_route", `${body.method ?? "POST"} ${body.path} does not declare @Upload`, 400, requestId);
2289
2895
  }
2290
- return new Response(JSON.stringify(grant), { status: 200, headers: JSON_HEADERS });
2896
+ return new Response(JSON.stringify(grant), {
2897
+ status: 200,
2898
+ headers: JSON_HEADERS
2899
+ });
2291
2900
  }
2901
+ __name(handleAuthorize, "handleAuthorize");
2292
2902
  async function handle(req) {
2293
2903
  const requestId = `req_${crypto.randomUUID()}`;
2294
2904
  const url = new URL(req.url);
@@ -2318,31 +2928,31 @@ async function createApp(opts) {
2318
2928
  if (req.method !== "GET" && req.method !== "HEAD") {
2319
2929
  const declared = Number(req.headers.get("content-length") ?? "");
2320
2930
  if (Number.isFinite(declared) && declared > MAX_BODY_BYTES) {
2321
- return new Response(
2322
- JSON.stringify({
2323
- error: "payload_too_large",
2324
- error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
2325
- status: 413,
2326
- request_id: requestId
2327
- }),
2328
- { status: 413, headers: JSON_HEADERS }
2329
- );
2931
+ return new Response(JSON.stringify({
2932
+ error: "payload_too_large",
2933
+ error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
2934
+ status: 413,
2935
+ request_id: requestId
2936
+ }), {
2937
+ status: 413,
2938
+ headers: JSON_HEADERS
2939
+ });
2330
2940
  }
2331
2941
  const buf = await req.arrayBuffer().catch(() => null);
2332
2942
  if (buf && buf.byteLength > MAX_BODY_BYTES) {
2333
- return new Response(
2334
- JSON.stringify({
2335
- error: "payload_too_large",
2336
- error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
2337
- status: 413,
2338
- request_id: requestId
2339
- }),
2340
- { status: 413, headers: JSON_HEADERS }
2341
- );
2943
+ return new Response(JSON.stringify({
2944
+ error: "payload_too_large",
2945
+ error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
2946
+ status: 413,
2947
+ request_id: requestId
2948
+ }), {
2949
+ status: 413,
2950
+ headers: JSON_HEADERS
2951
+ });
2342
2952
  }
2343
2953
  if (buf && buf.byteLength > 0) rawBody = new Uint8Array(buf);
2344
2954
  }
2345
- const readParsedBody = () => {
2955
+ const readParsedBody = /* @__PURE__ */ __name(() => {
2346
2956
  if (bodyRead) return parsedBody;
2347
2957
  bodyRead = true;
2348
2958
  if (!rawBody) {
@@ -2355,49 +2965,54 @@ async function createApp(opts) {
2355
2965
  parsedBody = {};
2356
2966
  }
2357
2967
  return parsedBody;
2358
- };
2359
- const attest = await attestGate(req, rawBody, { userId });
2968
+ }, "readParsedBody");
2969
+ const attest = await attestGate(req, rawBody, {
2970
+ userId
2971
+ });
2360
2972
  if (attest.observation) observations.record(attest.observation);
2361
2973
  if (attest.outcome === "reject") {
2362
- const headers = { ...JSON_HEADERS };
2974
+ const headers = {
2975
+ ...JSON_HEADERS
2976
+ };
2363
2977
  if (attest.nextChallenge) headers["x-palbase-attest-challenge"] = attest.nextChallenge;
2364
- return new Response(
2365
- JSON.stringify({
2366
- error: attest.reason,
2367
- error_description: "This endpoint requires a verified app instance",
2368
- status: 401,
2369
- request_id: requestId
2370
- }),
2371
- { status: 401, headers }
2372
- );
2978
+ return new Response(JSON.stringify({
2979
+ error: attest.reason,
2980
+ error_description: "This endpoint requires a verified app instance",
2981
+ status: 401,
2982
+ request_id: requestId
2983
+ }), {
2984
+ status: 401,
2985
+ headers
2986
+ });
2373
2987
  }
2374
2988
  if (attest.device && claims) attestedDevice = attest.device;
2375
2989
  attestChallengeOut = attest.nextChallenge;
2376
- const retryAfter = limiter.check(
2377
- meta.options?.rateLimit,
2378
- RateLimiter.key(hit.entry.id, userId, req.headers),
2379
- Date.now()
2380
- );
2990
+ const retryAfter = limiter.check(meta.options?.rateLimit, RateLimiter.key(hit.entry.id, userId, req.headers), Date.now());
2381
2991
  if (retryAfter !== null) {
2382
- return new Response(
2383
- JSON.stringify({
2384
- error: "too_many_requests",
2385
- error_description: "Rate limit exceeded for this endpoint",
2386
- status: 429,
2387
- request_id: requestId,
2388
- data: { retryAfter }
2389
- }),
2390
- { status: 429, headers: { ...JSON_HEADERS, "retry-after": String(retryAfter) } }
2391
- );
2992
+ return new Response(JSON.stringify({
2993
+ error: "too_many_requests",
2994
+ error_description: "Rate limit exceeded for this endpoint",
2995
+ status: 429,
2996
+ request_id: requestId,
2997
+ data: {
2998
+ retryAfter
2999
+ }
3000
+ }), {
3001
+ status: 429,
3002
+ headers: {
3003
+ ...JSON_HEADERS,
3004
+ "retry-after": String(retryAfter)
3005
+ }
3006
+ });
2392
3007
  }
2393
3008
  let completionUploadId = null;
2394
3009
  const args = [];
2395
3010
  let sseEnqueue = null;
2396
- let sseSettle = async () => {
2397
- };
3011
+ let sseSettle = /* @__PURE__ */ __name(async () => {
3012
+ }, "sseSettle");
2398
3013
  const sseWriter = makeSseWriter({
2399
- enqueue: (chunk) => sseEnqueue?.(chunk),
2400
- onFirstWrite: () => sseSettle()
3014
+ enqueue: /* @__PURE__ */ __name((chunk) => sseEnqueue?.(chunk), "enqueue"),
3015
+ onFirstWrite: /* @__PURE__ */ __name(() => sseSettle(), "onFirstWrite")
2401
3016
  });
2402
3017
  for (const p of meta.params ?? []) {
2403
3018
  switch (p.kind) {
@@ -2406,7 +3021,9 @@ async function createApp(opts) {
2406
3021
  const r = p.schema.safeParse(parsedBody);
2407
3022
  if (!r.success) {
2408
3023
  return envelope("bad_request", "Request body failed validation", 400, requestId, {
2409
- data: { fields: fieldErrors(r.error) }
3024
+ data: {
3025
+ fields: fieldErrors(r.error)
3026
+ }
2410
3027
  });
2411
3028
  }
2412
3029
  args[p.index] = r.data;
@@ -2416,7 +3033,9 @@ async function createApp(opts) {
2416
3033
  const r = p.schema.safeParse(Object.fromEntries(url.searchParams));
2417
3034
  if (!r.success) {
2418
3035
  return envelope("bad_request", "Query parameters failed validation", 400, requestId, {
2419
- data: { fields: fieldErrors(r.error) }
3036
+ data: {
3037
+ fields: fieldErrors(r.error)
3038
+ }
2420
3039
  });
2421
3040
  }
2422
3041
  args[p.index] = r.data;
@@ -2434,7 +3053,9 @@ async function createApp(opts) {
2434
3053
  const r = p.schema.safeParse(headersFor(raw, p.schema));
2435
3054
  if (!r.success) {
2436
3055
  return envelope("bad_request", "Request headers failed validation", 400, requestId, {
2437
- data: { fields: fieldErrors(r.error) }
3056
+ data: {
3057
+ fields: fieldErrors(r.error)
3058
+ }
2438
3059
  });
2439
3060
  }
2440
3061
  args[p.index] = r.data;
@@ -2457,12 +3078,7 @@ async function createApp(opts) {
2457
3078
  break;
2458
3079
  case "uploadedObject": {
2459
3080
  if (uploadSecret === "" || !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? "", uploadSecret)) {
2460
- return envelope(
2461
- "unauthorized",
2462
- "This endpoint accepts uploads through storage, not directly",
2463
- 401,
2464
- requestId
2465
- );
3081
+ return envelope("unauthorized", "This endpoint accepts uploads through storage, not directly", 401, requestId);
2466
3082
  }
2467
3083
  readParsedBody();
2468
3084
  const envelopeIn = parsedBody;
@@ -2475,7 +3091,9 @@ async function createApp(opts) {
2475
3091
  if (already) {
2476
3092
  return new Response(already.body, {
2477
3093
  status: already.status,
2478
- headers: already.contentType ? { "content-type": already.contentType } : void 0
3094
+ headers: already.contentType ? {
3095
+ "content-type": already.contentType
3096
+ } : void 0
2479
3097
  });
2480
3098
  }
2481
3099
  completionUploadId = uploadId;
@@ -2535,26 +3153,24 @@ async function createApp(opts) {
2535
3153
  sseController = c;
2536
3154
  }
2537
3155
  });
2538
- sseEnqueue = (chunk) => {
3156
+ sseEnqueue = /* @__PURE__ */ __name((chunk) => {
2539
3157
  try {
2540
3158
  sseController.enqueue(sseEncoder.encode(chunk));
2541
3159
  } catch {
2542
3160
  }
2543
- };
3161
+ }, "sseEnqueue");
2544
3162
  let sawFirstFrame;
2545
3163
  const firstFrame = new Promise((r) => sawFirstFrame = r);
2546
- sseSettle = async () => {
3164
+ sseSettle = /* @__PURE__ */ __name(async () => {
2547
3165
  await db.commit();
2548
3166
  sawFirstFrame();
2549
- };
3167
+ }, "sseSettle");
2550
3168
  const guarded = {
2551
3169
  ...services,
2552
3170
  Database: new Proxy(services.Database, {
2553
3171
  get(target, prop, recv) {
2554
3172
  if (sseWriter.started()) {
2555
- throw new Error(
2556
- `sse_db_after_write: ${hit.entry.id} touched the database after its first write(). A streaming response settles its transaction with the first frame \u2014 do the database work before the first write.`
2557
- );
3173
+ throw new Error(`sse_db_after_write: ${hit.entry.id} touched the database after its first write(). A streaming response settles its transaction with the first frame \u2014 do the database work before the first write.`);
2558
3174
  }
2559
3175
  return Reflect.get(target, prop, recv);
2560
3176
  }
@@ -2570,23 +3186,23 @@ async function createApp(opts) {
2570
3186
  }
2571
3187
  const method = hit.entry.instance[meta.fnName];
2572
3188
  if (typeof method !== "function") {
2573
- throw new Error(
2574
- `route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`
2575
- );
3189
+ throw new Error(`route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`);
2576
3190
  }
2577
3191
  return method.apply(hit.entry.instance, args);
2578
- })).then(
2579
- () => void 0,
2580
- (err) => {
2581
- thrown = err;
2582
- }
2583
- );
2584
- await Promise.race([firstFrame, ran]);
3192
+ })).then(() => void 0, (err) => {
3193
+ thrown = err;
3194
+ });
3195
+ await Promise.race([
3196
+ firstFrame,
3197
+ ran
3198
+ ]);
2585
3199
  if (!sseWriter.started()) {
2586
3200
  await ran;
2587
3201
  await db.commit();
2588
3202
  if (thrown !== null) throw thrown;
2589
- return new Response(null, { status: 204 });
3203
+ return new Response(null, {
3204
+ status: 204
3205
+ });
2590
3206
  }
2591
3207
  void (async () => {
2592
3208
  await ran;
@@ -2602,7 +3218,10 @@ async function createApp(opts) {
2602
3218
  })();
2603
3219
  return new Response(stream, {
2604
3220
  status: 200,
2605
- headers: { "content-type": SSE_CONTENT_TYPE, "cache-control": "no-cache" }
3221
+ headers: {
3222
+ "content-type": SSE_CONTENT_TYPE,
3223
+ "cache-control": "no-cache"
3224
+ }
2606
3225
  });
2607
3226
  }
2608
3227
  const result = await runWithRuntime(services, () => {
@@ -2614,9 +3233,7 @@ async function createApp(opts) {
2614
3233
  }
2615
3234
  const method = hit.entry.instance[meta.fnName];
2616
3235
  if (typeof method !== "function") {
2617
- throw new Error(
2618
- `route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`
2619
- );
3236
+ throw new Error(`route ${hit.entry.id} names method ${meta.fnName}, which the controller does not define`);
2620
3237
  }
2621
3238
  return method.apply(hit.entry.instance, args);
2622
3239
  });
@@ -2625,19 +3242,20 @@ async function createApp(opts) {
2625
3242
  const v = meta.returnSchema.safeParse(result);
2626
3243
  if (!v.success) {
2627
3244
  log.error(`[engine] ${hit.entry.id} returned a value its declared type rejects`, v.error.issues);
2628
- return envelope(
2629
- "output_invalid",
2630
- "The handler returned a value its declared return type rejects",
2631
- 500,
2632
- requestId
2633
- );
3245
+ return envelope("output_invalid", "The handler returned a value its declared return type rejects", 500, requestId);
2634
3246
  }
2635
3247
  }
2636
3248
  if (result === void 0 || result === null) {
2637
3249
  if (completionUploadId) {
2638
- completions.remember(completionUploadId, { status: 204, body: null, contentType: null });
3250
+ completions.remember(completionUploadId, {
3251
+ status: 204,
3252
+ body: null,
3253
+ contentType: null
3254
+ });
2639
3255
  }
2640
- return new Response(null, { status: 204 });
3256
+ return new Response(null, {
3257
+ status: 204
3258
+ });
2641
3259
  }
2642
3260
  const payload = JSON.stringify(result);
2643
3261
  if (completionUploadId) {
@@ -2649,7 +3267,10 @@ async function createApp(opts) {
2649
3267
  }
2650
3268
  return new Response(payload, {
2651
3269
  status: 200,
2652
- headers: attestChallengeOut ? { ...JSON_HEADERS, "x-palbase-attest-challenge": attestChallengeOut } : JSON_HEADERS
3270
+ headers: attestChallengeOut ? {
3271
+ ...JSON_HEADERS,
3272
+ "x-palbase-attest-challenge": attestChallengeOut
3273
+ } : JSON_HEADERS
2653
3274
  });
2654
3275
  } catch (err) {
2655
3276
  await db.rollback(err);
@@ -2657,18 +3278,15 @@ async function createApp(opts) {
2657
3278
  if (isEngineRaised(err) || !AUTHOR_ANSWERED.has(err.status)) {
2658
3279
  log.error(`[engine] unhandled ${err.error} in ${hit.entry.id}`, err);
2659
3280
  }
2660
- return envelope(
2661
- err.error,
2662
- err.errorDescription,
2663
- err.status,
2664
- requestId,
2665
- err.data !== void 0 ? { data: err.data } : void 0
2666
- );
3281
+ return envelope(err.error, err.errorDescription, err.status, requestId, err.data !== void 0 ? {
3282
+ data: err.data
3283
+ } : void 0);
2667
3284
  }
2668
3285
  log.error(`[engine] unhandled error in ${hit.entry.id}`, err);
2669
3286
  return envelope("internal_error", "The request could not be completed", 500, requestId);
2670
3287
  }
2671
3288
  }
3289
+ __name(handle, "handle");
2672
3290
  const bootServices = buildServices(null);
2673
3291
  let runShutdownHooks;
2674
3292
  try {
@@ -2681,18 +3299,22 @@ async function createApp(opts) {
2681
3299
  handle,
2682
3300
  routes,
2683
3301
  config,
3302
+ container: liveContainer,
2684
3303
  runInServiceScope,
2685
3304
  async shutdown() {
2686
3305
  await runShutdownHooks();
2687
3306
  await closeDriver(sql);
3307
+ released = true;
2688
3308
  }
2689
3309
  };
2690
3310
  }
3311
+ __name(createApp, "createApp");
2691
3312
  async function closeDriver(sql) {
2692
3313
  const closable = sql;
2693
3314
  await closable.close?.();
2694
3315
  await closable.end?.();
2695
3316
  }
3317
+ __name(closeDriver, "closeDriver");
2696
3318
 
2697
3319
  export {
2698
3320
  BootRefused,
@@ -2713,4 +3335,4 @@ export {
2713
3335
  installEgressFence,
2714
3336
  createApp
2715
3337
  };
2716
- //# sourceMappingURL=chunk-VDF2T4AS.js.map
3338
+ //# sourceMappingURL=chunk-OO7R25AI.js.map