@palbase/backend 30.0.1 → 33.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 (69) hide show
  1. package/dist/bin/palbase-backend.cjs +210 -24
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +7 -7
  4. package/dist/{chunk-TWX6JTGJ.js → chunk-26GH54D2.js} +3 -5
  5. package/dist/{chunk-TWX6JTGJ.js.map → chunk-26GH54D2.js.map} +1 -1
  6. package/dist/{chunk-VVMJEVQP.js → chunk-BRLJOXWS.js} +2 -2
  7. package/dist/{chunk-3TUJWHC2.js → chunk-C4ZA5AT2.js} +378 -19
  8. package/dist/chunk-C4ZA5AT2.js.map +1 -0
  9. package/dist/{chunk-RADVOY7Y.js → chunk-DCDHAKF3.js} +147 -33
  10. package/dist/chunk-DCDHAKF3.js.map +1 -0
  11. package/dist/{chunk-ENZ2RFFJ.js → chunk-GOPZPM2A.js} +3 -310
  12. package/dist/chunk-GOPZPM2A.js.map +1 -0
  13. package/dist/{chunk-CGNN2PUH.js → chunk-KATPXCJ5.js} +37 -4
  14. package/dist/{chunk-CGNN2PUH.js.map → chunk-KATPXCJ5.js.map} +1 -1
  15. package/dist/{chunk-YRVIWHJC.js → chunk-N54QZER3.js} +23 -323
  16. package/dist/chunk-N54QZER3.js.map +1 -0
  17. package/dist/chunk-QMFOL2K6.js +371 -0
  18. package/dist/chunk-QMFOL2K6.js.map +1 -0
  19. package/dist/chunk-XOX6RFPZ.js +383 -0
  20. package/dist/chunk-XOX6RFPZ.js.map +1 -0
  21. package/dist/db/index.cjs +41 -2
  22. package/dist/db/index.cjs.map +1 -1
  23. package/dist/db/index.d.cts +1 -1
  24. package/dist/db/index.d.ts +1 -1
  25. package/dist/db/index.js +12 -13
  26. package/dist/engine/index.cjs +210 -24
  27. package/dist/engine/index.cjs.map +1 -1
  28. package/dist/engine/index.d.cts +3 -3
  29. package/dist/engine/index.d.ts +3 -3
  30. package/dist/engine/index.js +7 -7
  31. package/dist/{index-DtCgaZAg.d.cts → index-BWgnGj68.d.cts} +185 -35
  32. package/dist/{index-b-Q3l7W5.d.ts → index-Bi74dcOu.d.ts} +9 -2
  33. package/dist/{index-8qy3kIuA.d.ts → index-Dg10RnZO.d.ts} +185 -35
  34. package/dist/{index-Zi7MptvP.d.cts → index-g6iQyYci.d.cts} +9 -2
  35. package/dist/index.cjs +135 -8
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +6 -23
  38. package/dist/index.d.ts +6 -23
  39. package/dist/index.js +48 -48
  40. package/dist/index.js.map +1 -1
  41. package/dist/openapi/index.d.cts +2 -2
  42. package/dist/openapi/index.d.ts +2 -2
  43. package/dist/openapi/index.js +3 -4
  44. package/dist/openapi/index.js.map +1 -1
  45. package/dist/{registry-CEYLH-Iz.d.cts → registry-6VT5RPeO.d.cts} +1 -1
  46. package/dist/{registry-BGJ-Al6F.d.ts → registry-B-sxJJN0.d.ts} +1 -1
  47. package/dist/test/index.cjs +733 -17
  48. package/dist/test/index.cjs.map +1 -1
  49. package/dist/test/index.d.cts +59 -4
  50. package/dist/test/index.d.ts +59 -4
  51. package/dist/test/index.js +56 -16
  52. package/dist/test/index.js.map +1 -1
  53. package/docs/README.md +1 -1
  54. package/docs/auth.md +102 -20
  55. package/docs/database.md +54 -0
  56. package/docs/llms-full.txt +215 -21
  57. package/docs/schema.md +58 -0
  58. package/package.json +1 -1
  59. package/template/db/public.ts +23 -0
  60. package/template/package.json +1 -1
  61. package/dist/chunk-3TUJWHC2.js.map +0 -1
  62. package/dist/chunk-ENZ2RFFJ.js.map +0 -1
  63. package/dist/chunk-RADVOY7Y.js.map +0 -1
  64. package/dist/chunk-SG4UTNOP.js +0 -374
  65. package/dist/chunk-SG4UTNOP.js.map +0 -1
  66. package/dist/chunk-VXPNPVAG.js +0 -40
  67. package/dist/chunk-VXPNPVAG.js.map +0 -1
  68. package/dist/chunk-YRVIWHJC.js.map +0 -1
  69. /package/dist/{chunk-VVMJEVQP.js.map → chunk-BRLJOXWS.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- export { f as AnyColumn, l as ColumnBuilder, m as ColumnDef, n as ColumnMap, o as ColumnType, E as EXTENSION_DEPENDENCIES, t as EmbeddingModelRef, v as EnvServiceDatabase, x as EnvTypedDatabase, O as InsertShape, W as Materialized, a1 as OnDeleteAction, a2 as PALBASE_EXTENSIONS, aC as PalbaseExtension, bz as PolicyBuilder, bA as PolicyCommand, bB as PolicyDef, bE as PolicyMode, bG as RawConstraintDef, bI as Ref, bK as RowShape, S as SchemaDef, bT as TABLE_META, bU as TableDef, bV as TableHandle, bW as TableInput, bY as TxColumnExpr, bZ as TxInsertShape, b$ as TxNow, c0 as TxPlan, T as TxPlanBody, c1 as TxPlanError, c2 as TxPlanHandle, c3 as TxPlanOpResult, c4 as TxPlanRejection, b as TxPlanResponse, c5 as TxRefError, c6 as TxRow, c7 as TxRows, c8 as TxSelectOptions, c9 as TxSetShape, cb as TxTable, cc as TxTables, cd as TxWhere, cj as TypedDB, ck as TypedTable, cl as TypedTx, cu as bigint, cv as boolean, cx as dec, cA as defineSchema, cB as defineTable, cC as enumType, cE as inc, cH as installationRef, cI as integer, cJ as isPalbaseExtension, cL as jsonb, cM as makeTypedDB, cN as now, cR as openai, cS as ownedByUser, cT as policy, cU as raw, cW as text, cX as timestamp, cY as userRef, cZ as uuid, c_ as vector } from '../index-DtCgaZAg.cjs';
1
+ export { h as AnyColumn, n as ColumnBuilder, o as ColumnDef, p as ColumnMap, q as ColumnType, v as EXTENSION_DEPENDENCIES, w as EmbeddingModelRef, E as EnvServiceDatabase, z as EnvTypedDatabase, V as InsertShape, $ as Materialized, a6 as OnDeleteAction, a8 as PALBASE_EXTENSIONS, aI as PalbaseExtension, bF as PolicyBuilder, bG as PolicyCommand, bH as PolicyDef, bK as PolicyMode, bN as RawConstraintDef, bP as Ref, bR as RowShape, S as SchemaDef, b_ as TABLE_META, b$ as TableDef, c0 as TableHandle, c1 as TableInput, c3 as TxColumnExpr, c4 as TxInsertShape, c6 as TxNow, c7 as TxPlan, T as TxPlanBody, c8 as TxPlanError, c9 as TxPlanHandle, ca as TxPlanOpResult, cb as TxPlanRejection, c as TxPlanResponse, cc as TxRefError, cd as TxRow, ce as TxRows, cf as TxSelectOptions, cg as TxSetShape, ci as TxTable, cj as TxTables, ck as TxWhere, cq as TypedDB, cr as TypedTable, cs as TypedTx, cD as bigint, cE as boolean, cG as dec, cJ as defineSchema, cK as defineTable, cL as enumType, cN as inc, cQ as installationRef, cR as integer, cS as isPalbaseExtension, cU as jsonb, cV as makeTypedDB, cW as now, c_ as openai, c$ as ownedByUser, d0 as policy, d1 as raw, d3 as text, d4 as timestamp, d5 as userRef, d6 as uuid, d7 as vector } from '../index-BWgnGj68.cjs';
2
2
  import './env.cjs';
3
3
  import '../stack.cjs';
4
4
  import 'zod';
@@ -1,4 +1,4 @@
1
- export { f as AnyColumn, l as ColumnBuilder, m as ColumnDef, n as ColumnMap, o as ColumnType, E as EXTENSION_DEPENDENCIES, t as EmbeddingModelRef, v as EnvServiceDatabase, x as EnvTypedDatabase, O as InsertShape, W as Materialized, a1 as OnDeleteAction, a2 as PALBASE_EXTENSIONS, aC as PalbaseExtension, bz as PolicyBuilder, bA as PolicyCommand, bB as PolicyDef, bE as PolicyMode, bG as RawConstraintDef, bI as Ref, bK as RowShape, S as SchemaDef, bT as TABLE_META, bU as TableDef, bV as TableHandle, bW as TableInput, bY as TxColumnExpr, bZ as TxInsertShape, b$ as TxNow, c0 as TxPlan, T as TxPlanBody, c1 as TxPlanError, c2 as TxPlanHandle, c3 as TxPlanOpResult, c4 as TxPlanRejection, b as TxPlanResponse, c5 as TxRefError, c6 as TxRow, c7 as TxRows, c8 as TxSelectOptions, c9 as TxSetShape, cb as TxTable, cc as TxTables, cd as TxWhere, cj as TypedDB, ck as TypedTable, cl as TypedTx, cu as bigint, cv as boolean, cx as dec, cA as defineSchema, cB as defineTable, cC as enumType, cE as inc, cH as installationRef, cI as integer, cJ as isPalbaseExtension, cL as jsonb, cM as makeTypedDB, cN as now, cR as openai, cS as ownedByUser, cT as policy, cU as raw, cW as text, cX as timestamp, cY as userRef, cZ as uuid, c_ as vector } from '../index-8qy3kIuA.js';
1
+ export { h as AnyColumn, n as ColumnBuilder, o as ColumnDef, p as ColumnMap, q as ColumnType, v as EXTENSION_DEPENDENCIES, w as EmbeddingModelRef, E as EnvServiceDatabase, z as EnvTypedDatabase, V as InsertShape, $ as Materialized, a6 as OnDeleteAction, a8 as PALBASE_EXTENSIONS, aI as PalbaseExtension, bF as PolicyBuilder, bG as PolicyCommand, bH as PolicyDef, bK as PolicyMode, bN as RawConstraintDef, bP as Ref, bR as RowShape, S as SchemaDef, b_ as TABLE_META, b$ as TableDef, c0 as TableHandle, c1 as TableInput, c3 as TxColumnExpr, c4 as TxInsertShape, c6 as TxNow, c7 as TxPlan, T as TxPlanBody, c8 as TxPlanError, c9 as TxPlanHandle, ca as TxPlanOpResult, cb as TxPlanRejection, c as TxPlanResponse, cc as TxRefError, cd as TxRow, ce as TxRows, cf as TxSelectOptions, cg as TxSetShape, ci as TxTable, cj as TxTables, ck as TxWhere, cq as TypedDB, cr as TypedTable, cs as TypedTx, cD as bigint, cE as boolean, cG as dec, cJ as defineSchema, cK as defineTable, cL as enumType, cN as inc, cQ as installationRef, cR as integer, cS as isPalbaseExtension, cU as jsonb, cV as makeTypedDB, cW as now, c_ as openai, c$ as ownedByUser, d0 as policy, d1 as raw, d3 as text, d4 as timestamp, d5 as userRef, d6 as uuid, d7 as vector } from '../index-Dg10RnZO.js';
2
2
  import './env.js';
3
3
  import '../stack.js';
4
4
  import 'zod';
package/dist/db/index.js CHANGED
@@ -3,37 +3,36 @@ import {
3
3
  PALBASE_EXTENSIONS,
4
4
  PolicyBuilder,
5
5
  TABLE_META,
6
- bigint,
7
- boolean,
8
6
  defineSchema,
9
7
  defineTable,
8
+ isPalbaseExtension,
9
+ openai,
10
+ policy,
11
+ raw
12
+ } from "../chunk-GOPZPM2A.js";
13
+ import {
14
+ bigint,
15
+ boolean,
10
16
  enumType,
11
17
  installationRef,
12
18
  integer,
13
- isPalbaseExtension,
14
19
  jsonb,
15
- openai,
16
20
  ownedByUser,
17
- policy,
18
- raw,
19
21
  text,
20
22
  timestamp,
21
23
  userRef,
22
24
  uuid,
23
25
  vector
24
- } from "../chunk-ENZ2RFFJ.js";
25
- import {
26
- makeTypedDB
27
- } from "../chunk-SG4UTNOP.js";
26
+ } from "../chunk-XOX6RFPZ.js";
28
27
  import {
29
28
  TxPlanError,
30
29
  TxRefError,
31
30
  dec,
32
31
  inc,
32
+ makeTypedDB,
33
33
  now
34
- } from "../chunk-3TUJWHC2.js";
35
- import "../chunk-CGNN2PUH.js";
36
- import "../chunk-VXPNPVAG.js";
34
+ } from "../chunk-C4ZA5AT2.js";
35
+ import "../chunk-KATPXCJ5.js";
37
36
  export {
38
37
  EXTENSION_DEPENDENCIES,
39
38
  PALBASE_EXTENSIONS,
@@ -863,7 +863,11 @@ function qualifiedTableKey(schemaName, tableName) {
863
863
  __name(qualifiedTableKey, "qualifiedTableKey");
864
864
 
865
865
  // src/runtime.ts
866
- var __requestALS = new import_node_async_hooks.AsyncLocalStorage();
866
+ var REQUEST_ALS = /* @__PURE__ */ Symbol.for("palbase.backend.requestALS");
867
+ var __requestALS = (() => {
868
+ const g = globalThis;
869
+ return g[REQUEST_ALS] ??= new import_node_async_hooks.AsyncLocalStorage();
870
+ })();
867
871
  var runtime = null;
868
872
  function __runWithRuntime(services, fn) {
869
873
  return __requestALS.run({
@@ -871,9 +875,29 @@ function __runWithRuntime(services, fn) {
871
875
  }, fn);
872
876
  }
873
877
  __name(__runWithRuntime, "__runWithRuntime");
878
+ var REQUIRED_SERVICES = [
879
+ "Database",
880
+ "Auth",
881
+ "Secrets",
882
+ "Documents",
883
+ "Storage",
884
+ "Cache",
885
+ "Log",
886
+ "Notifications",
887
+ "Flags",
888
+ "Realtime"
889
+ ];
890
+ function refuseIncompleteBox(services) {
891
+ const missing = REQUIRED_SERVICES.filter((k) => services[k] === void 0);
892
+ if (missing.length > 0) {
893
+ throw new Error(`the request scope is missing ${missing.join(", ")} \u2014 this box was most likely written by a DIFFERENT @palbase/backend major sharing the same process (the request store is a process-wide well-known Symbol, deliberately, so two bundles of ONE version can share it). Align the versions, or pass every service when building the scope yourself.`);
894
+ }
895
+ return services;
896
+ }
897
+ __name(refuseIncompleteBox, "refuseIncompleteBox");
874
898
  function __getRuntime() {
875
899
  const scoped = __requestALS.getStore();
876
- if (scoped) return scoped.runtime;
900
+ if (scoped) return refuseIncompleteBox(scoped.runtime);
877
901
  if (runtime === null) {
878
902
  throw new Error("Palbase services accessed outside a request scope. The Database/Documents/\u2026 singletons are only available inside an endpoint handler (or after the runtime has called __runWithRuntime / __setRuntime).");
879
903
  }
@@ -996,7 +1020,12 @@ function makeTypedSurface(raw) {
996
1020
  $findById: /* @__PURE__ */ __name((table, id) => raw.findById(table, id), "$findById"),
997
1021
  $findMany: /* @__PURE__ */ __name((table, query, opts) => raw.findMany(table, query, opts), "$findMany"),
998
1022
  $put: /* @__PURE__ */ __name((table, data, opts) => raw.put(table, data, opts), "$put"),
999
- $updateMany: /* @__PURE__ */ __name((table, where, set) => raw.updateMany(table, where, set), "$updateMany"),
1023
+ // `opts` İLETİLİR. Düşürüldüğü sürece `Database.$updateMany(t, w, s,
1024
+ // { returning: false })` sessizce SATIRLARI döndürüyordu, sayıyı değil —
1025
+ // ve `if (n === 0) throw new Conflict(...)` guard'ı HİÇ çalışmıyordu,
1026
+ // çünkü `[] === 0` yanlıştır. Komşu forwarder'lar (`$findMany`, `$put`)
1027
+ // kendi opsiyonlarını zaten iletiyordu; bu biri unutulmuştu.
1028
+ $updateMany: /* @__PURE__ */ __name((table, where, set, opts) => raw.updateMany(table, where, set, opts), "$updateMany"),
1000
1029
  $deleteMany: /* @__PURE__ */ __name((table, where) => raw.deleteMany(table, where), "$deleteMany"),
1001
1030
  $count: /* @__PURE__ */ __name((table, where) => raw.count(table, where), "$count"),
1002
1031
  $search: /* @__PURE__ */ __name((table, params) => raw.search(table, params), "$search"),
@@ -1127,10 +1156,23 @@ var Flags = Object.assign({
1127
1156
  * Lazily resolve the runtime's cross-user sibling on each call. We do NOT
1128
1157
  * cache it: `rawFlags.asService()` reads the CURRENT request scope through
1129
1158
  * the runtime proxy, so caching would leak one request's sibling into
1130
- * another concurrent request. Mirrors `Database.asService()`.
1159
+ * another concurrent request. Mirrors `Database.$asService()`.
1131
1160
  */
1132
- asService() {
1161
+ $asService() {
1133
1162
  return rawFlags.asService();
1163
+ },
1164
+ /**
1165
+ * The name this member carried before 32.0.0.
1166
+ *
1167
+ * It does NOT work silently. A retired member that quietly keeps returning
1168
+ * is how a rename becomes a mystery: the old call site goes on compiling,
1169
+ * the new name never spreads, and the two live side by side until somebody
1170
+ * greps for one and misses half the codebase. `Database` made this split
1171
+ * first (`$asService`), and this JSDoc promised "exactly like
1172
+ * Database.$asService()" while the promise went unkept.
1173
+ */
1174
+ asService() {
1175
+ throw new Error("Flags.asService() was renamed to Flags.$asService() in 32.0.0 \u2014 system members carry the `$` prefix, like Database.$asService().");
1134
1176
  }
1135
1177
  });
1136
1178
  var Realtime = makeServiceProxy("Realtime");
@@ -1503,6 +1545,37 @@ function makeMemoryCache(opts = {}) {
1503
1545
  }
1504
1546
  __name(makeMemoryCache, "makeMemoryCache");
1505
1547
 
1548
+ // src/db/columns.ts
1549
+ var CODECS = {
1550
+ // Exact-precision column → JS number. Safe below 2^53; a value above it is
1551
+ // not representable and the author wants `asDecimal()` instead.
1552
+ number: {
1553
+ fromDb: /* @__PURE__ */ __name((v) => Number(v), "fromDb"),
1554
+ // YAZMA YOLUNDA SESSİZ BOZULMA YOK. `toDb(9007199254740993)` bir zamanlar
1555
+ // "9007199254740992" yazıyordu: uygulamanın tuttuğundan BAŞKA bir sayı
1556
+ // kolona gidiyordu ve hiçbir şey söylemiyordu. `asNumber()`'ın JSDoc'u
1557
+ // "2^53'ün altında güvenli" diyordu ama bunu uygulayan bir şey yoktu.
1558
+ toDb: /* @__PURE__ */ __name((v) => {
1559
+ if (typeof v === "number" && !Number.isSafeInteger(v)) {
1560
+ throw new Error(`asNumber() cannot write ${v}: it is outside the safe integer range and would be stored as a different number. Declare .asDecimal() and hand this column a string.`);
1561
+ }
1562
+ return String(v);
1563
+ }, "toDb"),
1564
+ tsType: "number"
1565
+ },
1566
+ // Exact-precision column → the string Postgres sent. It exists so the
1567
+ // DECLARATION is explicit: "this column is a decimal I handle as text",
1568
+ // rather than the ABSENCE of a declaration meaning the same thing by default.
1569
+ // NULL güvencesi ÇİFTİN KENDİSİNDE. Motor NULL'ı zaten atlıyor (üç ayrı
1570
+ // yerde), ama bir değişmez, onu koruyan üç `if`'in DIŞINDA yazılmalı: biri
1571
+ // düşerse `String(null)` kolonu "null" dizesine çevirirdi.
1572
+ decimal: {
1573
+ fromDb: /* @__PURE__ */ __name((v) => v === null || v === void 0 ? v : String(v), "fromDb"),
1574
+ toDb: /* @__PURE__ */ __name((v) => v === null || v === void 0 ? v : String(v), "toDb"),
1575
+ tsType: "string"
1576
+ }
1577
+ };
1578
+
1506
1579
  // src/db/env-gen.ts
1507
1580
  function forwardName(column) {
1508
1581
  return column.endsWith("_id") ? column.slice(0, -3) : column;
@@ -1716,6 +1789,15 @@ function transformsOf(schema, table) {
1716
1789
  if (def) {
1717
1790
  for (const [col, c] of Object.entries(def.columns ?? {})) {
1718
1791
  const d = c !== null && typeof c === "object" && "_def" in c ? c._def : c;
1792
+ const codec = d?.codec;
1793
+ if (typeof codec === "string" && codec in CODECS) {
1794
+ const c2 = CODECS[codec];
1795
+ out.set(col, {
1796
+ fromDb: c2.fromDb,
1797
+ toDb: c2.toDb
1798
+ });
1799
+ continue;
1800
+ }
1719
1801
  const t = d?.transform;
1720
1802
  if (t !== null && typeof t === "object") {
1721
1803
  out.set(col, t);
@@ -2051,6 +2133,29 @@ function selectClause(table, known, select) {
2051
2133
  }).join(", ");
2052
2134
  }
2053
2135
  __name(selectClause, "selectClause");
2136
+ function quoteLiteral(v) {
2137
+ return `'${v.replace(/'/g, "''")}'`;
2138
+ }
2139
+ __name(quoteLiteral, "quoteLiteral");
2140
+ function orderClauseFor(table, known, orderBy, alias) {
2141
+ if (orderBy === void 0 || orderBy === null) return "";
2142
+ const items = Array.isArray(orderBy) ? orderBy : [
2143
+ orderBy
2144
+ ];
2145
+ if (items.length === 0) return "";
2146
+ const rendered = items.map((o) => {
2147
+ const col = o.column;
2148
+ const shapeOK = /^[A-Za-z_][A-Za-z0-9_]*$/.test(col);
2149
+ if (known !== null ? !known.has(col) : !shapeOK) {
2150
+ throw new Error(`with(${table}): orderBy kolonu "${col}" tabloda yok`);
2151
+ }
2152
+ const dir = o.direction === "desc" ? "DESC" : "ASC";
2153
+ const nulls = o.nulls === "first" ? " NULLS FIRST" : o.nulls === "last" ? " NULLS LAST" : "";
2154
+ return `${alias}.${quoteIdent(col)} ${dir}${nulls}`;
2155
+ });
2156
+ return ` ORDER BY ${rendered.join(", ")}`;
2157
+ }
2158
+ __name(orderClauseFor, "orderClauseFor");
2054
2159
  function orderClause(table, known, orderBy) {
2055
2160
  if (!orderBy) return "";
2056
2161
  const items = Array.isArray(orderBy) ? orderBy : [
@@ -2354,6 +2459,65 @@ function aggregateExpr(table, fn, col, alias) {
2354
2459
  return t !== null && NUMERIC_PG_TYPES.has(t) && t !== "integer" ? `${fn}(${q})::text AS ${quoteIdent(alias)}` : `${fn}(${q}) AS ${quoteIdent(alias)}`;
2355
2460
  }
2356
2461
  __name(aggregateExpr, "aggregateExpr");
2462
+ function jsonObjectFor(table, cols, alias) {
2463
+ const pairs = cols.map((c) => {
2464
+ const t = columnTypeOf(table, c);
2465
+ const expr = t !== null && (t === "numeric" || t === "bigint") ? `${alias}.${quoteIdent(c)}::text` : `${alias}.${quoteIdent(c)}`;
2466
+ return `${quoteLiteral(c)}, ${expr}`;
2467
+ });
2468
+ return `json_build_object(${pairs.join(", ")})`;
2469
+ }
2470
+ __name(jsonObjectFor, "jsonObjectFor");
2471
+ function withClauses(table, spec, add, caller) {
2472
+ const rels = currentRelations.get(table) ?? [];
2473
+ const select = [];
2474
+ const joins = [];
2475
+ let i = 0;
2476
+ for (const [name, opt] of Object.entries(spec)) {
2477
+ if (opt === false || opt === void 0) continue;
2478
+ const rel = rels.find((r) => r.name === name);
2479
+ if (rel === void 0) {
2480
+ const known = rels.map((r) => r.name).sort();
2481
+ throw new Error(`${caller}(${table}): with.${name} diye bir ili\u015Fki yok` + (known.length > 0 ? ` (bilinenler: ${known.join(", ")})` : `. Bu tablo hi\xE7 yabanc\u0131 anahtar bildirmiyor ve ili\u015Fkiler onlardan T\xDCRET\u0130L\u0130R`) + `. \u0130li\u015Fkiler references(() => <tablo>.<kolon>) ile bildirilir.`);
2482
+ }
2483
+ const ourCol = rel.kind === "many" ? primaryKeyOf(table) : rel.via;
2484
+ const theirCol = rel.kind === "many" ? rel.via : primaryKeyOf(rel.to);
2485
+ if (ourCol === null || theirCol === null) {
2486
+ throw new Error(`${caller}(${table}): with.${name} birincil anahtar bilmeden kurulamaz \u2014 ili\u015Fkinin bir ucu tablonun PK's\u0131 ve bu tablo tek kolonlu bir PK bildirmiyor.`);
2487
+ }
2488
+ const o = typeof opt === "object" && opt !== null ? opt : {};
2489
+ const childAlias = `w${++i}`;
2490
+ const childKnown = schemaColumns(rel.to);
2491
+ const childCols = Array.isArray(o["select"]) && o["select"].length > 0 ? o["select"] : childKnown !== null ? [
2492
+ ...childKnown
2493
+ ] : [];
2494
+ if (childCols.length === 0) {
2495
+ throw new Error(`${caller}(${table}): with.${name} i\xE7in "${rel.to}" tablosunun kolonlar\u0131 bilinmiyor \u2014 select ile hangi kolonlar\u0131 istedi\u011Finizi yaz\u0131n.`);
2496
+ }
2497
+ for (const c of childCols) {
2498
+ if (childKnown !== null && !childKnown.has(c)) {
2499
+ throw new Error(`${caller}(${table}): with.${name}.select kolonu "${c}" "${rel.to}" tablosunda yok`);
2500
+ }
2501
+ }
2502
+ const obj = jsonObjectFor(rel.to, childCols, childAlias);
2503
+ const innerWhere = o["where"] !== void 0 && o["where"] !== null ? compileWhereBare(rel.to, childKnown, o["where"], add, caller, childAlias, i) : "";
2504
+ const link = `${childAlias}.${quoteIdent(theirCol)} = t.${quoteIdent(ourCol)}`;
2505
+ const cond = innerWhere === "" ? link : `${link} AND ${innerWhere}`;
2506
+ const inner = orderClauseFor(rel.to, childKnown, o["orderBy"], childAlias) + limitClause(o["limit"]);
2507
+ const outAlias = `wj${i}`;
2508
+ if (rel.kind === "many") {
2509
+ joins.push(`LEFT JOIN LATERAL (SELECT coalesce(json_agg(x.o), '[]'::json) AS d FROM (SELECT ${obj} AS o FROM ${quoteTable(rel.to)} ${childAlias} WHERE ${cond}${inner}) x) ${quoteIdent(outAlias)} ON true`);
2510
+ } else {
2511
+ joins.push(`LEFT JOIN LATERAL (SELECT ${obj} AS d FROM ${quoteTable(rel.to)} ${childAlias} WHERE ${cond}${inner} LIMIT 1) ${quoteIdent(outAlias)} ON true`);
2512
+ }
2513
+ select.push(`${quoteIdent(outAlias)}."d" AS ${quoteIdent(name)}`);
2514
+ }
2515
+ return {
2516
+ select,
2517
+ joins
2518
+ };
2519
+ }
2520
+ __name(withClauses, "withClauses");
2357
2521
  function createOps(tx) {
2358
2522
  const at = /* @__PURE__ */ __name(() => resolveTx(tx), "at");
2359
2523
  const ops = {
@@ -2797,7 +2961,13 @@ function createOps(tx) {
2797
2961
  const limit = limitClause(opts.limit);
2798
2962
  const offset = offsetClause(opts.offset, opts.limit);
2799
2963
  const cols = selectClause(table, known, opts.select);
2800
- const sql = `SELECT ${cols} FROM ${quoteTable(table)} t WHERE true${whereSql}${order}${limit}${offset}`;
2964
+ const w = opts.with !== void 0 && Object.keys(opts.with).length > 0 ? withClauses(table, opts.with, add, "findMany") : {
2965
+ select: [],
2966
+ joins: []
2967
+ };
2968
+ const selectList = w.select.length > 0 ? `${cols === "*" ? "t.*" : cols}, ${w.select.join(", ")}` : cols;
2969
+ const joinSql = w.joins.length > 0 ? ` ${w.joins.join(" ")}` : "";
2970
+ const sql = `SELECT ${selectList} FROM ${quoteTable(table)} t${joinSql} WHERE true${whereSql}${order}${limit}${offset}`;
2801
2971
  return asTableRows(table, await (await at()).unsafe(sql, params));
2802
2972
  },
2803
2973
  /**
@@ -4727,23 +4897,21 @@ async function createApp(opts) {
4727
4897
  if (spec.required && !callerClaims) {
4728
4898
  return envelope("unauthorized", "A valid access token is required", 401, requestId);
4729
4899
  }
4730
- if (callerClaims) {
4731
- const uploadDb = createRequestDatabase(sql, {
4732
- role: config.dbRole,
4733
- serviceRole: config.dbServiceRole,
4734
- claimsJson: JSON.stringify(callerClaims)
4735
- });
4736
- try {
4737
- const refusal = await refuseUnlessAuthorized(uploadDb.client, spec, requestId, makeRoleResolver(uploadDb.client));
4738
- if (refusal) {
4739
- await uploadDb.commit();
4740
- return refusal;
4741
- }
4900
+ const uploadDb = createRequestDatabase(sql, {
4901
+ role: config.dbRole,
4902
+ serviceRole: config.dbServiceRole,
4903
+ claimsJson: JSON.stringify(callerClaims ?? {})
4904
+ });
4905
+ try {
4906
+ const refusal = await refuseUnlessAuthorized(uploadDb.client, spec, requestId, makeRoleResolver(uploadDb.client));
4907
+ if (refusal) {
4742
4908
  await uploadDb.commit();
4743
- } catch (err) {
4744
- await uploadDb.rollback(err);
4745
- throw err;
4909
+ return refusal;
4746
4910
  }
4911
+ await uploadDb.commit();
4912
+ } catch (err) {
4913
+ await uploadDb.rollback(err);
4914
+ throw err;
4747
4915
  }
4748
4916
  const grant = grantFor(target?.entry, {
4749
4917
  userId: typeof callerClaims?.sub === "string" ? callerClaims.sub : null,
@@ -4782,11 +4950,18 @@ async function createApp(opts) {
4782
4950
  claimsJson: JSON.stringify(claims ?? {})
4783
4951
  });
4784
4952
  const rolesOfCaller = makeRoleResolver(db.client);
4785
- if (claims) {
4786
- const refusal = await refuseUnlessAuthorized(db.client, spec, requestId, rolesOfCaller);
4787
- if (refusal) return refusal;
4953
+ let dispatched = false;
4954
+ const settleBeforeRefusal = /* @__PURE__ */ __name(async () => {
4955
+ if (dispatched) return;
4956
+ await db.rollback(new Error("request refused before dispatch"));
4957
+ }, "settleBeforeRefusal");
4958
+ const refusal = await refuseUnlessAuthorized(db.client, spec, requestId, rolesOfCaller);
4959
+ if (refusal) {
4960
+ await settleBeforeRefusal();
4961
+ return refusal;
4788
4962
  }
4789
4963
  if (claims && spec.verifiedEmail && claims.email_verified !== true) {
4964
+ await settleBeforeRefusal();
4790
4965
  return envelope("email_not_verified", "A verified email address is required", 403, requestId);
4791
4966
  }
4792
4967
  let parsedBody;
@@ -4795,6 +4970,7 @@ async function createApp(opts) {
4795
4970
  if (req.method !== "GET" && req.method !== "HEAD") {
4796
4971
  const declared = Number(req.headers.get("content-length") ?? "");
4797
4972
  if (Number.isFinite(declared) && declared > MAX_BODY_BYTES) {
4973
+ await settleBeforeRefusal();
4798
4974
  return new Response(JSON.stringify({
4799
4975
  error: "payload_too_large",
4800
4976
  error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
@@ -4807,6 +4983,7 @@ async function createApp(opts) {
4807
4983
  }
4808
4984
  const buf = await req.arrayBuffer().catch(() => null);
4809
4985
  if (buf && buf.byteLength > MAX_BODY_BYTES) {
4986
+ await settleBeforeRefusal();
4810
4987
  return new Response(JSON.stringify({
4811
4988
  error: "payload_too_large",
4812
4989
  error_description: `Request body exceeds ${MAX_BODY_BYTES} bytes`,
@@ -4842,6 +5019,7 @@ async function createApp(opts) {
4842
5019
  ...JSON_HEADERS
4843
5020
  };
4844
5021
  if (attest.nextChallenge) headers["x-palbase-attest-challenge"] = attest.nextChallenge;
5022
+ await settleBeforeRefusal();
4845
5023
  return new Response(JSON.stringify({
4846
5024
  error: attest.reason,
4847
5025
  error_description: "This endpoint requires a verified app instance",
@@ -4856,6 +5034,7 @@ async function createApp(opts) {
4856
5034
  attestChallengeOut = attest.nextChallenge;
4857
5035
  const retryAfter = limiter.check(meta.options?.rateLimit, RateLimiter.key(hit.entry.id, userId, req.headers), Date.now());
4858
5036
  if (retryAfter !== null) {
5037
+ await settleBeforeRefusal();
4859
5038
  return new Response(JSON.stringify({
4860
5039
  error: "too_many_requests",
4861
5040
  error_description: "Rate limit exceeded for this endpoint",
@@ -4887,6 +5066,7 @@ async function createApp(opts) {
4887
5066
  readParsedBody();
4888
5067
  const r = p.schema.safeParse(parsedBody);
4889
5068
  if (!r.success) {
5069
+ await settleBeforeRefusal();
4890
5070
  return envelope("bad_request", "Request body failed validation", 400, requestId, {
4891
5071
  data: {
4892
5072
  fields: fieldErrors(r.error)
@@ -4899,6 +5079,7 @@ async function createApp(opts) {
4899
5079
  case "query": {
4900
5080
  const r = p.schema.safeParse(Object.fromEntries(url.searchParams));
4901
5081
  if (!r.success) {
5082
+ await settleBeforeRefusal();
4902
5083
  return envelope("bad_request", "Query parameters failed validation", 400, requestId, {
4903
5084
  data: {
4904
5085
  fields: fieldErrors(r.error)
@@ -4919,6 +5100,7 @@ async function createApp(opts) {
4919
5100
  }
4920
5101
  const r = p.schema.safeParse(headersFor(raw, p.schema));
4921
5102
  if (!r.success) {
5103
+ await settleBeforeRefusal();
4922
5104
  return envelope("bad_request", "Request headers failed validation", 400, requestId, {
4923
5105
  data: {
4924
5106
  fields: fieldErrors(r.error)
@@ -4951,17 +5133,20 @@ async function createApp(opts) {
4951
5133
  break;
4952
5134
  case "uploadedObject": {
4953
5135
  if (uploadSecret === "" || !verifySignature(req.headers.get(SIGNATURE_HEADER) ?? "", uploadSecret)) {
5136
+ await settleBeforeRefusal();
4954
5137
  return envelope("unauthorized", "This endpoint accepts uploads through storage, not directly", 401, requestId);
4955
5138
  }
4956
5139
  readParsedBody();
4957
5140
  const envelopeIn = parsedBody;
4958
5141
  if (!envelopeIn?.uploadedObject) {
5142
+ await settleBeforeRefusal();
4959
5143
  return envelope("bad_request", "the completion call carried no uploaded object", 400, requestId);
4960
5144
  }
4961
5145
  const uploadId = envelopeIn.uploadedObject.uploadId;
4962
5146
  if (typeof uploadId === "string" && uploadId !== "") {
4963
5147
  const already = completions.recall(uploadId);
4964
5148
  if (already) {
5149
+ await settleBeforeRefusal();
4965
5150
  return new Response(already.body, {
4966
5151
  status: already.status,
4967
5152
  headers: already.contentType ? {
@@ -5011,6 +5196,7 @@ async function createApp(opts) {
5011
5196
  args[p.index] = void 0;
5012
5197
  }
5013
5198
  }
5199
+ dispatched = true;
5014
5200
  try {
5015
5201
  const services = buildServices(db);
5016
5202
  if (meta.options?.sseConfig !== void 0) {