@palbase/backend 33.0.2 → 34.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/bin/palbase-backend.cjs +2273 -358
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +9 -7
  4. package/dist/bin/palbase-backend.js.map +1 -1
  5. package/dist/{chunk-YIQ4RS4F.js → chunk-5UGPXKMJ.js} +331 -5
  6. package/dist/chunk-5UGPXKMJ.js.map +1 -0
  7. package/dist/chunk-GHNC2UHS.js +20 -0
  8. package/dist/chunk-GHNC2UHS.js.map +1 -0
  9. package/dist/{chunk-AAT5G7KY.js → chunk-JJW3L62T.js} +2 -2
  10. package/dist/chunk-JJW3L62T.js.map +1 -0
  11. package/dist/{chunk-SI4KGEM3.js → chunk-P7MGSAFT.js} +102 -96
  12. package/dist/chunk-P7MGSAFT.js.map +1 -0
  13. package/dist/{chunk-XOX6RFPZ.js → chunk-PRH45NZU.js} +46 -3
  14. package/dist/chunk-PRH45NZU.js.map +1 -0
  15. package/dist/{chunk-26GH54D2.js → chunk-RZLY4BOY.js} +5 -3
  16. package/dist/{chunk-26GH54D2.js.map → chunk-RZLY4BOY.js.map} +1 -1
  17. package/dist/{chunk-KATPXCJ5.js → chunk-UMESJJRS.js} +19 -40
  18. package/dist/chunk-UMESJJRS.js.map +1 -0
  19. package/dist/chunk-VXPNPVAG.js +40 -0
  20. package/dist/chunk-VXPNPVAG.js.map +1 -0
  21. package/dist/{chunk-WWUG2QXF.js → chunk-X2UYIXDS.js} +59 -4
  22. package/dist/chunk-X2UYIXDS.js.map +1 -0
  23. package/dist/{chunk-C6COAB3E.js → chunk-XZPDPYVY.js} +1905 -195
  24. package/dist/chunk-XZPDPYVY.js.map +1 -0
  25. package/dist/{chunk-TVCCR6SO.js → chunk-YO5GYM73.js} +58 -9
  26. package/dist/chunk-YO5GYM73.js.map +1 -0
  27. package/dist/db/env.cjs.map +1 -1
  28. package/dist/db/env.d.cts +2 -0
  29. package/dist/db/env.d.ts +2 -0
  30. package/dist/db/index.cjs +285 -2
  31. package/dist/db/index.cjs.map +1 -1
  32. package/dist/db/index.d.cts +46 -3
  33. package/dist/db/index.d.ts +46 -3
  34. package/dist/db/index.js +14 -5
  35. package/dist/{index-DMZG3kpo.d.ts → endpoint-BXPdsTA5.d.ts} +370 -58
  36. package/dist/{index-DB_nW-AV.d.cts → endpoint-DqhUP7RT.d.cts} +370 -58
  37. package/dist/engine/index.cjs +2279 -356
  38. package/dist/engine/index.cjs.map +1 -1
  39. package/dist/engine/index.d.cts +5 -5
  40. package/dist/engine/index.d.ts +5 -5
  41. package/dist/engine/index.js +17 -7
  42. package/dist/{index-DLveQoOf.d.cts → index-Co0Hj_aO.d.cts} +108 -50
  43. package/dist/{index-D-3duy8Y.d.ts → index-MhCL7ll4.d.ts} +108 -50
  44. package/dist/index.cjs +806 -386
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.d.cts +7 -6
  47. package/dist/index.d.ts +7 -6
  48. package/dist/index.js +27 -15
  49. package/dist/index.js.map +1 -1
  50. package/dist/openapi/index.cjs +7 -0
  51. package/dist/openapi/index.cjs.map +1 -1
  52. package/dist/openapi/index.d.cts +3 -3
  53. package/dist/openapi/index.d.ts +3 -3
  54. package/dist/openapi/index.js +4 -3
  55. package/dist/openapi/index.js.map +1 -1
  56. package/dist/{registry-DSTThhKf.d.cts → registry-BkIVHPzB.d.cts} +3 -1
  57. package/dist/{registry-JjF5lcj4.d.ts → registry-CvGLR5j1.d.ts} +3 -1
  58. package/dist/test/index.cjs +103 -66
  59. package/dist/test/index.cjs.map +1 -1
  60. package/dist/test/index.d.cts +3 -3
  61. package/dist/test/index.d.ts +3 -3
  62. package/dist/test/index.js +33 -7
  63. package/dist/test/index.js.map +1 -1
  64. package/docs/README.md +1 -1
  65. package/docs/auth.md +58 -0
  66. package/docs/database.md +308 -0
  67. package/docs/examples/check-query-contracts.ts +5 -0
  68. package/docs/examples/database-dx.contract.json +65 -0
  69. package/docs/examples/database-dx.ts +63 -0
  70. package/docs/examples/money-transfer.ts +73 -0
  71. package/docs/llms-full.txt +382 -1
  72. package/docs/schema.md +15 -0
  73. package/package.json +1 -2
  74. package/template/db/public.ts +12 -0
  75. package/template/package.json +1 -1
  76. package/dist/chunk-AAT5G7KY.js.map +0 -1
  77. package/dist/chunk-C6COAB3E.js.map +0 -1
  78. package/dist/chunk-KATPXCJ5.js.map +0 -1
  79. package/dist/chunk-SI4KGEM3.js.map +0 -1
  80. package/dist/chunk-TVCCR6SO.js.map +0 -1
  81. package/dist/chunk-WWUG2QXF.js.map +0 -1
  82. package/dist/chunk-XOX6RFPZ.js.map +0 -1
  83. package/dist/chunk-YIQ4RS4F.js.map +0 -1
  84. package/stack-images.json +0 -24
package/dist/index.cjs CHANGED
@@ -102,11 +102,13 @@ __export(src_exports, {
102
102
  __runWithRuntime: () => __runWithRuntime,
103
103
  __setRuntime: () => __setRuntime,
104
104
  assertNoOrphanEntryPoints: () => assertNoOrphanEntryPoints,
105
+ assertQueryManifest: () => assertQueryManifest,
105
106
  assertZeroArgConstructor: () => assertZeroArgConstructor,
106
107
  bigint: () => bigint,
107
108
  boolean: () => boolean,
108
109
  buildContainer: () => buildContainer,
109
110
  buildModuleClients: () => buildModuleClients,
111
+ can: () => can,
110
112
  col: () => col,
111
113
  controllersOf: () => controllersOf,
112
114
  dec: () => dec,
@@ -115,8 +117,10 @@ __export(src_exports, {
115
117
  defineDefaultAuth: () => defineDefaultAuth,
116
118
  defineError: () => defineError,
117
119
  defineMiddleware: () => defineMiddleware,
120
+ defineQuery: () => defineQuery,
118
121
  defineSchema: () => defineSchema,
119
122
  defineTable: () => defineTable,
123
+ defineWorkload: () => defineWorkload,
120
124
  enumType: () => enumType,
121
125
  exprCtx: () => exprCtx,
122
126
  getErrorRegistry: () => getErrorRegistry,
@@ -152,6 +156,7 @@ __export(src_exports, {
152
156
  ownerOnly: () => ownerOnly,
153
157
  policy: () => policy,
154
158
  publicChannel: () => publicChannel,
159
+ queryManifest: () => queryManifest,
155
160
  raw: () => raw,
156
161
  recordThrows: () => recordThrows,
157
162
  resolveEffectiveAuth: () => resolveEffectiveAuth,
@@ -165,7 +170,7 @@ __export(src_exports, {
165
170
  vector: () => vector,
166
171
  webhooksOf: () => webhooksOf,
167
172
  withRetry: () => withRetry,
168
- z: () => import_zod2.z
173
+ z: () => import_zod4.z
169
174
  });
170
175
  module.exports = __toCommonJS(src_exports);
171
176
 
@@ -741,260 +746,54 @@ function translateRejection(err, builder) {
741
746
  }
742
747
  __name(translateRejection, "translateRejection");
743
748
 
744
- // src/errors.ts
745
- var HTTP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("palbase.backend.httpError");
746
- var HttpError = class extends Error {
747
- static {
748
- __name(this, "HttpError");
749
- }
750
- status;
751
- error;
752
- errorDescription;
753
- data;
754
- /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */
755
- [HTTP_ERROR_BRAND] = true;
756
- constructor(status, error, errorDescription, data) {
757
- super(errorDescription);
758
- this.name = "HttpError";
759
- this.status = status;
760
- this.error = error;
761
- this.errorDescription = errorDescription;
762
- if (data !== void 0) {
763
- this.data = data;
764
- }
765
- }
766
- /**
767
- * Serialize to the standard Palbase error response format.
768
- * The `requestId` is injected by the runtime layer from the request context.
769
- * When called without arguments (e.g. JSON.stringify), request_id is omitted.
770
- * When `data` is set, it is appended as a strict-superset field.
771
- */
772
- toJSON(requestId) {
773
- const result = {
774
- error: this.error,
775
- error_description: this.errorDescription,
776
- status: this.status
777
- };
778
- if (requestId) {
779
- result.request_id = requestId;
780
- }
781
- if (this.data !== void 0) {
782
- result.data = this.data;
783
- }
784
- return result;
785
- }
786
- };
787
- var PalError = class extends HttpError {
788
- static {
789
- __name(this, "PalError");
790
- }
791
- constructor(status, code, description, data) {
792
- super(status, code, description, data);
793
- this.name = "PalError";
794
- }
795
- };
796
- var NamedHttpError = class NamedHttpError2 extends HttpError {
797
- static {
798
- __name(this, "NamedHttpError");
799
- }
800
- constructor(status, defaultCode, name, message, code, data) {
801
- super(status, code ?? defaultCode, message ?? defaultMessage(name), data);
802
- this.name = name;
803
- }
804
- };
805
- function defaultMessage(name) {
806
- const spaced = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
807
- return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
808
- }
809
- __name(defaultMessage, "defaultMessage");
810
- var BadRequest = class extends NamedHttpError {
811
- static {
812
- __name(this, "BadRequest");
813
- }
814
- constructor(data, message) {
815
- super(400, "bad_request", "BadRequest", message, void 0, data);
816
- }
817
- };
818
- var Unauthorized = class extends NamedHttpError {
819
- static {
820
- __name(this, "Unauthorized");
821
- }
822
- constructor(message, code, data) {
823
- super(401, "unauthorized", "Unauthorized", message, code, data);
824
- }
825
- };
826
- var Forbidden = class extends NamedHttpError {
827
- static {
828
- __name(this, "Forbidden");
829
- }
830
- constructor(message, code, data) {
831
- super(403, "forbidden", "Forbidden", message, code, data);
832
- }
833
- };
834
- var NotFound = class extends NamedHttpError {
835
- static {
836
- __name(this, "NotFound");
837
- }
838
- constructor(message, code, data) {
839
- super(404, "not_found", "NotFound", message, code, data);
840
- }
841
- };
842
- var Conflict = class extends NamedHttpError {
843
- static {
844
- __name(this, "Conflict");
845
- }
846
- constructor(message, code, data) {
847
- super(409, "conflict", "Conflict", message, code, data);
848
- }
849
- };
850
- var UniqueViolation = class extends Conflict {
851
- static {
852
- __name(this, "UniqueViolation");
853
- }
854
- /**
855
- * Whether `e` is a unique violation — REGARDLESS of which copy of this SDK
856
- * constructed it.
857
- *
858
- * Use this instead of `instanceof`. Measured on a live stack: a controller
859
- * bundle INLINES its own copy of `@palbase/backend`, and the engine that
860
- * raises this error is the runtime's copy. Two copies, two class identities,
861
- * and `e instanceof UniqueViolation` is false in the one place a caller
862
- * writes it — a check that reads as correct and silently never matches.
863
- */
864
- static is(e) {
865
- return typeof e === "object" && e !== null && e.name === "UniqueViolation" && typeof e.constraint === "string";
866
- }
867
- /** The unique constraint the statement violated, as Postgres named it.
868
- * `""` when the driver did not say which — see `engine/db.ts`. */
869
- constraint;
870
- constructor(constraint, message, code, data) {
871
- super(message ?? "Unique constraint violated", code ?? "unique_violation", data);
872
- this.name = "UniqueViolation";
873
- this.constraint = constraint;
874
- }
875
- };
876
- function isRetryable(e) {
877
- return typeof e === "object" && e !== null && e.retryable === true && typeof e.sqlstate === "string";
878
- }
879
- __name(isRetryable, "isRetryable");
880
- var SerializationFailure = class extends Conflict {
881
- static {
882
- __name(this, "SerializationFailure");
883
- }
884
- retryable = true;
885
- sqlstate;
886
- static is(e) {
887
- return typeof e === "object" && e !== null && e.name === "SerializationFailure";
888
- }
889
- constructor(sqlstate = "40001", message, data) {
890
- super(message ?? "i\u015Flem e\u015Fzamanl\u0131 bir i\u015Flemle serile\u015Ftirilemedi \u2014 ayn\u0131 i\u015Flemi ba\u015Ftan \xE7al\u0131\u015Ft\u0131r\u0131n ($transaction'a { retry: n } verebilirsiniz)", "serialization_failure", data);
891
- this.name = "SerializationFailure";
892
- this.sqlstate = sqlstate;
893
- }
894
- };
895
- var DeadlockDetected = class extends Conflict {
896
- static {
897
- __name(this, "DeadlockDetected");
898
- }
899
- retryable = true;
900
- sqlstate;
901
- static is(e) {
902
- return typeof e === "object" && e !== null && e.name === "DeadlockDetected";
903
- }
904
- constructor(sqlstate = "40P01", message, data) {
905
- super(message ?? "deadlock: iki i\u015Flem birbirinin kilidini bekledi ve bu i\u015Flem iptal edildi \u2014 kilit s\u0131ras\u0131n\u0131 sabitlemek i\xE7in Database.$lockRows(tablo, id'ler) kullan\u0131n", "deadlock_detected", data);
906
- this.name = "DeadlockDetected";
907
- this.sqlstate = sqlstate;
908
- }
909
- };
910
- var TooManyRequests = class extends NamedHttpError {
911
- static {
912
- __name(this, "TooManyRequests");
913
- }
914
- constructor(data, message) {
915
- super(429, "too_many_requests", "TooManyRequests", message, void 0, data);
916
- }
917
- };
918
-
919
- // src/db/typed-db.ts
920
- function makeTypedTable(name, raw2) {
921
- return {
922
- insert: /* @__PURE__ */ __name((data) => raw2.insert(name, data), "insert"),
923
- aggregate: /* @__PURE__ */ __name((q) => raw2.aggregate(name, q), "aggregate"),
924
- insertMany: /* @__PURE__ */ __name((rows, opts) => raw2.insertMany(name, rows, opts), "insertMany"),
925
- put: /* @__PURE__ */ __name((q) => raw2.put(name, q.data, {
926
- onConflict: q.onConflict
927
- }), "put"),
928
- update: /* @__PURE__ */ __name((q) => raw2.update(name, q.where.id, q.set), "update"),
929
- delete: /* @__PURE__ */ __name((id) => raw2.delete(name, id), "delete"),
930
- findById: /* @__PURE__ */ __name((id) => raw2.findById(name, id), "findById"),
931
- findMany: /* @__PURE__ */ __name((q) => {
932
- const { where, ...opts } = q ?? {};
933
- return raw2.findMany(name, where, opts);
934
- }, "findMany"),
935
- updateMany: /* @__PURE__ */ __name((q) => raw2.updateMany(name, q.where, q.set, q.returning === void 0 ? void 0 : {
936
- returning: q.returning
937
- }), "updateMany"),
938
- deleteMany: /* @__PURE__ */ __name((q) => raw2.deleteMany(name, q.where), "deleteMany"),
939
- count: /* @__PURE__ */ __name((q) => raw2.count(name, q?.where), "count")
940
- };
941
- }
942
- __name(makeTypedTable, "makeTypedTable");
943
- function makeTypedDB(schema, raw2) {
944
- const tables = {};
945
- for (const key of Object.keys(schema.tables)) {
946
- const tableDef = schema.tables[key];
947
- if (tableDef !== void 0) {
948
- tables[key] = makeTypedTable(tableDef.name, raw2);
949
- }
950
- }
749
+ // src/db/workload.ts
750
+ function defineWorkload(name, options) {
951
751
  const result = {
952
- tables,
953
- transaction(fn) {
954
- const builder = new TxPlanBuilder();
955
- const planTables = {};
956
- for (const key of Object.keys(schema.tables)) {
957
- const tableDef = schema.tables[key];
958
- if (tableDef !== void 0) planTables[key] = builder.table(tableDef.name);
959
- }
960
- return runTxPlan(raw2, {
961
- tables: planTables
962
- }, builder, fn);
963
- }
752
+ name,
753
+ concurrency: options.concurrency,
754
+ queueLimit: options.queueLimit,
755
+ tenantConcurrency: options.tenantConcurrency ?? options.concurrency,
756
+ tenantQueueLimit: options.tenantQueueLimit ?? options.queueLimit,
757
+ queueTimeoutMs: options.queueTimeoutMs ?? 1e3,
758
+ tenantClaim: options.tenantClaim ?? "tenant_id"
964
759
  };
965
- return result;
966
- }
967
- __name(makeTypedDB, "makeTypedDB");
968
- function col(name) {
969
- return brandRef({
970
- $col: name
971
- }, "col");
972
- }
973
- __name(col, "col");
974
- async function withRetry(fn, opts = {}) {
975
- const budget = opts.retry ?? 0;
976
- let attempt = 0;
977
- for (; ; ) {
978
- try {
979
- return await fn();
980
- } catch (e) {
981
- if (attempt >= budget || !isRetryable(e)) throw e;
982
- attempt += 1;
983
- }
760
+ validateWorkload(result);
761
+ return Object.freeze(result);
762
+ }
763
+ __name(defineWorkload, "defineWorkload");
764
+ function validateWorkload(value) {
765
+ if (typeof value.name !== "string" || !/^[a-zA-Z][a-zA-Z0-9_.-]{0,63}$/.test(value.name)) throw new Error("workload name must be 1\u201364 letters/digits/dots/dashes");
766
+ for (const name of [
767
+ "concurrency",
768
+ "tenantConcurrency",
769
+ "queueLimit",
770
+ "tenantQueueLimit",
771
+ "queueTimeoutMs"
772
+ ]) {
773
+ const n = value[name], min = name.endsWith("Limit") ? 0 : 1;
774
+ const max = name === "queueTimeoutMs" ? 6e4 : name.endsWith("Limit") ? 1e4 : 1e3;
775
+ if (!Number.isInteger(n) || n < min || n > max) throw new Error(`workload ${name} must be an integer between ${min} and ${max}`);
776
+ }
777
+ if (value.tenantConcurrency > value.concurrency || value.tenantQueueLimit > value.queueLimit) throw new Error("workload tenant limits cannot exceed global limits");
778
+ if (typeof value.tenantClaim !== "string" || !/^[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(value.tenantClaim)) throw new Error("workload tenantClaim must be a top-level claim name");
779
+ }
780
+ __name(validateWorkload, "validateWorkload");
781
+
782
+ // src/db/transaction-options.ts
783
+ function retryBudget(value) {
784
+ const n = value ?? 0;
785
+ if (!Number.isInteger(n) || n < 0 || n > 10) {
786
+ throw new Error("transaction retry must be an integer between 0 and 10");
984
787
  }
788
+ return n;
985
789
  }
986
- __name(withRetry, "withRetry");
987
- function sqlFragment(strings, ...values) {
988
- return brandRef({
989
- $sql: {
990
- text: [
991
- ...strings
992
- ],
993
- values
994
- }
995
- }, "sql");
790
+ __name(retryBudget, "retryBudget");
791
+ function assertPlanRetry(options) {
792
+ if (retryBudget(options?.retry) !== 0) {
793
+ throw new Error("Database.$transaction is a savepoint plan on the request transaction and cannot retry its snapshot or COMMIT. Use Database.$atomic(async tx => { ... }, { retry, isolation }) and put all decision reads and writes inside that callback.");
794
+ }
996
795
  }
997
- __name(sqlFragment, "sqlFragment");
796
+ __name(assertPlanRetry, "assertPlanRetry");
998
797
 
999
798
  // src/db/schema-json.ts
1000
799
  function defOf(column) {
@@ -1177,6 +976,11 @@ function tableToJSON(table, schemaName) {
1177
976
  // drifts — the direction it drifted last time was "expose everything", and
1178
977
  // the live proof was one user reading another's rows.
1179
978
  rls: table.rls,
979
+ // KOŞAN SÜRÜMÜN SÖZÜ TELE ÇIKAR — yoksa daralma kapısı onu göremez.
980
+ // `ColumnJSON.ignored` ile aynı sözleşme: işaretlenmemişse alan YOK.
981
+ ...table.ignored === true ? {
982
+ ignored: true
983
+ } : {},
1180
984
  policies: (table.policies ?? []).map(policyToJSON)
1181
985
  };
1182
986
  if (table.primaryKey !== void 0 && table.primaryKey.length > 0) {
@@ -1407,6 +1211,14 @@ function makeTableProxy(ops, prefix) {
1407
1211
  update: /* @__PURE__ */ __name((q) => ops().update(name, q.where.id, q.set), "update"),
1408
1212
  delete: /* @__PURE__ */ __name((id) => ops().delete(name, id), "delete"),
1409
1213
  findById: /* @__PURE__ */ __name((id) => ops().findById(name, id), "findById"),
1214
+ findUnique: /* @__PURE__ */ __name((q) => ops().findUnique(name, q.where, {
1215
+ select: q.select,
1216
+ with: q.with
1217
+ }), "findUnique"),
1218
+ page: /* @__PURE__ */ __name((q) => {
1219
+ const { where, ...opts } = q ?? {};
1220
+ return ops().page(name, where, opts);
1221
+ }, "page"),
1410
1222
  findMany: /* @__PURE__ */ __name((q) => {
1411
1223
  const { where, ...opts } = q ?? {};
1412
1224
  return ops().findMany(name, where, opts);
@@ -1444,10 +1256,16 @@ function makeTypedSurface(raw2) {
1444
1256
  const reco = raw2;
1445
1257
  const ops = {
1446
1258
  $query: /* @__PURE__ */ __name((sql, params) => raw2.query(sql, params), "$query"),
1259
+ $diagnostics: /* @__PURE__ */ __name(() => raw2.diagnostics(), "$diagnostics"),
1260
+ $readQuery: /* @__PURE__ */ __name((query) => raw2.readQuery(query), "$readQuery"),
1261
+ $compileQuery: /* @__PURE__ */ __name((query) => raw2.compileQuery(query), "$compileQuery"),
1262
+ $explainQuery: /* @__PURE__ */ __name((query) => raw2.explainQuery(query), "$explainQuery"),
1447
1263
  $insert: /* @__PURE__ */ __name((table, data) => raw2.insert(table, data), "$insert"),
1448
1264
  $update: /* @__PURE__ */ __name((table, id, data) => raw2.update(table, id, data), "$update"),
1449
1265
  $delete: /* @__PURE__ */ __name((table, id) => raw2.delete(table, id), "$delete"),
1450
1266
  $findById: /* @__PURE__ */ __name((table, id) => raw2.findById(table, id), "$findById"),
1267
+ $findUnique: /* @__PURE__ */ __name((table, where, opts) => raw2.findUnique(table, where, opts), "$findUnique"),
1268
+ $page: /* @__PURE__ */ __name((table, query, opts) => raw2.page(table, query, opts), "$page"),
1451
1269
  $findMany: /* @__PURE__ */ __name((table, query, opts) => raw2.findMany(table, query, opts), "$findMany"),
1452
1270
  $put: /* @__PURE__ */ __name((table, data, opts) => raw2.put(table, data, opts), "$put"),
1453
1271
  // `opts` İLETİLİR. Düşürüldüğü sürece `Database.$updateMany(t, w, s,
@@ -1470,16 +1288,51 @@ function makeTypedSurface(raw2) {
1470
1288
  $supersede: /* @__PURE__ */ __name((table, id, row) => raw2.supersede(table, id, row), "$supersede")
1471
1289
  };
1472
1290
  const base = Object.assign(ops, {
1291
+ $atomic(fn, options) {
1292
+ if (typeof raw2.atomic !== "function") {
1293
+ throw new Error("This Database handle cannot open a root transaction; nested $atomic is not supported");
1294
+ }
1295
+ const parent = __requestALS.getStore();
1296
+ let runtime2;
1297
+ try {
1298
+ runtime2 = __getRuntime();
1299
+ } catch {
1300
+ }
1301
+ return raw2.atomic(async (tx) => {
1302
+ const typed = makeTypedSurface(tx);
1303
+ const invoke = /* @__PURE__ */ __name(() => fn(typed), "invoke");
1304
+ if (!runtime2) return invoke();
1305
+ const refuse2 = /* @__PURE__ */ __name(() => {
1306
+ throw new Error("Database.$atomic owns one transaction and identity; nested roots and $asService are not allowed");
1307
+ }, "refuse");
1308
+ const ambient = Object.assign({}, tx, {
1309
+ atomic: refuse2,
1310
+ asService: refuse2
1311
+ });
1312
+ return __requestALS.run({
1313
+ ...parent,
1314
+ runtime: {
1315
+ ...runtime2,
1316
+ Database: ambient
1317
+ }
1318
+ }, invoke);
1319
+ }, options);
1320
+ },
1473
1321
  // Both surfaces get it: a savepoint on the service transaction is as useful
1474
1322
  // as one on the request's, and each is bound to its own connection.
1475
1323
  $attempt: /* @__PURE__ */ __name((fn) => raw2.attempt(fn), "$attempt"),
1476
1324
  $transaction(fn, opts) {
1477
- return withRetry(() => {
1478
- const builder = new TxPlanBuilder();
1479
- return runTxPlan(raw2, makeTxPlanHandle(builder), builder, fn);
1480
- }, opts ?? {});
1481
- }
1482
- });
1325
+ assertPlanRetry(opts);
1326
+ const builder = new TxPlanBuilder();
1327
+ return runTxPlan(raw2, makeTxPlanHandle(builder), builder, fn);
1328
+ },
1329
+ $command(fn, options) {
1330
+ const builder = new TxPlanBuilder();
1331
+ return runTxPlan({
1332
+ txPlan: /* @__PURE__ */ __name((plan) => raw2.command(plan, options), "txPlan")
1333
+ }, makeTxPlanHandle(builder), builder, fn);
1334
+ }
1335
+ });
1483
1336
  return new Proxy(base, {
1484
1337
  get(target, prop, receiver) {
1485
1338
  if (prop === "tables") return makeTableProxy(() => reco, "");
@@ -2738,6 +2591,7 @@ function buildModuleClients(cfg) {
2738
2591
  __name(buildModuleClients, "buildModuleClients");
2739
2592
 
2740
2593
  // src/db/policy.ts
2594
+ var import_zod = require("zod");
2741
2595
  var PolicyExprRef = class _PolicyExprRef {
2742
2596
  static {
2743
2597
  __name(this, "PolicyExprRef");
@@ -2970,6 +2824,45 @@ function policy(name) {
2970
2824
  return new PolicyBuilder(name);
2971
2825
  }
2972
2826
  __name(policy, "policy");
2827
+ function can(table) {
2828
+ const def = table;
2829
+ if (typeof def.name !== "string" || def.columns === null || typeof def.columns !== "object" || !Array.isArray(def.policies)) {
2830
+ throw new Error("can(<table>): expects the schema's table definition \u2014 can(publicSchema.tables.notes) \u2014 not the defineTable handle (`notes`)");
2831
+ }
2832
+ if (Object.prototype.hasOwnProperty.call(table.columns, "can")) {
2833
+ throw new Error(`can(${table.name}): the table declares a column named "can", so the row carries that column and no policy echo \u2014 rename the column to get can`);
2834
+ }
2835
+ const rel = reservedCanRelation(table.name, table.columns);
2836
+ if (rel !== null) {
2837
+ throw new Error(`can(${table.name}): ${rel}`);
2838
+ }
2839
+ const names = table.policies.filter((p) => p.command === "update" && p.permissive !== false && Buffer.byteLength(`can:${p.name}`, "utf8") <= 63).map((p) => p.name);
2840
+ if (names.length === 0) {
2841
+ const all = table.policies.filter((p) => p.command === "all").map((p) => p.name);
2842
+ const hint = all.length > 0 ? ` The table's ${all.map((n) => `"${n}"`).join(", ")} ${all.length === 1 ? "policy is" : "policies are"} for("all") \u2014 for("all") governs UPDATE but is not a named update policy and never appears in can.` : "";
2843
+ throw new Error(`can(${table.name}): the table declares no update policy \u2014 there is nothing a row could echo. Name one with policy("<name>").for("update").using(\u2026) first.${hint}`);
2844
+ }
2845
+ return import_zod.z.array(import_zod.z.enum(names));
2846
+ }
2847
+ __name(can, "can");
2848
+ function reservedCanRelation(tableName, columns) {
2849
+ if (tableName === "can") {
2850
+ return `a table named "can" would put a relation named "can" on every parent it references \u2014 rename the table`;
2851
+ }
2852
+ for (const [col2, b] of Object.entries(columns)) {
2853
+ const def = b._def;
2854
+ if (def.referencesThunk === void 0 && def.selfRefColumn === void 0) continue;
2855
+ if (def.reverseAs === "can") {
2856
+ return `column "${col2}" names its reverse relation "can" \u2014 the parent's rows would carry a relation where can is reserved; pick another reverseAs`;
2857
+ }
2858
+ const forward = def.owns === true ? "owner" : def.refAs ?? (col2.endsWith("_id") ? col2.slice(0, -3) : col2);
2859
+ if (forward === "can") {
2860
+ return `column "${col2}" would be read as a relation named "can" (${def.refAs === void 0 ? "derived from the column name" : "its as: option"}) \u2014 can is reserved for the policy echo; rename it`;
2861
+ }
2862
+ }
2863
+ return null;
2864
+ }
2865
+ __name(reservedCanRelation, "reservedCanRelation");
2973
2866
 
2974
2867
  // src/db/schema.ts
2975
2868
  var IndexBuilder = class {
@@ -3047,6 +2940,10 @@ function defineTable(name, input) {
3047
2940
  if (name.trim() === "") {
3048
2941
  throw new Error("defineTable(name, \u2026): name must not be empty");
3049
2942
  }
2943
+ {
2944
+ const reserved = reservedCanRelation(name, input.columns);
2945
+ if (reserved !== null) throw new Error(`defineTable(${JSON.stringify(name)}): ${reserved}`);
2946
+ }
3050
2947
  const policies = (input.policies?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map(toPolicyDef);
3051
2948
  const rls = policies.length > 0 || input.rls !== false;
3052
2949
  const owned2 = {};
@@ -3075,6 +2972,7 @@ function defineTable(name, input) {
3075
2972
  const declaredIndexes = (input.indexes?.(exprCtx(Object.keys(input.columns), 0, name)) ?? []).map((i) => i instanceof IndexBuilder ? i._def : i);
3076
2973
  if (declaredIndexes.length > 0) def.indexes = declaredIndexes;
3077
2974
  if (input.appendOnly === true) def.appendOnly = true;
2975
+ if (input.ignored === true) def.ignored = true;
3078
2976
  if (input.search !== void 0) {
3079
2977
  const s = input.search;
3080
2978
  if (s.from !== void 0) {
@@ -3134,6 +3032,13 @@ function defineTable(name, input) {
3134
3032
  }
3135
3033
  __name(defineTable, "defineTable");
3136
3034
  var declaringSchemaOf = /* @__PURE__ */ new WeakMap();
3035
+ function declaredTableKey(table) {
3036
+ const metadata = table[TABLE_META];
3037
+ const schema = declaringSchemaOf.get(metadata);
3038
+ if (schema === void 0) throw new Error(`defineQuery: table ${metadata.name} must belong to defineSchema before defining its query`);
3039
+ return qualifiedTableKey(schema, metadata.name);
3040
+ }
3041
+ __name(declaredTableKey, "declaredTableKey");
3137
3042
  function resolveReferences(tables, schemaName) {
3138
3043
  for (const table of Object.values(tables)) {
3139
3044
  for (const [colName, builder] of Object.entries(table.columns)) {
@@ -3603,135 +3508,424 @@ var ColumnBuilder = class _ColumnBuilder {
3603
3508
  codec
3604
3509
  });
3605
3510
  }
3606
- transform(fns) {
3607
- if (this._def.codec !== void 0) {
3608
- throw new Error(`column already declares a named codec; .transform() and .as*() are two ways to say the same thing \u2014 keep the codec.`);
3609
- }
3610
- return new _ColumnBuilder(this._def.type, {
3611
- ...this._def,
3612
- transform: fns
3613
- });
3511
+ transform(fns) {
3512
+ if (this._def.codec !== void 0) {
3513
+ throw new Error(`column already declares a named codec; .transform() and .as*() are two ways to say the same thing \u2014 keep the codec.`);
3514
+ }
3515
+ return new _ColumnBuilder(this._def.type, {
3516
+ ...this._def,
3517
+ transform: fns
3518
+ });
3519
+ }
3520
+ };
3521
+ function uuid() {
3522
+ return new ColumnBuilder("uuid");
3523
+ }
3524
+ __name(uuid, "uuid");
3525
+ function text() {
3526
+ return new ColumnBuilder("text");
3527
+ }
3528
+ __name(text, "text");
3529
+ function integer() {
3530
+ return new ColumnBuilder("integer");
3531
+ }
3532
+ __name(integer, "integer");
3533
+ function bigint() {
3534
+ return new ColumnBuilder("bigint");
3535
+ }
3536
+ __name(bigint, "bigint");
3537
+ function numeric() {
3538
+ return new ColumnBuilder("numeric");
3539
+ }
3540
+ __name(numeric, "numeric");
3541
+ function boolean() {
3542
+ return new ColumnBuilder("boolean");
3543
+ }
3544
+ __name(boolean, "boolean");
3545
+ function timestamp() {
3546
+ return new ColumnBuilder("timestamp");
3547
+ }
3548
+ __name(timestamp, "timestamp");
3549
+ function jsonb() {
3550
+ return new ColumnBuilder("jsonb");
3551
+ }
3552
+ __name(jsonb, "jsonb");
3553
+ function enumType(name, values) {
3554
+ const builder = new ColumnBuilder("enum");
3555
+ builder._def.enumName = name;
3556
+ builder._def.enumValues = [
3557
+ ...values
3558
+ ];
3559
+ return builder;
3560
+ }
3561
+ __name(enumType, "enumType");
3562
+ function vector(dimensions) {
3563
+ if (!Number.isInteger(dimensions) || dimensions < 1 || dimensions > 2e3) {
3564
+ throw new Error(`vector(): dimensions must be an integer in [1, 2000], got ${String(dimensions)}`);
3565
+ }
3566
+ const b = new ColumnBuilder("vector");
3567
+ b._def.dimensions = dimensions;
3568
+ return b;
3569
+ }
3570
+ __name(vector, "vector");
3571
+ function ownedByUser() {
3572
+ const b = new ColumnBuilder("text");
3573
+ b._def.nullable = false;
3574
+ b._def.references = {
3575
+ table: "auth.users",
3576
+ column: "id"
3577
+ };
3578
+ b._def.onDeleteAction = "cascade";
3579
+ b._def.owns = true;
3580
+ return b;
3581
+ }
3582
+ __name(ownedByUser, "ownedByUser");
3583
+ function userRef(opts) {
3584
+ const b = new ColumnBuilder("text");
3585
+ b._def.references = {
3586
+ table: "auth.users",
3587
+ column: "id"
3588
+ };
3589
+ b._def.onDeleteAction = opts.onDelete;
3590
+ if (opts.as !== void 0) b._def.refAs = opts.as;
3591
+ return b;
3592
+ }
3593
+ __name(userRef, "userRef");
3594
+ function installationRef(opts) {
3595
+ const b = new ColumnBuilder("text");
3596
+ b._def.references = {
3597
+ table: "auth.installations",
3598
+ column: "id"
3599
+ };
3600
+ b._def.onDeleteAction = opts.onDelete;
3601
+ if (opts.as !== void 0) b._def.refAs = opts.as;
3602
+ return b;
3603
+ }
3604
+ __name(installationRef, "installationRef");
3605
+
3606
+ // src/db/raw.ts
3607
+ function raw(name, up, opts) {
3608
+ return {
3609
+ name,
3610
+ up,
3611
+ ...opts?.down != null ? {
3612
+ down: opts.down
3613
+ } : {}
3614
+ };
3615
+ }
3616
+ __name(raw, "raw");
3617
+
3618
+ // src/db/embedding.ts
3619
+ var openai = {
3620
+ embedding(model, opts) {
3621
+ return {
3622
+ provider: "openai",
3623
+ model,
3624
+ apiKeyName: opts?.apiKeyName ?? "OPENAI_API_KEY",
3625
+ ...opts?.dimensions !== void 0 ? {
3626
+ dimensions: opts.dimensions
3627
+ } : {},
3628
+ ...opts?.baseURL !== void 0 ? {
3629
+ baseURL: opts.baseURL
3630
+ } : {}
3631
+ };
3632
+ },
3633
+ chat(model) {
3634
+ return {
3635
+ provider: "openai",
3636
+ model
3637
+ };
3638
+ }
3639
+ };
3640
+
3641
+ // src/db/sqlstate.ts
3642
+ var SQLSTATE = Object.freeze({
3643
+ serializationFailure: "40001",
3644
+ deadlockDetected: "40P01",
3645
+ commandGuardFailed: "PBC01"
3646
+ });
3647
+ function isTransactionRollbackState(state) {
3648
+ return state === SQLSTATE.serializationFailure || state === SQLSTATE.deadlockDetected;
3649
+ }
3650
+ __name(isTransactionRollbackState, "isTransactionRollbackState");
3651
+
3652
+ // src/errors.ts
3653
+ var HTTP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("palbase.backend.httpError");
3654
+ var HttpError = class extends Error {
3655
+ static {
3656
+ __name(this, "HttpError");
3657
+ }
3658
+ status;
3659
+ error;
3660
+ errorDescription;
3661
+ data;
3662
+ /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */
3663
+ [HTTP_ERROR_BRAND] = true;
3664
+ constructor(status, error, errorDescription, data) {
3665
+ super(errorDescription);
3666
+ this.name = "HttpError";
3667
+ this.status = status;
3668
+ this.error = error;
3669
+ this.errorDescription = errorDescription;
3670
+ if (data !== void 0) {
3671
+ this.data = data;
3672
+ }
3673
+ }
3674
+ /**
3675
+ * Serialize to the standard Palbase error response format.
3676
+ * The `requestId` is injected by the runtime layer from the request context.
3677
+ * When called without arguments (e.g. JSON.stringify), request_id is omitted.
3678
+ * When `data` is set, it is appended as a strict-superset field.
3679
+ */
3680
+ toJSON(requestId) {
3681
+ const result = {
3682
+ error: this.error,
3683
+ error_description: this.errorDescription,
3684
+ status: this.status
3685
+ };
3686
+ if (requestId) {
3687
+ result.request_id = requestId;
3688
+ }
3689
+ if (this.data !== void 0) {
3690
+ result.data = this.data;
3691
+ }
3692
+ return result;
3693
+ }
3694
+ };
3695
+ var PalError = class extends HttpError {
3696
+ static {
3697
+ __name(this, "PalError");
3698
+ }
3699
+ constructor(status, code, description, data) {
3700
+ super(status, code, description, data);
3701
+ this.name = "PalError";
3702
+ }
3703
+ };
3704
+ var NamedHttpError = class NamedHttpError2 extends HttpError {
3705
+ static {
3706
+ __name(this, "NamedHttpError");
3707
+ }
3708
+ constructor(status, defaultCode, name, message, code, data) {
3709
+ super(status, code ?? defaultCode, message ?? defaultMessage(name), data);
3710
+ this.name = name;
3711
+ }
3712
+ };
3713
+ function defaultMessage(name) {
3714
+ const spaced = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
3715
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
3716
+ }
3717
+ __name(defaultMessage, "defaultMessage");
3718
+ var BadRequest = class extends NamedHttpError {
3719
+ static {
3720
+ __name(this, "BadRequest");
3721
+ }
3722
+ constructor(data, message) {
3723
+ super(400, "bad_request", "BadRequest", message, void 0, data);
3724
+ }
3725
+ };
3726
+ var Unauthorized = class extends NamedHttpError {
3727
+ static {
3728
+ __name(this, "Unauthorized");
3729
+ }
3730
+ constructor(message, code, data) {
3731
+ super(401, "unauthorized", "Unauthorized", message, code, data);
3732
+ }
3733
+ };
3734
+ var Forbidden = class extends NamedHttpError {
3735
+ static {
3736
+ __name(this, "Forbidden");
3737
+ }
3738
+ constructor(message, code, data) {
3739
+ super(403, "forbidden", "Forbidden", message, code, data);
3740
+ }
3741
+ };
3742
+ var NotFound = class extends NamedHttpError {
3743
+ static {
3744
+ __name(this, "NotFound");
3745
+ }
3746
+ constructor(message, code, data) {
3747
+ super(404, "not_found", "NotFound", message, code, data);
3748
+ }
3749
+ };
3750
+ var Conflict = class extends NamedHttpError {
3751
+ static {
3752
+ __name(this, "Conflict");
3753
+ }
3754
+ constructor(message, code, data) {
3755
+ super(409, "conflict", "Conflict", message, code, data);
3756
+ }
3757
+ };
3758
+ var UniqueViolation = class extends Conflict {
3759
+ static {
3760
+ __name(this, "UniqueViolation");
3761
+ }
3762
+ /**
3763
+ * Whether `e` is a unique violation — REGARDLESS of which copy of this SDK
3764
+ * constructed it.
3765
+ *
3766
+ * Use this instead of `instanceof`. Measured on a live stack: a controller
3767
+ * bundle INLINES its own copy of `@palbase/backend`, and the engine that
3768
+ * raises this error is the runtime's copy. Two copies, two class identities,
3769
+ * and `e instanceof UniqueViolation` is false in the one place a caller
3770
+ * writes it — a check that reads as correct and silently never matches.
3771
+ */
3772
+ static is(e) {
3773
+ return typeof e === "object" && e !== null && e.name === "UniqueViolation" && typeof e.constraint === "string";
3774
+ }
3775
+ /** The unique constraint the statement violated, as Postgres named it.
3776
+ * `""` when the driver did not say which — see `engine/db.ts`. */
3777
+ constraint;
3778
+ constructor(constraint, message, code, data) {
3779
+ super(message ?? "Unique constraint violated", code ?? "unique_violation", data);
3780
+ this.name = "UniqueViolation";
3781
+ this.constraint = constraint;
3782
+ }
3783
+ };
3784
+ function isRetryable(e) {
3785
+ return typeof e === "object" && e !== null && e.retryable === true && isTransactionRollbackState(e.sqlstate);
3786
+ }
3787
+ __name(isRetryable, "isRetryable");
3788
+ var SerializationFailure = class extends Conflict {
3789
+ static {
3790
+ __name(this, "SerializationFailure");
3791
+ }
3792
+ retryable = true;
3793
+ sqlstate;
3794
+ static is(e) {
3795
+ return typeof e === "object" && e !== null && e.name === "SerializationFailure";
3796
+ }
3797
+ constructor(sqlstate = SQLSTATE.serializationFailure, message, data) {
3798
+ super(message ?? "i\u015Flem e\u015Fzamanl\u0131 bir i\u015Flemle serile\u015Ftirilemedi \u2014 ayn\u0131 i\u015Flemi ba\u015Ftan \xE7al\u0131\u015Ft\u0131r\u0131n (karar okumalar\u0131 ve yazmalar\u0131 $atomic i\xE7ine al\u0131p { retry: n } verin)", "serialization_failure", data);
3799
+ this.name = "SerializationFailure";
3800
+ this.sqlstate = sqlstate;
3801
+ }
3802
+ };
3803
+ var DeadlockDetected = class extends Conflict {
3804
+ static {
3805
+ __name(this, "DeadlockDetected");
3806
+ }
3807
+ retryable = true;
3808
+ sqlstate;
3809
+ static is(e) {
3810
+ return typeof e === "object" && e !== null && e.name === "DeadlockDetected";
3811
+ }
3812
+ constructor(sqlstate = SQLSTATE.deadlockDetected, message, data) {
3813
+ super(message ?? "deadlock: iki i\u015Flem birbirinin kilidini bekledi ve bu i\u015Flem iptal edildi \u2014 kilit s\u0131ras\u0131n\u0131 sabitlemek i\xE7in Database.$lockRows(tablo, id'ler) kullan\u0131n", "deadlock_detected", data);
3814
+ this.name = "DeadlockDetected";
3815
+ this.sqlstate = sqlstate;
3816
+ }
3817
+ };
3818
+ var TooManyRequests = class extends NamedHttpError {
3819
+ static {
3820
+ __name(this, "TooManyRequests");
3821
+ }
3822
+ constructor(data, message) {
3823
+ super(429, "too_many_requests", "TooManyRequests", message, void 0, data);
3614
3824
  }
3615
3825
  };
3616
- function uuid() {
3617
- return new ColumnBuilder("uuid");
3618
- }
3619
- __name(uuid, "uuid");
3620
- function text() {
3621
- return new ColumnBuilder("text");
3622
- }
3623
- __name(text, "text");
3624
- function integer() {
3625
- return new ColumnBuilder("integer");
3626
- }
3627
- __name(integer, "integer");
3628
- function bigint() {
3629
- return new ColumnBuilder("bigint");
3630
- }
3631
- __name(bigint, "bigint");
3632
- function numeric() {
3633
- return new ColumnBuilder("numeric");
3634
- }
3635
- __name(numeric, "numeric");
3636
- function boolean() {
3637
- return new ColumnBuilder("boolean");
3638
- }
3639
- __name(boolean, "boolean");
3640
- function timestamp() {
3641
- return new ColumnBuilder("timestamp");
3642
- }
3643
- __name(timestamp, "timestamp");
3644
- function jsonb() {
3645
- return new ColumnBuilder("jsonb");
3646
- }
3647
- __name(jsonb, "jsonb");
3648
- function enumType(name, values) {
3649
- const builder = new ColumnBuilder("enum");
3650
- builder._def.enumName = name;
3651
- builder._def.enumValues = [
3652
- ...values
3653
- ];
3654
- return builder;
3826
+
3827
+ // src/db/typed-db.ts
3828
+ function makeTypedTable(name, raw2) {
3829
+ return {
3830
+ insert: /* @__PURE__ */ __name((data) => raw2.insert(name, data), "insert"),
3831
+ aggregate: /* @__PURE__ */ __name((q) => raw2.aggregate(name, q), "aggregate"),
3832
+ insertMany: /* @__PURE__ */ __name((rows, opts) => raw2.insertMany(name, rows, opts), "insertMany"),
3833
+ put: /* @__PURE__ */ __name((q) => raw2.put(name, q.data, {
3834
+ onConflict: q.onConflict
3835
+ }), "put"),
3836
+ update: /* @__PURE__ */ __name((q) => raw2.update(name, q.where.id, q.set), "update"),
3837
+ delete: /* @__PURE__ */ __name((id) => raw2.delete(name, id), "delete"),
3838
+ findUnique: /* @__PURE__ */ __name((q) => raw2.findUnique(name, q.where, {
3839
+ select: q.select
3840
+ }), "findUnique"),
3841
+ findById: /* @__PURE__ */ __name((id) => raw2.findById(name, id), "findById"),
3842
+ page: /* @__PURE__ */ __name((q) => {
3843
+ const { where, ...opts } = q ?? {};
3844
+ return raw2.page(name, where, opts);
3845
+ }, "page"),
3846
+ findMany: /* @__PURE__ */ __name((q) => {
3847
+ const { where, ...opts } = q ?? {};
3848
+ return raw2.findMany(name, where, opts);
3849
+ }, "findMany"),
3850
+ updateMany: /* @__PURE__ */ __name((q) => raw2.updateMany(name, q.where, q.set, q.returning === void 0 ? void 0 : {
3851
+ returning: q.returning
3852
+ }), "updateMany"),
3853
+ deleteMany: /* @__PURE__ */ __name((q) => raw2.deleteMany(name, q.where), "deleteMany"),
3854
+ count: /* @__PURE__ */ __name((q) => raw2.count(name, q?.where), "count")
3855
+ };
3655
3856
  }
3656
- __name(enumType, "enumType");
3657
- function vector(dimensions) {
3658
- if (!Number.isInteger(dimensions) || dimensions < 1 || dimensions > 2e3) {
3659
- throw new Error(`vector(): dimensions must be an integer in [1, 2000], got ${String(dimensions)}`);
3857
+ __name(makeTypedTable, "makeTypedTable");
3858
+ function makeTypedDB(schema, raw2) {
3859
+ const tables = {};
3860
+ for (const key of Object.keys(schema.tables)) {
3861
+ const tableDef = schema.tables[key];
3862
+ if (tableDef !== void 0) {
3863
+ tables[key] = makeTypedTable(qualifiedTableKey(schema.name, tableDef.name), raw2);
3864
+ }
3660
3865
  }
3661
- const b = new ColumnBuilder("vector");
3662
- b._def.dimensions = dimensions;
3663
- return b;
3664
- }
3665
- __name(vector, "vector");
3666
- function ownedByUser() {
3667
- const b = new ColumnBuilder("text");
3668
- b._def.nullable = false;
3669
- b._def.references = {
3670
- table: "auth.users",
3671
- column: "id"
3866
+ const result = {
3867
+ tables,
3868
+ diagnostics: /* @__PURE__ */ __name(() => raw2.diagnostics(), "diagnostics"),
3869
+ readQuery: /* @__PURE__ */ __name((query) => raw2.readQuery(query), "readQuery"),
3870
+ compileQuery: /* @__PURE__ */ __name((query) => raw2.compileQuery(query), "compileQuery"),
3871
+ explainQuery: /* @__PURE__ */ __name((query) => raw2.explainQuery(query), "explainQuery"),
3872
+ command(fn, options) {
3873
+ const builder = new TxPlanBuilder();
3874
+ const planTables = Object.fromEntries(Object.entries(schema.tables).map(([key, table]) => [
3875
+ key,
3876
+ builder.table(qualifiedTableKey(schema.name, table.name))
3877
+ ]));
3878
+ return runTxPlan({
3879
+ txPlan: /* @__PURE__ */ __name((plan) => raw2.command(plan, options), "txPlan")
3880
+ }, {
3881
+ tables: planTables
3882
+ }, builder, fn);
3883
+ },
3884
+ transaction(fn) {
3885
+ const builder = new TxPlanBuilder();
3886
+ const planTables = {};
3887
+ for (const key of Object.keys(schema.tables)) {
3888
+ const tableDef = schema.tables[key];
3889
+ if (tableDef !== void 0) planTables[key] = builder.table(qualifiedTableKey(schema.name, tableDef.name));
3890
+ }
3891
+ return runTxPlan(raw2, {
3892
+ tables: planTables
3893
+ }, builder, fn);
3894
+ }
3672
3895
  };
3673
- b._def.onDeleteAction = "cascade";
3674
- b._def.owns = true;
3675
- return b;
3896
+ return result;
3676
3897
  }
3677
- __name(ownedByUser, "ownedByUser");
3678
- function userRef(opts) {
3679
- const b = new ColumnBuilder("text");
3680
- b._def.references = {
3681
- table: "auth.users",
3682
- column: "id"
3683
- };
3684
- b._def.onDeleteAction = opts.onDelete;
3685
- if (opts.as !== void 0) b._def.refAs = opts.as;
3686
- return b;
3898
+ __name(makeTypedDB, "makeTypedDB");
3899
+ function col(name) {
3900
+ return brandRef({
3901
+ $col: name
3902
+ }, "col");
3687
3903
  }
3688
- __name(userRef, "userRef");
3689
- function installationRef(opts) {
3690
- const b = new ColumnBuilder("text");
3691
- b._def.references = {
3692
- table: "auth.installations",
3693
- column: "id"
3694
- };
3695
- b._def.onDeleteAction = opts.onDelete;
3696
- if (opts.as !== void 0) b._def.refAs = opts.as;
3697
- return b;
3904
+ __name(col, "col");
3905
+ async function withRetry(fn, opts = {}) {
3906
+ const budget = retryBudget(opts.retry);
3907
+ let attempt = 0;
3908
+ for (; ; ) {
3909
+ try {
3910
+ return await fn();
3911
+ } catch (e) {
3912
+ if (attempt >= budget || !isRetryable(e)) throw e;
3913
+ attempt += 1;
3914
+ }
3915
+ }
3698
3916
  }
3699
- __name(installationRef, "installationRef");
3700
-
3701
- // src/db/raw.ts
3702
- function raw(name, up, opts) {
3703
- return {
3704
- name,
3705
- up,
3706
- ...opts?.down != null ? {
3707
- down: opts.down
3708
- } : {}
3709
- };
3917
+ __name(withRetry, "withRetry");
3918
+ function sqlFragment(strings, ...values) {
3919
+ return brandRef({
3920
+ $sql: {
3921
+ text: [
3922
+ ...strings
3923
+ ],
3924
+ values
3925
+ }
3926
+ }, "sql");
3710
3927
  }
3711
- __name(raw, "raw");
3712
-
3713
- // src/db/embedding.ts
3714
- var openai = {
3715
- embedding(model, opts) {
3716
- return {
3717
- provider: "openai",
3718
- model,
3719
- apiKeyName: opts?.apiKeyName ?? "OPENAI_API_KEY",
3720
- ...opts?.dimensions !== void 0 ? {
3721
- dimensions: opts.dimensions
3722
- } : {},
3723
- ...opts?.baseURL !== void 0 ? {
3724
- baseURL: opts.baseURL
3725
- } : {}
3726
- };
3727
- },
3728
- chat(model) {
3729
- return {
3730
- provider: "openai",
3731
- model
3732
- };
3733
- }
3734
- };
3928
+ __name(sqlFragment, "sqlFragment");
3735
3929
 
3736
3930
  // src/refusals.ts
3737
3931
  var DECLARATION_REFUSAL = /* @__PURE__ */ Symbol.for("palbase.backend.declarationRefusal");
@@ -3751,6 +3945,39 @@ function isDeclarationRefused(e) {
3751
3945
  }
3752
3946
  __name(isDeclarationRefused, "isDeclarationRefused");
3753
3947
 
3948
+ // src/db/unique.ts
3949
+ function uniqueKeysOf(table) {
3950
+ const columns = table.columns ?? {};
3951
+ const inlinePrimary = [], keys = [];
3952
+ for (const [name, value] of Object.entries(columns)) {
3953
+ const col2 = value && typeof value === "object" && "_def" in value ? value._def : value;
3954
+ if (col2?.primaryKey) inlinePrimary.push(name);
3955
+ if (col2?.unique) keys.push([
3956
+ name
3957
+ ]);
3958
+ }
3959
+ const primary = table.primaryKey ?? inlinePrimary;
3960
+ if (primary.length) keys.unshift([
3961
+ ...primary
3962
+ ]);
3963
+ for (const key of table.unique ?? []) keys.push([
3964
+ ...key.columns
3965
+ ]);
3966
+ const seen = /* @__PURE__ */ new Set();
3967
+ return keys.filter((key) => {
3968
+ if (!key.length || new Set(key).size !== key.length || key.some((col2) => !Object.hasOwn(columns, col2))) {
3969
+ throw new Error("Unique lookup requires a nonempty declared key of distinct, known columns");
3970
+ }
3971
+ const identity = JSON.stringify([
3972
+ ...key
3973
+ ].sort());
3974
+ if (seen.has(identity)) return false;
3975
+ seen.add(identity);
3976
+ return true;
3977
+ });
3978
+ }
3979
+ __name(uniqueKeysOf, "uniqueKeysOf");
3980
+
3754
3981
  // src/db/env-gen.ts
3755
3982
  function baseTsType(def) {
3756
3983
  if (def.codec !== void 0 && def.codec in CODECS) {
@@ -3902,6 +4129,9 @@ function tableBlock(table, relations, indent) {
3902
4129
  const rowLines = cols.map(([col2, builder]) => {
3903
4130
  return `${indent} ${col2}: ${rowType(builder._def)};`;
3904
4131
  });
4132
+ const hasCanColumn = Object.prototype.hasOwnProperty.call(table.columns, "can") || relations.some((r) => r.name === "can");
4133
+ const canNames = (table.policies ?? []).filter((p) => p.command === "update" && p.permissive !== false && Buffer.byteLength(`can:${p.name}`, "utf8") <= 63).map((p) => JSON.stringify(p.name));
4134
+ const canLine = hasCanColumn ? null : `${indent} can: ${canNames.length === 0 ? "never[]" : `(${canNames.join(" | ")})[]`};`;
3905
4135
  const insertLines = cols.map(([col2, builder]) => {
3906
4136
  const def = builder._def;
3907
4137
  const opt = optionalOnInsert(def) ? "?" : "";
@@ -3912,11 +4142,15 @@ function tableBlock(table, relations, indent) {
3912
4142
  `${indent}${table.name}: {`,
3913
4143
  `${indent} row: {`,
3914
4144
  ...rowLines,
4145
+ ...canLine === null ? [] : [
4146
+ canLine
4147
+ ],
3915
4148
  `${indent} };`,
3916
4149
  `${indent} insert: {`,
3917
4150
  ...insertLines,
3918
4151
  `${indent} };`,
3919
4152
  `${indent} relations: {${relEntries === "" ? "" : ` ${relEntries} `}};`,
4153
+ `${indent} uniqueKeys: ${JSON.stringify(uniqueKeysOf(table))};`,
3920
4154
  // searchable: vector kolonu YA DA search beyanı → EnvTypedTable'da search()
3921
4155
  // üyesini açan yapısal bayrak (FR-013). Yokken satır hiç üretilmez ki
3922
4156
  // mevcut şemaların d.ts'i bayt-aynı kalsın.
@@ -4733,18 +4967,18 @@ __name(defineMiddleware, "defineMiddleware");
4733
4967
 
4734
4968
  // src/error-registry.ts
4735
4969
  var import_zod_to_openapi = require("@asteasolutions/zod-to-openapi");
4736
- var import_zod = require("zod");
4737
- (0, import_zod_to_openapi.extendZodWithOpenApi)(import_zod.z);
4970
+ var import_zod2 = require("zod");
4971
+ (0, import_zod_to_openapi.extendZodWithOpenApi)(import_zod2.z);
4738
4972
  var ERROR_REGISTRY = /* @__PURE__ */ Symbol.for("palbase.backend.errorRegistry");
4739
4973
  var BUILTIN_DATA_SCHEMAS = {
4740
- bad_request: import_zod.z.object({
4741
- fields: import_zod.z.array(import_zod.z.object({
4742
- field: import_zod.z.string(),
4743
- message: import_zod.z.string()
4974
+ bad_request: import_zod2.z.object({
4975
+ fields: import_zod2.z.array(import_zod2.z.object({
4976
+ field: import_zod2.z.string(),
4977
+ message: import_zod2.z.string()
4744
4978
  }))
4745
4979
  }),
4746
- too_many_requests: import_zod.z.object({
4747
- retryAfter: import_zod.z.number().int()
4980
+ too_many_requests: import_zod2.z.object({
4981
+ retryAfter: import_zod2.z.number().int()
4748
4982
  })
4749
4983
  };
4750
4984
  function getErrorRegistry() {
@@ -4861,7 +5095,7 @@ __name(defineError, "defineError");
4861
5095
  function digestOf(code, dataSchema) {
4862
5096
  const TMP_REF = "__PalbaseErrorDataDigest";
4863
5097
  const tmpRegistry = new import_zod_to_openapi.OpenAPIRegistry();
4864
- tmpRegistry.register(TMP_REF, import_zod.z.object({
5098
+ tmpRegistry.register(TMP_REF, import_zod2.z.object({
4865
5099
  data: dataSchema
4866
5100
  }).openapi(TMP_REF));
4867
5101
  const generated = new import_zod_to_openapi.OpenApiGeneratorV31(tmpRegistry.definitions).generateComponents();
@@ -5455,7 +5689,188 @@ function getJobConfig(ctor, container) {
5455
5689
  __name(getJobConfig, "getJobConfig");
5456
5690
 
5457
5691
  // src/index.ts
5458
- var import_zod2 = require("zod");
5692
+ var import_zod4 = require("zod");
5693
+
5694
+ // src/db/query.ts
5695
+ var import_zod3 = require("zod");
5696
+ var import_zod_to_openapi2 = require("@asteasolutions/zod-to-openapi");
5697
+
5698
+ // src/db/query-contract.ts
5699
+ function queryColumnContract(column) {
5700
+ const def = column && typeof column === "object" && "_def" in column ? column._def : column;
5701
+ if (!def?.type) throw new Error("Query contract requires declared column types");
5702
+ if (def.transform !== void 0 && def.codec === void 0) throw new Error("Query contracts require a named codec instead of a free-form column transform");
5703
+ return {
5704
+ type: def.type,
5705
+ nullable: def.nullable === true,
5706
+ ...def.codec === void 0 ? {} : {
5707
+ codec: def.codec
5708
+ },
5709
+ ...def.enumValues === void 0 ? {} : {
5710
+ enumValues: [
5711
+ ...def.enumValues
5712
+ ]
5713
+ },
5714
+ ...def.dimensions === void 0 ? {} : {
5715
+ dimensions: def.dimensions
5716
+ }
5717
+ };
5718
+ }
5719
+ __name(queryColumnContract, "queryColumnContract");
5720
+ function stableContract(value) {
5721
+ if (Array.isArray(value)) return `[${value.map(stableContract).join(",")}]`;
5722
+ if (value && typeof value === "object") return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableContract(value[key])}`).join(",")}}`;
5723
+ return JSON.stringify(value) ?? "null";
5724
+ }
5725
+ __name(stableContract, "stableContract");
5726
+
5727
+ // src/db/query.ts
5728
+ (0, import_zod_to_openapi2.extendZodWithOpenApi)(import_zod3.z);
5729
+ function responseColumn(column, validator) {
5730
+ const contract = queryColumnContract(column);
5731
+ let schema;
5732
+ if (validator) return validator;
5733
+ if (contract.codec === "number") schema = import_zod3.z.number().finite();
5734
+ else if (contract.codec === "decimal") schema = import_zod3.z.string();
5735
+ else switch (contract.type) {
5736
+ case "integer":
5737
+ schema = import_zod3.z.number().int().min(-2147483648).max(2147483647);
5738
+ break;
5739
+ case "boolean":
5740
+ schema = import_zod3.z.boolean();
5741
+ break;
5742
+ case "vector":
5743
+ schema = import_zod3.z.array(import_zod3.z.number().finite());
5744
+ break;
5745
+ case "enum": {
5746
+ const values = contract.enumValues;
5747
+ if (!values?.length) throw new Error("Query response requires declared enum values");
5748
+ schema = import_zod3.z.enum(values);
5749
+ break;
5750
+ }
5751
+ case "uuid":
5752
+ case "text":
5753
+ case "timestamp":
5754
+ case "numeric":
5755
+ case "bigint":
5756
+ schema = import_zod3.z.string();
5757
+ break;
5758
+ case "jsonb":
5759
+ throw new Error("Query response requires a fields validator for a selected jsonb column: its TypeScript payload is erased at runtime");
5760
+ default:
5761
+ throw new Error(`Query response does not support column type ${contract.type}`);
5762
+ }
5763
+ return contract.nullable ? schema.nullable() : schema;
5764
+ }
5765
+ __name(responseColumn, "responseColumn");
5766
+ function defineQuery(name, options) {
5767
+ if (typeof name !== "string" || !/^[A-Za-z][A-Za-z0-9_]{0,127}$/.test(name)) throw new Error("defineQuery requires a stable name of 1\u2013128 letters, digits or underscores");
5768
+ const table = declaredTableKey(options.table);
5769
+ const select = [
5770
+ ...options.select
5771
+ ];
5772
+ if (!select.length || new Set(select).size !== select.length) throw new Error(`Query ${name}: select must be explicit, nonempty and distinct`);
5773
+ const shape = {}, columns = {};
5774
+ for (const key of select) {
5775
+ if (!Object.hasOwn(options.table[TABLE_META].columns, key)) throw new Error(`Query ${name}: unknown column ${key}`);
5776
+ columns[key] = queryColumnContract(options.table[key]);
5777
+ shape[key] = responseColumn(options.table[key], options.fields?.[key]);
5778
+ }
5779
+ const response = import_zod3.z.array(import_zod3.z.object(shape).strict());
5780
+ const queryInput = options.input, where = options.where, limit = options.limit;
5781
+ const orderBy = options.orderBy === void 0 ? void 0 : JSON.parse(JSON.stringify(options.orderBy));
5782
+ const prepare = /* @__PURE__ */ __name((input) => {
5783
+ const parsed = queryInput.parse(input);
5784
+ const filter = where === void 0 ? {} : where(parsed);
5785
+ if (!filter || typeof filter !== "object" || Array.isArray(filter) || typeof filter.then === "function") {
5786
+ throw new Error(`Query ${name}: where must return a synchronous filter object`);
5787
+ }
5788
+ const size = typeof limit === "function" ? limit(parsed) : limit;
5789
+ if (limit !== void 0 && (typeof size !== "number" || !Number.isSafeInteger(size) || size < 0)) throw new Error(`Query ${name}: limit must produce a nonnegative safe integer`);
5790
+ return {
5791
+ name,
5792
+ table,
5793
+ columns: JSON.parse(JSON.stringify(columns)),
5794
+ where: filter,
5795
+ options: {
5796
+ select: [
5797
+ ...select
5798
+ ],
5799
+ ...orderBy === void 0 ? {} : {
5800
+ orderBy: structuredClone(orderBy)
5801
+ },
5802
+ ...limit === void 0 ? {} : {
5803
+ limit: size
5804
+ }
5805
+ }
5806
+ };
5807
+ }, "prepare");
5808
+ const attach = /* @__PURE__ */ __name((schema) => {
5809
+ const api = {
5810
+ queryName: name,
5811
+ input: queryInput,
5812
+ prepare,
5813
+ async run(database, input) {
5814
+ const request = prepare(input);
5815
+ const rows = await ("$readQuery" in database ? database.$readQuery(request) : database.readQuery(request));
5816
+ return schema.parse(rows);
5817
+ },
5818
+ sql(database, input) {
5819
+ const request = prepare(input);
5820
+ return "$compileQuery" in database ? database.$compileQuery(request) : database.compileQuery(request);
5821
+ },
5822
+ explain(database, input) {
5823
+ const request = prepare(input);
5824
+ return "$explainQuery" in database ? database.$explainQuery(request) : database.explainQuery(request);
5825
+ },
5826
+ contract() {
5827
+ const registry2 = new import_zod_to_openapi2.OpenAPIRegistry();
5828
+ registry2.register(`${name}Input`, queryInput);
5829
+ registry2.register(`${name}Response`, schema);
5830
+ return JSON.parse(JSON.stringify({
5831
+ name,
5832
+ table,
5833
+ select,
5834
+ columns,
5835
+ components: new import_zod_to_openapi2.OpenApiGeneratorV31(registry2.definitions).generateComponents().components
5836
+ }));
5837
+ }
5838
+ };
5839
+ for (const key of [
5840
+ "min",
5841
+ "max",
5842
+ "length",
5843
+ "describe",
5844
+ "openapi"
5845
+ ]) {
5846
+ const modify = schema[key].bind(schema);
5847
+ Object.defineProperty(schema, key, {
5848
+ value: /* @__PURE__ */ __name((...args) => attach(modify(...args)), "value"),
5849
+ configurable: true
5850
+ });
5851
+ }
5852
+ return Object.assign(schema, api);
5853
+ }, "attach");
5854
+ return attach(response);
5855
+ }
5856
+ __name(defineQuery, "defineQuery");
5857
+ function queryManifest(queries) {
5858
+ const sorted = [
5859
+ ...queries
5860
+ ].sort((a, b) => a.queryName.localeCompare(b.queryName));
5861
+ if (new Set(sorted.map((query) => query.queryName)).size !== sorted.length) throw new Error("Query manifest contains duplicate names");
5862
+ return JSON.parse(stableContract({
5863
+ version: 1,
5864
+ queries: sorted.map((query) => query.contract())
5865
+ }));
5866
+ }
5867
+ __name(queryManifest, "queryManifest");
5868
+ function assertQueryManifest(queries, baseline) {
5869
+ if (stableContract(queryManifest(queries)) !== stableContract(baseline)) {
5870
+ throw new Error("Query contract drift: compare queryManifest() with the committed manifest and review the API/client changes before updating it");
5871
+ }
5872
+ }
5873
+ __name(assertQueryManifest, "assertQueryManifest");
5459
5874
  // Annotate the CommonJS export names for ESM import in node:
5460
5875
  0 && (module.exports = {
5461
5876
  Auth,
@@ -5539,11 +5954,13 @@ var import_zod2 = require("zod");
5539
5954
  __runWithRuntime,
5540
5955
  __setRuntime,
5541
5956
  assertNoOrphanEntryPoints,
5957
+ assertQueryManifest,
5542
5958
  assertZeroArgConstructor,
5543
5959
  bigint,
5544
5960
  boolean,
5545
5961
  buildContainer,
5546
5962
  buildModuleClients,
5963
+ can,
5547
5964
  col,
5548
5965
  controllersOf,
5549
5966
  dec,
@@ -5552,8 +5969,10 @@ var import_zod2 = require("zod");
5552
5969
  defineDefaultAuth,
5553
5970
  defineError,
5554
5971
  defineMiddleware,
5972
+ defineQuery,
5555
5973
  defineSchema,
5556
5974
  defineTable,
5975
+ defineWorkload,
5557
5976
  enumType,
5558
5977
  exprCtx,
5559
5978
  getErrorRegistry,
@@ -5589,6 +6008,7 @@ var import_zod2 = require("zod");
5589
6008
  ownerOnly,
5590
6009
  policy,
5591
6010
  publicChannel,
6011
+ queryManifest,
5592
6012
  raw,
5593
6013
  recordThrows,
5594
6014
  resolveEffectiveAuth,