@palbase/backend 5.2.0 → 7.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.
package/dist/index.cjs CHANGED
@@ -52,6 +52,7 @@ __export(src_exports, {
52
52
  Query: () => Query,
53
53
  Queue: () => Queue,
54
54
  RESERVED_SECRET_PREFIX: () => RESERVED_SECRET_PREFIX,
55
+ Realtime: () => Realtime,
55
56
  Req: () => Req,
56
57
  RequestId: () => RequestId,
57
58
  Resource: () => Resource,
@@ -72,6 +73,7 @@ __export(src_exports, {
72
73
  boolean: () => boolean,
73
74
  bucket: () => bucket,
74
75
  buildProvider: () => buildProvider,
76
+ defineError: () => defineError,
75
77
  defineFlags: () => defineFlags,
76
78
  defineJob: () => defineJob,
77
79
  defineMiddleware: () => defineMiddleware,
@@ -83,6 +85,7 @@ __export(src_exports, {
83
85
  documents: () => documents,
84
86
  enumType: () => enumType,
85
87
  flag: () => flag,
88
+ getErrorRegistry: () => getErrorRegistry,
86
89
  integer: () => integer,
87
90
  isPalbaseExtension: () => isPalbaseExtension,
88
91
  jsonb: () => jsonb,
@@ -90,12 +93,13 @@ __export(src_exports, {
90
93
  makeTypedDB: () => makeTypedDB,
91
94
  parseFileSizeLimit: () => parseFileSizeLimit,
92
95
  policy: () => policy,
96
+ recordThrows: () => recordThrows,
93
97
  reservedSecretKey: () => reservedSecretKey,
94
98
  storage: () => storage,
95
99
  text: () => text,
96
100
  timestamp: () => timestamp,
97
101
  uuid: () => uuid,
98
- z: () => import_zod.z
102
+ z: () => import_zod2.z
99
103
  });
100
104
  module.exports = __toCommonJS(src_exports);
101
105
 
@@ -183,7 +187,35 @@ var Cache = makeServiceProxy("Cache");
183
187
  var Queue = makeServiceProxy("Queue");
184
188
  var Log = makeServiceProxy("Log");
185
189
  var Notifications = makeServiceProxy("Notifications");
186
- var Flags = makeServiceProxy("Flags");
190
+ var rawFlags = makeServiceProxy("Flags");
191
+ var Flags = Object.assign(
192
+ {
193
+ isEnabled(flagName, context) {
194
+ return rawFlags.isEnabled(flagName, context);
195
+ },
196
+ getVariant(flagName, context) {
197
+ return rawFlags.getVariant(flagName, context);
198
+ },
199
+ getAll(context) {
200
+ return rawFlags.getAll(context);
201
+ },
202
+ setOverride(key, value) {
203
+ return rawFlags.setOverride(key, value);
204
+ }
205
+ },
206
+ {
207
+ /**
208
+ * Lazily resolve the runtime's cross-user sibling on each call. We do NOT
209
+ * cache it: `rawFlags.asService()` reads the CURRENT request scope through
210
+ * the runtime proxy, so caching would leak one request's sibling into
211
+ * another concurrent request. Mirrors `Database.asService()`.
212
+ */
213
+ asService() {
214
+ return rawFlags.asService();
215
+ }
216
+ }
217
+ );
218
+ var Realtime = makeServiceProxy("Realtime");
187
219
 
188
220
  // src/db/policy.ts
189
221
  var PolicyBuilder = class {
@@ -773,6 +805,7 @@ function Controller(basePath, options = {}) {
773
805
  var ROUTES = /* @__PURE__ */ Symbol.for("palbase.backend.routes");
774
806
  var PARAM_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.paramBuffer");
775
807
  var RETURN_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.returnBuffer");
808
+ var THROWS_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.throwsBuffer");
776
809
  function carrierOf(target) {
777
810
  const ctor = typeof target === "function" ? target : target.constructor ?? target;
778
811
  return ctor;
@@ -799,6 +832,10 @@ function recordRoute(target, fnName, method, subpath, options) {
799
832
  if (returnBuffer && returnBuffer[fnName] !== void 0) {
800
833
  route.returnSchema = returnBuffer[fnName];
801
834
  }
835
+ const throwsBuffer = carrier[THROWS_BUFFER];
836
+ if (throwsBuffer && throwsBuffer[fnName] !== void 0) {
837
+ route.throws = throwsBuffer[fnName];
838
+ }
802
839
  routes.push(route);
803
840
  }
804
841
  function recordParam(target, fnName, meta) {
@@ -814,6 +851,20 @@ function recordParam(target, fnName, meta) {
814
851
  }
815
852
  }
816
853
  }
854
+ function recordThrows(target, fnName, throws) {
855
+ const carrier = carrierOf(target);
856
+ const routes = carrier[ROUTES];
857
+ const route = routes?.find((r) => r.fnName === fnName);
858
+ if (route) {
859
+ route.throws = throws;
860
+ return;
861
+ }
862
+ if (!Object.prototype.hasOwnProperty.call(carrier, THROWS_BUFFER)) {
863
+ carrier[THROWS_BUFFER] = {};
864
+ }
865
+ const throwsBuffer = carrier[THROWS_BUFFER];
866
+ if (throwsBuffer) throwsBuffer[fnName] = throws;
867
+ }
817
868
 
818
869
  // src/decorators/methods.ts
819
870
  function makeMethodDecorator(method) {
@@ -960,6 +1011,97 @@ var TooManyRequests = class extends NamedHttpError {
960
1011
  }
961
1012
  };
962
1013
 
1014
+ // src/error-registry.ts
1015
+ var import_zod_to_openapi = require("@asteasolutions/zod-to-openapi");
1016
+ var import_zod = require("zod");
1017
+ (0, import_zod_to_openapi.extendZodWithOpenApi)(import_zod.z);
1018
+ var ERROR_REGISTRY = /* @__PURE__ */ Symbol.for("palbase.backend.errorRegistry");
1019
+ function getErrorRegistry() {
1020
+ const g = globalThis;
1021
+ if (!g[ERROR_REGISTRY]) {
1022
+ const m = /* @__PURE__ */ new Map();
1023
+ for (const [code, status, className] of [
1024
+ ["bad_request", 400, "BadRequest"],
1025
+ ["unauthorized", 401, "Unauthorized"],
1026
+ ["forbidden", 403, "Forbidden"],
1027
+ ["not_found", 404, "NotFound"],
1028
+ ["conflict", 409, "Conflict"],
1029
+ ["too_many_requests", 429, "TooManyRequests"]
1030
+ ]) {
1031
+ m.set(code, { code, status, className, builtin: true });
1032
+ }
1033
+ g[ERROR_REGISTRY] = m;
1034
+ }
1035
+ return g[ERROR_REGISTRY];
1036
+ }
1037
+ function defineError(code, status, dataSchema) {
1038
+ if (!Number.isInteger(status) || status < 400 || status > 599) {
1039
+ throw new Error(
1040
+ `defineError: status for "${code}" must be a 4xx/5xx integer, got ${status} \u2014 error responses must not clobber success responses in the project spec.`
1041
+ );
1042
+ }
1043
+ const registry2 = getErrorRegistry();
1044
+ const existing = registry2.get(code);
1045
+ const className = defaultClassName(code);
1046
+ const dataDigest = dataSchema ? digestOf(code, dataSchema) : void 0;
1047
+ if (existing) {
1048
+ const sameShape = existing.status === status && !existing.builtin && existing.dataDigest === dataDigest;
1049
+ if (!sameShape) {
1050
+ throw new Error(
1051
+ `defineError: duplicate error code "${code}" with a different shape (existing: status ${existing.status}${existing.builtin ? ", built-in" : ""}${existing.status === status && !existing.builtin ? ", different data schema" : ""}). Error codes are project-unique.`
1052
+ );
1053
+ }
1054
+ }
1055
+ const makeWithData = (schema) => class extends HttpError {
1056
+ static code = code;
1057
+ static status = status;
1058
+ constructor(data, message) {
1059
+ super(status, code, message ?? humanize(code), schema.parse(data));
1060
+ this.name = className;
1061
+ }
1062
+ };
1063
+ const makeWithoutData = () => class extends HttpError {
1064
+ static code = code;
1065
+ static status = status;
1066
+ constructor(message) {
1067
+ super(status, code, message ?? humanize(code));
1068
+ this.name = className;
1069
+ }
1070
+ };
1071
+ const cls = dataSchema ? makeWithData(dataSchema) : makeWithoutData();
1072
+ Object.defineProperty(cls, "name", { value: className });
1073
+ registry2.set(code, {
1074
+ code,
1075
+ status,
1076
+ className,
1077
+ builtin: false,
1078
+ ...dataSchema ? { dataSchema } : {},
1079
+ ...dataDigest !== void 0 ? { dataDigest } : {}
1080
+ });
1081
+ return cls;
1082
+ }
1083
+ function digestOf(code, dataSchema) {
1084
+ const TMP_REF = "__PalbaseErrorDataDigest";
1085
+ const tmpRegistry = new import_zod_to_openapi.OpenAPIRegistry();
1086
+ tmpRegistry.register(TMP_REF, import_zod.z.object({ data: dataSchema }).openapi(TMP_REF));
1087
+ const generated = new import_zod_to_openapi.OpenApiGeneratorV31(tmpRegistry.definitions).generateComponents();
1088
+ const out = generated.components?.schemas?.[TMP_REF];
1089
+ const digest = JSON.stringify(out ?? null);
1090
+ if (digest.includes('"$ref"')) {
1091
+ throw new Error(
1092
+ `defineError: dataSchema for "${code}" carries .openapi(refId) metadata \u2014 it would emit dangling $ref pointers in the project spec. Use a plain zod schema (z.object({...})) without .openapi(...).`
1093
+ );
1094
+ }
1095
+ return digest;
1096
+ }
1097
+ function defaultClassName(code) {
1098
+ return code.split("_").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
1099
+ }
1100
+ function humanize(code) {
1101
+ const s = code.replace(/_/g, " ");
1102
+ return s.charAt(0).toUpperCase() + s.slice(1);
1103
+ }
1104
+
963
1105
  // src/worker.ts
964
1106
  var VALID_WORKER_NAME = /^[a-zA-Z0-9_-]+$/;
965
1107
  var WORKER_DEFAULTS = {
@@ -1258,7 +1400,7 @@ var documents = {
1258
1400
  };
1259
1401
 
1260
1402
  // src/index.ts
1261
- var import_zod = require("zod");
1403
+ var import_zod2 = require("zod");
1262
1404
  // Annotate the CommonJS export names for ESM import in node:
1263
1405
  0 && (module.exports = {
1264
1406
  BadRequest,
@@ -1293,6 +1435,7 @@ var import_zod = require("zod");
1293
1435
  Query,
1294
1436
  Queue,
1295
1437
  RESERVED_SECRET_PREFIX,
1438
+ Realtime,
1296
1439
  Req,
1297
1440
  RequestId,
1298
1441
  Resource,
@@ -1313,6 +1456,7 @@ var import_zod = require("zod");
1313
1456
  boolean,
1314
1457
  bucket,
1315
1458
  buildProvider,
1459
+ defineError,
1316
1460
  defineFlags,
1317
1461
  defineJob,
1318
1462
  defineMiddleware,
@@ -1324,6 +1468,7 @@ var import_zod = require("zod");
1324
1468
  documents,
1325
1469
  enumType,
1326
1470
  flag,
1471
+ getErrorRegistry,
1327
1472
  integer,
1328
1473
  isPalbaseExtension,
1329
1474
  jsonb,
@@ -1331,6 +1476,7 @@ var import_zod = require("zod");
1331
1476
  makeTypedDB,
1332
1477
  parseFileSizeLimit,
1333
1478
  policy,
1479
+ recordThrows,
1334
1480
  reservedSecretKey,
1335
1481
  storage,
1336
1482
  text,