@infuro/cms-core 1.0.31 → 1.0.34

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 (41) hide show
  1. package/README.md +12 -8
  2. package/dist/admin.cjs +1907 -1144
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +7 -2
  5. package/dist/admin.d.ts +7 -2
  6. package/dist/admin.js +1955 -1191
  7. package/dist/admin.js.map +1 -1
  8. package/dist/api.cjs +2704 -914
  9. package/dist/api.cjs.map +1 -1
  10. package/dist/api.d.cts +1 -1
  11. package/dist/api.d.ts +1 -1
  12. package/dist/api.js +2664 -875
  13. package/dist/api.js.map +1 -1
  14. package/dist/auth.cjs +251 -23
  15. package/dist/auth.cjs.map +1 -1
  16. package/dist/auth.d.cts +53 -22
  17. package/dist/auth.d.ts +53 -22
  18. package/dist/auth.js +240 -23
  19. package/dist/auth.js.map +1 -1
  20. package/dist/cli.cjs +42 -2
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +42 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/{index-BcMRGNjS.d.cts → index-Bf5GO8fu.d.cts} +4 -3
  25. package/dist/{index-Bda8D1Rm.d.ts → index-DOiJuMQA.d.ts} +4 -3
  26. package/dist/index.cjs +3408 -1284
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +121 -35
  29. package/dist/index.d.ts +121 -35
  30. package/dist/index.js +3334 -1226
  31. package/dist/index.js.map +1 -1
  32. package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
  33. package/dist/migrations/1778660000004-CreateCustomerAndCustomerContacts.ts +99 -0
  34. package/dist/migrations/1778660000005-AddCustomerIdToVendorCustomers.ts +39 -0
  35. package/dist/migrations/1778660000006-UpdateVendorCustomersContactNullable.ts +36 -0
  36. package/dist/migrations/1778660000007-VendorOwnerCustomerContactsPermission.ts +39 -0
  37. package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
  38. package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
  39. package/dist/migrations/1779300000000-VendorOwnerContactsPermission.ts +39 -0
  40. package/dist/migrations/1779400000000-AddCustomerContactIdToOrders.ts +33 -0
  41. package/package.json +5 -3
package/dist/auth.js CHANGED
@@ -72,6 +72,30 @@ var init_permission_entities = __esm({
72
72
  }
73
73
  });
74
74
 
75
+ // src/auth/role-helpers.ts
76
+ function isSuperAdmin(user) {
77
+ if (!user) return false;
78
+ if (user.groupId === SUPER_ADMIN_GROUP_ID) return true;
79
+ if (user.isRBACAdmin === true) return true;
80
+ return isSuperAdminGroupName(user.groupName);
81
+ }
82
+ function isVendorAdmin(user) {
83
+ if (!user?.email || isSuperAdmin(user)) return false;
84
+ if (user.groupId === VENDOR_ADMIN_GROUP_ID) return true;
85
+ if ((user.vendorIds?.length ?? 0) > 0) return true;
86
+ return isVendorGroupName(user.groupName);
87
+ }
88
+ var SUPER_ADMIN_GROUP_ID, VENDOR_ADMIN_GROUP_ID;
89
+ var init_role_helpers = __esm({
90
+ "src/auth/role-helpers.ts"() {
91
+ "use strict";
92
+ init_permission_entities();
93
+ init_vendor_scope();
94
+ SUPER_ADMIN_GROUP_ID = 1;
95
+ VENDOR_ADMIN_GROUP_ID = 5;
96
+ }
97
+ });
98
+
75
99
  // src/auth/vendor-scope.ts
76
100
  function isVendorGroupName(name) {
77
101
  if (!name?.trim()) return false;
@@ -80,12 +104,12 @@ function isVendorGroupName(name) {
80
104
  }
81
105
  function isPlatformAdministrator(user) {
82
106
  if (!user?.email) return false;
83
- return !!(user.isRBACAdmin || isSuperAdminGroupName(user.groupName));
107
+ return isSuperAdmin(user);
84
108
  }
85
109
  function isVendorPortalUser(user) {
86
110
  if (user?.isVendorPortal === true) return true;
87
111
  if (!user?.email || isPlatformAdministrator(user)) return false;
88
- if ((user.vendorIds?.length ?? 0) > 0) return true;
112
+ if (isVendorAdmin(user)) return true;
89
113
  return isVendorGroupName(user.groupName);
90
114
  }
91
115
  function isVendorStaff(user) {
@@ -127,7 +151,7 @@ var VENDOR_SCOPED_STORE_ENTITIES, VENDOR_STORE_RBAC_ENTITIES, VENDOR_OWNER_GROUP
127
151
  var init_vendor_scope = __esm({
128
152
  "src/auth/vendor-scope.ts"() {
129
153
  "use strict";
130
- init_permission_entities();
154
+ init_role_helpers();
131
155
  VENDOR_SCOPED_STORE_ENTITIES = /* @__PURE__ */ new Set([
132
156
  "products",
133
157
  "collections",
@@ -455,6 +479,7 @@ function createAuthHelpersFromGetSession(getSession, NextResponse) {
455
479
 
456
480
  // src/auth/index.ts
457
481
  init_rbac_debug();
482
+ init_role_helpers();
458
483
  init_vendor_scope();
459
484
  init_permission_entities();
460
485
 
@@ -491,6 +516,59 @@ async function seedAdministratorPermissions(dataSource, entityMap) {
491
516
  }
492
517
  }
493
518
 
519
+ // src/auth/middleware.ts
520
+ import { getToken } from "next-auth/jwt";
521
+
522
+ // src/auth/auth-debug.ts
523
+ var LOG_PREFIX2 = "[cms-auth]";
524
+ function isAuthDebugEnabled() {
525
+ const v = process.env.CMS_AUTH_DEBUG?.trim().toLowerCase();
526
+ if (v === "1" || v === "true" || v === "yes") return true;
527
+ if (v === "0" || v === "false" || v === "no") return false;
528
+ return process.env.NODE_ENV === "development";
529
+ }
530
+ function isAuthDebugClientEnabled() {
531
+ if (typeof window === "undefined") return false;
532
+ const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
533
+ if (v === "1" || v === "true" || v === "yes") return true;
534
+ if (v === "0" || v === "false" || v === "no") return false;
535
+ return process.env.NODE_ENV === "development";
536
+ }
537
+ function logAuth(message, data) {
538
+ if (!isAuthDebugEnabled()) return;
539
+ if (data) console.info(LOG_PREFIX2, message, data);
540
+ else console.info(LOG_PREFIX2, message);
541
+ }
542
+ function logAuthClient(message, data) {
543
+ if (!isAuthDebugClientEnabled()) return;
544
+ if (data) console.info(LOG_PREFIX2, message, data);
545
+ else console.info(LOG_PREFIX2, message);
546
+ }
547
+ function summarizeSessionUserForLog(user) {
548
+ if (!user || typeof user !== "object") return { present: false };
549
+ const u = user;
550
+ return {
551
+ present: true,
552
+ email: u.email ?? null,
553
+ id: u.id ?? null,
554
+ adminAccess: u.adminAccess ?? null,
555
+ isRBACAdmin: u.isRBACAdmin ?? null,
556
+ isVendorPortal: u.isVendorPortal ?? null,
557
+ groupName: u.groupName ?? null
558
+ };
559
+ }
560
+ function nextAuthCookieDebugInfo() {
561
+ const nextAuthUrl = process.env.NEXTAUTH_URL ?? "(unset)";
562
+ const isHttps = nextAuthUrl.startsWith("https");
563
+ return {
564
+ nextAuthUrl,
565
+ hasSecret: Boolean(process.env.NEXTAUTH_SECRET),
566
+ cookieName: isHttps ? "__Secure-next-auth.session-token" : "next-auth.session-token",
567
+ cookieSecure: isHttps,
568
+ nodeEnv: process.env.NODE_ENV ?? "(unset)"
569
+ };
570
+ }
571
+
494
572
  // src/auth/middleware.ts
495
573
  var defaultPublicApiMethods = {
496
574
  "/api/contacts": ["POST"],
@@ -503,8 +581,21 @@ var defaultPublicApiMethods = {
503
581
  "/api/users/set-password": ["POST"],
504
582
  "/api/users/invite": ["POST"]
505
583
  };
506
- function defaultGetSessionToken(request) {
507
- return request.cookies.get("__Secure-next-auth.session-token")?.value ?? request.cookies.get("next-auth.session-token")?.value;
584
+ function legacyGetSessionToken(request) {
585
+ const secure = request.cookies.get("__Secure-next-auth.session-token")?.value;
586
+ const regular = request.cookies.get("next-auth.session-token")?.value;
587
+ return secure ?? regular;
588
+ }
589
+ function sessionCookiePresence(request) {
590
+ const secure = request.cookies.get("__Secure-next-auth.session-token")?.value;
591
+ const regular = request.cookies.get("next-auth.session-token")?.value;
592
+ const hasChunked = Boolean(request.cookies.get("next-auth.session-token.0")?.value) || Boolean(request.cookies.get("__Secure-next-auth.session-token.0")?.value);
593
+ return {
594
+ hasSecureToken: Boolean(secure),
595
+ hasRegularToken: Boolean(regular),
596
+ hasChunkedToken: hasChunked,
597
+ resolved: Boolean(secure ?? regular)
598
+ };
508
599
  }
509
600
  function isPublicMethod2(pathname, method, publicApiMethods) {
510
601
  for (const [endpoint, methods] of Object.entries(publicApiMethods)) {
@@ -512,31 +603,59 @@ function isPublicMethod2(pathname, method, publicApiMethods) {
512
603
  }
513
604
  return false;
514
605
  }
606
+ async function hasValidSession(request, secret, legacyGetToken) {
607
+ if (request.req) {
608
+ const token = await getToken({ req: request.req, secret });
609
+ return token != null;
610
+ }
611
+ return Boolean(legacyGetToken(request));
612
+ }
515
613
  function createCmsMiddleware(config = {}) {
516
614
  const {
517
615
  publicAdminPaths = ["/admin/signin", "/admin/forgot-password", "/admin/reset-password", "/admin/invite"],
518
616
  publicApiMethods = defaultPublicApiMethods,
519
617
  signInPath = "/admin/signin",
520
- getSessionToken = defaultGetSessionToken
618
+ getSessionToken = legacyGetSessionToken,
619
+ secret = process.env.NEXTAUTH_SECRET
521
620
  } = config;
522
- return function cmsMiddleware(request) {
621
+ return async function cmsMiddleware(request) {
523
622
  const pathname = request.nextUrl.pathname;
524
623
  const method = request.method;
525
624
  if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + "/"))) {
526
625
  return { type: "next" };
527
626
  }
528
627
  if (pathname.startsWith("/admin")) {
529
- const token = getSessionToken(request);
530
- if (!token) {
628
+ const authenticated = await hasValidSession(request, secret, getSessionToken);
629
+ const cookies = sessionCookiePresence(request);
630
+ if (!authenticated) {
631
+ logAuth("middleware: admin redirect to signin (no session)", {
632
+ pathname,
633
+ method,
634
+ usesGetToken: Boolean(request.req),
635
+ ...cookies,
636
+ expectedCookieName: process.env.NEXTAUTH_URL?.startsWith("https") ? "__Secure-next-auth.session-token" : "next-auth.session-token"
637
+ });
531
638
  return { type: "redirect", url: new URL(signInPath, request.url).toString() };
532
639
  }
640
+ logAuth("middleware: admin allowed", {
641
+ pathname,
642
+ method,
643
+ usesGetToken: Boolean(request.req),
644
+ ...cookies
645
+ });
533
646
  }
534
647
  if (pathname.startsWith("/api")) {
535
648
  if (isPublicMethod2(pathname, method, publicApiMethods)) {
536
649
  return { type: "next" };
537
650
  }
538
- const token = getSessionToken(request);
539
- if (!token) {
651
+ const authenticated = await hasValidSession(request, secret, getSessionToken);
652
+ if (!authenticated) {
653
+ logAuth("middleware: api 401 (no session)", {
654
+ pathname,
655
+ method,
656
+ usesGetToken: Boolean(request.req),
657
+ ...sessionCookiePresence(request)
658
+ });
540
659
  return { type: "json", status: 401, body: { error: "Unauthorized" } };
541
660
  }
542
661
  }
@@ -546,12 +665,17 @@ function createCmsMiddleware(config = {}) {
546
665
 
547
666
  // src/auth/nextauth-options.ts
548
667
  init_permission_entities();
668
+ init_role_helpers();
549
669
  init_vendor_scope();
550
670
  import _CredentialsProvider from "next-auth/providers/credentials";
551
671
  var CredentialsProvider = _CredentialsProvider.default ?? _CredentialsProvider;
552
672
  function sessionUserFromNextAuthUser(user) {
553
673
  const g = user.group;
554
- const isRBACAdmin = isSuperAdminGroupName(g?.name);
674
+ const isRBACAdmin = isSuperAdmin({
675
+ groupId: user.groupId ?? void 0,
676
+ groupName: g?.name,
677
+ isRBACAdmin: false
678
+ });
555
679
  const entityPerms = permissionRowsToRecord(g?.permissions);
556
680
  const rawAdminAccess = user.adminAccess;
557
681
  const adminAccess = rawAdminAccess === true ? true : rawAdminAccess === false ? false : void 0;
@@ -580,6 +704,26 @@ function sessionUserFromNextAuthUser(user) {
580
704
  isVendorOwner: isVendorOwner2
581
705
  };
582
706
  }
707
+ function isCustomerGroupUser(user) {
708
+ return user.group?.name?.toLocaleLowerCase().trim() === "customer";
709
+ }
710
+ function callbackUrlTargetsAdmin(callbackUrl) {
711
+ const raw = callbackUrl.trim();
712
+ if (!raw) return false;
713
+ if (raw.startsWith("/admin")) return true;
714
+ try {
715
+ const path = raw.startsWith("http") ? new URL(raw).pathname : raw.split("?")[0] ?? raw;
716
+ return path.startsWith("/admin");
717
+ } catch {
718
+ return raw.includes("/admin");
719
+ }
720
+ }
721
+ function permitsCustomerLogin(allowCustomerLogin, credentials) {
722
+ if (allowCustomerLogin === true) return true;
723
+ if (allowCustomerLogin === false) return false;
724
+ const callbackUrl = typeof credentials?.callbackUrl === "string" ? credentials.callbackUrl : "";
725
+ return !callbackUrlTargetsAdmin(callbackUrl);
726
+ }
583
727
  function getNextAuthOptions(config) {
584
728
  const {
585
729
  getUserByEmail,
@@ -589,8 +733,10 @@ function getNextAuthOptions(config) {
589
733
  extend,
590
734
  enablePasswordLogin = true,
591
735
  enableOtpLogin = false,
592
- authorizeOtp
736
+ authorizeOtp,
737
+ allowCustomerLogin
593
738
  } = config;
739
+ logAuth("getNextAuthOptions init", nextAuthCookieDebugInfo());
594
740
  const providers = [];
595
741
  if (enablePasswordLogin) {
596
742
  providers.push(
@@ -601,15 +747,53 @@ function getNextAuthOptions(config) {
601
747
  password: { label: "Password", type: "password" }
602
748
  },
603
749
  async authorize(credentials) {
604
- if (!credentials?.email || !credentials?.password) return null;
750
+ const creds = credentials;
751
+ const email = creds?.email?.trim() ?? "";
752
+ if (!email || !creds?.password) {
753
+ logAuth("authorize(credentials) rejected", { reason: "missing_email_or_password" });
754
+ return null;
755
+ }
605
756
  try {
606
- const user = await getUserByEmail(credentials.email);
607
- if (!user || user.blocked || user.deleted || !user.password) return null;
608
- const valid = await comparePassword(credentials.password, user.password);
609
- if (!valid) return null;
610
- return sessionUserFromNextAuthUser(user);
757
+ const user = await getUserByEmail(email);
758
+ if (!user) {
759
+ logAuth("authorize(credentials) rejected", { reason: "user_not_found", email });
760
+ return null;
761
+ }
762
+ if (user.blocked) {
763
+ logAuth("authorize(credentials) rejected", { reason: "blocked", email, userId: user.id });
764
+ return null;
765
+ }
766
+ if (user.deleted) {
767
+ logAuth("authorize(credentials) rejected", { reason: "deleted", email, userId: user.id });
768
+ return null;
769
+ }
770
+ if (!user.password) {
771
+ logAuth("authorize(credentials) rejected", { reason: "no_password", email, userId: user.id });
772
+ return null;
773
+ }
774
+ const valid = await comparePassword(creds.password, user.password);
775
+ if (!valid) {
776
+ logAuth("authorize(credentials) rejected", { reason: "invalid_password", email, userId: user.id });
777
+ return null;
778
+ }
779
+ if (isCustomerGroupUser(user) && !permitsCustomerLogin(allowCustomerLogin, creds)) {
780
+ logAuth("authorize(credentials) rejected", {
781
+ reason: "customer_group",
782
+ email,
783
+ userId: user.id,
784
+ callbackUrl: creds?.callbackUrl ?? null
785
+ });
786
+ return null;
787
+ }
788
+ const sessionUser = sessionUserFromNextAuthUser(user);
789
+ logAuth("authorize(credentials) ok", summarizeSessionUserForLog(sessionUser));
790
+ return sessionUser;
611
791
  } catch (err) {
612
792
  console.error("[cms-auth] authorize error (credentials):", err instanceof Error ? err.message : err);
793
+ logAuth("authorize(credentials) error", {
794
+ email,
795
+ message: err instanceof Error ? err.message : String(err)
796
+ });
613
797
  return null;
614
798
  }
615
799
  }
@@ -627,13 +811,22 @@ function getNextAuthOptions(config) {
627
811
  channel: { label: "Channel", type: "text" }
628
812
  },
629
813
  async authorize(credentials) {
630
- const identifier = typeof credentials?.identifier === "string" ? credentials.identifier.trim() : "";
631
- const code = typeof credentials?.code === "string" ? credentials.code.trim() : "";
632
- const ch = credentials?.channel === "sms" ? "sms" : "email";
814
+ const creds = credentials;
815
+ const identifier = typeof creds?.identifier === "string" ? creds.identifier.trim() : "";
816
+ const code = typeof creds?.code === "string" ? creds.code.trim() : "";
817
+ const ch = creds?.channel === "sms" ? "sms" : "email";
633
818
  if (!identifier || !code) return null;
634
819
  try {
635
820
  const user = await authorizeOtp({ identifier, channel: ch, code });
636
821
  if (!user || user.blocked || user.deleted) return null;
822
+ if (isCustomerGroupUser(user) && !permitsCustomerLogin(allowCustomerLogin, creds)) {
823
+ logAuth("authorize(otp) rejected", {
824
+ reason: "customer_group",
825
+ identifier,
826
+ callbackUrl: creds?.callbackUrl ?? null
827
+ });
828
+ return null;
829
+ }
637
830
  return sessionUserFromNextAuthUser(user);
638
831
  } catch (err) {
639
832
  console.error("[cms-auth] authorize error (otp):", err instanceof Error ? err.message : err);
@@ -662,6 +855,10 @@ function getNextAuthOptions(config) {
662
855
  callbacks: {
663
856
  async jwt({ token, user, trigger, session }) {
664
857
  if (user) {
858
+ logAuth("jwt callback: new sign-in", {
859
+ trigger,
860
+ user: summarizeSessionUserForLog(user)
861
+ });
665
862
  const u = user;
666
863
  token.id = u.id;
667
864
  token.groupId = u.groupId;
@@ -676,6 +873,7 @@ function getNextAuthOptions(config) {
676
873
  token.isVendorOwner = u.isVendorOwner;
677
874
  }
678
875
  if (trigger === "update" && session && typeof session === "object") {
876
+ logAuth("jwt callback: session update", { trigger });
679
877
  const s = session;
680
878
  const t = token;
681
879
  if (typeof s.name === "string") t.name = s.name;
@@ -685,8 +883,13 @@ function getNextAuthOptions(config) {
685
883
  return token;
686
884
  },
687
885
  async session({ session, token }) {
886
+ const t = token;
887
+ logAuth("session callback", {
888
+ tokenHasId: t.id != null,
889
+ tokenEmail: typeof t.email === "string" ? t.email : null,
890
+ sessionUser: summarizeSessionUserForLog(session.user)
891
+ });
688
892
  if (session.user) {
689
- const t = token;
690
893
  if (typeof t.name === "string") session.user.name = t.name;
691
894
  if (typeof t.email === "string") session.user.email = t.email;
692
895
  session.user.id = t.id;
@@ -707,11 +910,16 @@ function getNextAuthOptions(config) {
707
910
  };
708
911
  return extend ? extend(options) : options;
709
912
  }
913
+ function getStorefrontNextAuthOptions(config) {
914
+ return getNextAuthOptions({ ...config, allowCustomerLogin: true });
915
+ }
710
916
  export {
711
917
  ADMIN_GROUP_NAME,
712
918
  OPEN_ENDPOINTS,
713
919
  PERMISSION_REQUIRED_ENDPOINTS,
714
920
  RBAC_ADMIN_ONLY_ENTITIES,
921
+ SUPER_ADMIN_GROUP_ID,
922
+ VENDOR_ADMIN_GROUP_ID,
715
923
  VENDOR_OWNER_GROUP_NAME,
716
924
  VENDOR_SCOPED_STORE_ENTITIES,
717
925
  VENDOR_STORE_RBAC_ENTITIES,
@@ -727,23 +935,32 @@ export {
727
935
  getNextAuthOptions,
728
936
  getPermissionableEntityKeys,
729
937
  getRequiredPermission,
938
+ getStorefrontNextAuthOptions,
730
939
  hasEntityPermission,
940
+ isAuthDebugClientEnabled,
941
+ isAuthDebugEnabled,
731
942
  isOpenEndpoint,
732
943
  isPlatformAdministrator,
733
944
  isPublicMethod,
734
945
  isRbacDebugEnabled,
946
+ isSuperAdmin,
735
947
  isSuperAdminGroupName,
948
+ isVendorAdmin,
736
949
  isVendorGroupName,
737
950
  isVendorOwner,
738
951
  isVendorPortalUser,
739
952
  isVendorStaff,
953
+ logAuth,
954
+ logAuthClient,
740
955
  logEntityAccessDecision,
741
956
  logRbac,
957
+ nextAuthCookieDebugInfo,
742
958
  permissionRowsToRecord,
743
959
  resolveVendorScopeFromSessionUser,
744
960
  seedAdministratorPermissions,
745
961
  sessionHasEntityAccess,
746
962
  summarizeEntityPerms,
963
+ summarizeSessionUserForLog,
747
964
  vendorPortalFlagsFromUser
748
965
  };
749
966
  //# sourceMappingURL=auth.js.map