@palbase/backend 12.0.0 → 13.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.js CHANGED
@@ -320,7 +320,13 @@ function baseTsType(def) {
320
320
  return "string";
321
321
  case "integer":
322
322
  return "number";
323
+ // Both are exact-precision in Postgres and lossy as a JSON number, so the
324
+ // database proxy serializes them as strings — measured: 9007199254740993
325
+ // used to arrive as ...992 and 41.00821234567890123 as 41.0082123456789.
326
+ // numeric had no case at all and fell through to `unknown`, which typed
327
+ // every numeric column out of existence.
323
328
  case "bigint":
329
+ case "numeric":
324
330
  return "string";
325
331
  case "boolean":
326
332
  return "boolean";
@@ -839,38 +845,6 @@ function defineFlags(input) {
839
845
  return { __config: FLAGS_CONFIG_KIND, flags };
840
846
  }
841
847
 
842
- // src/decorators/controller.ts
843
- var CONTROLLER_META = /* @__PURE__ */ Symbol.for("palbase.backend.controllerMeta");
844
- function Controller(basePath, options = {}) {
845
- return function(ctor) {
846
- const normalized = basePath.replace(/\/+$/, "");
847
- if (normalized === "/webhooks" || normalized.startsWith("/webhooks/")) {
848
- throw new Error(
849
- `@Controller("${basePath}") uses the reserved /webhooks path \u2014 inbound webhooks are served there`
850
- );
851
- }
852
- const carrier = ctor;
853
- const meta = {
854
- __palbase: "controller",
855
- basePath,
856
- ...options.auth !== void 0 ? { defaultAuth: options.auth } : {}
857
- };
858
- Object.defineProperty(carrier, CONTROLLER_META, {
859
- value: meta,
860
- enumerable: false,
861
- configurable: true,
862
- writable: false
863
- });
864
- Object.defineProperty(carrier, "__palbase", {
865
- value: "controller",
866
- enumerable: false,
867
- configurable: true,
868
- writable: false
869
- });
870
- return ctor;
871
- };
872
- }
873
-
874
848
  // src/decorators/registry.ts
875
849
  var ROUTES = /* @__PURE__ */ Symbol.for("palbase.backend.routes");
876
850
  var PARAM_BUFFER = /* @__PURE__ */ Symbol.for("palbase.backend.paramBuffer");
@@ -963,6 +937,48 @@ function getRoutes(ctor) {
963
937
  }));
964
938
  }
965
939
 
940
+ // src/decorators/controller.ts
941
+ var CONTROLLER_META = /* @__PURE__ */ Symbol.for("palbase.backend.controllerMeta");
942
+ var RESERVED_FIRST_SEGMENT = "webhooks";
943
+ function assertNotReserved(path, subject) {
944
+ const [first] = path.split("/").filter(Boolean);
945
+ if (first === RESERVED_FIRST_SEGMENT) {
946
+ throw new Error(
947
+ `${subject} resolves under the reserved /${RESERVED_FIRST_SEGMENT} path \u2014 inbound webhooks are served there and would shadow this route`
948
+ );
949
+ }
950
+ }
951
+ function Controller(basePath, options = {}) {
952
+ return function(ctor) {
953
+ assertNotReserved(basePath, `@Controller("${basePath}")`);
954
+ for (const route of getRoutes(ctor)) {
955
+ assertNotReserved(
956
+ `${basePath}${route.subpath}`,
957
+ `@${route.method}("${route.subpath}") in @Controller("${basePath}")`
958
+ );
959
+ }
960
+ const carrier = ctor;
961
+ const meta = {
962
+ __palbase: "controller",
963
+ basePath,
964
+ ...options.auth !== void 0 ? { defaultAuth: options.auth } : {}
965
+ };
966
+ Object.defineProperty(carrier, CONTROLLER_META, {
967
+ value: meta,
968
+ enumerable: false,
969
+ configurable: true,
970
+ writable: false
971
+ });
972
+ Object.defineProperty(carrier, "__palbase", {
973
+ value: "controller",
974
+ enumerable: false,
975
+ configurable: true,
976
+ writable: false
977
+ });
978
+ return ctor;
979
+ };
980
+ }
981
+
966
982
  // src/decorators/methods.ts
967
983
  function makeMethodDecorator(method) {
968
984
  return function(subpath, options = {}) {
@@ -1292,6 +1308,29 @@ function getWebhookConfig(ctor) {
1292
1308
  "@Webhook requires either a `provider` preset or an explicit `signature` \u2014 an endpoint with no verification would accept forged deliveries"
1293
1309
  );
1294
1310
  }
1311
+ if (meta.provider && meta.signature) {
1312
+ throw new Error(
1313
+ "@Webhook declares BOTH a `provider` preset and an explicit `signature` \u2014 these are alternatives; keep the one that describes the sender, because only `provider` would be used"
1314
+ );
1315
+ }
1316
+ if (meta.signature) {
1317
+ const sig = meta.signature;
1318
+ if (!sig.header) {
1319
+ throw new Error("@Webhook signature requires `header` \u2014 the header the signature arrives in");
1320
+ }
1321
+ if (sig.algo !== "hmac-sha256" && sig.algo !== "hmac-sha1") {
1322
+ throw new Error(`@Webhook signature has an unsupported algo "${sig.algo}"`);
1323
+ }
1324
+ if (sig.encoding !== "hex" && sig.encoding !== "base64") {
1325
+ throw new Error(`@Webhook signature has an unsupported encoding "${sig.encoding}"`);
1326
+ }
1327
+ if (!sig.signs?.includes("{body}")) {
1328
+ throw new Error("@Webhook signature `signs` must contain {body} \u2014 signing a constant is not a signature");
1329
+ }
1330
+ if (sig.signs.includes("{ts}") && !sig.timestampHeader) {
1331
+ throw new Error("@Webhook signature uses {ts} but declares no `timestampHeader` to read it from");
1332
+ }
1333
+ }
1295
1334
  if (!meta.secret?.env) {
1296
1335
  throw new Error('@Webhook requires `secret: { env: "VAR_NAME" }`');
1297
1336
  }