@innvoid/getmarket-sdk 0.1.10 → 0.1.11

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.
@@ -379,6 +379,37 @@ function normalizeUid2(v) {
379
379
  const s = String(v ?? "").trim();
380
380
  return s.length ? s : null;
381
381
  }
382
+ function normalizeCodes(list, kind) {
383
+ if (!Array.isArray(list)) return [];
384
+ const out = [];
385
+ for (const item of list) {
386
+ if (!item) continue;
387
+ if (typeof item === "string") {
388
+ const s2 = item.trim();
389
+ if (s2) out.push(s2);
390
+ continue;
391
+ }
392
+ const s = String(item.code || item.name || "").trim();
393
+ if (s) out.push(s);
394
+ }
395
+ return Array.from(new Set(out));
396
+ }
397
+ function extractEmployeeUid(decoded) {
398
+ const direct = normalizeUid2(decoded?.employee_uid);
399
+ if (direct) return direct;
400
+ const sub = normalizeUid2(decoded?.sub);
401
+ if (!sub) return null;
402
+ const m = /^emp:(.+)$/i.exec(sub);
403
+ return m?.[1] ? normalizeUid2(m[1]) : null;
404
+ }
405
+ function extractCustomerUid(decoded) {
406
+ const direct = normalizeUid2(decoded?.customer_uid);
407
+ if (direct) return direct;
408
+ const sub = normalizeUid2(decoded?.sub);
409
+ if (!sub) return null;
410
+ const m = /^cus:(.+)$/i.exec(sub);
411
+ return m?.[1] ? normalizeUid2(m[1]) : null;
412
+ }
382
413
  function deriveCompanyBranch(decoded, companyUid, branchUid) {
383
414
  const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];
384
415
  const company = decoded?.company ?? (companyUid ? companiesFromToken.find((c) => c?.uid === companyUid) : null) ?? null;
@@ -410,9 +441,10 @@ function createAuthMiddleware2(opts) {
410
441
  companies: companiesFromToken,
411
442
  company,
412
443
  branch,
413
- roles: Array.isArray(decoded?.roles) ? decoded.roles : [],
414
- permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],
415
- denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],
444
+ // canonical string[]
445
+ roles: normalizeCodes(decoded?.roles, "role"),
446
+ permissions: normalizeCodes(decoded?.permissions, "perm"),
447
+ denied_permissions: normalizeCodes(decoded?.denied_permissions, "perm"),
416
448
  session: {
417
449
  jti: decoded?.jti,
418
450
  device_id: decoded?.device_id,
@@ -420,25 +452,35 @@ function createAuthMiddleware2(opts) {
420
452
  }
421
453
  };
422
454
  if (subject === "employee") {
423
- const employee = decoded?.employee ?? decoded?.user ?? null;
424
- if (!employee) {
455
+ const employeeUid = extractEmployeeUid(decoded);
456
+ const employeeEmbedded = decoded?.employee ?? decoded?.user ?? null;
457
+ if (employeeEmbedded) {
458
+ ctx.employee = employeeUid ? { ...employeeEmbedded, uid: employeeEmbedded?.uid ?? employeeUid } : employeeEmbedded;
459
+ } else if (employeeUid) {
460
+ ctx.employee = { uid: employeeUid };
461
+ } else {
425
462
  return res.status(401).json({
426
463
  ok: false,
427
464
  code: "AUTH_EMPLOYEE_NOT_FOUND",
428
- message: "Employee not found in token"
465
+ message: "Employee not found in token (expected employee_uid or sub=emp:<uid>)"
429
466
  });
430
467
  }
431
- ctx.employee = employee;
468
+ ctx.employee_uid = employeeUid ?? void 0;
432
469
  } else {
433
- const customer = decoded?.customer ?? null;
434
- if (!customer) {
470
+ const customerUid = extractCustomerUid(decoded);
471
+ const customerEmbedded = decoded?.customer ?? null;
472
+ if (customerEmbedded) {
473
+ ctx.customer = customerUid ? { ...customerEmbedded, uid: customerEmbedded?.uid ?? customerUid } : customerEmbedded;
474
+ } else if (customerUid) {
475
+ ctx.customer = { uid: customerUid };
476
+ } else {
435
477
  return res.status(401).json({
436
478
  ok: false,
437
479
  code: "AUTH_CUSTOMER_NOT_FOUND",
438
- message: "Customer not found in token"
480
+ message: "Customer not found in token (expected customer_uid or sub=cus:<uid>)"
439
481
  });
440
482
  }
441
- ctx.customer = customer;
483
+ ctx.customer_uid = customerUid ?? void 0;
442
484
  }
443
485
  req.auth = ctx;
444
486
  return next();
@@ -508,14 +550,13 @@ function getAuth2(req) {
508
550
  return req.auth ?? {};
509
551
  }
510
552
  function permissionSets(auth) {
511
- const allow = new Set(
512
- (auth.permissions ?? []).map(normalizePerm).filter(Boolean)
513
- );
514
- const deny = new Set(
515
- (auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean)
516
- );
553
+ const allow = new Set((auth.permissions ?? []).map(normalizePerm).filter(Boolean));
554
+ const deny = new Set((auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean));
517
555
  return { allow, deny };
518
556
  }
557
+ function roleSet(auth) {
558
+ return new Set((auth.roles ?? []).map(normalizeRole).filter(Boolean));
559
+ }
519
560
  function allowSysAdminOrAnyPermission(...perms) {
520
561
  const required = (perms ?? []).filter(Boolean);
521
562
  return [
@@ -527,16 +568,12 @@ function allowSysAdminOrAnyPermission(...perms) {
527
568
  const { allow, deny } = permissionSets(auth);
528
569
  for (const p of required) {
529
570
  if (deny.has(p)) {
530
- return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
531
- denied: p
532
- });
571
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
533
572
  }
534
573
  }
535
574
  const ok = required.some((p) => allow.has(p));
536
575
  if (!ok) {
537
- return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", {
538
- required
539
- });
576
+ return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", { required });
540
577
  }
541
578
  return next();
542
579
  }
@@ -553,17 +590,12 @@ function allowSysAdminOrPermissionsAll(...perms) {
553
590
  const { allow, deny } = permissionSets(auth);
554
591
  for (const p of required) {
555
592
  if (deny.has(p)) {
556
- return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
557
- denied: p
558
- });
593
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
559
594
  }
560
595
  }
561
596
  const missing = required.filter((p) => !allow.has(p));
562
597
  if (missing.length) {
563
- return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", {
564
- required,
565
- missing
566
- });
598
+ return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", { required, missing });
567
599
  }
568
600
  return next();
569
601
  }
@@ -577,55 +609,33 @@ function allowSysAdminOrRoles(...roles) {
577
609
  (req, res, next) => {
578
610
  const auth = getAuth2(req);
579
611
  if (isSysAdmin2(auth.roles)) return next();
580
- const have = new Set(
581
- (auth.roles ?? []).map(normalizeRole).filter(Boolean)
582
- );
612
+ const have = roleSet(auth);
583
613
  const ok = required.some((r) => have.has(r));
584
614
  if (!ok) {
585
- return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", {
586
- required
587
- });
615
+ return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", { required });
588
616
  }
589
617
  return next();
590
618
  }
591
619
  ];
592
620
  }
593
-
594
- // src/middlewares/accessControl.ts
595
- function normalizeList(v) {
596
- return Array.isArray(v) ? v : [v];
597
- }
598
- function roleCode(r) {
599
- if (!r) return null;
600
- return typeof r === "string" ? r : r.code || r.name || null;
601
- }
602
- function permCode(p) {
603
- if (!p) return null;
604
- return typeof p === "string" ? p : p.code || p.name || null;
605
- }
606
- function isSysAdmin3(roles) {
607
- if (!Array.isArray(roles)) return false;
608
- return roles.map(roleCode).filter(Boolean).includes("SYS_ADMIN");
609
- }
610
621
  function allowSysAdminOrRolesOrAnyPermission(roles, permissions) {
611
- const requiredRoles = normalizeList(roles).filter(Boolean);
612
- const requiredPerms = normalizeList(permissions).filter(Boolean);
622
+ const requiredRoles = (Array.isArray(roles) ? roles : [roles]).filter(Boolean);
623
+ const requiredPerms = (Array.isArray(permissions) ? permissions : [permissions]).filter(Boolean);
613
624
  return [
614
625
  parseHeaders,
615
626
  authEmployeeRequired,
616
627
  (req, res, next) => {
617
- const auth = req.auth || {};
618
- if (isSysAdmin3(auth.roles)) return next();
619
- const deny = new Set((auth.denied_permissions || []).map(permCode).filter(Boolean));
628
+ const auth = getAuth2(req);
629
+ if (isSysAdmin2(auth.roles)) return next();
630
+ const { allow, deny } = permissionSets(auth);
620
631
  for (const p of requiredPerms) {
621
632
  if (deny.has(p)) {
622
633
  return sendError(req, res, 403, "FORBIDDEN", `Denied: ${p}`, { permission: p });
623
634
  }
624
635
  }
625
- const haveRoles = new Set((auth.roles || []).map(roleCode).filter(Boolean));
636
+ const haveRoles = roleSet(auth);
626
637
  if (requiredRoles.some((r) => haveRoles.has(r))) return next();
627
- const havePerms = new Set((auth.permissions || []).map(permCode).filter(Boolean));
628
- if (requiredPerms.some((p) => havePerms.has(p))) return next();
638
+ if (requiredPerms.some((p) => allow.has(p))) return next();
629
639
  return sendError(req, res, 403, "FORBIDDEN", "Permission denied", {
630
640
  roles: requiredRoles,
631
641
  permissions: requiredPerms,
@@ -662,4 +672,4 @@ export {
662
672
  allowSysAdminOrRolesOrAnyPermission,
663
673
  allowAuthAdminOrPerm
664
674
  };
665
- //# sourceMappingURL=chunk-6E3X3D6Q.js.map
675
+ //# sourceMappingURL=chunk-WK3P3MDA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/middlewares/parseHeaders.ts","../src/middlewares/internalAuth.ts","../src/middlewares/respond.ts","../src/middlewares/authorization.ts","../src/auth/jwt.ts","../src/auth/middleware.ts","../src/auth/authentication.ts","../src/middlewares/guards.ts"],"sourcesContent":["// sdk/src/middlewares/parseHeaders.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY / ESTÁNDAR:\n * - Lee SOLO x-company y x-branch (UIDs planos)\n * - Setea req.context = { company_uid, branch_uid }\n * - NO toca req.auth (auth lo setea authentication/requireAuth)\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n (req as any).context = getRequestContextFromHeaders(req.headers as any);\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n","// packages/sdk/src/middlewares/authorization.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {sendError} from \"./respond\";\n\ntype AuthRole = string | { code?: string; name?: string };\ntype AuthPermission = string | { code?: string; name?: string };\n\ntype AuthShape = {\n roles?: AuthRole[];\n permissions?: AuthPermission[];\n denied_permissions?: AuthPermission[];\n};\n\nfunction getAuth(req: Request): AuthShape {\n return ((req as any).auth ?? {}) as AuthShape;\n}\n\nfunction normalizeCode(v: any): string | null {\n if (!v) return null;\n if (typeof v === \"string\") return v;\n if (typeof v === \"object\") return v.code || v.name || null;\n return null;\n}\n\nfunction rolesSet(auth: AuthShape): Set<string> {\n const out = new Set<string>();\n for (const r of auth.roles || []) {\n const c = normalizeCode(r);\n if (c) out.add(c);\n }\n return out;\n}\n\nfunction permsSet(list?: AuthPermission[]): Set<string> {\n const out = new Set<string>();\n for (const p of list || []) {\n const c = normalizeCode(p);\n if (c) out.add(c);\n }\n return out;\n}\n\n/**\n * 401 si no existe req.auth (contexto auth).\n * Útil para proteger rutas donde SIEMPRE debe existir auth.\n */\nexport function requireAuthContext() {\n return (req: Request, res: Response, next: NextFunction) => {\n if (!(req as any).auth) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", \"Missing auth context\");\n }\n return next();\n };\n}\n\n/**\n * Helper: SYS_ADMIN bypass (por defecto activo)\n */\nfunction isSysAdmin(auth: AuthShape, sysAdminRole: string) {\n const have = rolesSet(auth);\n return have.has(sysAdminRole);\n}\n\n/**\n * Requiere TODOS los permisos indicados.\n * Regla: denied_permissions siempre gana sobre permissions.\n *\n * options:\n * - sysAdminBypass: default true\n * - sysAdminRole: default \"SYS_ADMIN\"\n */\nexport function requirePermissions(\n perms: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const allow = permsSet(auth.permissions);\n const deny = permsSet(auth.denied_permissions);\n\n // deny gana siempre\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {\n denied: p,\n });\n }\n }\n\n const missing = perms.filter((p) => !allow.has(p));\n if (missing.length) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions\", {\n missing,\n mode: \"ALL\",\n });\n }\n\n return next();\n };\n}\n\n/**\n * Requiere AL MENOS 1 permiso de la lista (ANY/OR).\n * Regla: denied_permissions siempre gana.\n */\nexport function requireAnyPermission(\n perms: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const allow = permsSet(auth.permissions);\n const deny = permsSet(auth.denied_permissions);\n\n // deny gana siempre (si alguno requerido está denegado explícitamente)\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {\n denied: p,\n });\n }\n }\n\n const ok = perms.some((p) => allow.has(p));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Permission denied\", {\n required: perms,\n mode: \"ANY\",\n });\n }\n\n return next();\n };\n}\n\n/**\n * Requiere al menos 1 rol (ANY/OR).\n * options:\n * - sysAdminBypass: default true\n * - sysAdminRole: default \"SYS_ADMIN\"\n */\nexport function requireRoles(\n roles: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n // SYS_ADMIN bypass aplica también aquí\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const have = rolesSet(auth);\n if (!roles.some((r) => have.has(r))) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Role not allowed\", {\n required: roles,\n mode: \"ANY\",\n });\n }\n\n return next();\n };\n}\n\n/**\n * Requiere (roles ANY) OR (permissions ANY).\n * deny_permissions siempre gana sobre permissions.\n */\nexport function requireRolesOrAnyPermission(\n roles: string[],\n perms: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const haveRoles = rolesSet(auth);\n const allow = permsSet(auth.permissions);\n const deny = permsSet(auth.denied_permissions);\n\n // deny gana siempre (si cualquiera de los permisos evaluados está denegado explícitamente)\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {\n denied: p,\n });\n }\n }\n\n const okRole = roles.some((r) => haveRoles.has(r));\n const okPerm = perms.some((p) => allow.has(p));\n\n if (!okRole && !okPerm) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Access denied\", {\n roles,\n permissions: perms,\n mode: \"ROLES_OR_PERMS_ANY\",\n });\n }\n\n return next();\n };\n}\n","import fs from \"fs\";\nimport jwt, {JwtPayload} from \"jsonwebtoken\";\n\nfunction readFileIfExists(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\n/**\n * ✅ Keys viven en getmarket-stack:\n * - JWT_PUBLIC_KEY_PATH=/run/secrets/jwtRS256.key.pub (recomendado)\n * - fallback env AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY\n */\nexport function readRs256PublicKey(): string {\n const fromFile = readFileIfExists(process.env.JWT_PUBLIC_KEY_PATH);\n if (fromFile) return fromFile;\n\n const fromEnv = String(process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || \"\")\n .replace(/\\\\n/g, \"\\n\")\n .trim();\n\n if (fromEnv) return fromEnv;\n\n throw new Error(\"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)\");\n}\n\nexport function verifyBackendJwtRS256(raw: string): JwtPayload {\n const publicKey = readRs256PublicKey();\n\n const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || \"getmarket.api\";\n const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || \"getmarket-auth\";\n\n // ✅ SOLO RS256\n return jwt.verify(raw, publicKey, {\n algorithms: [\"RS256\"],\n audience,\n issuer,\n }) as JwtPayload;\n}\n","import type {NextFunction, Response} from \"express\";\nimport {verifyBackendJwtRS256} from \"./jwt\";\nimport type {AuthContext, AuthMiddlewareOptions} from \"./types\";\n\nfunction getBearerToken(req: any): string | null {\n const auth = String(req.headers?.authorization || \"\");\n if (!auth.startsWith(\"Bearer \")) return null;\n const token = auth.slice(7).trim();\n return token.length ? token : null;\n}\n\nfunction normalizeUid(v: any): string | null {\n const s = String(v ?? \"\").trim();\n return s.length ? s : null;\n}\n\n/**\n * ✅ Middleware estándar:\n * - Solo Authorization: Bearer\n * - Solo RS256\n * - Cero legacy\n * - Hidrata vía hook (OBLIGATORIO)\n */\nexport function createAuthMiddleware(opts: AuthMiddlewareOptions) {\n const {subject, allowFirebaseIdToken = false, requireSubject = true, hydrate} = opts;\n\n return async (req: any, res: Response, next: NextFunction) => {\n const token = getBearerToken(req);\n if (!token) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_MISSING_TOKEN\",\n message: \"Missing Authorization Bearer token\",\n });\n }\n\n // Contexto desde parseHeaders (SDK) -> req.context\n const headerCtx = (req as any).context || {};\n const company_uid = normalizeUid(headerCtx.company_uid);\n const branch_uid = normalizeUid(headerCtx.branch_uid);\n\n // 1) RS256 backend JWT\n try {\n const decoded: any = verifyBackendJwtRS256(token);\n\n const baseCtx: AuthContext = {\n tokenType: \"backend\",\n subject,\n company_uid: company_uid ?? undefined,\n branch_uid: branch_uid ?? undefined,\n roles: Array.isArray(decoded?.roles) ? decoded.roles : [],\n permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],\n denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],\n session: {\n jti: decoded?.jti,\n device_id: decoded?.device_id,\n expires_at: decoded?.exp,\n },\n };\n\n // ✅ hydrate obligatorio\n const hydrated = await hydrate({decoded, req, subject, company_uid, branch_uid});\n Object.assign(baseCtx, hydrated);\n\n if (requireSubject) {\n if (subject === \"employee\" && !baseCtx.employee) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMPLOYEE_NOT_FOUND\",\n message: \"Employee not resolved by hydrator\",\n });\n }\n if (subject === \"customer\" && !baseCtx.customer) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_CUSTOMER_NOT_FOUND\",\n message: \"Customer not resolved by hydrator\",\n });\n }\n }\n\n (req as any).auth = baseCtx;\n return next();\n } catch {\n // 2) Firebase opcional\n if (!allowFirebaseIdToken) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n\n try {\n const {default: admin} = await import(\"firebase-admin\");\n const firebaseDecoded = await admin.auth().verifyIdToken(token);\n\n if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMAIL_NOT_VERIFIED\",\n message: \"Email not verified\",\n });\n }\n\n (req as any).auth = {\n tokenType: \"backend\",\n subject,\n firebase: firebaseDecoded,\n company_uid: company_uid ?? undefined,\n branch_uid: branch_uid ?? undefined,\n companies: [],\n roles: [],\n permissions: [],\n denied_permissions: [],\n } satisfies AuthContext;\n\n return next();\n } catch {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n }\n };\n}\n","// packages/sdk/src/auth/authentication.ts\nimport type { NextFunction, Response } from \"express\";\nimport admin from \"firebase-admin\";\nimport jwt, { JwtPayload } from \"jsonwebtoken\";\nimport fs from \"fs\";\n\ntype Subject = \"employee\" | \"customer\";\ntype TokenType = \"backend\";\n\nexport interface AuthContext {\n tokenType: TokenType;\n subject: Subject;\n\n employee?: any;\n customer?: any;\n\n company_uid?: string;\n branch_uid?: string;\n\n company?: any;\n branch?: any;\n companies?: any[];\n\n // ✅ canonical: string[]\n roles?: string[];\n permissions?: string[];\n denied_permissions?: string[];\n\n session?: { jti?: string; device_id?: string; expires_at?: number };\n firebase?: admin.auth.DecodedIdToken;\n\n // ✅ opcional, pero útil para debug / consumers\n employee_uid?: string;\n customer_uid?: string;\n}\n\n/**\n * ✅ ÚNICO estándar:\n * - Authorization: Bearer <token>\n */\nfunction getBearerToken(req: any): string | null {\n const auth = String(req.headers?.authorization || \"\");\n if (!auth.startsWith(\"Bearer \")) return null;\n const token = auth.slice(7).trim();\n return token.length ? token : null;\n}\n\nfunction readPublicKey(): string {\n const publicKeyPath = process.env.JWT_PUBLIC_KEY_PATH;\n const publicKeyEnv = process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || \"\";\n\n if (publicKeyPath) {\n const v = fs.readFileSync(publicKeyPath, \"utf8\").trim();\n if (v) return v;\n }\n\n const envKey = publicKeyEnv.replace(/\\\\n/g, \"\\n\").trim();\n if (envKey) return envKey;\n\n throw new Error(\n \"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)\"\n );\n}\n\nfunction verifyBackendJwtRS256(raw: string): JwtPayload {\n const publicKey = readPublicKey();\n const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || \"getmarket.api\";\n const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || \"getmarket-auth\";\n\n return jwt.verify(raw, publicKey, {\n algorithms: [\"RS256\"],\n audience,\n issuer,\n }) as JwtPayload;\n}\n\nfunction normalizeUid(v: any): string | null {\n const s = String(v ?? \"\").trim();\n return s.length ? s : null;\n}\n\n/**\n * roles/perms pueden venir como:\n * - string[]\n * - {code,name}[]\n */\ntype RoleShape = string | { code?: string; name?: string };\ntype PermShape = string | { code?: string; name?: string };\n\nfunction normalizeCodes(list: any, kind: \"role\" | \"perm\"): string[] {\n if (!Array.isArray(list)) return [];\n const out: string[] = [];\n for (const item of list as (RoleShape | PermShape)[]) {\n if (!item) continue;\n if (typeof item === \"string\") {\n const s = item.trim();\n if (s) out.push(s);\n continue;\n }\n const s = String(item.code || item.name || \"\").trim();\n if (s) out.push(s);\n }\n // uniq\n return Array.from(new Set(out));\n}\n\n/**\n * UID-first extraction:\n * - decoded.employee_uid / customer_uid\n * - decoded.sub = \"emp:<uid>\" / \"cus:<uid>\"\n */\nfunction extractEmployeeUid(decoded: any): string | null {\n const direct = normalizeUid(decoded?.employee_uid);\n if (direct) return direct;\n\n const sub = normalizeUid(decoded?.sub);\n if (!sub) return null;\n\n const m = /^emp:(.+)$/i.exec(sub);\n return m?.[1] ? normalizeUid(m[1]) : null;\n}\n\nfunction extractCustomerUid(decoded: any): string | null {\n const direct = normalizeUid(decoded?.customer_uid);\n if (direct) return direct;\n\n const sub = normalizeUid(decoded?.sub);\n if (!sub) return null;\n\n const m = /^cus:(.+)$/i.exec(sub);\n return m?.[1] ? normalizeUid(m[1]) : null;\n}\n\nfunction deriveCompanyBranch(decoded: any, companyUid: string | null, branchUid: string | null) {\n const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];\n\n const company =\n decoded?.company ??\n (companyUid ? companiesFromToken.find((c: any) => c?.uid === companyUid) : null) ??\n null;\n\n const branch =\n decoded?.branch ??\n (branchUid && company?.branches ? (company.branches || []).find((b: any) => b?.uid === branchUid) : null) ??\n null;\n\n return { companiesFromToken, company, branch };\n}\n\nexport function createAuthMiddleware(opts: { subject: Subject; allowFirebaseIdToken?: boolean }) {\n const { subject, allowFirebaseIdToken = false } = opts;\n\n return async (req: any, res: Response, next: NextFunction) => {\n const token = getBearerToken(req);\n if (!token) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_MISSING_TOKEN\",\n message: \"Missing Authorization Bearer token\",\n });\n }\n\n try {\n const decoded: any = verifyBackendJwtRS256(token);\n\n const headerCtx = (req as any).context || {};\n const companyUid = normalizeUid(headerCtx.company_uid);\n const branchUid = normalizeUid(headerCtx.branch_uid);\n\n const { companiesFromToken, company, branch } = deriveCompanyBranch(decoded, companyUid, branchUid);\n\n const ctx: AuthContext = {\n tokenType: \"backend\",\n subject,\n\n company_uid: companyUid ?? undefined,\n branch_uid: branchUid ?? undefined,\n\n companies: companiesFromToken,\n company,\n branch,\n\n // ✅ canonical string[]\n roles: normalizeCodes(decoded?.roles, \"role\"),\n permissions: normalizeCodes(decoded?.permissions, \"perm\"),\n denied_permissions: normalizeCodes(decoded?.denied_permissions, \"perm\"),\n\n session: {\n jti: decoded?.jti,\n device_id: decoded?.device_id,\n expires_at: decoded?.exp,\n },\n };\n\n if (subject === \"employee\") {\n const employeeUid = extractEmployeeUid(decoded);\n\n // Preferir embebido, si existe\n const employeeEmbedded = decoded?.employee ?? decoded?.user ?? null;\n\n // ✅ UID-first: si no viene embebido, basta con stub {uid}\n if (employeeEmbedded) {\n ctx.employee = employeeUid\n ? { ...employeeEmbedded, uid: employeeEmbedded?.uid ?? employeeUid }\n : employeeEmbedded;\n } else if (employeeUid) {\n ctx.employee = { uid: employeeUid };\n } else {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMPLOYEE_NOT_FOUND\",\n message: \"Employee not found in token (expected employee_uid or sub=emp:<uid>)\",\n });\n }\n\n ctx.employee_uid = employeeUid ?? undefined;\n } else {\n const customerUid = extractCustomerUid(decoded);\n const customerEmbedded = decoded?.customer ?? null;\n\n if (customerEmbedded) {\n ctx.customer = customerUid\n ? { ...customerEmbedded, uid: customerEmbedded?.uid ?? customerUid }\n : customerEmbedded;\n } else if (customerUid) {\n ctx.customer = { uid: customerUid };\n } else {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_CUSTOMER_NOT_FOUND\",\n message: \"Customer not found in token (expected customer_uid or sub=cus:<uid>)\",\n });\n }\n\n ctx.customer_uid = customerUid ?? undefined;\n }\n\n req.auth = ctx;\n return next();\n } catch {\n if (!allowFirebaseIdToken) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n\n try {\n const firebaseDecoded = await admin.auth().verifyIdToken(token);\n\n if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMAIL_NOT_VERIFIED\",\n message: \"Email not verified\",\n });\n }\n\n const headerCtx = (req as any).context || {};\n const companyUid = normalizeUid(headerCtx.company_uid);\n const branchUid = normalizeUid(headerCtx.branch_uid);\n\n req.auth = {\n tokenType: \"backend\",\n subject,\n firebase: firebaseDecoded,\n company_uid: companyUid ?? undefined,\n branch_uid: branchUid ?? undefined,\n companies: [],\n roles: [],\n permissions: [],\n denied_permissions: [],\n };\n\n return next();\n } catch {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n }\n };\n}\n\nexport const authEmployeeRequired = createAuthMiddleware({ subject: \"employee\", allowFirebaseIdToken: false });\nexport const authCustomerRequired = createAuthMiddleware({ subject: \"customer\", allowFirebaseIdToken: false });\nexport const authEmployeeAllowFirebase = createAuthMiddleware({ subject: \"employee\", allowFirebaseIdToken: true });\nexport const authCustomerAllowFirebase = createAuthMiddleware({ subject: \"customer\", allowFirebaseIdToken: true });\n","// packages/sdk/src/middlewares/guards.ts\nimport type {Request, Response, NextFunction, RequestHandler} from \"express\";\nimport parseHeaders from \"./parseHeaders\";\nimport {authEmployeeRequired} from \"../auth\";\nimport {sendError} from \"./respond\";\n\ntype RoleShape = string | { code?: string; name?: string };\ntype PermShape = string | { code?: string; name?: string };\n\nfunction normalizeRole(r: RoleShape): string | null {\n if (!r) return null;\n if (typeof r === \"string\") return r;\n return r.code || r.name || null;\n}\n\nfunction normalizePerm(p: PermShape): string | null {\n if (!p) return null;\n if (typeof p === \"string\") return p;\n return p.code || p.name || null;\n}\n\nfunction isSysAdmin(roles: RoleShape[] | undefined): boolean {\n if (!Array.isArray(roles)) return false;\n return roles.some((r) => normalizeRole(r) === \"SYS_ADMIN\");\n}\n\nfunction getAuth(req: Request) {\n return ((req as any).auth ?? {}) as {\n roles?: RoleShape[];\n permissions?: PermShape[];\n denied_permissions?: PermShape[];\n };\n}\n\nfunction permissionSets(auth: ReturnType<typeof getAuth>) {\n const allow = new Set<string>((auth.permissions ?? []).map(normalizePerm).filter(Boolean) as string[]);\n const deny = new Set<string>((auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean) as string[]);\n return {allow, deny};\n}\n\nfunction roleSet(auth: ReturnType<typeof getAuth>) {\n return new Set<string>((auth.roles ?? []).map(normalizeRole).filter(Boolean) as string[]);\n}\n\n/**\n * ✅ SysAdmin bypass OR (ANY) permissions\n * - Si tiene alguno de los permisos => OK\n * - denied_permissions gana siempre\n */\nexport function allowSysAdminOrAnyPermission(...perms: string[]): RequestHandler[] {\n const required = (perms ?? []).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const {allow, deny} = permissionSets(auth);\n\n for (const p of required) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {denied: p});\n }\n }\n\n const ok = required.some((p) => allow.has(p));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions (ANY)\", {required});\n }\n\n return next();\n },\n ];\n}\n\n/**\n * ✅ SysAdmin bypass OR (ALL) permissions (AND)\n */\nexport function allowSysAdminOrPermissionsAll(...perms: string[]): RequestHandler[] {\n const required = (perms ?? []).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const {allow, deny} = permissionSets(auth);\n\n for (const p of required) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {denied: p});\n }\n }\n\n const missing = required.filter((p) => !allow.has(p));\n if (missing.length) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions (ALL)\", {required, missing});\n }\n\n return next();\n },\n ];\n}\n\n/**\n * ✅ SysAdmin bypass OR roles (ANY)\n */\nexport function allowSysAdminOrRoles(...roles: string[]): RequestHandler[] {\n const required = (roles ?? []).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const have = roleSet(auth);\n\n const ok = required.some((r) => have.has(r));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Role not allowed\", {required});\n }\n\n return next();\n },\n ];\n}\n\n/**\n * ✅ SYS_ADMIN bypass OR (ANY) roles OR (ANY) permissions\n * - denied_permissions siempre gana\n */\nexport function allowSysAdminOrRolesOrAnyPermission(\n roles: string | string[],\n permissions: string | string[]\n): RequestHandler[] {\n const requiredRoles = (Array.isArray(roles) ? roles : [roles]).filter(Boolean);\n const requiredPerms = (Array.isArray(permissions) ? permissions : [permissions]).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const {allow, deny} = permissionSets(auth);\n for (const p of requiredPerms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied: ${p}`, {permission: p});\n }\n }\n\n const haveRoles = roleSet(auth);\n if (requiredRoles.some((r) => haveRoles.has(r))) return next();\n\n if (requiredPerms.some((p) => allow.has(p))) return next();\n\n return sendError(req, res, 403, \"FORBIDDEN\", \"Permission denied\", {\n roles: requiredRoles,\n permissions: requiredPerms,\n mode: \"ROLES_OR_ANY_PERMISSION\",\n });\n },\n ];\n}\n\n/**\n * ✅ Helper específico Auth:\n * Rol AUTH_ADMIN o permiso fino (y SYS_ADMIN bypass)\n */\nexport function allowAuthAdminOrPerm(permission: string): RequestHandler[] {\n return allowSysAdminOrRolesOrAnyPermission([\"AUTH_ADMIN\"], [permission]);\n}\n"],"mappings":"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","names":["fs","admin","jwt","fs","getBearerToken","verifyBackendJwtRS256","normalizeUid","s","createAuthMiddleware","isSysAdmin","getAuth"]}
package/dist/index.cjs CHANGED
@@ -939,6 +939,37 @@ function normalizeUid2(v) {
939
939
  const s = String(v ?? "").trim();
940
940
  return s.length ? s : null;
941
941
  }
942
+ function normalizeCodes(list, kind) {
943
+ if (!Array.isArray(list)) return [];
944
+ const out = [];
945
+ for (const item of list) {
946
+ if (!item) continue;
947
+ if (typeof item === "string") {
948
+ const s2 = item.trim();
949
+ if (s2) out.push(s2);
950
+ continue;
951
+ }
952
+ const s = String(item.code || item.name || "").trim();
953
+ if (s) out.push(s);
954
+ }
955
+ return Array.from(new Set(out));
956
+ }
957
+ function extractEmployeeUid(decoded) {
958
+ const direct = normalizeUid2(decoded?.employee_uid);
959
+ if (direct) return direct;
960
+ const sub = normalizeUid2(decoded?.sub);
961
+ if (!sub) return null;
962
+ const m = /^emp:(.+)$/i.exec(sub);
963
+ return m?.[1] ? normalizeUid2(m[1]) : null;
964
+ }
965
+ function extractCustomerUid(decoded) {
966
+ const direct = normalizeUid2(decoded?.customer_uid);
967
+ if (direct) return direct;
968
+ const sub = normalizeUid2(decoded?.sub);
969
+ if (!sub) return null;
970
+ const m = /^cus:(.+)$/i.exec(sub);
971
+ return m?.[1] ? normalizeUid2(m[1]) : null;
972
+ }
942
973
  function deriveCompanyBranch(decoded, companyUid, branchUid) {
943
974
  const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];
944
975
  const company = decoded?.company ?? (companyUid ? companiesFromToken.find((c) => c?.uid === companyUid) : null) ?? null;
@@ -970,9 +1001,10 @@ function createAuthMiddleware2(opts) {
970
1001
  companies: companiesFromToken,
971
1002
  company,
972
1003
  branch,
973
- roles: Array.isArray(decoded?.roles) ? decoded.roles : [],
974
- permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],
975
- denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],
1004
+ // canonical string[]
1005
+ roles: normalizeCodes(decoded?.roles, "role"),
1006
+ permissions: normalizeCodes(decoded?.permissions, "perm"),
1007
+ denied_permissions: normalizeCodes(decoded?.denied_permissions, "perm"),
976
1008
  session: {
977
1009
  jti: decoded?.jti,
978
1010
  device_id: decoded?.device_id,
@@ -980,25 +1012,35 @@ function createAuthMiddleware2(opts) {
980
1012
  }
981
1013
  };
982
1014
  if (subject === "employee") {
983
- const employee = decoded?.employee ?? decoded?.user ?? null;
984
- if (!employee) {
1015
+ const employeeUid = extractEmployeeUid(decoded);
1016
+ const employeeEmbedded = decoded?.employee ?? decoded?.user ?? null;
1017
+ if (employeeEmbedded) {
1018
+ ctx.employee = employeeUid ? { ...employeeEmbedded, uid: employeeEmbedded?.uid ?? employeeUid } : employeeEmbedded;
1019
+ } else if (employeeUid) {
1020
+ ctx.employee = { uid: employeeUid };
1021
+ } else {
985
1022
  return res.status(401).json({
986
1023
  ok: false,
987
1024
  code: "AUTH_EMPLOYEE_NOT_FOUND",
988
- message: "Employee not found in token"
1025
+ message: "Employee not found in token (expected employee_uid or sub=emp:<uid>)"
989
1026
  });
990
1027
  }
991
- ctx.employee = employee;
1028
+ ctx.employee_uid = employeeUid ?? void 0;
992
1029
  } else {
993
- const customer = decoded?.customer ?? null;
994
- if (!customer) {
1030
+ const customerUid = extractCustomerUid(decoded);
1031
+ const customerEmbedded = decoded?.customer ?? null;
1032
+ if (customerEmbedded) {
1033
+ ctx.customer = customerUid ? { ...customerEmbedded, uid: customerEmbedded?.uid ?? customerUid } : customerEmbedded;
1034
+ } else if (customerUid) {
1035
+ ctx.customer = { uid: customerUid };
1036
+ } else {
995
1037
  return res.status(401).json({
996
1038
  ok: false,
997
1039
  code: "AUTH_CUSTOMER_NOT_FOUND",
998
- message: "Customer not found in token"
1040
+ message: "Customer not found in token (expected customer_uid or sub=cus:<uid>)"
999
1041
  });
1000
1042
  }
1001
- ctx.customer = customer;
1043
+ ctx.customer_uid = customerUid ?? void 0;
1002
1044
  }
1003
1045
  req.auth = ctx;
1004
1046
  return next();
@@ -1068,14 +1110,13 @@ function getAuth2(req) {
1068
1110
  return req.auth ?? {};
1069
1111
  }
1070
1112
  function permissionSets(auth) {
1071
- const allow = new Set(
1072
- (auth.permissions ?? []).map(normalizePerm).filter(Boolean)
1073
- );
1074
- const deny = new Set(
1075
- (auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean)
1076
- );
1113
+ const allow = new Set((auth.permissions ?? []).map(normalizePerm).filter(Boolean));
1114
+ const deny = new Set((auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean));
1077
1115
  return { allow, deny };
1078
1116
  }
1117
+ function roleSet(auth) {
1118
+ return new Set((auth.roles ?? []).map(normalizeRole).filter(Boolean));
1119
+ }
1079
1120
  function allowSysAdminOrAnyPermission(...perms) {
1080
1121
  const required = (perms ?? []).filter(Boolean);
1081
1122
  return [
@@ -1087,16 +1128,12 @@ function allowSysAdminOrAnyPermission(...perms) {
1087
1128
  const { allow, deny } = permissionSets(auth);
1088
1129
  for (const p of required) {
1089
1130
  if (deny.has(p)) {
1090
- return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
1091
- denied: p
1092
- });
1131
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
1093
1132
  }
1094
1133
  }
1095
1134
  const ok = required.some((p) => allow.has(p));
1096
1135
  if (!ok) {
1097
- return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", {
1098
- required
1099
- });
1136
+ return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", { required });
1100
1137
  }
1101
1138
  return next();
1102
1139
  }
@@ -1113,17 +1150,12 @@ function allowSysAdminOrPermissionsAll(...perms) {
1113
1150
  const { allow, deny } = permissionSets(auth);
1114
1151
  for (const p of required) {
1115
1152
  if (deny.has(p)) {
1116
- return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
1117
- denied: p
1118
- });
1153
+ return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
1119
1154
  }
1120
1155
  }
1121
1156
  const missing = required.filter((p) => !allow.has(p));
1122
1157
  if (missing.length) {
1123
- return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", {
1124
- required,
1125
- missing
1126
- });
1158
+ return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", { required, missing });
1127
1159
  }
1128
1160
  return next();
1129
1161
  }
@@ -1137,55 +1169,33 @@ function allowSysAdminOrRoles(...roles) {
1137
1169
  (req, res, next) => {
1138
1170
  const auth = getAuth2(req);
1139
1171
  if (isSysAdmin2(auth.roles)) return next();
1140
- const have = new Set(
1141
- (auth.roles ?? []).map(normalizeRole).filter(Boolean)
1142
- );
1172
+ const have = roleSet(auth);
1143
1173
  const ok = required.some((r) => have.has(r));
1144
1174
  if (!ok) {
1145
- return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", {
1146
- required
1147
- });
1175
+ return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", { required });
1148
1176
  }
1149
1177
  return next();
1150
1178
  }
1151
1179
  ];
1152
1180
  }
1153
-
1154
- // src/middlewares/accessControl.ts
1155
- function normalizeList(v) {
1156
- return Array.isArray(v) ? v : [v];
1157
- }
1158
- function roleCode(r) {
1159
- if (!r) return null;
1160
- return typeof r === "string" ? r : r.code || r.name || null;
1161
- }
1162
- function permCode(p) {
1163
- if (!p) return null;
1164
- return typeof p === "string" ? p : p.code || p.name || null;
1165
- }
1166
- function isSysAdmin3(roles) {
1167
- if (!Array.isArray(roles)) return false;
1168
- return roles.map(roleCode).filter(Boolean).includes("SYS_ADMIN");
1169
- }
1170
1181
  function allowSysAdminOrRolesOrAnyPermission(roles, permissions) {
1171
- const requiredRoles = normalizeList(roles).filter(Boolean);
1172
- const requiredPerms = normalizeList(permissions).filter(Boolean);
1182
+ const requiredRoles = (Array.isArray(roles) ? roles : [roles]).filter(Boolean);
1183
+ const requiredPerms = (Array.isArray(permissions) ? permissions : [permissions]).filter(Boolean);
1173
1184
  return [
1174
1185
  parseHeaders,
1175
1186
  authEmployeeRequired,
1176
1187
  (req, res, next) => {
1177
- const auth = req.auth || {};
1178
- if (isSysAdmin3(auth.roles)) return next();
1179
- const deny = new Set((auth.denied_permissions || []).map(permCode).filter(Boolean));
1188
+ const auth = getAuth2(req);
1189
+ if (isSysAdmin2(auth.roles)) return next();
1190
+ const { allow, deny } = permissionSets(auth);
1180
1191
  for (const p of requiredPerms) {
1181
1192
  if (deny.has(p)) {
1182
1193
  return sendError(req, res, 403, "FORBIDDEN", `Denied: ${p}`, { permission: p });
1183
1194
  }
1184
1195
  }
1185
- const haveRoles = new Set((auth.roles || []).map(roleCode).filter(Boolean));
1196
+ const haveRoles = roleSet(auth);
1186
1197
  if (requiredRoles.some((r) => haveRoles.has(r))) return next();
1187
- const havePerms = new Set((auth.permissions || []).map(permCode).filter(Boolean));
1188
- if (requiredPerms.some((p) => havePerms.has(p))) return next();
1198
+ if (requiredPerms.some((p) => allow.has(p))) return next();
1189
1199
  return sendError(req, res, 403, "FORBIDDEN", "Permission denied", {
1190
1200
  roles: requiredRoles,
1191
1201
  permissions: requiredPerms,