@palbase/backend 22.0.1 → 23.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 (73) hide show
  1. package/dist/bin/palbase-backend.cjs +764 -25
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +4 -4
  4. package/dist/{chunk-POYAFBLF.js → chunk-FSGSB42K.js} +13 -6
  5. package/dist/chunk-FSGSB42K.js.map +1 -0
  6. package/dist/{chunk-SSGAMC26.js → chunk-HAF67F2H.js} +114 -5
  7. package/dist/chunk-HAF67F2H.js.map +1 -0
  8. package/dist/{chunk-QMVK4X3V.js → chunk-OMRTHM4X.js} +98 -98
  9. package/dist/chunk-OMRTHM4X.js.map +1 -0
  10. package/dist/{chunk-QYOHMVUW.js → chunk-REZU6UKT.js} +755 -24
  11. package/dist/chunk-REZU6UKT.js.map +1 -0
  12. package/dist/{chunk-YL4C5NRY.js → chunk-Y5HXVUMP.js} +2 -2
  13. package/dist/{chunk-N32VDWKH.js → chunk-ZC6Q2BRD.js} +4 -59
  14. package/dist/chunk-ZC6Q2BRD.js.map +1 -0
  15. package/dist/db/env.cjs.map +1 -1
  16. package/dist/db/env.d.cts +3 -21
  17. package/dist/db/env.d.ts +3 -21
  18. package/dist/db/index.cjs +117 -6
  19. package/dist/db/index.cjs.map +1 -1
  20. package/dist/db/index.d.cts +3 -2
  21. package/dist/db/index.d.ts +3 -2
  22. package/dist/db/index.js +7 -3
  23. package/dist/{endpoint-B0LpZixz.d.cts → endpoint-BavvbW4P.d.ts} +116 -14
  24. package/dist/{endpoint-B0LpZixz.d.ts → endpoint-i8TTCohk.d.cts} +116 -14
  25. package/dist/engine/index.cjs +764 -25
  26. package/dist/engine/index.cjs.map +1 -1
  27. package/dist/engine/index.d.cts +6 -5
  28. package/dist/engine/index.d.ts +6 -5
  29. package/dist/engine/index.js +3 -3
  30. package/dist/{index-g-EzitI-.d.ts → index-B3jmmItD.d.ts} +203 -7
  31. package/dist/{index-BCNtlG1w.d.ts → index-B7YBEG5w.d.ts} +117 -93
  32. package/dist/{index-BGSCWlUa.d.cts → index-Bmvx1EvJ.d.cts} +203 -7
  33. package/dist/{index-B4W6d2VJ.d.cts → index-E7OscPJT.d.cts} +117 -93
  34. package/dist/index.cjs +509 -1085
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +203 -1133
  37. package/dist/index.d.ts +203 -1133
  38. package/dist/index.js +288 -900
  39. package/dist/index.js.map +1 -1
  40. package/dist/openapi/index.cjs +3 -57
  41. package/dist/openapi/index.cjs.map +1 -1
  42. package/dist/openapi/index.d.cts +3 -2
  43. package/dist/openapi/index.d.ts +3 -2
  44. package/dist/openapi/index.js +5 -22
  45. package/dist/openapi/index.js.map +1 -1
  46. package/dist/{registry-3BLYv4si.d.ts → registry-C3H2uPeZ.d.cts} +13 -169
  47. package/dist/{registry-Cw0YEYCg.d.cts → registry-DY3d9l1k.d.ts} +13 -169
  48. package/dist/{purchases/keys.cjs → stack.cjs} +4 -4
  49. package/dist/stack.cjs.map +1 -0
  50. package/dist/stack.d.cts +76 -0
  51. package/dist/stack.d.ts +76 -0
  52. package/dist/stack.js +1 -0
  53. package/docs/README.md +7 -6
  54. package/docs/endpoints.md +1 -1
  55. package/docs/errors.md +9 -0
  56. package/docs/llms-full.txt +17 -261
  57. package/docs/llms.txt +0 -2
  58. package/package.json +7 -7
  59. package/template/package.json +1 -1
  60. package/dist/chunk-N32VDWKH.js.map +0 -1
  61. package/dist/chunk-POYAFBLF.js.map +0 -1
  62. package/dist/chunk-QMVK4X3V.js.map +0 -1
  63. package/dist/chunk-QYOHMVUW.js.map +0 -1
  64. package/dist/chunk-SSGAMC26.js.map +0 -1
  65. package/dist/purchases/keys.cjs.map +0 -1
  66. package/dist/purchases/keys.d.cts +0 -42
  67. package/dist/purchases/keys.d.ts +0 -42
  68. package/dist/purchases/keys.js +0 -1
  69. package/docs/config.md +0 -147
  70. package/docs/resources.md +0 -97
  71. package/template/config/secrets.ts +0 -24
  72. /package/dist/{chunk-YL4C5NRY.js.map → chunk-Y5HXVUMP.js.map} +0 -0
  73. /package/dist/{purchases/keys.js.map → stack.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -26,17 +26,11 @@ __export(src_exports, {
26
26
  Client: () => Client,
27
27
  Conflict: () => Conflict,
28
28
  Controller: () => Controller,
29
- DEFAULT_TEMPLATE_LOCALE: () => DEFAULT_TEMPLATE_LOCALE,
30
29
  Database: () => Database,
31
30
  Delete: () => Delete,
32
31
  Deny: () => Deny,
33
32
  Documents: () => Documents,
34
- EGRESS_CONFIG_KIND: () => EGRESS_CONFIG_KIND,
35
- EGRESS_TIMEOUT_DEFAULT_MS: () => EGRESS_TIMEOUT_DEFAULT_MS,
36
- EGRESS_TIMEOUT_MAX_MS: () => EGRESS_TIMEOUT_MAX_MS,
37
- EGRESS_TIMEOUT_MIN_MS: () => EGRESS_TIMEOUT_MIN_MS,
38
33
  EXTENSION_DEPENDENCIES: () => EXTENSION_DEPENDENCIES,
39
- FLAGS_CONFIG_KIND: () => FLAGS_CONFIG_KIND,
40
34
  Flags: () => Flags,
41
35
  Forbidden: () => Forbidden,
42
36
  Get: () => Get,
@@ -45,35 +39,25 @@ __export(src_exports, {
45
39
  HttpError: () => HttpError,
46
40
  Job: () => Job,
47
41
  Log: () => Log,
48
- NOTIFICATIONS_CONFIG_KIND: () => NOTIFICATIONS_CONFIG_KIND,
49
42
  NotFound: () => NotFound,
50
43
  Notifications: () => Notifications,
51
44
  On: () => On,
52
45
  OptionalUser: () => OptionalUser,
53
46
  PALBASE_EXTENSIONS: () => PALBASE_EXTENSIONS,
54
- PROVIDER_CATALOG: () => PROVIDER_CATALOG,
55
47
  PalError: () => PalError,
56
48
  PalbaseModuleError: () => PalbaseModuleError,
57
49
  Param: () => Param,
58
50
  Patch: () => Patch,
59
51
  PolicyBuilder: () => PolicyBuilder,
60
52
  Post: () => Post,
61
- Purchases: () => Purchases,
62
53
  Put: () => Put,
63
54
  Query: () => Query,
64
55
  QueryParams: () => QueryParams,
65
- RESERVED_SECRET_PREFIX: () => RESERVED_SECRET_PREFIX,
66
56
  Realtime: () => Realtime,
67
57
  Req: () => Req,
68
58
  RequestId: () => RequestId,
69
- RequireEntitlement: () => RequireEntitlement,
70
- Resource: () => Resource,
71
- SECRETS_CONFIG_KIND: () => SECRETS_CONFIG_KIND,
72
- STORAGE_CONFIG_KIND: () => STORAGE_CONFIG_KIND,
73
59
  Secrets: () => Secrets,
74
- Spend: () => Spend,
75
60
  Storage: () => Storage,
76
- TEST_USERS_CONFIG_KIND: () => TEST_USERS_CONFIG_KIND,
77
61
  TooManyRequests: () => TooManyRequests,
78
62
  TraceId: () => TraceId,
79
63
  TxPlanError: () => TxPlanError,
@@ -84,32 +68,19 @@ __export(src_exports, {
84
68
  User: () => User,
85
69
  Webhook: () => Webhook,
86
70
  __getRuntime: () => __getRuntime,
87
- __registerResource: () => __registerResource,
88
71
  __requestALS: () => __requestALS,
89
72
  __resetRegisteredControllers: () => __resetRegisteredControllers,
90
- __runResourceBoot: () => __runResourceBoot,
91
73
  __runWithRuntime: () => __runWithRuntime,
92
74
  __setRuntime: () => __setRuntime,
93
- __shutdownResources: () => __shutdownResources,
94
75
  bigint: () => bigint,
95
76
  boolean: () => boolean,
96
- bucket: () => bucket,
97
77
  buildModuleClients: () => buildModuleClients,
98
- buildProvider: () => buildProvider,
99
78
  dec: () => dec,
100
- defineEgress: () => defineEgress,
79
+ defineChannels: () => defineChannels,
101
80
  defineError: () => defineError,
102
- defineFlags: () => defineFlags,
103
81
  defineMiddleware: () => defineMiddleware,
104
- defineNotifications: () => defineNotifications,
105
82
  defineSchema: () => defineSchema,
106
- defineSecrets: () => defineSecrets,
107
- defineStorage: () => defineStorage,
108
- defineTestUsers: () => defineTestUsers,
109
- entitlementFor: () => entitlementFor,
110
83
  enumType: () => enumType,
111
- extractVariables: () => extractVariables,
112
- flag: () => flag,
113
84
  getErrorRegistry: () => getErrorRegistry,
114
85
  getHookConfig: () => getHookConfig,
115
86
  getJobConfig: () => getJobConfig,
@@ -122,23 +93,21 @@ __export(src_exports, {
122
93
  jsonb: () => jsonb,
123
94
  makeEnvDts: () => makeEnvDts,
124
95
  makeHttpClient: () => makeHttpClient,
125
- makePurchasesDts: () => makePurchasesDts,
96
+ makeStackDts: () => makeStackDts,
126
97
  makeTypedDB: () => makeTypedDB,
127
98
  now: () => now,
128
99
  numeric: () => numeric,
129
- parseFileSizeLimit: () => parseFileSizeLimit,
100
+ openai: () => openai,
101
+ ownerOnly: () => ownerOnly,
130
102
  policy: () => policy,
103
+ publicChannel: () => publicChannel,
131
104
  raw: () => raw,
132
105
  recordThrows: () => recordThrows,
133
- reservedSecretKey: () => reservedSecretKey,
134
- secret: () => secret,
135
- spendFor: () => spendFor,
136
- testUser: () => testUser,
137
106
  text: () => text,
138
107
  timestamp: () => timestamp,
139
108
  toSchemaJSON: () => toSchemaJSON,
140
109
  uuid: () => uuid,
141
- validateUploadAgainstStorage: () => validateUploadAgainstStorage,
110
+ vector: () => vector,
142
111
  z: () => import_zod2.z
143
112
  });
144
113
  module.exports = __toCommonJS(src_exports);
@@ -595,7 +564,11 @@ function makeTablesAccessor(ops) {
595
564
  update: (id, data) => ops().update(name, id, data),
596
565
  delete: (id) => ops().delete(name, id),
597
566
  findById: (id) => ops().findById(name, id),
598
- findMany: (query) => ops().findMany(name, query)
567
+ findMany: (query) => ops().findMany(name, query),
568
+ search: (params) => ops().search(name, params),
569
+ similar: (id, params) => ops().similar(name, id, params),
570
+ recommend: (params) => ops().recommend(name, params),
571
+ supersede: (id, row) => ops().supersede(name, id, row)
599
572
  };
600
573
  }
601
574
  }
@@ -604,16 +577,21 @@ function makeTablesAccessor(ops) {
604
577
  }
605
578
  var rawDatabase = makeServiceProxy("Database");
606
579
  function makeTypedSurface(raw2) {
580
+ const reco = raw2;
607
581
  const ops = {
608
582
  query: (sql, params) => raw2.query(sql, params),
609
583
  insert: (table, data) => raw2.insert(table, data),
610
584
  update: (table, id, data) => raw2.update(table, id, data),
611
585
  delete: (table, id) => raw2.delete(table, id),
612
586
  findById: (table, id) => raw2.findById(table, id),
613
- findMany: (table, query) => raw2.findMany(table, query)
587
+ findMany: (table, query) => raw2.findMany(table, query),
588
+ search: (table, params) => raw2.search(table, params),
589
+ similar: (table, id, params) => reco.similar(table, id, params),
590
+ recommend: (table, params) => reco.recommend(table, params),
591
+ supersede: (table, id, row) => raw2.supersede(table, id, row)
614
592
  };
615
593
  return Object.assign(ops, {
616
- tables: makeTablesAccessor(() => raw2),
594
+ tables: makeTablesAccessor(() => reco),
617
595
  transaction(fn) {
618
596
  const builder = new TxPlanBuilder();
619
597
  return runTxPlan(raw2, makeTxTablesAccessor(builder), builder, fn);
@@ -676,7 +654,6 @@ var Cache = makeServiceProxy("Cache");
676
654
  var Secrets = makeServiceProxy("Secrets");
677
655
  var Log = makeServiceProxy("Log");
678
656
  var Notifications = makeServiceProxy("Notifications");
679
- var Purchases = makeServiceProxy("Purchases");
680
657
  var rawFlags = makeServiceProxy("Flags");
681
658
  var Flags = Object.assign(
682
659
  {
@@ -720,250 +697,6 @@ var Flags = Object.assign(
720
697
  );
721
698
  var Realtime = makeServiceProxy("Realtime");
722
699
 
723
- // src/errors.ts
724
- var HTTP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("palbase.backend.httpError");
725
- var HttpError = class extends Error {
726
- status;
727
- error;
728
- errorDescription;
729
- data;
730
- /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */
731
- [HTTP_ERROR_BRAND] = true;
732
- constructor(status, error, errorDescription, data) {
733
- super(errorDescription);
734
- this.name = "HttpError";
735
- this.status = status;
736
- this.error = error;
737
- this.errorDescription = errorDescription;
738
- if (data !== void 0) {
739
- this.data = data;
740
- }
741
- }
742
- /**
743
- * Serialize to the standard Palbase error response format.
744
- * The `requestId` is injected by the runtime layer from the request context.
745
- * When called without arguments (e.g. JSON.stringify), request_id is omitted.
746
- * When `data` is set, it is appended as a strict-superset field.
747
- */
748
- toJSON(requestId) {
749
- const result = {
750
- error: this.error,
751
- error_description: this.errorDescription,
752
- status: this.status
753
- };
754
- if (requestId) {
755
- result.request_id = requestId;
756
- }
757
- if (this.data !== void 0) {
758
- result.data = this.data;
759
- }
760
- return result;
761
- }
762
- };
763
- var PalError = class extends HttpError {
764
- constructor(status, code, description, data) {
765
- super(status, code, description, data);
766
- this.name = "PalError";
767
- }
768
- };
769
- var NamedHttpError = class extends HttpError {
770
- constructor(status, defaultCode, name, message, code, data) {
771
- super(status, code ?? defaultCode, message ?? defaultMessage(name), data);
772
- this.name = name;
773
- }
774
- };
775
- function defaultMessage(name) {
776
- const spaced = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
777
- return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
778
- }
779
- var BadRequest = class extends NamedHttpError {
780
- constructor(data, message) {
781
- super(400, "bad_request", "BadRequest", message, void 0, data);
782
- }
783
- };
784
- var Unauthorized = class extends NamedHttpError {
785
- constructor(message, code, data) {
786
- super(401, "unauthorized", "Unauthorized", message, code, data);
787
- }
788
- };
789
- var Forbidden = class extends NamedHttpError {
790
- constructor(message, code, data) {
791
- super(403, "forbidden", "Forbidden", message, code, data);
792
- }
793
- };
794
- var NotFound = class extends NamedHttpError {
795
- constructor(message, code, data) {
796
- super(404, "not_found", "NotFound", message, code, data);
797
- }
798
- };
799
- var Conflict = class extends NamedHttpError {
800
- constructor(message, code, data) {
801
- super(409, "conflict", "Conflict", message, code, data);
802
- }
803
- };
804
- var TooManyRequests = class extends NamedHttpError {
805
- constructor(data, message) {
806
- super(429, "too_many_requests", "TooManyRequests", message, void 0, data);
807
- }
808
- };
809
-
810
- // src/purchases/errors.ts
811
- function asPalstoreError(err) {
812
- if (!(err instanceof Error)) return null;
813
- const e = err;
814
- if (typeof e.code !== "string" || typeof e.status !== "number") return null;
815
- return { code: e.code, status: e.status, message: e.message };
816
- }
817
- function toHttpError(err) {
818
- if (err instanceof HttpError) return err;
819
- const p = asPalstoreError(err);
820
- if (!p) return err;
821
- switch (p.code) {
822
- case "entitlement_required": {
823
- const entitlement = err.entitlement ?? null;
824
- return new PalError(403, "entitlement_required", p.message, { entitlement });
825
- }
826
- case "quota_exceeded":
827
- case "credit_insufficient": {
828
- const state = err.state;
829
- return new PalError(429, p.code, p.message, state);
830
- }
831
- default:
832
- return err;
833
- }
834
- }
835
-
836
- // src/purchases/registry.ts
837
- var ENTITLEMENTS = /* @__PURE__ */ Symbol.for("palbase.backend.purchases.entitlements");
838
- var SPENDS = /* @__PURE__ */ Symbol.for("palbase.backend.purchases.spends");
839
- function carrierOf(target) {
840
- return typeof target === "function" ? target : target.constructor ?? target;
841
- }
842
- function own(carrier, slot) {
843
- if (!Object.prototype.hasOwnProperty.call(carrier, slot)) {
844
- carrier[slot] = {};
845
- }
846
- return carrier[slot];
847
- }
848
- function recordEntitlement(target, fnName, key) {
849
- own(carrierOf(target), ENTITLEMENTS)[fnName] = key;
850
- }
851
- function recordSpend(target, fnName, meta) {
852
- own(carrierOf(target), SPENDS)[fnName] = meta;
853
- }
854
- function entitlementFor(ctor, fnName) {
855
- return carrierOf(ctor)[ENTITLEMENTS]?.[fnName];
856
- }
857
- function spendFor(ctor, fnName) {
858
- return carrierOf(ctor)[SPENDS]?.[fnName];
859
- }
860
-
861
- // src/purchases/subject.ts
862
- var subjectByRequest = /* @__PURE__ */ new WeakMap();
863
- function storeEnv() {
864
- return process.env.PALSTORE_STORE_ENV === "sandbox" ? "sandbox" : "production";
865
- }
866
- async function currentSubjectId() {
867
- const store = __requestALS.getStore();
868
- if (!store) {
869
- throw new Error(
870
- "Purchases decorators used outside a request scope. @RequireEntitlement/@Spend resolve the subject from the request's authenticated user, so they only work inside an endpoint handler."
871
- );
872
- }
873
- const memoized = subjectByRequest.get(store);
874
- if (memoized) return memoized;
875
- const userId = store.userId;
876
- if (!userId) {
877
- throw new Unauthorized(
878
- "This endpoint requires an authenticated user: purchases entitlements and quota are per-user, and the subject is resolved from the request's identity."
879
- );
880
- }
881
- const resolving = Purchases.resolveSubject({ userRef: userId, storeEnv: storeEnv() }).then(
882
- (r) => r.subjectId
883
- );
884
- subjectByRequest.set(store, resolving);
885
- resolving.catch(() => subjectByRequest.delete(store));
886
- return resolving;
887
- }
888
-
889
- // src/purchases/decorators.ts
890
- var WRAPPED = /* @__PURE__ */ Symbol.for("palbase.backend.purchases.wrapped");
891
- function idempotencyKeyFor(key) {
892
- const store = __requestALS.getStore();
893
- const base = store?.idempotencyKey || store?.requestId;
894
- if (!base) {
895
- throw new Error(
896
- "@Spend needs a request-scoped idempotency key, and the runtime supplied neither an Idempotency-Key header nor a request id. Spending without one would let a retried request charge the user twice."
897
- );
898
- }
899
- return `${base}:${key}`;
900
- }
901
- function ensureWrapper(target, fnName, descriptor) {
902
- const original = descriptor.value;
903
- if (typeof original !== "function") {
904
- throw new Error(
905
- `@RequireEntitlement/@Spend can only decorate a method; "${fnName}" is not one.`
906
- );
907
- }
908
- if (original[WRAPPED]) return;
909
- const wrapper = async function(...args) {
910
- const ctor = this.constructor;
911
- const entitlement = entitlementFor(ctor, fnName);
912
- const spend = spendFor(ctor, fnName);
913
- let subjectId;
914
- try {
915
- subjectId = await currentSubjectId();
916
- } catch (err) {
917
- throw toHttpError(err);
918
- }
919
- if (entitlement !== void 0) {
920
- try {
921
- await Purchases.require(subjectId, entitlement);
922
- } catch (err) {
923
- throw toHttpError(err);
924
- }
925
- }
926
- if (spend === void 0) {
927
- return original.apply(this, args);
928
- }
929
- let handlerFailure;
930
- try {
931
- return await Purchases.withSpend(
932
- subjectId,
933
- spend.key,
934
- { count: spend.count, idempotencyKey: idempotencyKeyFor(spend.key) },
935
- async () => {
936
- try {
937
- return await original.apply(this, args);
938
- } catch (err) {
939
- handlerFailure = { err };
940
- throw err;
941
- }
942
- }
943
- );
944
- } catch (err) {
945
- if (handlerFailure !== void 0 && handlerFailure.err === err) throw err;
946
- throw toHttpError(err);
947
- }
948
- };
949
- wrapper[WRAPPED] = true;
950
- descriptor.value = wrapper;
951
- }
952
- function RequireEntitlement(key) {
953
- return function(target, propertyKey, descriptor) {
954
- const fnName = String(propertyKey);
955
- recordEntitlement(target, fnName, key);
956
- ensureWrapper(target, fnName, descriptor);
957
- };
958
- }
959
- function Spend(key) {
960
- return function(target, propertyKey, descriptor) {
961
- const fnName = String(propertyKey);
962
- recordSpend(target, fnName, { key, count: 1 });
963
- ensureWrapper(target, fnName, descriptor);
964
- };
965
- }
966
-
967
700
  // src/clients/http.ts
968
701
  var PalbaseModuleError = class extends Error {
969
702
  code;
@@ -1309,12 +1042,12 @@ function buildFlagsClient(http, cfg) {
1309
1042
  return {
1310
1043
  data: Object.keys(values).map((name) => {
1311
1044
  const value = values[name];
1312
- const flag2 = {
1045
+ const flag = {
1313
1046
  name,
1314
1047
  enabled: flagEnabled(value)
1315
1048
  };
1316
- if (typeof value === "string") flag2.variant = { name: value };
1317
- return flag2;
1049
+ if (typeof value === "string") flag.variant = { name: value };
1050
+ return flag;
1318
1051
  }),
1319
1052
  error: null,
1320
1053
  status: res.status
@@ -1542,18 +1275,99 @@ function buildNotificationsClient(http) {
1542
1275
 
1543
1276
  // src/clients/realtime.ts
1544
1277
  var import_node_crypto = require("crypto");
1545
- function mintToken(secret2) {
1278
+ function mintToken(secret) {
1546
1279
  const now2 = Math.floor(Date.now() / 1e3);
1547
1280
  const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
1548
1281
  const payload = Buffer.from(
1549
1282
  JSON.stringify({ iss: "backend-runtime", role: "service_role", iat: now2, exp: now2 + 60 })
1550
1283
  ).toString("base64url");
1551
- const sig = (0, import_node_crypto.createHmac)("sha256", secret2).update(`${header}.${payload}`).digest("base64url");
1284
+ const sig = (0, import_node_crypto.createHmac)("sha256", secret).update(`${header}.${payload}`).digest("base64url");
1552
1285
  return `${header}.${payload}.${sig}`;
1553
1286
  }
1554
1287
  function buildRealtimeClient(cfg) {
1555
1288
  const url = `${cfg.baseUrl}/realtime/api/broadcast`;
1289
+ const stateUrl = `${cfg.baseUrl}/realtime/api/state`;
1290
+ async function writeState(topic, key, value, del) {
1291
+ if (typeof topic !== "string" || topic.length === 0) {
1292
+ return {
1293
+ data: null,
1294
+ error: new PalbaseModuleError("invalid_argument", "topic must be a non-empty string", 400)
1295
+ };
1296
+ }
1297
+ if (typeof key !== "string" || key.length === 0) {
1298
+ return {
1299
+ data: null,
1300
+ error: new PalbaseModuleError("invalid_argument", "key must be a non-empty string", 400)
1301
+ };
1302
+ }
1303
+ if (!cfg.apiJwtSecret) {
1304
+ return {
1305
+ data: null,
1306
+ error: new PalbaseModuleError(
1307
+ "realtime_unconfigured",
1308
+ "Realtime.state is unavailable: realtime is not provisioned for this Environment (PALBASE_REALTIME_API_JWT_SECRET unset).",
1309
+ 503
1310
+ )
1311
+ };
1312
+ }
1313
+ let token;
1314
+ try {
1315
+ token = mintToken(cfg.apiJwtSecret);
1316
+ } catch (err) {
1317
+ return {
1318
+ data: null,
1319
+ error: new PalbaseModuleError(
1320
+ "realtime_token_error",
1321
+ err instanceof Error ? err.message : "token mint failed",
1322
+ 500
1323
+ )
1324
+ };
1325
+ }
1326
+ const op = del ? { topic, key, del: true } : { topic, key, value: value ?? {} };
1327
+ const doFetch = cfg.fetchImpl ?? globalThis.fetch;
1328
+ let response;
1329
+ try {
1330
+ response = await doFetch(stateUrl, {
1331
+ method: "POST",
1332
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
1333
+ body: JSON.stringify({ ops: [op] })
1334
+ });
1335
+ } catch (err) {
1336
+ return {
1337
+ data: null,
1338
+ error: new PalbaseModuleError(
1339
+ "network_error",
1340
+ err instanceof Error ? err.message : "state request failed",
1341
+ 0
1342
+ )
1343
+ };
1344
+ }
1345
+ if (response.status === 202 || response.status === 200) {
1346
+ return { data: void 0, error: null };
1347
+ }
1348
+ const detail = await response.text().catch(() => "");
1349
+ return {
1350
+ data: null,
1351
+ error: new PalbaseModuleError(
1352
+ "realtime_state_failed",
1353
+ `realtime state write returned ${response.status}${detail ? `: ${detail}` : ""}`,
1354
+ response.status
1355
+ )
1356
+ };
1357
+ }
1556
1358
  return {
1359
+ state: {
1360
+ /** Write one DURABLE entry on a channel's shared state.
1361
+ *
1362
+ * The difference from broadcast is WHO it reaches: a broadcast reaches
1363
+ * whoever is listening at that instant, while state is also handed to
1364
+ * whoever joins afterwards. "This value is now X" wants the second — a
1365
+ * client connecting a second later should not have to wait for the next
1366
+ * change to learn X. */
1367
+ set: (topic, key, value) => writeState(topic, key, value, false),
1368
+ /** Remove one entry. */
1369
+ clear: (topic, key) => writeState(topic, key, void 0, true)
1370
+ },
1557
1371
  async broadcast(channel, event, payload) {
1558
1372
  if (typeof channel !== "string" || channel.length === 0) {
1559
1373
  return {
@@ -1638,11 +1452,11 @@ function validateStoragePath(p) {
1638
1452
  );
1639
1453
  }
1640
1454
  }
1641
- function toFileObject(bucket2, row) {
1455
+ function toFileObject(bucket, row) {
1642
1456
  return {
1643
1457
  name: row.path ?? "",
1644
1458
  path: row.path ?? "",
1645
- bucket: row.bucket ?? bucket2,
1459
+ bucket: row.bucket ?? bucket,
1646
1460
  size: typeof row.size === "number" ? row.size : 0,
1647
1461
  contentType: row.contentType ?? "",
1648
1462
  checksum: row.checksum ?? "",
@@ -1758,35 +1572,6 @@ function buildModuleClients(cfg) {
1758
1572
  };
1759
1573
  }
1760
1574
 
1761
- // src/purchases/keys-gen.ts
1762
- function liveKeys(entries) {
1763
- return Object.entries(entries ?? {}).filter(([, def]) => def?.removed !== true).map(([key]) => key).sort();
1764
- }
1765
- function memberName(key) {
1766
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
1767
- }
1768
- function members(keys) {
1769
- if (keys.length === 0) return "";
1770
- return `
1771
- ${keys.map((k) => ` ${memberName(k)}: true;`).join("\n")}
1772
- `;
1773
- }
1774
- function makePurchasesDts(manifest) {
1775
- const entitlements = liveKeys(manifest.entitlements);
1776
- const limits = liveKeys({ ...manifest.limits, ...manifest.credits });
1777
- return `// palbase-purchases.d.ts \u2014 GENERATED by @palbase/backend. Do not edit.
1778
- // Source: the project's palstore catalog revision.
1779
-
1780
- declare module "@palbase/backend/purchases" {
1781
- interface Entitlements {${members(entitlements)}}
1782
-
1783
- interface Limits {${members(limits)}}
1784
- }
1785
-
1786
- export {};
1787
- `;
1788
- }
1789
-
1790
1575
  // src/db/policy.ts
1791
1576
  var PolicyBuilder = class {
1792
1577
  _def;
@@ -1861,8 +1646,82 @@ function defineSchema(input) {
1861
1646
  if (table.raw !== void 0 && table.raw.length > 0) tableDef.raw = table.raw.slice();
1862
1647
  if (table.checks !== void 0 && table.checks.length > 0) tableDef.checks = table.checks.slice();
1863
1648
  if (table.indexes !== void 0 && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();
1649
+ if (table.search !== void 0) {
1650
+ const s = table.search;
1651
+ if (s.from !== void 0) {
1652
+ if (s.vector !== void 0) {
1653
+ throw new Error(
1654
+ `table ${String(name)}: search beyan\u0131nda tek bi\xE7im kullan\u0131n \u2014 'from' (yeni) ile 'vector' (eski) birlikte olamaz`
1655
+ );
1656
+ }
1657
+ if (s.from.length === 0) {
1658
+ throw new Error(`table ${String(name)}: search.from bo\u015F olamaz`);
1659
+ }
1660
+ if (s.model === void 0) {
1661
+ throw new Error(
1662
+ `table ${String(name)}: search.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin (BYO i\xE7in eski 'vector' bi\xE7imini kullan\u0131n)`
1663
+ );
1664
+ }
1665
+ if (Array.isArray(s.text) && s.text.length === 0) {
1666
+ throw new Error(`table ${String(name)}: search.text bo\u015F dizi olamaz \u2014 FTS istemiyorsan text: false yaz\u0131n`);
1667
+ }
1668
+ } else {
1669
+ if (typeof s.text === "boolean") {
1670
+ throw new Error(`table ${String(name)}: text:${String(s.text)} yaln\u0131z yeni bi\xE7imde ('from' ile) ge\xE7erli`);
1671
+ }
1672
+ if (s.text === void 0 && s.vector === void 0) {
1673
+ throw new Error(
1674
+ `table ${String(name)}: search beyan\u0131 bo\u015F \u2014 en az bir kol (text ya da vector) verin, yoksa alan\u0131 hi\xE7 yazmay\u0131n`
1675
+ );
1676
+ }
1677
+ if (s.text !== void 0 && s.text.length === 0) {
1678
+ throw new Error(`table ${String(name)}: search.text bo\u015F olamaz \u2014 FTS kolu istemiyorsan alan\u0131 hi\xE7 yazma`);
1679
+ }
1680
+ const legs = s.vector === void 0 ? [] : Array.isArray(s.vector) ? s.vector : [s.vector];
1681
+ for (const leg of legs) {
1682
+ if (leg.model !== void 0 && (leg.from === void 0 || leg.from.length === 0)) {
1683
+ throw new Error(`table ${String(name)}: search.vector.model beyan edildi ama 'from' yok \u2014 embed kayna\u011F\u0131 kolonlar zorunlu (C-2)`);
1684
+ }
1685
+ if (leg.model === void 0 && leg.from !== void 0) {
1686
+ throw new Error(`table ${String(name)}: search.vector.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin`);
1687
+ }
1688
+ }
1689
+ }
1690
+ tableDef.search = s;
1691
+ }
1692
+ if (table.memory !== void 0) {
1693
+ if (table.memory.from.length === 0) {
1694
+ throw new Error(`table ${String(name)}: memory.from bo\u015F olamaz`);
1695
+ }
1696
+ tableDef.memory = table.memory;
1697
+ }
1864
1698
  tables[name] = tableDef;
1865
1699
  }
1700
+ for (const [name, def] of Object.entries(tables)) {
1701
+ const m = def.memory;
1702
+ if (m === void 0) continue;
1703
+ const target = Object.values(tables).find((t) => t.name === m.into);
1704
+ if (target === void 0) {
1705
+ throw new Error(`table ${name}: memory.into "${m.into}" \u015Femada declared de\u011Fil`);
1706
+ }
1707
+ const subject = m.subject ?? "owner";
1708
+ if (!(subject in def.columns)) {
1709
+ throw new Error(`table ${name}: memory.subject "${subject}" kolonu kaynak tabloda yok`);
1710
+ }
1711
+ if (!(subject in target.columns)) {
1712
+ throw new Error(`table ${name}: memory.subject "${subject}" kolonu hedef "${m.into}" tablosunda yok`);
1713
+ }
1714
+ const factCol = target.columns["fact"];
1715
+ const factDef = factCol !== void 0 && "_def" in factCol ? factCol._def : factCol;
1716
+ if (factDef === void 0 || factDef.type !== "text") {
1717
+ throw new Error(`table ${name}: memory.into "${m.into}" tablosunda "fact" (text) kolonu zorunlu`);
1718
+ }
1719
+ for (const c of m.from) {
1720
+ if (!(c in def.columns)) {
1721
+ throw new Error(`table ${name}: memory.from kolonu "${c}" kaynak tabloda yok`);
1722
+ }
1723
+ }
1724
+ }
1866
1725
  const extensions = [...new Set(input.extensions ?? [])];
1867
1726
  return { tables, extensions };
1868
1727
  }
@@ -1889,6 +1748,7 @@ function columnToJSON(column) {
1889
1748
  if (def.enumName !== void 0) out.enumName = def.enumName;
1890
1749
  if (def.enumValues !== void 0) out.enumValues = [...def.enumValues];
1891
1750
  if (def.unique === true) out.unique = true;
1751
+ if (def.dimensions !== void 0) out.dimensions = def.dimensions;
1892
1752
  return out;
1893
1753
  }
1894
1754
  function policyToJSON(policy2) {
@@ -1904,6 +1764,75 @@ function policyToJSON(policy2) {
1904
1764
  permissive: policy2.permissive !== false
1905
1765
  };
1906
1766
  }
1767
+ function commonSearchFields(search, out) {
1768
+ if (search.synonyms !== void 0 && Object.keys(search.synonyms).length > 0) {
1769
+ out.synonyms = Object.fromEntries(
1770
+ Object.entries(search.synonyms).map(([word, alts]) => [word, [...alts]])
1771
+ );
1772
+ }
1773
+ if (search.validity === true) out.validity = true;
1774
+ }
1775
+ function searchToJSON(search, vectorColumn) {
1776
+ if (search.from !== void 0 && search.model !== void 0) {
1777
+ const out2 = {};
1778
+ const textCols = search.text === false ? void 0 : Array.isArray(search.text) && search.text.length > 0 ? search.text : search.from;
1779
+ if (textCols !== void 0) out2.text = { columns: [...textCols] };
1780
+ const v = { metric: search.metric ?? "cosine" };
1781
+ if (vectorColumn !== void 0) v.column = vectorColumn;
1782
+ v.embed = {
1783
+ provider: search.model.provider,
1784
+ model: search.model.model,
1785
+ from: [...search.from],
1786
+ ...search.model.apiKeyName !== void 0 ? { apiKeyName: search.model.apiKeyName } : {},
1787
+ ...search.model.dimensions !== void 0 ? { dimensions: search.model.dimensions } : {},
1788
+ ...search.model.baseURL !== void 0 ? { baseURL: search.model.baseURL } : {}
1789
+ };
1790
+ if (search.staleness !== void 0) v.staleness = search.staleness;
1791
+ if (vectorColumn === void 0) {
1792
+ v.mode = "chunks";
1793
+ if (search.chunks !== void 0) {
1794
+ const c = {};
1795
+ if (search.chunks.size !== void 0 && search.chunks.size > 0) c.sizeChars = search.chunks.size;
1796
+ if (search.chunks.overlap !== void 0 && search.chunks.overlap > 0) c.overlapChars = search.chunks.overlap;
1797
+ if (Object.keys(c).length > 0) v.chunks = c;
1798
+ }
1799
+ }
1800
+ out2.vector = [v];
1801
+ commonSearchFields(search, out2);
1802
+ return out2;
1803
+ }
1804
+ const out = {};
1805
+ if (Array.isArray(search.text) && search.text.length > 0) out.text = { columns: [...search.text] };
1806
+ const legs = search.vector === void 0 ? [] : Array.isArray(search.vector) ? search.vector : [search.vector];
1807
+ if (legs.length > 0) {
1808
+ out.vector = legs.map((leg) => {
1809
+ const v = { metric: leg.metric ?? "cosine" };
1810
+ if (leg.column !== void 0) v.column = leg.column;
1811
+ if (leg.staleness !== void 0) v.staleness = leg.staleness;
1812
+ if (leg.model !== void 0) {
1813
+ v.embed = {
1814
+ provider: leg.model.provider,
1815
+ model: leg.model.model,
1816
+ from: [...leg.from ?? []],
1817
+ ...leg.model.apiKeyName !== void 0 ? { apiKeyName: leg.model.apiKeyName } : {},
1818
+ ...leg.model.dimensions !== void 0 ? { dimensions: leg.model.dimensions } : {},
1819
+ ...leg.model.baseURL !== void 0 ? { baseURL: leg.model.baseURL } : {}
1820
+ };
1821
+ }
1822
+ return v;
1823
+ });
1824
+ }
1825
+ commonSearchFields(search, out);
1826
+ return out;
1827
+ }
1828
+ function memoryToJSON(m) {
1829
+ return {
1830
+ from: [...m.from],
1831
+ into: m.into,
1832
+ ...m.subject !== void 0 ? { subject: m.subject } : {},
1833
+ extract: { provider: m.extract.provider, model: m.extract.model }
1834
+ };
1835
+ }
1907
1836
  function tableToJSON(table) {
1908
1837
  const columns = {};
1909
1838
  for (const [name, column] of Object.entries(table.columns)) {
@@ -1939,6 +1868,14 @@ function tableToJSON(table) {
1939
1868
  if (table.indexes !== void 0 && table.indexes.length > 0) {
1940
1869
  out.indexes = table.indexes.map((i) => ({ name: i.name, columns: [...i.columns] }));
1941
1870
  }
1871
+ if (table.search !== void 0) {
1872
+ const vectorColumn = Object.entries(columns).find(([, c]) => c.dimensions !== void 0)?.[0];
1873
+ const sj = searchToJSON(table.search, vectorColumn);
1874
+ if (sj.text !== void 0 || sj.vector !== void 0) out.search = sj;
1875
+ }
1876
+ if (table.memory !== void 0) {
1877
+ out.memory = memoryToJSON(table.memory);
1878
+ }
1942
1879
  return out;
1943
1880
  }
1944
1881
  function toSchemaJSON(schema) {
@@ -1950,6 +1887,63 @@ function toSchemaJSON(schema) {
1950
1887
  return { tables, extensions: [...new Set(schema.extensions ?? [])] };
1951
1888
  }
1952
1889
 
1890
+ // src/channels.ts
1891
+ var CHANNELS = /* @__PURE__ */ Symbol.for("palbase.backend.channels");
1892
+ function ownerOnly() {
1893
+ return { kind: "owner" };
1894
+ }
1895
+ function publicChannel(opts = {}) {
1896
+ return { kind: "public", publish: opts.publish ?? false, state: opts.state };
1897
+ }
1898
+ function paramCount(pattern) {
1899
+ return pattern.split(":").filter((s) => s.startsWith("{") && s.endsWith("}")).length;
1900
+ }
1901
+ function defineChannels(map) {
1902
+ const entries = [];
1903
+ for (const [pattern, entry] of Object.entries(map)) {
1904
+ if ("kind" in entry && entry.kind === "owner") {
1905
+ if (paramCount(pattern) !== 1) {
1906
+ throw new Error(
1907
+ `defineChannels: ownerOnly() pattern "${pattern}" must carry exactly one {param} (its value is compared to the token subject)`
1908
+ );
1909
+ }
1910
+ entries.push({ pattern, kind: "owner" });
1911
+ } else if ("kind" in entry && entry.kind === "public") {
1912
+ entries.push({ pattern, kind: "public", publish: entry.publish, state: entry.state });
1913
+ } else {
1914
+ const c = entry;
1915
+ entries.push({ pattern, kind: "custom", authorize: c.authorize, handler: c.handler });
1916
+ }
1917
+ }
1918
+ const def = { entries };
1919
+ const carrier = globalThis;
1920
+ const existing = carrier[CHANNELS];
1921
+ if (existing && !sameDeclaration(existing, def)) {
1922
+ throw new Error(
1923
+ `defineChannels: channels were already declared (${existing.entries.length} pattern(s): ${existing.entries.map((e) => e.pattern).join(", ")}). A project declares its channels ONCE \u2014 a second call would overwrite the first, and channels nobody declared are refused.`
1924
+ );
1925
+ }
1926
+ carrier[CHANNELS] = def;
1927
+ return def;
1928
+ }
1929
+ function wireRow(e) {
1930
+ return JSON.stringify([
1931
+ e.pattern,
1932
+ e.kind,
1933
+ e.publish ?? false,
1934
+ e.state?.read ?? false,
1935
+ e.state?.write ?? false,
1936
+ // The handler is compared by SOURCE, like authorize: two evaluations of one
1937
+ // module give the same text, while different logic gives different text.
1938
+ e.handler ? e.handler.toString() : "",
1939
+ e.authorize ? e.authorize.toString() : ""
1940
+ ]);
1941
+ }
1942
+ function sameDeclaration(a, b) {
1943
+ if (a.entries.length !== b.entries.length) return false;
1944
+ return a.entries.every((x, i) => wireRow(x) === wireRow(b.entries[i]));
1945
+ }
1946
+
1953
1947
  // src/db/extensions.ts
1954
1948
  var PALBASE_EXTENSIONS = [
1955
1949
  // Search & text
@@ -1963,8 +1957,6 @@ var PALBASE_EXTENSIONS = [
1963
1957
  "citext",
1964
1958
  // case-insensitive text type
1965
1959
  // Geospatial / location
1966
- "postgis",
1967
- // geospatial types + queries (maps, "near me")
1968
1960
  "cube",
1969
1961
  // multi-dimensional cubes (dependency of earthdistance)
1970
1962
  "earthdistance",
@@ -1979,8 +1971,6 @@ var PALBASE_EXTENSIONS = [
1979
1971
  // GiST operator classes for scalar types — needed for EXCLUDE
1980
1972
  // constraints that mix "=" with a range/&& overlap (e.g. no-double-booking).
1981
1973
  // Scheduling
1982
- "pg_cron",
1983
- // schedule jobs inside the database
1984
1974
  // Crypto / ids (also installed by default; listable for explicitness)
1985
1975
  "pgcrypto",
1986
1976
  // cryptographic functions (hashing, encryption)
@@ -1995,6 +1985,11 @@ function isPalbaseExtension(name) {
1995
1985
  }
1996
1986
 
1997
1987
  // src/db/columns.ts
1988
+ function refuseOnVector(def, modifier) {
1989
+ if (def.type === "vector") {
1990
+ throw new Error(`vector column: .${modifier}() is not supported (FR-002 \u2014 allowed: nullable()/notNull())`);
1991
+ }
1992
+ }
1998
1993
  var ColumnBuilder = class _ColumnBuilder {
1999
1994
  _def;
2000
1995
  constructor(type, existingDef) {
@@ -2006,6 +2001,7 @@ var ColumnBuilder = class _ColumnBuilder {
2006
2001
  }
2007
2002
  /** Mark this column as the primary key. */
2008
2003
  primaryKey() {
2004
+ refuseOnVector(this._def, "primaryKey");
2009
2005
  this._def.primaryKey = true;
2010
2006
  return new _ColumnBuilder(this._def.type, this._def);
2011
2007
  }
@@ -2021,16 +2017,19 @@ var ColumnBuilder = class _ColumnBuilder {
2021
2017
  }
2022
2018
  /** Set a default value. */
2023
2019
  default(value) {
2020
+ refuseOnVector(this._def, "default");
2024
2021
  this._def.defaultValue = value;
2025
2022
  return new _ColumnBuilder(this._def.type, this._def);
2026
2023
  }
2027
2024
  /** UUID: generate a random default (gen_random_uuid()). */
2028
2025
  defaultRandom() {
2026
+ refuseOnVector(this._def, "defaultRandom");
2029
2027
  this._def.defaultRandom = true;
2030
2028
  return new _ColumnBuilder(this._def.type, this._def);
2031
2029
  }
2032
2030
  /** Timestamp: default to now(). */
2033
2031
  defaultNow() {
2032
+ refuseOnVector(this._def, "defaultNow");
2034
2033
  this._def.defaultNow = true;
2035
2034
  return new _ColumnBuilder(this._def.type, this._def);
2036
2035
  }
@@ -2051,6 +2050,7 @@ var ColumnBuilder = class _ColumnBuilder {
2051
2050
  return this;
2052
2051
  }
2053
2052
  references(table, column) {
2053
+ refuseOnVector(this._def, "references");
2054
2054
  this._def.references = { table, column };
2055
2055
  return new _ColumnBuilder(this._def.type, this._def);
2056
2056
  }
@@ -2075,6 +2075,7 @@ var ColumnBuilder = class _ColumnBuilder {
2075
2075
  * as the real boundary; this signature is the compile-time DX mirror.
2076
2076
  */
2077
2077
  referencesAuthUser(onDelete) {
2078
+ refuseOnVector(this._def, "referencesAuthUser");
2078
2079
  this._def.references = { table: "auth.users", column: "id" };
2079
2080
  this._def.onDeleteAction = onDelete;
2080
2081
  return new _ColumnBuilder(this._def.type, this._def);
@@ -2098,6 +2099,7 @@ var ColumnBuilder = class _ColumnBuilder {
2098
2099
  * boundary; this signature is the compile-time DX mirror.
2099
2100
  */
2100
2101
  referencesInstallation(onDelete) {
2102
+ refuseOnVector(this._def, "referencesInstallation");
2101
2103
  this._def.references = { table: "auth.installations", column: "id" };
2102
2104
  this._def.onDeleteAction = onDelete;
2103
2105
  return new _ColumnBuilder(this._def.type, this._def);
@@ -2109,6 +2111,7 @@ var ColumnBuilder = class _ColumnBuilder {
2109
2111
  }
2110
2112
  /** Add a single-column UNIQUE constraint. */
2111
2113
  unique() {
2114
+ refuseOnVector(this._def, "unique");
2112
2115
  this._def.unique = true;
2113
2116
  return new _ColumnBuilder(this._def.type, this._def);
2114
2117
  }
@@ -2143,12 +2146,36 @@ function enumType(name, values) {
2143
2146
  builder._def.enumValues = [...values];
2144
2147
  return builder;
2145
2148
  }
2149
+ function vector(dimensions) {
2150
+ if (!Number.isInteger(dimensions) || dimensions < 1 || dimensions > 2e3) {
2151
+ throw new Error(`vector(): dimensions must be an integer in [1, 2000], got ${String(dimensions)}`);
2152
+ }
2153
+ const b = new ColumnBuilder("vector");
2154
+ b._def.dimensions = dimensions;
2155
+ return b;
2156
+ }
2146
2157
 
2147
2158
  // src/db/raw.ts
2148
2159
  function raw(name, up, opts) {
2149
2160
  return { name, up, ...opts?.down != null ? { down: opts.down } : {} };
2150
2161
  }
2151
2162
 
2163
+ // src/db/embedding.ts
2164
+ var openai = {
2165
+ embedding(model, opts) {
2166
+ return {
2167
+ provider: "openai",
2168
+ model,
2169
+ apiKeyName: opts?.apiKeyName ?? "OPENAI_API_KEY",
2170
+ ...opts?.dimensions !== void 0 ? { dimensions: opts.dimensions } : {},
2171
+ ...opts?.baseURL !== void 0 ? { baseURL: opts.baseURL } : {}
2172
+ };
2173
+ },
2174
+ chat(model) {
2175
+ return { provider: "openai", model };
2176
+ }
2177
+ };
2178
+
2152
2179
  // src/db/typed-db.ts
2153
2180
  function makeTypedTable(name, raw2) {
2154
2181
  return {
@@ -2208,6 +2235,11 @@ function baseTsType(def) {
2208
2235
  return "boolean";
2209
2236
  case "jsonb":
2210
2237
  return "unknown";
2238
+ // FR-008: the authoring type of a pgvector column. The default `unknown`
2239
+ // branch below STAYS — an unknown wire type is refused on the Go side
2240
+ // (FR-005), never papered over here.
2241
+ case "vector":
2242
+ return "number[]";
2211
2243
  case "enum": {
2212
2244
  const values = def.enumValues ?? [];
2213
2245
  if (values.length === 0) return "string";
@@ -2241,10 +2273,10 @@ function buildChildEdges(schema) {
2241
2273
  const ref = builder._def.references;
2242
2274
  if (ref === void 0) continue;
2243
2275
  if (ref.table === childName) continue;
2244
- const bucket2 = edges.get(ref.table);
2245
- if (bucket2 === void 0) continue;
2246
- if (bucket2.some((e) => e.child === childName)) continue;
2247
- bucket2.push({ child: childName, column: col });
2276
+ const bucket = edges.get(ref.table);
2277
+ if (bucket === void 0) continue;
2278
+ if (bucket.some((e) => e.child === childName)) continue;
2279
+ bucket.push({ child: childName, column: col });
2248
2280
  }
2249
2281
  }
2250
2282
  return edges;
@@ -2289,6 +2321,10 @@ function tableBlock(table, children, indent) {
2289
2321
  `${indent} };`,
2290
2322
  `${indent} owner: ${owner === null ? "null" : JSON.stringify(owner)};`,
2291
2323
  `${indent} children: {${childEntries === "" ? "" : ` ${childEntries} `}};`,
2324
+ // searchable: vector kolonu YA DA search beyanı → EnvTypedTable'da search()
2325
+ // üyesini açan yapısal bayrak (FR-013). Yokken satır hiç üretilmez ki
2326
+ // mevcut şemaların d.ts'i bayt-aynı kalsın.
2327
+ ...cols.some(([, b]) => b._def.type === "vector") || table.search !== void 0 ? [`${indent} searchable: true;`] : [],
2292
2328
  `${indent}};`
2293
2329
  ].join("\n");
2294
2330
  }
@@ -2314,638 +2350,50 @@ export {};
2314
2350
  `;
2315
2351
  }
2316
2352
 
2317
- // src/config/storage.ts
2318
- var STORAGE_CONFIG_KIND = "storage";
2319
- var VARIANT_FORMATS = ["webp", "avif", "jpeg", "png"];
2320
- var VARIANT_FITS = ["cover", "contain", "inside"];
2321
- function normalizeVariants(input) {
2322
- if (input === null || typeof input !== "object" || Array.isArray(input)) {
2323
- throw new Error("bucket variants must be an object of { <name>: { width?, height?, format? } }");
2324
- }
2325
- const out = {};
2326
- for (const [name, spec] of Object.entries(input)) {
2327
- if (!/^[a-z0-9][a-z0-9_-]*$/i.test(name)) {
2328
- throw new Error(
2329
- `bucket variant name "${name}" must be alphanumeric with optional - or _ (e.g. "thumb", "card_2x")`
2330
- );
2331
- }
2332
- if (spec === null || typeof spec !== "object" || Array.isArray(spec)) {
2333
- throw new Error(`bucket variant "${name}" must be an object like { width: 100, height: 100 }`);
2334
- }
2335
- for (const dim of ["width", "height"]) {
2336
- const value = spec[dim];
2337
- if (value === void 0) continue;
2338
- if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
2339
- throw new Error(`bucket variant "${name}" ${dim} must be a positive integer, got ${String(value)}`);
2340
- }
2341
- }
2342
- if (spec.width === void 0 && spec.height === void 0) {
2343
- throw new Error(`bucket variant "${name}" must set width and/or height`);
2344
- }
2345
- if (spec.format !== void 0 && !VARIANT_FORMATS.includes(spec.format)) {
2346
- throw new Error(
2347
- `bucket variant "${name}" format must be one of ${VARIANT_FORMATS.join(", ")}, got "${String(spec.format)}"`
2348
- );
2349
- }
2350
- if (spec.fit !== void 0 && !VARIANT_FITS.includes(spec.fit)) {
2351
- throw new Error(
2352
- `bucket variant "${name}" fit must be one of ${VARIANT_FITS.join(", ")}, got "${String(spec.fit)}"`
2353
- );
2354
- }
2355
- if (spec.quality !== void 0) {
2356
- const q = spec.quality;
2357
- if (typeof q !== "number" || !Number.isInteger(q) || q < 1 || q > 100) {
2358
- throw new Error(`bucket variant "${name}" quality must be an integer 1\u2013100, got ${String(q)}`);
2359
- }
2360
- }
2361
- if (spec.fit === "cover" && (spec.width === void 0 || spec.height === void 0)) {
2362
- throw new Error(`bucket variant "${name}" uses fit "cover", which needs BOTH width and height`);
2363
- }
2364
- out[name] = {
2365
- ...spec.width !== void 0 ? { width: spec.width } : {},
2366
- ...spec.height !== void 0 ? { height: spec.height } : {},
2367
- ...spec.fit !== void 0 ? { fit: spec.fit } : {},
2368
- ...spec.format !== void 0 ? { format: spec.format } : {},
2369
- ...spec.quality !== void 0 ? { quality: spec.quality } : {}
2370
- };
2371
- }
2372
- return out;
2353
+ // src/stack-gen.ts
2354
+ function liveNames(names) {
2355
+ return [...new Set(names)].sort();
2373
2356
  }
2374
- var UNIT_BYTES = {
2375
- b: 1,
2376
- kb: 1024,
2377
- mb: 1024 ** 2,
2378
- gb: 1024 ** 3,
2379
- tb: 1024 ** 4
2380
- };
2381
- function parseFileSizeLimit(input) {
2382
- if (typeof input === "number") {
2383
- if (!Number.isFinite(input) || input < 0 || !Number.isInteger(input)) {
2384
- throw new Error(
2385
- `bucket fileSizeLimit must be a non-negative integer number of bytes, got ${input}`
2386
- );
2387
- }
2388
- return input;
2389
- }
2390
- const trimmed = input.trim();
2391
- const match = /^(\d+(?:\.\d+)?)\s*([a-zA-Z]+)?$/.exec(trimmed);
2392
- if (!match) {
2393
- throw new Error(
2394
- `bucket fileSizeLimit string must be "<number><unit>" like "5MB" or "1GB", got "${input}"`
2395
- );
2396
- }
2397
- const value = Number.parseFloat(match[1]);
2398
- const unit = (match[2] ?? "b").toLowerCase();
2399
- const multiplier = UNIT_BYTES[unit];
2400
- if (multiplier === void 0) {
2401
- throw new Error(
2402
- `bucket fileSizeLimit has an unknown unit "${match[2]}" \u2014 use B, KB, MB, GB, or TB (e.g. "5MB")`
2403
- );
2404
- }
2405
- const bytes = value * multiplier;
2406
- if (!Number.isFinite(bytes) || bytes < 0) {
2407
- throw new Error(`bucket fileSizeLimit resolved to an invalid byte count: ${bytes}`);
2408
- }
2409
- return Math.round(bytes);
2357
+ function memberName(name) {
2358
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
2410
2359
  }
2411
- var MIME_RE = /^[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*\/(?:\*|[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]*)$/;
2412
- function bucket(opts = {}) {
2413
- const fileSizeLimit = opts.fileSizeLimit === void 0 ? null : parseFileSizeLimit(opts.fileSizeLimit);
2414
- let allowedMimeTypes = null;
2415
- if (opts.allowedMimeTypes !== void 0) {
2416
- if (!Array.isArray(opts.allowedMimeTypes)) {
2417
- throw new Error("bucket allowedMimeTypes must be an array of MIME-type strings");
2418
- }
2419
- for (const mime of opts.allowedMimeTypes) {
2420
- if (typeof mime !== "string" || !MIME_RE.test(mime.trim())) {
2421
- throw new Error(
2422
- `bucket allowedMimeTypes entry "${mime}" is not a valid MIME type (expected "type/subtype", e.g. "image/png")`
2423
- );
2424
- }
2425
- }
2426
- allowedMimeTypes = [...new Set(opts.allowedMimeTypes.map((m) => m.trim()))];
2427
- }
2428
- return {
2429
- public: opts.public ?? false,
2430
- fileSizeLimit,
2431
- allowedMimeTypes,
2432
- variants: opts.variants === void 0 ? null : normalizeVariants(opts.variants)
2433
- };
2360
+ function members(names) {
2361
+ if (names.length === 0) return "";
2362
+ return `
2363
+ ${names.map((n) => ` ${memberName(n)}: true;`).join("\n")}
2364
+ `;
2434
2365
  }
2435
- function defineStorage(input) {
2436
- if (input === null || typeof input !== "object" || typeof input.buckets !== "object") {
2437
- throw new Error("defineStorage expects { buckets: { <name>: bucket({...}) } }");
2438
- }
2439
- const buckets = {};
2440
- for (const name of Object.keys(input.buckets)) {
2441
- if (name.length === 0) {
2442
- throw new Error("bucket name must be a non-empty string");
2443
- }
2444
- const def = input.buckets[name];
2445
- if (def === void 0) continue;
2446
- buckets[name] = def;
2447
- }
2448
- return { __config: STORAGE_CONFIG_KIND, buckets };
2366
+ function bucketMembers(buckets) {
2367
+ const normalized = buckets.map((b) => typeof b === "string" ? { name: b, variants: [] } : b);
2368
+ const byName = /* @__PURE__ */ new Map();
2369
+ for (const b of normalized) byName.set(b.name, b.variants);
2370
+ const names = [...byName.keys()].sort();
2371
+ if (names.length === 0) return "";
2372
+ const rows = names.map((name) => {
2373
+ const variants = [...new Set(byName.get(name) ?? [])].sort();
2374
+ const union = variants.length === 0 ? "never" : variants.map((v) => JSON.stringify(v)).join(" | ");
2375
+ return ` ${memberName(name)}: { variants: ${union} };`;
2376
+ });
2377
+ return `
2378
+ ${rows.join("\n")}
2379
+ `;
2449
2380
  }
2381
+ function makeStackDts(names) {
2382
+ const secrets = liveNames(names.secrets);
2383
+ const flags = liveNames(names.flags);
2384
+ return `// palbase-stack.d.ts \u2014 GENERATED by @palbase/backend. Do not edit.
2385
+ // Source: the linked environment's stack.
2450
2386
 
2451
- // src/config/egress.ts
2452
- var EGRESS_CONFIG_KIND = "egress";
2453
- var EGRESS_TIMEOUT_MIN_MS = 1e3;
2454
- var EGRESS_TIMEOUT_MAX_MS = 3e5;
2455
- var EGRESS_TIMEOUT_DEFAULT_MS = 3e4;
2456
- function defineEgress(input) {
2457
- if (input === null || typeof input !== "object" || !Array.isArray(input.hosts)) {
2458
- throw new Error("defineEgress expects { hosts: string[] }");
2459
- }
2460
- const hosts = [];
2461
- for (const h of input.hosts) {
2462
- if (typeof h !== "string" || h.trim().length === 0) {
2463
- throw new Error("defineEgress: every host must be a non-empty string");
2464
- }
2465
- hosts.push(h.trim().toLowerCase());
2466
- }
2467
- if (input.timeoutMs === void 0) {
2468
- return { __config: EGRESS_CONFIG_KIND, hosts };
2469
- }
2470
- const timeoutMs = input.timeoutMs;
2471
- if (typeof timeoutMs !== "number" || !Number.isInteger(timeoutMs)) {
2472
- throw new Error("defineEgress: timeoutMs must be an integer number of milliseconds");
2473
- }
2474
- if (timeoutMs < EGRESS_TIMEOUT_MIN_MS || timeoutMs > EGRESS_TIMEOUT_MAX_MS) {
2475
- throw new Error(
2476
- `defineEgress: timeoutMs must be between ${EGRESS_TIMEOUT_MIN_MS} and ${EGRESS_TIMEOUT_MAX_MS} (got ${timeoutMs})`
2477
- );
2478
- }
2479
- return { __config: EGRESS_CONFIG_KIND, hosts, timeoutMs };
2480
- }
2387
+ declare module "@palbase/backend/stack" {
2388
+ interface Secrets {${members(secrets)}}
2481
2389
 
2482
- // src/config/notifications.ts
2483
- var NOTIFICATIONS_CONFIG_KIND = "notifications";
2484
- var RESERVED_SECRET_PREFIX = "PB_NOTIFICATIONS";
2485
- var PROVIDER_CATALOG = {
2486
- apns: {
2487
- channel: "push",
2488
- required: ["teamId", "keyId", "bundleId"],
2489
- optional: ["isProduction"],
2490
- secrets: ["p8"]
2491
- },
2492
- fcm: {
2493
- channel: "push",
2494
- required: [],
2495
- optional: [],
2496
- secrets: ["serviceAccount"]
2497
- },
2498
- sendgrid: {
2499
- channel: "email",
2500
- required: ["fromDomain"],
2501
- optional: [],
2502
- secrets: ["apiKey"]
2503
- },
2504
- ses: {
2505
- channel: "email",
2506
- required: ["region", "accessKeyId", "fromDomain"],
2507
- optional: [],
2508
- secrets: ["secretAccessKey"]
2509
- },
2510
- smtp: {
2511
- channel: "email",
2512
- required: ["host", "port", "fromEmail"],
2513
- optional: ["username", "useStarttls"],
2514
- secrets: ["password"]
2515
- },
2516
- acs: {
2517
- channel: "email",
2518
- required: ["fromEmail"],
2519
- optional: ["fromName"],
2520
- secrets: ["connectionString"]
2521
- },
2522
- twilio: {
2523
- channel: "sms",
2524
- // account_sid required; one of from_number / messaging_service_sid required
2525
- // (enforced by the refine in buildProvider, not by the flat `required` list).
2526
- required: ["accountSid"],
2527
- optional: ["fromNumber", "messagingServiceSid"],
2528
- secrets: ["authToken"]
2529
- }
2530
- };
2531
- var DEFAULT_TEMPLATE_LOCALE = "en";
2532
- function extractVariables(...sources) {
2533
- const found = /* @__PURE__ */ new Set();
2534
- for (const src of sources) {
2535
- if (!src) continue;
2536
- for (const match of src.matchAll(/\{\{\{?\s*([^{}]+?)\s*\}?\}\}/g)) {
2537
- const token = (match[1] ?? "").trim();
2538
- if (token === "" || "#/^!>&".includes(token.charAt(0)) || token === "else") continue;
2539
- if (/\s/.test(token)) continue;
2540
- const root = token.split(".")[0] ?? "";
2541
- if (root === "" || root === "this" || root.startsWith("@")) continue;
2542
- found.add(root);
2543
- }
2544
- }
2545
- return [...found].sort();
2546
- }
2547
- function buildEmailTemplate(slug, opts) {
2548
- const row = (locale, c) => {
2549
- if (!c.subject) throw new Error(`notifications: email template "${slug}" (${locale}) needs a subject`);
2550
- if (!c.html) throw new Error(`notifications: email template "${slug}" (${locale}) needs an html body`);
2551
- const def = {
2552
- slug,
2553
- locale,
2554
- subject: c.subject,
2555
- html_body: c.html,
2556
- variables: c.variables ? [...c.variables] : extractVariables(c.subject, c.html, c.text)
2557
- };
2558
- if (c.text !== void 0) def.text_body = c.text;
2559
- return def;
2560
- };
2561
- const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];
2562
- for (const [locale, content] of Object.entries(opts.locales ?? {})) {
2563
- rows.push(row(locale, content));
2564
- }
2565
- return rows;
2566
- }
2567
- function buildSmsTemplate(slug, opts) {
2568
- const row = (locale, c) => {
2569
- if (!c.body) throw new Error(`notifications: sms template "${slug}" (${locale}) needs a body`);
2570
- return {
2571
- slug,
2572
- locale,
2573
- body: c.body,
2574
- variables: c.variables ? [...c.variables] : extractVariables(c.body)
2575
- };
2576
- };
2577
- const rows = [row(opts.locale ?? DEFAULT_TEMPLATE_LOCALE, opts)];
2578
- for (const [locale, content] of Object.entries(opts.locales ?? {})) {
2579
- rows.push(row(locale, content));
2580
- }
2581
- return rows;
2582
- }
2583
- function buildTemplates(input) {
2584
- const out = { email: [], sms: [] };
2585
- const seen = /* @__PURE__ */ new Set();
2586
- const claim = (channel, slug, locale) => {
2587
- const key = `${channel}/${slug}/${locale}`;
2588
- if (seen.has(key)) {
2589
- throw new Error(`notifications: ${channel} template "${slug}" declares locale "${locale}" twice`);
2590
- }
2591
- seen.add(key);
2592
- };
2593
- for (const [slug, opts] of Object.entries(input.email ?? {})) {
2594
- for (const row of buildEmailTemplate(slug, opts)) {
2595
- claim("email", row.slug, row.locale);
2596
- out.email.push(row);
2597
- }
2598
- }
2599
- for (const [slug, opts] of Object.entries(input.sms ?? {})) {
2600
- for (const row of buildSmsTemplate(slug, opts)) {
2601
- claim("sms", row.slug, row.locale);
2602
- out.sms.push(row);
2603
- }
2604
- }
2605
- return out;
2606
- }
2607
- function buildProvider(name, opts) {
2608
- const entry = PROVIDER_CATALOG[name];
2609
- const src = { ...opts };
2610
- const enabled = src.enabled === void 0 ? false : Boolean(src.enabled);
2611
- if (!enabled) {
2612
- return { enabled: false };
2613
- }
2614
- const def = { enabled: true };
2615
- for (const field of entry.required) {
2616
- const value = src[field];
2617
- if (value === void 0 || value === null || value === "") {
2618
- throw new Error(
2619
- `notifications: provider "${name}" is enabled but missing required field "${field}"`
2620
- );
2621
- }
2622
- def[field] = value;
2623
- }
2624
- for (const field of entry.optional) {
2625
- if (src[field] !== void 0) {
2626
- def[field] = src[field];
2627
- }
2628
- }
2629
- if (name === "twilio") {
2630
- const hasFrom = Boolean(def.fromNumber);
2631
- const hasMsg = Boolean(def.messagingServiceSid);
2632
- if (!hasFrom && !hasMsg) {
2633
- throw new Error(
2634
- 'notifications: provider "twilio" requires one of "fromNumber" or "messagingServiceSid"'
2635
- );
2636
- }
2637
- }
2638
- return def;
2639
- }
2640
- function defineNotifications(input) {
2641
- if (input === null || typeof input !== "object") {
2642
- throw new Error("defineNotifications expects { push?, email?, sms? }");
2643
- }
2644
- const config = {
2645
- __config: NOTIFICATIONS_CONFIG_KIND,
2646
- push: {},
2647
- email: {},
2648
- sms: {},
2649
- templates: buildTemplates(input.templates ?? {})
2650
- };
2651
- const push = input.push ?? {};
2652
- if (push.apns !== void 0) config.push.apns = buildProvider("apns", push.apns);
2653
- if (push.fcm !== void 0) config.push.fcm = buildProvider("fcm", push.fcm);
2654
- const email = input.email ?? {};
2655
- if (email.sendgrid !== void 0) config.email.sendgrid = buildProvider("sendgrid", email.sendgrid);
2656
- if (email.ses !== void 0) config.email.ses = buildProvider("ses", email.ses);
2657
- if (email.smtp !== void 0) config.email.smtp = buildProvider("smtp", email.smtp);
2658
- if (email.acs !== void 0) config.email.acs = buildProvider("acs", email.acs);
2659
- const sms = input.sms ?? {};
2660
- if (sms.twilio !== void 0) config.sms.twilio = buildProvider("twilio", sms.twilio);
2661
- return config;
2662
- }
2663
- function reservedSecretKey(provider, secretField) {
2664
- return `${RESERVED_SECRET_PREFIX}_${camelToUpperSnake(provider)}_${camelToUpperSnake(secretField)}`;
2665
- }
2666
- function camelToUpperSnake(s) {
2667
- return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
2668
- }
2390
+ interface Flags {${members(flags)}}
2669
2391
 
2670
- // src/config/test-users.ts
2671
- var TEST_USERS_CONFIG_KIND = "test-users";
2672
- var TEST_USER_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;
2673
- var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2674
- var E164_RE = /^\+[1-9]\d{1,14}$/;
2675
- var OTP_LENGTH = 6;
2676
- var OTP_RE = /^\d{6}$/;
2677
- var MIN_PASSWORD_LENGTH = 8;
2678
- function isPlainObject2(value) {
2679
- return typeof value === "object" && value !== null && !Array.isArray(value);
2680
- }
2681
- function normalizeSeed(seed, userName) {
2682
- if (seed === void 0) return {};
2683
- if (!isPlainObject2(seed)) {
2684
- throw new Error(`testUser ${JSON.stringify(userName)}: seed must be { <table>: [ {...} ] }`);
2685
- }
2686
- const out = {};
2687
- for (const [table, rows] of Object.entries(seed)) {
2688
- if (!Array.isArray(rows)) {
2689
- throw new Error(
2690
- `testUser ${JSON.stringify(userName)}: seed.${table} must be an array of rows`
2691
- );
2692
- }
2693
- if (rows.length === 0) {
2694
- throw new Error(
2695
- `testUser ${JSON.stringify(userName)}: seed.${table} is empty \u2014 remove it or add a row`
2696
- );
2697
- }
2698
- for (const row of rows) {
2699
- if (!isPlainObject2(row)) {
2700
- throw new Error(
2701
- `testUser ${JSON.stringify(userName)}: every row in seed.${table} must be an object`
2702
- );
2703
- }
2704
- }
2705
- out[table] = rows;
2706
- }
2707
- return out;
2708
- }
2709
- function testUser(opts = {}) {
2710
- if (!isPlainObject2(opts)) {
2711
- throw new Error("testUser() expects { email?, password?, phone?, otp?, seed? }");
2712
- }
2713
- const hasEmail = opts.email !== void 0;
2714
- const hasPassword = opts.password !== void 0;
2715
- if (hasEmail !== hasPassword) {
2716
- throw new Error(
2717
- "testUser() needs email AND password together (a fixture with stable credentials) or neither (a template the server generates credentials for)"
2718
- );
2719
- }
2720
- let email = null;
2721
- let password = null;
2722
- if (hasEmail) {
2723
- if (typeof opts.email !== "string" || !EMAIL_RE.test(opts.email)) {
2724
- throw new Error(`testUser email ${JSON.stringify(opts.email)} is not a valid address`);
2725
- }
2726
- if (typeof opts.password !== "string" || opts.password.length < MIN_PASSWORD_LENGTH) {
2727
- throw new Error(
2728
- `testUser password must be at least ${MIN_PASSWORD_LENGTH} characters (got ${typeof opts.password === "string" ? opts.password.length : 0})`
2729
- );
2730
- }
2731
- email = opts.email;
2732
- password = opts.password;
2733
- }
2734
- const hasPhone = opts.phone !== void 0;
2735
- const hasOTP = opts.otp !== void 0;
2736
- if (hasPhone !== hasOTP) {
2737
- throw new Error(
2738
- "testUser() needs phone AND otp together \u2014 nothing can receive an SMS at a fabricated number, so a phone fixture without its fixed code can never be signed in as"
2739
- );
2740
- }
2741
- let phone = null;
2742
- let otp = null;
2743
- if (hasPhone) {
2744
- if (typeof opts.phone !== "string" || !E164_RE.test(opts.phone)) {
2745
- throw new Error(
2746
- `testUser phone ${JSON.stringify(opts.phone)} must be E.164, e.g. "+905551112233"`
2747
- );
2748
- }
2749
- if (typeof opts.otp !== "string" || !OTP_RE.test(opts.otp)) {
2750
- throw new Error(
2751
- `testUser otp ${JSON.stringify(opts.otp)} must be ${OTP_LENGTH} digits`
2752
- );
2753
- }
2754
- phone = opts.phone;
2755
- otp = opts.otp;
2756
- }
2757
- return { email, password, phone, otp, seed: normalizeSeed(opts.seed, email ?? "<template>") };
2758
- }
2759
- function defineTestUsers(input) {
2760
- if (!isPlainObject2(input) || !isPlainObject2(input.users)) {
2761
- throw new Error("defineTestUsers expects { users: { <name>: testUser({...}) } }");
2762
- }
2763
- const users = {};
2764
- const emails = /* @__PURE__ */ new Map();
2765
- for (const name of Object.keys(input.users)) {
2766
- if (!TEST_USER_NAME_RE.test(name)) {
2767
- throw new Error(
2768
- `test user name ${JSON.stringify(name)} is invalid \u2014 must start with a letter and contain only letters, digits, and underscores`
2769
- );
2770
- }
2771
- const def = input.users[name];
2772
- if (def === void 0) continue;
2773
- if (def.email !== null) {
2774
- const lower = def.email.toLowerCase();
2775
- const already = emails.get(lower);
2776
- if (already !== void 0) {
2777
- throw new Error(
2778
- `test users ${JSON.stringify(already)} and ${JSON.stringify(name)} declare the same e-mail ${JSON.stringify(def.email)}`
2779
- );
2780
- }
2781
- emails.set(lower, name);
2782
- }
2783
- users[name] = def;
2784
- }
2785
- return { __config: TEST_USERS_CONFIG_KIND, users };
2392
+ interface Buckets {${bucketMembers(names.buckets)}}
2786
2393
  }
2787
2394
 
2788
- // src/config/flags.ts
2789
- var FLAGS_CONFIG_KIND = "flags";
2790
- var FLAG_KEY_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;
2791
- function valueMatchesType(type, value) {
2792
- switch (type) {
2793
- case "boolean":
2794
- return typeof value === "boolean";
2795
- case "number":
2796
- return typeof value === "number" && Number.isFinite(value);
2797
- case "string":
2798
- return typeof value === "string";
2799
- case "json":
2800
- return typeof value === "object" && value !== null && !Array.isArray(value);
2801
- }
2802
- }
2803
- function flag(opts) {
2804
- if (opts === null || typeof opts !== "object") {
2805
- throw new Error("flag() expects { type, default, variants?, description? }");
2806
- }
2807
- const { type } = opts;
2808
- if (type !== "boolean" && type !== "number" && type !== "string" && type !== "json") {
2809
- throw new Error(`flag type must be "boolean", "number", "string", or "json", got ${JSON.stringify(type)}`);
2810
- }
2811
- if (!valueMatchesType(type, opts.default)) {
2812
- throw new Error(
2813
- `flag default ${JSON.stringify(opts.default)} does not match type "${type}"`
2814
- );
2815
- }
2816
- let variants = null;
2817
- if (opts.variants !== void 0) {
2818
- if (opts.type !== "string") {
2819
- throw new Error(`flag variants are only valid for type "string" (got type "${type}")`);
2820
- }
2821
- if (!Array.isArray(opts.variants)) {
2822
- throw new Error("flag variants must be an array of strings");
2823
- }
2824
- for (const v of opts.variants) {
2825
- if (typeof v !== "string" || v.length === 0) {
2826
- throw new Error(`flag variant ${JSON.stringify(v)} must be a non-empty string`);
2827
- }
2828
- }
2829
- variants = [...new Set(opts.variants)];
2830
- if (variants.length === 0) {
2831
- throw new Error("flag variants must be a non-empty list when supplied");
2832
- }
2833
- if (!variants.includes(opts.default)) {
2834
- throw new Error(
2835
- `flag default ${JSON.stringify(opts.default)} is not one of its variants [${variants.map((v) => JSON.stringify(v)).join(", ")}]`
2836
- );
2837
- }
2838
- }
2839
- let conditions = null;
2840
- if (opts.conditions !== void 0) {
2841
- if (!Array.isArray(opts.conditions)) {
2842
- throw new Error("flag conditions must be an array of { when, value }");
2843
- }
2844
- const compiled = [];
2845
- for (const [i, branch] of opts.conditions.entries()) {
2846
- if (branch === null || typeof branch !== "object") {
2847
- throw new Error(`flag condition ${i} must be an object { when, value }`);
2848
- }
2849
- if (typeof branch.when !== "string" || branch.when.trim().length === 0) {
2850
- throw new Error(`flag condition ${i} needs a non-empty "when" expression`);
2851
- }
2852
- if (!valueMatchesType(type, branch.value)) {
2853
- throw new Error(
2854
- `flag condition ${i} value ${JSON.stringify(branch.value)} does not match type "${type}"`
2855
- );
2856
- }
2857
- if (variants !== null && !variants.includes(branch.value)) {
2858
- throw new Error(
2859
- `flag condition ${i} value ${JSON.stringify(branch.value)} is not one of its variants [${variants.map((v) => JSON.stringify(v)).join(", ")}]`
2860
- );
2861
- }
2862
- compiled.push({ when: branch.when.trim(), value: branch.value });
2863
- }
2864
- conditions = compiled.length > 0 ? compiled : null;
2865
- }
2866
- let description = null;
2867
- if (opts.description !== void 0) {
2868
- if (typeof opts.description !== "string") {
2869
- throw new Error("flag description must be a string");
2870
- }
2871
- const trimmed = opts.description.trim();
2872
- description = trimmed.length > 0 ? trimmed : null;
2873
- }
2874
- return {
2875
- type,
2876
- default: opts.default,
2877
- variants,
2878
- conditions,
2879
- description
2880
- };
2881
- }
2882
- function defineFlags(input) {
2883
- if (input === null || typeof input !== "object" || typeof input.flags !== "object") {
2884
- throw new Error("defineFlags expects { flags: { <key>: flag({...}) } }");
2885
- }
2886
- const flags = {};
2887
- for (const key of Object.keys(input.flags)) {
2888
- if (!FLAG_KEY_RE.test(key)) {
2889
- throw new Error(
2890
- `flag key ${JSON.stringify(key)} is invalid \u2014 must start with a letter and contain only letters, digits, and underscores`
2891
- );
2892
- }
2893
- const def = input.flags[key];
2894
- if (def === void 0) continue;
2895
- flags[key] = def;
2896
- }
2897
- return { __config: FLAGS_CONFIG_KIND, flags };
2898
- }
2899
-
2900
- // src/config/secrets.ts
2901
- var SECRETS_CONFIG_KIND = "secrets";
2902
- var SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
2903
- function secret(name, opts = {}) {
2904
- if (typeof name !== "string" || !SECRET_NAME_RE.test(name)) {
2905
- throw new Error(
2906
- `secret name ${JSON.stringify(name)} is invalid \u2014 must be an environment-variable name: an uppercase letter, then uppercase letters, digits, and underscores (e.g. "NEO4J_PASSWORD")`
2907
- );
2908
- }
2909
- if (opts === null || typeof opts !== "object") {
2910
- throw new Error(`secret("${name}") expects { required?, description? }`);
2911
- }
2912
- let required = true;
2913
- if (opts.required !== void 0) {
2914
- if (typeof opts.required !== "boolean") {
2915
- throw new Error(`secret("${name}") required must be a boolean`);
2916
- }
2917
- required = opts.required;
2918
- }
2919
- let description = null;
2920
- if (opts.description !== void 0) {
2921
- if (typeof opts.description !== "string") {
2922
- throw new Error(`secret("${name}") description must be a string`);
2923
- }
2924
- const trimmed = opts.description.trim();
2925
- description = trimmed.length > 0 ? trimmed : null;
2926
- }
2927
- return { name, required, description };
2928
- }
2929
- function defineSecrets(input) {
2930
- if (input === null || typeof input !== "object" || !Array.isArray(input.secrets)) {
2931
- throw new Error('defineSecrets expects { secrets: [secret("NAME"), ...] }');
2932
- }
2933
- const byName = /* @__PURE__ */ new Map();
2934
- for (const def of input.secrets) {
2935
- if (def === null || typeof def !== "object" || typeof def.name !== "string" || typeof def.required !== "boolean") {
2936
- throw new Error(
2937
- `defineSecrets: every entry must come from secret() \u2014 got ${JSON.stringify(def)}`
2938
- );
2939
- }
2940
- if (byName.has(def.name)) {
2941
- throw new Error(
2942
- `secret "${def.name}" is declared twice in config/secrets.ts \u2014 remove one; a name has exactly one requirement`
2943
- );
2944
- }
2945
- byName.set(def.name, def);
2946
- }
2947
- const secrets = [...byName.values()].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
2948
- return { __config: SECRETS_CONFIG_KIND, secrets };
2395
+ export {};
2396
+ `;
2949
2397
  }
2950
2398
 
2951
2399
  // src/decorators/registry.ts
@@ -2953,7 +2401,7 @@ var ROUTES = /* @__PURE__ */ Symbol.for("palbase.backend.routes");
2953
2401
  var PARAM_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.paramBuffer");
2954
2402
  var RETURN_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.returnBuffer");
2955
2403
  var THROWS_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.throwsBuffer");
2956
- function carrierOf2(target) {
2404
+ function carrierOf(target) {
2957
2405
  const ctor = typeof target === "function" ? target : target.constructor ?? target;
2958
2406
  return ctor;
2959
2407
  }
@@ -2970,7 +2418,7 @@ function ownParamBuffer(carrier) {
2970
2418
  return carrier[PARAM_BUFFER];
2971
2419
  }
2972
2420
  function recordRoute(target, fnName, method, subpath, options) {
2973
- const carrier = carrierOf2(target);
2421
+ const carrier = carrierOf(target);
2974
2422
  const routes = ownRoutes(carrier);
2975
2423
  const buffer = ownParamBuffer(carrier);
2976
2424
  const params = (buffer[fnName] ?? []).slice().sort((a, b) => a.index - b.index);
@@ -2986,7 +2434,7 @@ function recordRoute(target, fnName, method, subpath, options) {
2986
2434
  routes.push(route);
2987
2435
  }
2988
2436
  function recordParam(target, fnName, meta) {
2989
- const carrier = carrierOf2(target);
2437
+ const carrier = carrierOf(target);
2990
2438
  const buffer = ownParamBuffer(carrier);
2991
2439
  (buffer[fnName] ??= []).push(meta);
2992
2440
  const routes = carrier[ROUTES];
@@ -2999,7 +2447,7 @@ function recordParam(target, fnName, meta) {
2999
2447
  }
3000
2448
  }
3001
2449
  function recordThrows(target, fnName, throws) {
3002
- const carrier = carrierOf2(target);
2450
+ const carrier = carrierOf(target);
3003
2451
  const routes = carrier[ROUTES];
3004
2452
  const route = routes?.find((r) => r.fnName === fnName);
3005
2453
  if (route) {
@@ -3013,7 +2461,7 @@ function recordThrows(target, fnName, throws) {
3013
2461
  if (throwsBuffer) throwsBuffer[fnName] = throws;
3014
2462
  }
3015
2463
  function getRoutes(ctor) {
3016
- const carrier = carrierOf2(ctor);
2464
+ const carrier = carrierOf(ctor);
3017
2465
  const routes = carrier[ROUTES] ?? [];
3018
2466
  const returnBuffer = carrier[RETURN_BUFFER];
3019
2467
  if (returnBuffer) {
@@ -3122,12 +2570,12 @@ var Query = makeMethodDecorator("QUERY");
3122
2570
  // src/decorators/webhook.ts
3123
2571
  var WEBHOOK_META = /* @__PURE__ */ Symbol.for("palbase.backend.webhookMeta");
3124
2572
  var WEBHOOK_EVENTS = /* @__PURE__ */ Symbol.for("palbase.backend.webhookEvents");
3125
- function carrierOf3(ctor) {
2573
+ function carrierOf2(ctor) {
3126
2574
  return ctor;
3127
2575
  }
3128
2576
  function Webhook(options) {
3129
2577
  return function(ctor) {
3130
- const carrier = carrierOf3(ctor);
2578
+ const carrier = carrierOf2(ctor);
3131
2579
  Object.defineProperty(carrier, WEBHOOK_META, {
3132
2580
  value: options,
3133
2581
  enumerable: false,
@@ -3145,7 +2593,7 @@ function Webhook(options) {
3145
2593
  }
3146
2594
  function On(event) {
3147
2595
  return function(target, fnName) {
3148
- const carrier = carrierOf3(target.constructor);
2596
+ const carrier = carrierOf2(target.constructor);
3149
2597
  const existing = carrier[WEBHOOK_EVENTS];
3150
2598
  const entries = existing ? [...existing] : [];
3151
2599
  entries.push({ event, fnName: String(fnName) });
@@ -3158,7 +2606,7 @@ function On(event) {
3158
2606
  };
3159
2607
  }
3160
2608
  function getWebhookConfig(ctor) {
3161
- const carrier = carrierOf3(ctor);
2609
+ const carrier = carrierOf2(ctor);
3162
2610
  const meta = carrier[WEBHOOK_META];
3163
2611
  const entries = carrier[WEBHOOK_EVENTS] ?? [];
3164
2612
  if (!meta) {
@@ -3293,22 +2741,14 @@ function validateUploadConfigShape(c) {
3293
2741
  if (c === null || typeof c !== "object") {
3294
2742
  throw new Error("@Upload config must be an object { bucket, pathTemplate, ... }");
3295
2743
  }
3296
- if (typeof c.bucket !== "string" || c.bucket.length === 0) {
2744
+ const bucket = c.bucket;
2745
+ if (typeof bucket !== "string" || bucket.length === 0) {
3297
2746
  throw new Error("@Upload config.bucket must be a non-empty bucket name");
3298
2747
  }
3299
2748
  if (typeof c.pathTemplate !== "string" || c.pathTemplate.length === 0) {
3300
2749
  throw new Error("@Upload config.pathTemplate must be a non-empty key template");
3301
2750
  }
3302
2751
  }
3303
- function validateUploadAgainstStorage(uploadConfig, storage, routeLabel) {
3304
- const def = storage.buckets[uploadConfig.bucket];
3305
- if (def === void 0) {
3306
- const known = Object.keys(storage.buckets);
3307
- throw new Error(
3308
- `@Upload route ${routeLabel} targets bucket "${uploadConfig.bucket}" which is not declared in defineStorage(...). ` + (known.length ? `Known buckets: ${known.join(", ")}.` : "No buckets are declared.")
3309
- );
3310
- }
3311
- }
3312
2752
 
3313
2753
  // src/decorators/params.ts
3314
2754
  function makeParamDecorator(kind, extra) {
@@ -3357,6 +2797,93 @@ function defineMiddleware(fn) {
3357
2797
  return fn;
3358
2798
  }
3359
2799
 
2800
+ // src/errors.ts
2801
+ var HTTP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("palbase.backend.httpError");
2802
+ var HttpError = class extends Error {
2803
+ status;
2804
+ error;
2805
+ errorDescription;
2806
+ data;
2807
+ /** See {@link HTTP_ERROR_BRAND} — how the engine recognises this across SDK copies. */
2808
+ [HTTP_ERROR_BRAND] = true;
2809
+ constructor(status, error, errorDescription, data) {
2810
+ super(errorDescription);
2811
+ this.name = "HttpError";
2812
+ this.status = status;
2813
+ this.error = error;
2814
+ this.errorDescription = errorDescription;
2815
+ if (data !== void 0) {
2816
+ this.data = data;
2817
+ }
2818
+ }
2819
+ /**
2820
+ * Serialize to the standard Palbase error response format.
2821
+ * The `requestId` is injected by the runtime layer from the request context.
2822
+ * When called without arguments (e.g. JSON.stringify), request_id is omitted.
2823
+ * When `data` is set, it is appended as a strict-superset field.
2824
+ */
2825
+ toJSON(requestId) {
2826
+ const result = {
2827
+ error: this.error,
2828
+ error_description: this.errorDescription,
2829
+ status: this.status
2830
+ };
2831
+ if (requestId) {
2832
+ result.request_id = requestId;
2833
+ }
2834
+ if (this.data !== void 0) {
2835
+ result.data = this.data;
2836
+ }
2837
+ return result;
2838
+ }
2839
+ };
2840
+ var PalError = class extends HttpError {
2841
+ constructor(status, code, description, data) {
2842
+ super(status, code, description, data);
2843
+ this.name = "PalError";
2844
+ }
2845
+ };
2846
+ var NamedHttpError = class extends HttpError {
2847
+ constructor(status, defaultCode, name, message, code, data) {
2848
+ super(status, code ?? defaultCode, message ?? defaultMessage(name), data);
2849
+ this.name = name;
2850
+ }
2851
+ };
2852
+ function defaultMessage(name) {
2853
+ const spaced = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
2854
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
2855
+ }
2856
+ var BadRequest = class extends NamedHttpError {
2857
+ constructor(data, message) {
2858
+ super(400, "bad_request", "BadRequest", message, void 0, data);
2859
+ }
2860
+ };
2861
+ var Unauthorized = class extends NamedHttpError {
2862
+ constructor(message, code, data) {
2863
+ super(401, "unauthorized", "Unauthorized", message, code, data);
2864
+ }
2865
+ };
2866
+ var Forbidden = class extends NamedHttpError {
2867
+ constructor(message, code, data) {
2868
+ super(403, "forbidden", "Forbidden", message, code, data);
2869
+ }
2870
+ };
2871
+ var NotFound = class extends NamedHttpError {
2872
+ constructor(message, code, data) {
2873
+ super(404, "not_found", "NotFound", message, code, data);
2874
+ }
2875
+ };
2876
+ var Conflict = class extends NamedHttpError {
2877
+ constructor(message, code, data) {
2878
+ super(409, "conflict", "Conflict", message, code, data);
2879
+ }
2880
+ };
2881
+ var TooManyRequests = class extends NamedHttpError {
2882
+ constructor(data, message) {
2883
+ super(429, "too_many_requests", "TooManyRequests", message, void 0, data);
2884
+ }
2885
+ };
2886
+
3360
2887
  // src/error-registry.ts
3361
2888
  var import_zod_to_openapi = require("@asteasolutions/zod-to-openapi");
3362
2889
  var import_zod = require("zod");
@@ -3366,27 +2893,7 @@ var BUILTIN_DATA_SCHEMAS = {
3366
2893
  bad_request: import_zod.z.object({
3367
2894
  fields: import_zod.z.array(import_zod.z.object({ field: import_zod.z.string(), message: import_zod.z.string() }))
3368
2895
  }),
3369
- too_many_requests: import_zod.z.object({ retryAfter: import_zod.z.number().int() }),
3370
- // Purchases (@RequireEntitlement / @Spend). Their payloads are what make a
3371
- // paywall renderable on the client: WHICH entitlement was missing, and for a
3372
- // spend the real ceiling and reset time rather than a guessed retry delay.
3373
- entitlement_required: import_zod.z.object({ entitlement: import_zod.z.string().nullable() }),
3374
- quota_exceeded: import_zod.z.object({
3375
- key: import_zod.z.string(),
3376
- scope: import_zod.z.string(),
3377
- window: import_zod.z.string(),
3378
- used: import_zod.z.number().int(),
3379
- reserved: import_zod.z.number().int(),
3380
- max: import_zod.z.number().int(),
3381
- remaining: import_zod.z.number().int(),
3382
- resetAt: import_zod.z.string()
3383
- }),
3384
- credit_insufficient: import_zod.z.object({
3385
- key: import_zod.z.string(),
3386
- balance: import_zod.z.number().int(),
3387
- reserved: import_zod.z.number().int(),
3388
- remaining: import_zod.z.number().int()
3389
- })
2896
+ too_many_requests: import_zod.z.object({ retryAfter: import_zod.z.number().int() })
3390
2897
  };
3391
2898
  function getErrorRegistry() {
3392
2899
  const g = globalThis;
@@ -3398,13 +2905,7 @@ function getErrorRegistry() {
3398
2905
  ["forbidden", 403, "Forbidden"],
3399
2906
  ["not_found", 404, "NotFound"],
3400
2907
  ["conflict", 409, "Conflict"],
3401
- ["too_many_requests", 429, "TooManyRequests"],
3402
- // Thrown by the purchases decorators, so they are pre-seeded like the
3403
- // other built-ins: a project never declares them, but every gated or
3404
- // metered route must surface them as TYPED errors on the client.
3405
- ["entitlement_required", 403, "EntitlementRequired"],
3406
- ["quota_exceeded", 429, "QuotaExceeded"],
3407
- ["credit_insufficient", 429, "CreditInsufficient"]
2908
+ ["too_many_requests", 429, "TooManyRequests"]
3408
2909
  ]) {
3409
2910
  const dataSchema = BUILTIN_DATA_SCHEMAS[code];
3410
2911
  m.set(code, {
@@ -3425,8 +2926,8 @@ function defineError(code, status, dataSchema) {
3425
2926
  `defineError: status for "${code}" must be a 4xx/5xx integer, got ${status} \u2014 error responses must not clobber success responses in the project spec.`
3426
2927
  );
3427
2928
  }
3428
- const registry3 = getErrorRegistry();
3429
- const existing = registry3.get(code);
2929
+ const registry2 = getErrorRegistry();
2930
+ const existing = registry2.get(code);
3430
2931
  const className = defaultClassName(code);
3431
2932
  const dataDigest = dataSchema ? digestOf(code, dataSchema) : void 0;
3432
2933
  if (existing) {
@@ -3455,7 +2956,7 @@ function defineError(code, status, dataSchema) {
3455
2956
  };
3456
2957
  const cls = dataSchema ? makeWithData(dataSchema) : makeWithoutData();
3457
2958
  Object.defineProperty(cls, "name", { value: className });
3458
- registry3.set(code, {
2959
+ registry2.set(code, {
3459
2960
  code,
3460
2961
  status,
3461
2962
  className,
@@ -3614,52 +3115,6 @@ function getJobConfig(ctor) {
3614
3115
  return { schedule: meta.schedule, timeout, retry, handler: run };
3615
3116
  }
3616
3117
 
3617
- // src/resource.ts
3618
- var Resource = class {
3619
- /** The env-var names this resource needs. Optional; omit for none. */
3620
- static secrets;
3621
- };
3622
- function hasSecrets(value) {
3623
- if (typeof value !== "object" && typeof value !== "function") return false;
3624
- const secrets = value.secrets;
3625
- return secrets === void 0 || Array.isArray(secrets);
3626
- }
3627
- var registry2 = [];
3628
- function __registerResource(resource) {
3629
- registry2.push({ resource, booted: false });
3630
- }
3631
- function declaredSecrets(resource) {
3632
- const ctor = resource.constructor;
3633
- return hasSecrets(ctor) ? ctor.secrets ?? [] : [];
3634
- }
3635
- async function __runResourceBoot(envMap) {
3636
- for (const entry of registry2) {
3637
- if (entry.booted) continue;
3638
- const secrets = declaredSecrets(entry.resource);
3639
- const env = {};
3640
- for (const name of secrets) {
3641
- const value = envMap[name];
3642
- if (value === void 0) {
3643
- throw new Error(
3644
- `Resource ${entry.resource.constructor.name} requires secret "${name}" but it is not set. Set it with \`palbase secret set ${name} ...\` (or in Studio) and redeploy.`
3645
- );
3646
- }
3647
- env[name] = value;
3648
- }
3649
- await entry.resource.init(env);
3650
- entry.booted = true;
3651
- }
3652
- }
3653
- async function __shutdownResources() {
3654
- for (let i = registry2.length - 1; i >= 0; i -= 1) {
3655
- const entry = registry2[i];
3656
- if (entry.booted && entry.resource.shutdown) {
3657
- await entry.resource.shutdown();
3658
- }
3659
- }
3660
- registry2.length = 0;
3661
- }
3662
-
3663
3118
  // src/index.ts
3664
3119
  var import_zod2 = require("zod");
3665
3120
  // Annotate the CommonJS export names for ESM import in node:
@@ -3670,17 +3125,11 @@ var import_zod2 = require("zod");
3670
3125
  Client,
3671
3126
  Conflict,
3672
3127
  Controller,
3673
- DEFAULT_TEMPLATE_LOCALE,
3674
3128
  Database,
3675
3129
  Delete,
3676
3130
  Deny,
3677
3131
  Documents,
3678
- EGRESS_CONFIG_KIND,
3679
- EGRESS_TIMEOUT_DEFAULT_MS,
3680
- EGRESS_TIMEOUT_MAX_MS,
3681
- EGRESS_TIMEOUT_MIN_MS,
3682
3132
  EXTENSION_DEPENDENCIES,
3683
- FLAGS_CONFIG_KIND,
3684
3133
  Flags,
3685
3134
  Forbidden,
3686
3135
  Get,
@@ -3689,35 +3138,25 @@ var import_zod2 = require("zod");
3689
3138
  HttpError,
3690
3139
  Job,
3691
3140
  Log,
3692
- NOTIFICATIONS_CONFIG_KIND,
3693
3141
  NotFound,
3694
3142
  Notifications,
3695
3143
  On,
3696
3144
  OptionalUser,
3697
3145
  PALBASE_EXTENSIONS,
3698
- PROVIDER_CATALOG,
3699
3146
  PalError,
3700
3147
  PalbaseModuleError,
3701
3148
  Param,
3702
3149
  Patch,
3703
3150
  PolicyBuilder,
3704
3151
  Post,
3705
- Purchases,
3706
3152
  Put,
3707
3153
  Query,
3708
3154
  QueryParams,
3709
- RESERVED_SECRET_PREFIX,
3710
3155
  Realtime,
3711
3156
  Req,
3712
3157
  RequestId,
3713
- RequireEntitlement,
3714
- Resource,
3715
- SECRETS_CONFIG_KIND,
3716
- STORAGE_CONFIG_KIND,
3717
3158
  Secrets,
3718
- Spend,
3719
3159
  Storage,
3720
- TEST_USERS_CONFIG_KIND,
3721
3160
  TooManyRequests,
3722
3161
  TraceId,
3723
3162
  TxPlanError,
@@ -3728,32 +3167,19 @@ var import_zod2 = require("zod");
3728
3167
  User,
3729
3168
  Webhook,
3730
3169
  __getRuntime,
3731
- __registerResource,
3732
3170
  __requestALS,
3733
3171
  __resetRegisteredControllers,
3734
- __runResourceBoot,
3735
3172
  __runWithRuntime,
3736
3173
  __setRuntime,
3737
- __shutdownResources,
3738
3174
  bigint,
3739
3175
  boolean,
3740
- bucket,
3741
3176
  buildModuleClients,
3742
- buildProvider,
3743
3177
  dec,
3744
- defineEgress,
3178
+ defineChannels,
3745
3179
  defineError,
3746
- defineFlags,
3747
3180
  defineMiddleware,
3748
- defineNotifications,
3749
3181
  defineSchema,
3750
- defineSecrets,
3751
- defineStorage,
3752
- defineTestUsers,
3753
- entitlementFor,
3754
3182
  enumType,
3755
- extractVariables,
3756
- flag,
3757
3183
  getErrorRegistry,
3758
3184
  getHookConfig,
3759
3185
  getJobConfig,
@@ -3766,23 +3192,21 @@ var import_zod2 = require("zod");
3766
3192
  jsonb,
3767
3193
  makeEnvDts,
3768
3194
  makeHttpClient,
3769
- makePurchasesDts,
3195
+ makeStackDts,
3770
3196
  makeTypedDB,
3771
3197
  now,
3772
3198
  numeric,
3773
- parseFileSizeLimit,
3199
+ openai,
3200
+ ownerOnly,
3774
3201
  policy,
3202
+ publicChannel,
3775
3203
  raw,
3776
3204
  recordThrows,
3777
- reservedSecretKey,
3778
- secret,
3779
- spendFor,
3780
- testUser,
3781
3205
  text,
3782
3206
  timestamp,
3783
3207
  toSchemaJSON,
3784
3208
  uuid,
3785
- validateUploadAgainstStorage,
3209
+ vector,
3786
3210
  z
3787
3211
  });
3788
3212
  //# sourceMappingURL=index.cjs.map