@innvoid/getmarket-sdk 0.1.4 → 0.1.6

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 (57) hide show
  1. package/dist/cache/index.js +0 -1
  2. package/dist/chunk-JXOLNJ7J.js +224 -0
  3. package/dist/chunk-JXOLNJ7J.js.map +1 -0
  4. package/dist/chunk-KJ64O2EG.js +19 -0
  5. package/dist/chunk-KJ64O2EG.js.map +1 -0
  6. package/dist/{chunk-GG7EI74E.js → chunk-OSYBK5AN.js} +5 -3
  7. package/dist/chunk-OSYBK5AN.js.map +1 -0
  8. package/dist/chunk-P2U3MT2E.js +39 -0
  9. package/dist/chunk-P2U3MT2E.js.map +1 -0
  10. package/dist/core/index.cjs +4 -2
  11. package/dist/core/index.cjs.map +1 -1
  12. package/dist/core/index.d.cts +1 -2
  13. package/dist/core/index.d.ts +1 -2
  14. package/dist/core/index.js +2 -4
  15. package/dist/express.cjs +19 -0
  16. package/dist/express.cjs.map +1 -0
  17. package/dist/express.d.cts +12 -0
  18. package/dist/express.d.ts +12 -0
  19. package/dist/express.js +1 -0
  20. package/dist/headers/index.cjs +12 -6
  21. package/dist/headers/index.cjs.map +1 -1
  22. package/dist/headers/index.d.cts +3 -18
  23. package/dist/headers/index.d.ts +3 -18
  24. package/dist/headers/index.js +1 -2
  25. package/dist/index.cjs +138 -51
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +34 -6
  28. package/dist/index.d.ts +34 -6
  29. package/dist/index.js +147 -14
  30. package/dist/index.js.map +1 -1
  31. package/dist/middlewares/index.cjs +133 -35
  32. package/dist/middlewares/index.cjs.map +1 -1
  33. package/dist/middlewares/index.d.cts +43 -14
  34. package/dist/middlewares/index.d.ts +43 -14
  35. package/dist/middlewares/index.js +9 -4
  36. package/dist/parse-C4vk-fmH.d.cts +16 -0
  37. package/dist/parse-C4vk-fmH.d.ts +16 -0
  38. package/dist/types-CRECQuHp.d.cts +54 -0
  39. package/dist/types-CRECQuHp.d.ts +54 -0
  40. package/package.json +6 -1
  41. package/dist/auth/index.cjs +0 -181
  42. package/dist/auth/index.cjs.map +0 -1
  43. package/dist/auth/index.d.cts +0 -3
  44. package/dist/auth/index.d.ts +0 -3
  45. package/dist/auth/index.js +0 -12
  46. package/dist/chunk-65HACONF.js +0 -33
  47. package/dist/chunk-65HACONF.js.map +0 -1
  48. package/dist/chunk-GG7EI74E.js.map +0 -1
  49. package/dist/chunk-PZ5AY32C.js +0 -10
  50. package/dist/chunk-PZ5AY32C.js.map +0 -1
  51. package/dist/chunk-W23UYULS.js +0 -156
  52. package/dist/chunk-W23UYULS.js.map +0 -1
  53. package/dist/chunk-Y2JJLHAY.js +0 -149
  54. package/dist/chunk-Y2JJLHAY.js.map +0 -1
  55. package/dist/index-WbfzvmOt.d.cts +0 -87
  56. package/dist/index-WbfzvmOt.d.ts +0 -87
  57. /package/dist/{auth/index.js.map → express.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/headers/index.ts","../../src/headers/constants.ts","../../src/headers/parse.ts"],"sourcesContent":["export * from \"./constants\";\nexport * from \"./parse\";\n","export const HEADER_REQUEST_ID = \"x-request-id\";\n\nexport const HEADER_COMPANY_UID = \"x-company\";\nexport const HEADER_BRANCH_UID = \"x-branch\";\nexport const HEADER_EMPLOYEE_UID = \"x-employee-uid\";\n\nexport const HEADER_INTERNAL_API_KEY = \"x-internal-api-key\";\nexport const HEADER_AUTHORIZATION = \"authorization\";\n","import {\n HEADER_BRANCH_UID,\n HEADER_COMPANY_UID,\n HEADER_EMPLOYEE_UID,\n HEADER_REQUEST_ID,\n} from \"./constants\";\n\nexport type RequestContext = {\n requestId?: string | null;\n\n company_uid?: string | null;\n branch_uid?: string | null;\n employee_uid?: string | null;\n};\n\nfunction asString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n return s ? s : null;\n}\n\n/**\n * ✅ NO-LEGACY:\n * - x-company: <UID>\n * - x-branch: <UID>\n * - x-employee-uid: <UID> (opcional)\n * - x-request-id: string (opcional)\n *\n * 🚫 No JSON, no _id, no objetos.\n */\nexport function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext {\n return {\n requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,\n company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,\n branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,\n employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,oBAAoB;AAE1B,IAAM,qBAAqB;AAC3B,IAAM,oBAAoB;AAC1B,IAAM,sBAAsB;AAE5B,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;;;ACQpC,SAAS,SAAS,GAA2B;AACzC,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,QAAM,IAAI,EAAE,KAAK;AACjB,SAAO,IAAI,IAAI;AACnB;AAWO,SAAS,6BAA6B,SAA8C;AACvF,SAAO;AAAA,IACH,WAAW,SAAS,QAAQ,iBAAiB,CAAC,KAAK;AAAA,IACnD,aAAa,SAAS,QAAQ,kBAAkB,CAAC,KAAK;AAAA,IACtD,YAAY,SAAS,QAAQ,iBAAiB,CAAC,KAAK;AAAA,IACpD,cAAc,SAAS,QAAQ,mBAAmB,CAAC,KAAK;AAAA,EAC5D;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../src/headers/index.ts","../../src/headers/constants.ts","../../src/headers/parse.ts"],"sourcesContent":["export * from \"./constants\";\nexport * from \"./parse\";\n","export const HEADER_REQUEST_ID = \"x-request-id\";\n\nexport const HEADER_COMPANY_UID = \"x-company\";\nexport const HEADER_BRANCH_UID = \"x-branch\";\nexport const HEADER_EMPLOYEE_UID = \"x-employee-uid\";\n\nexport const HEADER_INTERNAL_API_KEY = \"x-internal-api-key\";\nexport const HEADER_AUTHORIZATION = \"authorization\";\n","import {\n HEADER_BRANCH_UID,\n HEADER_COMPANY_UID,\n HEADER_EMPLOYEE_UID,\n HEADER_REQUEST_ID,\n} from \"./constants\";\n\nexport type RequestContext = {\n requestId?: string | null;\n company_uid?: string | null;\n branch_uid?: string | null;\n employee_uid?: string | null;\n};\n\nfunction normalizeHeaderValue(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n if (!s) return null;\n\n // ✅ NO-LEGACY: bloquea JSON en headers\n if (s.startsWith(\"{\") || s.startsWith(\"[\") || s.includes('\"')) return null;\n\n // Evitar valores demasiado cortos (basura)\n if (s.length < 6) return null;\n\n return s;\n}\n\n/**\n * Lee header aunque venga en mayúsculas/minúsculas (Express suele bajar a lower-case).\n */\nfunction h(headers: Record<string, any>, key: string): unknown {\n return headers[key] ?? headers[key.toLowerCase()] ?? headers[key.toUpperCase()];\n}\n\n/**\n * ✅ NO-LEGACY:\n * - x-company: <UID>\n * - x-branch: <UID>\n * - x-employee-uid: <UID> (opcional; NO reemplaza JWT)\n * - x-request-id: string (opcional)\n */\nexport function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext {\n return {\n requestId: normalizeHeaderValue(h(headers, HEADER_REQUEST_ID)) ?? null,\n company_uid: normalizeHeaderValue(h(headers, HEADER_COMPANY_UID)) ?? null,\n branch_uid: normalizeHeaderValue(h(headers, HEADER_BRANCH_UID)) ?? null,\n employee_uid: normalizeHeaderValue(h(headers, HEADER_EMPLOYEE_UID)) ?? null,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,oBAAoB;AAE1B,IAAM,qBAAqB;AAC3B,IAAM,oBAAoB;AAC1B,IAAM,sBAAsB;AAE5B,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;;;ACOpC,SAAS,qBAAqB,GAA2B;AACrD,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,QAAM,IAAI,EAAE,KAAK;AACjB,MAAI,CAAC,EAAG,QAAO;AAGf,MAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,EAAG,QAAO;AAGtE,MAAI,EAAE,SAAS,EAAG,QAAO;AAEzB,SAAO;AACX;AAKA,SAAS,EAAE,SAA8B,KAAsB;AAC3D,SAAO,QAAQ,GAAG,KAAK,QAAQ,IAAI,YAAY,CAAC,KAAK,QAAQ,IAAI,YAAY,CAAC;AAClF;AASO,SAAS,6BAA6B,SAA8C;AACvF,SAAO;AAAA,IACH,WAAW,qBAAqB,EAAE,SAAS,iBAAiB,CAAC,KAAK;AAAA,IAClE,aAAa,qBAAqB,EAAE,SAAS,kBAAkB,CAAC,KAAK;AAAA,IACrE,YAAY,qBAAqB,EAAE,SAAS,iBAAiB,CAAC,KAAK;AAAA,IACnE,cAAc,qBAAqB,EAAE,SAAS,mBAAmB,CAAC,KAAK;AAAA,EAC3E;AACJ;","names":[]}
@@ -1,3 +1,5 @@
1
+ export { R as RequestContext, g as getRequestContextFromHeaders } from '../parse-C4vk-fmH.cjs';
2
+
1
3
  declare const HEADER_REQUEST_ID = "x-request-id";
2
4
  declare const HEADER_COMPANY_UID = "x-company";
3
5
  declare const HEADER_BRANCH_UID = "x-branch";
@@ -5,21 +7,4 @@ declare const HEADER_EMPLOYEE_UID = "x-employee-uid";
5
7
  declare const HEADER_INTERNAL_API_KEY = "x-internal-api-key";
6
8
  declare const HEADER_AUTHORIZATION = "authorization";
7
9
 
8
- type RequestContext = {
9
- requestId?: string | null;
10
- company_uid?: string | null;
11
- branch_uid?: string | null;
12
- employee_uid?: string | null;
13
- };
14
- /**
15
- * ✅ NO-LEGACY:
16
- * - x-company: <UID>
17
- * - x-branch: <UID>
18
- * - x-employee-uid: <UID> (opcional)
19
- * - x-request-id: string (opcional)
20
- *
21
- * 🚫 No JSON, no _id, no objetos.
22
- */
23
- declare function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext;
24
-
25
- export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID, type RequestContext, getRequestContextFromHeaders };
10
+ export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID };
@@ -1,3 +1,5 @@
1
+ export { R as RequestContext, g as getRequestContextFromHeaders } from '../parse-C4vk-fmH.js';
2
+
1
3
  declare const HEADER_REQUEST_ID = "x-request-id";
2
4
  declare const HEADER_COMPANY_UID = "x-company";
3
5
  declare const HEADER_BRANCH_UID = "x-branch";
@@ -5,21 +7,4 @@ declare const HEADER_EMPLOYEE_UID = "x-employee-uid";
5
7
  declare const HEADER_INTERNAL_API_KEY = "x-internal-api-key";
6
8
  declare const HEADER_AUTHORIZATION = "authorization";
7
9
 
8
- type RequestContext = {
9
- requestId?: string | null;
10
- company_uid?: string | null;
11
- branch_uid?: string | null;
12
- employee_uid?: string | null;
13
- };
14
- /**
15
- * ✅ NO-LEGACY:
16
- * - x-company: <UID>
17
- * - x-branch: <UID>
18
- * - x-employee-uid: <UID> (opcional)
19
- * - x-request-id: string (opcional)
20
- *
21
- * 🚫 No JSON, no _id, no objetos.
22
- */
23
- declare function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext;
24
-
25
- export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID, type RequestContext, getRequestContextFromHeaders };
10
+ export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID };
@@ -6,8 +6,7 @@ import {
6
6
  HEADER_INTERNAL_API_KEY,
7
7
  HEADER_REQUEST_ID,
8
8
  getRequestContextFromHeaders
9
- } from "../chunk-65HACONF.js";
10
- import "../chunk-PZ5AY32C.js";
9
+ } from "../chunk-P2U3MT2E.js";
11
10
  export {
12
11
  HEADER_AUTHORIZATION,
13
12
  HEADER_BRANCH_UID,
package/dist/index.cjs CHANGED
@@ -37,10 +37,8 @@ __export(src_exports, {
37
37
  HEADER_INTERNAL_API_KEY: () => HEADER_INTERNAL_API_KEY,
38
38
  HEADER_REQUEST_ID: () => HEADER_REQUEST_ID,
39
39
  InternalHttp: () => InternalHttp,
40
- REQUEST_ID_HEADER: () => REQUEST_ID_HEADER,
41
40
  TwoLevelCache: () => TwoLevelCache,
42
41
  UpstreamError: () => UpstreamError,
43
- auth: () => auth_exports,
44
42
  closeCache: () => closeCache,
45
43
  createAuthMiddleware: () => createAuthMiddleware,
46
44
  createHttpClient: () => createHttpClient,
@@ -52,9 +50,11 @@ __export(src_exports, {
52
50
  parseHeaders: () => parseHeaders,
53
51
  readRs256PublicKey: () => readRs256PublicKey,
54
52
  requestId: () => requestId,
53
+ requireAnyPermission: () => requireAnyPermission,
55
54
  requireAuthContext: () => requireAuthContext,
56
55
  requirePermissions: () => requirePermissions,
57
56
  requireRoles: () => requireRoles,
57
+ requireRolesOrAnyPermission: () => requireRolesOrAnyPermission,
58
58
  sendError: () => sendError,
59
59
  sendOk: () => sendOk,
60
60
  verifyBackendJwtRS256: () => verifyBackendJwtRS256,
@@ -384,12 +384,27 @@ function mapAxiosToUpstreamError(err, svc) {
384
384
 
385
385
  // src/core/http.ts
386
386
  var import_axios = __toESM(require("axios"), 1);
387
+
388
+ // src/middlewares/requestId.ts
389
+ var import_crypto = require("crypto");
387
390
  var REQUEST_ID_HEADER = "x-request-id";
391
+ var REQUEST_ID_HEADER_ALT = "x-requestid";
392
+ var RESPONSE_REQUEST_ID_HEADER = "X-Request-Id";
393
+ function requestId(req, res, next) {
394
+ const headerId = req.headers[REQUEST_ID_HEADER] || req.headers[REQUEST_ID_HEADER_ALT];
395
+ const id = headerId?.trim() || (0, import_crypto.randomUUID)();
396
+ req.requestId = id;
397
+ res.locals.requestId = id;
398
+ res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);
399
+ next();
400
+ }
401
+
402
+ // src/core/http.ts
388
403
  function withRequestId(headers, requestId2) {
389
- const h = headers && typeof headers === "object" ? { ...headers } : {};
404
+ const h2 = headers && typeof headers === "object" ? { ...headers } : {};
390
405
  const rid = (requestId2 || "").trim();
391
- if (rid) h[REQUEST_ID_HEADER] = rid;
392
- return h;
406
+ if (rid) h2[REQUEST_ID_HEADER] = rid;
407
+ return h2;
393
408
  }
394
409
  function withRequestIdConfig(config = {}, requestId2) {
395
410
  return {
@@ -518,42 +533,29 @@ var HEADER_INTERNAL_API_KEY = "x-internal-api-key";
518
533
  var HEADER_AUTHORIZATION = "authorization";
519
534
 
520
535
  // src/headers/parse.ts
521
- function asString(v) {
536
+ function normalizeHeaderValue(v) {
522
537
  if (typeof v !== "string") return null;
523
538
  const s = v.trim();
524
- return s ? s : null;
539
+ if (!s) return null;
540
+ if (s.startsWith("{") || s.startsWith("[") || s.includes('"')) return null;
541
+ if (s.length < 6) return null;
542
+ return s;
543
+ }
544
+ function h(headers, key) {
545
+ return headers[key] ?? headers[key.toLowerCase()] ?? headers[key.toUpperCase()];
525
546
  }
526
547
  function getRequestContextFromHeaders(headers) {
527
548
  return {
528
- requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,
529
- company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,
530
- branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,
531
- employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null
549
+ requestId: normalizeHeaderValue(h(headers, HEADER_REQUEST_ID)) ?? null,
550
+ company_uid: normalizeHeaderValue(h(headers, HEADER_COMPANY_UID)) ?? null,
551
+ branch_uid: normalizeHeaderValue(h(headers, HEADER_BRANCH_UID)) ?? null,
552
+ employee_uid: normalizeHeaderValue(h(headers, HEADER_EMPLOYEE_UID)) ?? null
532
553
  };
533
554
  }
534
555
 
535
- // src/middlewares/requestId.ts
536
- var import_crypto = require("crypto");
537
- var REQUEST_ID_HEADER2 = "x-request-id";
538
- var REQUEST_ID_HEADER_ALT = "x-requestid";
539
- var RESPONSE_REQUEST_ID_HEADER = "X-Request-Id";
540
- function requestId(req, res, next) {
541
- const headerId = req.headers[REQUEST_ID_HEADER2] || req.headers[REQUEST_ID_HEADER_ALT];
542
- const id = headerId?.trim() || (0, import_crypto.randomUUID)();
543
- req.requestId = id;
544
- res.locals.requestId = id;
545
- res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);
546
- next();
547
- }
548
-
549
556
  // src/middlewares/parseHeaders.ts
550
557
  function parseHeaders(req, _res, next) {
551
- const context = getRequestContextFromHeaders(req.headers);
552
- req.context = context;
553
- const auth = req.auth ?? (req.auth = {});
554
- if (context.company_uid) auth.company_uid = context.company_uid;
555
- if (context.branch_uid) auth.branch_uid = context.branch_uid;
556
- if (context.employee_uid) auth.employee_uid = context.employee_uid;
558
+ req.context = getRequestContextFromHeaders(req.headers);
557
559
  next();
558
560
  }
559
561
 
@@ -625,10 +627,32 @@ function internalAuth(req, res, next) {
625
627
  return next();
626
628
  }
627
629
 
628
- // src/middlewares/autorization.ts
630
+ // src/middlewares/authorization.ts
629
631
  function getAuth(req) {
630
632
  return req.auth ?? {};
631
633
  }
634
+ function normalizeCode(v) {
635
+ if (!v) return null;
636
+ if (typeof v === "string") return v;
637
+ if (typeof v === "object") return v.code || v.name || null;
638
+ return null;
639
+ }
640
+ function rolesSet(auth) {
641
+ const out = /* @__PURE__ */ new Set();
642
+ for (const r of auth.roles || []) {
643
+ const c = normalizeCode(r);
644
+ if (c) out.add(c);
645
+ }
646
+ return out;
647
+ }
648
+ function permsSet(list) {
649
+ const out = /* @__PURE__ */ new Set();
650
+ for (const p of list || []) {
651
+ const c = normalizeCode(p);
652
+ if (c) out.add(c);
653
+ }
654
+ return out;
655
+ }
632
656
  function requireAuthContext() {
633
657
  return (req, res, next) => {
634
658
  if (!req.auth) {
@@ -637,41 +661,104 @@ function requireAuthContext() {
637
661
  return next();
638
662
  };
639
663
  }
640
- function requirePermissions(...perms) {
664
+ function isSysAdmin(auth, sysAdminRole) {
665
+ const have = rolesSet(auth);
666
+ return have.has(sysAdminRole);
667
+ }
668
+ function requirePermissions(perms, options) {
669
+ const sysAdminBypass = options?.sysAdminBypass !== false;
670
+ const sysAdminRole = options?.sysAdminRole || "SYS_ADMIN";
641
671
  return (req, res, next) => {
642
672
  const auth = getAuth(req);
643
- const allow = new Set(auth.permissions ?? []);
644
- const deny = new Set(auth.denied_permissions ?? []);
673
+ if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();
674
+ const allow = permsSet(auth.permissions);
675
+ const deny = permsSet(auth.denied_permissions);
645
676
  for (const p of perms) {
646
677
  if (deny.has(p)) {
647
- return sendError(req, res, 403, "FORBIDDEN", `Denied: ${p}`);
678
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
679
+ denied: p
680
+ });
648
681
  }
649
682
  }
650
683
  const missing = perms.filter((p) => !allow.has(p));
651
684
  if (missing.length) {
652
- return sendError(req, res, 403, "FORBIDDEN", "Missing permissions", { missing });
685
+ return sendError(req, res, 403, "FORBIDDEN", "Missing permissions", {
686
+ missing,
687
+ mode: "ALL"
688
+ });
689
+ }
690
+ return next();
691
+ };
692
+ }
693
+ function requireAnyPermission(perms, options) {
694
+ const sysAdminBypass = options?.sysAdminBypass !== false;
695
+ const sysAdminRole = options?.sysAdminRole || "SYS_ADMIN";
696
+ return (req, res, next) => {
697
+ const auth = getAuth(req);
698
+ if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();
699
+ const allow = permsSet(auth.permissions);
700
+ const deny = permsSet(auth.denied_permissions);
701
+ for (const p of perms) {
702
+ if (deny.has(p)) {
703
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
704
+ denied: p
705
+ });
706
+ }
707
+ }
708
+ const ok = perms.some((p) => allow.has(p));
709
+ if (!ok) {
710
+ return sendError(req, res, 403, "FORBIDDEN", "Permission denied", {
711
+ required: perms,
712
+ mode: "ANY"
713
+ });
653
714
  }
654
715
  return next();
655
716
  };
656
717
  }
657
- function requireRoles(...roles) {
718
+ function requireRoles(roles, options) {
719
+ const sysAdminBypass = options?.sysAdminBypass !== false;
720
+ const sysAdminRole = options?.sysAdminRole || "SYS_ADMIN";
658
721
  return (req, res, next) => {
659
722
  const auth = getAuth(req);
660
- const have = new Set(auth.roles ?? []);
723
+ if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();
724
+ const have = rolesSet(auth);
661
725
  if (!roles.some((r) => have.has(r))) {
662
- return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", { required: roles });
726
+ return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", {
727
+ required: roles,
728
+ mode: "ANY"
729
+ });
730
+ }
731
+ return next();
732
+ };
733
+ }
734
+ function requireRolesOrAnyPermission(roles, perms, options) {
735
+ const sysAdminBypass = options?.sysAdminBypass !== false;
736
+ const sysAdminRole = options?.sysAdminRole || "SYS_ADMIN";
737
+ return (req, res, next) => {
738
+ const auth = getAuth(req);
739
+ if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();
740
+ const haveRoles = rolesSet(auth);
741
+ const allow = permsSet(auth.permissions);
742
+ const deny = permsSet(auth.denied_permissions);
743
+ for (const p of perms) {
744
+ if (deny.has(p)) {
745
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
746
+ denied: p
747
+ });
748
+ }
749
+ }
750
+ const okRole = roles.some((r) => haveRoles.has(r));
751
+ const okPerm = perms.some((p) => allow.has(p));
752
+ if (!okRole && !okPerm) {
753
+ return sendError(req, res, 403, "FORBIDDEN", "Access denied", {
754
+ roles,
755
+ permissions: perms,
756
+ mode: "ROLES_OR_PERMS_ANY"
757
+ });
663
758
  }
664
759
  return next();
665
760
  };
666
761
  }
667
-
668
- // src/auth/index.ts
669
- var auth_exports = {};
670
- __export(auth_exports, {
671
- createAuthMiddleware: () => createAuthMiddleware,
672
- readRs256PublicKey: () => readRs256PublicKey,
673
- verifyBackendJwtRS256: () => verifyBackendJwtRS256
674
- });
675
762
 
676
763
  // src/auth/jwt.ts
677
764
  var import_fs2 = __toESM(require("fs"), 1);
@@ -769,7 +856,7 @@ function createAuthMiddleware(opts) {
769
856
  }
770
857
  req.auth = baseCtx;
771
858
  return next();
772
- } catch (errJwt) {
859
+ } catch {
773
860
  if (!allowFirebaseIdToken) {
774
861
  return res.status(401).json({
775
862
  ok: false,
@@ -818,10 +905,8 @@ function createAuthMiddleware(opts) {
818
905
  HEADER_INTERNAL_API_KEY,
819
906
  HEADER_REQUEST_ID,
820
907
  InternalHttp,
821
- REQUEST_ID_HEADER,
822
908
  TwoLevelCache,
823
909
  UpstreamError,
824
- auth,
825
910
  closeCache,
826
911
  createAuthMiddleware,
827
912
  createHttpClient,
@@ -833,9 +918,11 @@ function createAuthMiddleware(opts) {
833
918
  parseHeaders,
834
919
  readRs256PublicKey,
835
920
  requestId,
921
+ requireAnyPermission,
836
922
  requireAuthContext,
837
923
  requirePermissions,
838
924
  requireRoles,
925
+ requireRolesOrAnyPermission,
839
926
  sendError,
840
927
  sendOk,
841
928
  verifyBackendJwtRS256,