@burdenoff/microfe-auth 2026.917.2 → 2026.1005.1

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 (161) hide show
  1. package/dist/auth/AuthRoot.d.ts +0 -1
  2. package/dist/auth/AuthRoot.js.map +1 -1
  3. package/dist/auth/AuthRoutes.d.ts +1 -1
  4. package/dist/auth/AuthRoutes.js.map +1 -1
  5. package/dist/auth/components/AuthIcons.d.ts +12 -13
  6. package/dist/auth/components/AuthIcons.js.map +1 -1
  7. package/dist/auth/components/AuthLayout.d.ts +1 -2
  8. package/dist/auth/components/AuthLayout.js.map +1 -1
  9. package/dist/auth/components/CaptchaV2.d.ts +1 -1
  10. package/dist/auth/components/CaptchaV2.js +2 -2
  11. package/dist/auth/components/CaptchaV2.js.map +1 -1
  12. package/dist/auth/components/ConfirmActionDialog.d.ts +1 -1
  13. package/dist/auth/components/ConfirmActionDialog.js.map +1 -1
  14. package/dist/auth/components/profile/UserProfileMenu.d.ts +1 -1
  15. package/dist/auth/components/profile/UserProfileMenu.js.map +1 -1
  16. package/dist/auth/components/workspace/WorkspaceSelector.d.ts +1 -2
  17. package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
  18. package/dist/auth/constants/permissions.js.map +1 -1
  19. package/dist/auth/hooks/useAccountOperations.d.ts +0 -1
  20. package/dist/auth/hooks/useAccountOperations.js.map +1 -1
  21. package/dist/auth/hooks/useActiveContextBootstrapMirror.js.map +1 -1
  22. package/dist/auth/hooks/useApiKeyOperations.d.ts +1 -2
  23. package/dist/auth/hooks/useAppOperations.d.ts +1 -2
  24. package/dist/auth/hooks/useAuthOperations.d.ts +0 -1
  25. package/dist/auth/hooks/useAuthOperations.js.map +1 -1
  26. package/dist/auth/hooks/useAuthPermissions.js.map +1 -1
  27. package/dist/auth/hooks/useCaptchaV3.js +1 -1
  28. package/dist/auth/hooks/useCaptchaV3.js.map +1 -1
  29. package/dist/auth/hooks/useContextSwitcherData.d.ts +1 -1
  30. package/dist/auth/hooks/useContextSwitcherData.js +356 -234
  31. package/dist/auth/hooks/useContextSwitcherData.js.map +1 -1
  32. package/dist/auth/hooks/useDelegationOperations.d.ts +0 -1
  33. package/dist/auth/hooks/useMfaOperations.d.ts +0 -1
  34. package/dist/auth/hooks/useMfaOperations.js.map +1 -1
  35. package/dist/auth/hooks/useMyWorkspaces.d.ts +0 -1
  36. package/dist/auth/hooks/useMyWorkspaces.js.map +1 -1
  37. package/dist/auth/hooks/useOAuthOperations.d.ts +0 -1
  38. package/dist/auth/hooks/useOAuthOperations.js +2 -2
  39. package/dist/auth/hooks/useOAuthOperations.js.map +1 -1
  40. package/dist/auth/hooks/usePasswordOperations.d.ts +0 -1
  41. package/dist/auth/hooks/usePasswordOperations.js.map +1 -1
  42. package/dist/auth/hooks/useSessionOperations.d.ts +0 -1
  43. package/dist/auth/hooks/useSessionOperations.js.map +1 -1
  44. package/dist/auth/hooks/useSignupCaptcha.js +1 -1
  45. package/dist/auth/hooks/useSignupCaptcha.js.map +1 -1
  46. package/dist/auth/hooks/useSsoOperations.d.ts +0 -1
  47. package/dist/auth/hooks/useSsoOperations.js.map +1 -1
  48. package/dist/auth/hooks/useTokenRefresh.js.map +1 -1
  49. package/dist/auth/hooks/useUserOperations.d.ts +0 -1
  50. package/dist/auth/hooks/useUserOperations.js.map +1 -1
  51. package/dist/auth/hooks/useWorkspaceOperations.d.ts +0 -1
  52. package/dist/auth/hooks/useWorkspaceOperations.js.map +1 -1
  53. package/dist/auth/hooks/useWorkspaceToken.js.map +1 -1
  54. package/dist/auth/pages/AuditLogPage.d.ts +1 -1
  55. package/dist/auth/pages/AuditLogPage.js.map +1 -1
  56. package/dist/auth/pages/EmailVerifyPage.d.ts +1 -1
  57. package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
  58. package/dist/auth/pages/LoginPage.d.ts +1 -1
  59. package/dist/auth/pages/LoginPage.js.map +1 -1
  60. package/dist/auth/pages/MagicLinkPage.d.ts +1 -1
  61. package/dist/auth/pages/MagicLinkPage.js.map +1 -1
  62. package/dist/auth/pages/MfaSetupPage.d.ts +1 -1
  63. package/dist/auth/pages/MfaSetupPage.js +88 -88
  64. package/dist/auth/pages/MfaSetupPage.js.map +1 -1
  65. package/dist/auth/pages/MfaVerifyPage.d.ts +1 -1
  66. package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
  67. package/dist/auth/pages/OAuthCallbackPage.d.ts +1 -1
  68. package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
  69. package/dist/auth/pages/PasswordResetPage.d.ts +1 -1
  70. package/dist/auth/pages/PasswordResetPage.js.map +1 -1
  71. package/dist/auth/pages/ReactivatePage.d.ts +1 -1
  72. package/dist/auth/pages/ReactivatePage.js.map +1 -1
  73. package/dist/auth/pages/RegisterPage.d.ts +1 -1
  74. package/dist/auth/pages/RegisterPage.js.map +1 -1
  75. package/dist/auth/pages/SSOClearPage.d.ts +1 -1
  76. package/dist/auth/pages/SSOClearPage.js.map +1 -1
  77. package/dist/auth/pages/SSODepositPage.d.ts +1 -1
  78. package/dist/auth/pages/SSODepositPage.js.map +1 -1
  79. package/dist/auth/pages/SSORelayCallbackPage.d.ts +1 -1
  80. package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -1
  81. package/dist/auth/pages/SSORelayPage.d.ts +1 -1
  82. package/dist/auth/pages/SSORelayPage.js.map +1 -1
  83. package/dist/auth/pages/SecurityPage.d.ts +1 -1
  84. package/dist/auth/pages/SecurityPage.js.map +1 -1
  85. package/dist/auth/pages/SessionBridgePage.d.ts +1 -1
  86. package/dist/auth/pages/SessionBridgePage.js.map +1 -1
  87. package/dist/auth/pages/SessionsPage.d.ts +1 -1
  88. package/dist/auth/pages/SessionsPage.js.map +1 -1
  89. package/dist/auth/pages/SsoCallbackPage.d.ts +1 -1
  90. package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
  91. package/dist/auth/pages/SsoConfigPage.d.ts +1 -1
  92. package/dist/auth/pages/SsoConfigPage.js.map +1 -1
  93. package/dist/auth/pages/SsoLoginPage.d.ts +1 -1
  94. package/dist/auth/pages/SsoLoginPage.js.map +1 -1
  95. package/dist/auth/pages/UserDetailsPage.d.ts +1 -1
  96. package/dist/auth/pages/UserDetailsPage.js.map +1 -1
  97. package/dist/auth/pages/UserProfilePage.d.ts +1 -1
  98. package/dist/auth/pages/UserProfilePage.js.map +1 -1
  99. package/dist/auth/pages/UsersPage.d.ts +1 -1
  100. package/dist/auth/pages/UsersPage.js.map +1 -1
  101. package/dist/auth/providers/AuthProvider.d.ts +0 -1
  102. package/dist/auth/providers/AuthProvider.js.map +1 -1
  103. package/dist/auth/providers/CaptchaProvider.d.ts +1 -2
  104. package/dist/auth/providers/CaptchaProvider.js +2 -2
  105. package/dist/auth/providers/CaptchaProvider.js.map +1 -1
  106. package/dist/auth/store/authStore.d.ts +0 -1
  107. package/dist/auth/store/authStore.js.map +1 -1
  108. package/dist/auth/types/index.d.ts +0 -1
  109. package/dist/auth/utils/captchaConfig.js.map +1 -1
  110. package/dist/auth/utils/formatters.js.map +1 -1
  111. package/dist/auth/utils/gatewayBaseUrls.js.map +1 -1
  112. package/dist/auth/utils/legalUrls.d.ts +1 -1
  113. package/dist/auth/utils/legalUrls.js.map +1 -1
  114. package/dist/auth/utils/redirect.js.map +1 -1
  115. package/dist/auth/utils/ssoOrigins.js +1 -1
  116. package/dist/auth/utils/ssoOrigins.js.map +1 -1
  117. package/dist/auth/utils/validation.d.ts +0 -1
  118. package/dist/auth/utils/validation.js.map +1 -1
  119. package/dist/dev/main.d.ts +0 -1
  120. package/dist/generated/global-operations.js.map +1 -1
  121. package/dist/generated/wspace-operations.js.map +1 -1
  122. package/dist/index.d.ts +0 -1
  123. package/dist/shared/hooks/useTr.js.map +1 -1
  124. package/dist/shared/types/index.d.ts +0 -1
  125. package/dist/translations/en.js.map +1 -1
  126. package/package.json +27 -20
  127. package/dist/_virtual/_rolldown/runtime.js +0 -13
  128. package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js +0 -70
  129. package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js.map +0 -1
  130. package/dist/node_modules/object-assign/index.js +0 -41
  131. package/dist/node_modules/object-assign/index.js.map +0 -1
  132. package/dist/node_modules/prop-types/checkPropTypes.js +0 -46
  133. package/dist/node_modules/prop-types/checkPropTypes.js.map +0 -1
  134. package/dist/node_modules/prop-types/factoryWithThrowingShims.js +0 -49
  135. package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +0 -1
  136. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js +0 -272
  137. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +0 -1
  138. package/dist/node_modules/prop-types/index.js +0 -16
  139. package/dist/node_modules/prop-types/index.js.map +0 -1
  140. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js +0 -10
  141. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +0 -1
  142. package/dist/node_modules/prop-types/lib/has.js +0 -10
  143. package/dist/node_modules/prop-types/lib/has.js.map +0 -1
  144. package/dist/node_modules/qrcode.react/lib/esm/index.js +0 -959
  145. package/dist/node_modules/qrcode.react/lib/esm/index.js.map +0 -1
  146. package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js +0 -114
  147. package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js.map +0 -1
  148. package/dist/node_modules/react-google-recaptcha/lib/esm/index.js +0 -8
  149. package/dist/node_modules/react-google-recaptcha/lib/esm/index.js.map +0 -1
  150. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js +0 -20
  151. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js.map +0 -1
  152. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js +0 -148
  153. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js.map +0 -1
  154. package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js +0 -445
  155. package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js.map +0 -1
  156. package/dist/node_modules/react-is/cjs/react-is.development.js +0 -84
  157. package/dist/node_modules/react-is/cjs/react-is.development.js.map +0 -1
  158. package/dist/node_modules/react-is/cjs/react-is.production.min.js +0 -64
  159. package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +0 -1
  160. package/dist/node_modules/react-is/index.js +0 -12
  161. package/dist/node_modules/react-is/index.js.map +0 -1
@@ -1,6 +1,5 @@
1
1
  import { FC } from 'react';
2
2
  import { AuthRootProps } from './types';
3
-
4
3
  /**
5
4
  * Root component for the Auth microfrontend.
6
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"AuthRoot.js","names":[],"sources":["../../src/auth/AuthRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo } from \"react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport { useLocation } from \"react-router\";\nimport { ShieldCheck, Laptop, Key, /* Code, */ Building } from \"lucide-react\";\nimport { AuthProvider } from \"./providers/AuthProvider\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { CaptchaProvider } from \"./providers/CaptchaProvider\";\nimport type { NavItem, AuthRootProps } from \"./types\";\nimport { AuthRoutes } from \"./AuthRoutes\";\nimport { useTr } from \"../shared/hooks/useTr\";\n\n/**\n * Root component for the Auth microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { AuthRoot, type AuthRootProps } from '@burdenoff/microfe-auth';\n *\n * function App() {\n * const props: AuthRootProps = {\n * basePath: '/auth',\n * navigate: (path) => router.push(path),\n * apiGatewayUrl: 'http://localhost:4002',\n * authToken: 'token',\n * onAuthSuccess: (user) => shellLogin(user),\n * onLogout: () => shellLogout(),\n * };\n *\n * return <AuthRoot {...props} />;\n * }\n * ```\n */\nexport const AuthRoot: FC<AuthRootProps> = (props) => {\n const {\n registerNavItems,\n registerFooterItems,\n basePath = \"/\",\n // Admin routes (`/auth/users`, `/auth/users/:id`, `/auth/sso`,\n // `/auth/audit-log`) are opt-in: only the admin app shell should pass\n // `enableAdminRoutes={true}`. User-facing product hosts (vibecontrols,\n // workspaces, botlit, healthybowl, etc.) intentionally do not expose\n // these surfaces — gateway RBAC still gates the underlying\n // queries/mutations, but hiding the routes prevents accidental UI\n // discoverability. Must match the corresponding default in\n // `AuthRoutes.tsx`.\n enableAdminRoutes = false,\n bypassEnterprisePlanGate = false,\n } = props;\n const tr = useTr();\n const location = useLocation();\n\n // Normalize basePath (remove trailing slash)\n const normalizedBasePath = useMemo(\n () =>\n basePath && basePath !== \"/\"\n ? basePath.endsWith(\"/\")\n ? basePath.slice(0, -1)\n : basePath\n : \"\",\n [basePath],\n );\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: \"auth-security\",\n label: tr(\"auth.root.navSecurity\", \"Security Settings\"),\n path: joinPath(basePath, \"security\"),\n icon: <ShieldCheck size={20} />,\n order: 10,\n group: \"auth\",\n },\n {\n id: \"auth-sessions\",\n label: tr(\"auth.root.navSessions\", \"Active Sessions\"),\n path: joinPath(basePath, \"sessions\"),\n icon: <Laptop size={20} />,\n order: 20,\n group: \"auth\",\n },\n {\n id: \"auth-mfa\",\n label: tr(\"auth.root.navMfa\", \"Multi-Factor Auth\"),\n path: joinPath(basePath, \"mfa\"),\n icon: <Key size={20} />,\n order: 30,\n group: \"auth\",\n },\n // Hidden — moved to Developer Portal\n // {\n // id: \"auth-api-keys\",\n // label: \"API Keys\",\n // path: joinPath(basePath, \"api-keys\"),\n // icon: <Code size={20} />,\n // order: 40,\n // group: \"auth\",\n // },\n ...(enableAdminRoutes\n ? [\n {\n id: \"auth-sso\",\n label: tr(\"auth.root.navSso\", \"SSO Configuration\"),\n path: joinPath(basePath, \"sso\"),\n icon: <Building size={20} />,\n order: 50,\n group: \"auth\",\n },\n ]\n : []),\n ];\n\n // Register and get cleanup function\n const cleanup = registerNavItems(navItems);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, enableAdminRoutes, tr]);\n\n // Register footer items (example: auth status indicator)\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"auth-status\",\n label: tr(\"auth.root.footerReady\", \"Auth Ready\"),\n type: \"status\" as const,\n order: 10,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n // Check if path matches - must be after all hooks\n const pathMatches = useMemo(() => {\n if (!normalizedBasePath) return true;\n return (\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + \"/\")\n );\n }, [normalizedBasePath, location.pathname]);\n\n // Early return after all hooks are called\n if (!pathMatches) {\n return null;\n }\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n {tr(\n \"auth.root.loadError\",\n \"Something went wrong loading this module. Please refresh the page.\",\n )}\n </div>\n }\n >\n <FeatureFlagProvider\n workspaceId={null}\n gateway=\"global\"\n defaultEnabled={true}\n >\n <AuthProvider {...props}>\n <CaptchaProvider>\n <AuthRoutes\n basePath={normalizedBasePath}\n enableAdminRoutes={enableAdminRoutes}\n bypassEnterprisePlanGate={bypassEnterprisePlanGate}\n />\n </CaptchaProvider>\n </AuthProvider>\n </FeatureFlagProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;AAqCA,IAAa,KAA+B,MAAU;CACpD,IAAM,EACJ,qBACA,wBACA,cAAW,KASX,uBAAoB,IACpB,8BAA2B,OACzB,GACE,IAAK,GAAO,EACZ,IAAW,GAAa,EAGxB,IAAqB,QAEvB,KAAY,MAAa,MACrB,EAAS,SAAS,IAAI,GACpB,EAAS,MAAM,GAAG,GAAG,GACrB,IACF,IACN,CAAC,EAAS,CACX,EAGK,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AA+FtD,QA1FA,QAAgB;AACT,QAsDL,QAHgB,EAjDY;GAC1B;IACE,IAAI;IACJ,OAAO,EAAG,yBAAyB,oBAAoB;IACvD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA;IAC/B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,yBAAyB,kBAAkB;IACrD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;IAC1B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,oBAAoB;IAClD,MAAM,EAAS,GAAU,MAAM;IAC/B,MAAM,kBAAC,GAAD,EAAK,MAAM,IAAM,CAAA;IACvB,OAAO;IACP,OAAO;IACR;GAUD,GAAI,IACA,CACE;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,oBAAoB;IAClD,MAAM,EAAS,GAAU,MAAM;IAC/B,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR,CACF,GACD,EAAE;GACP,CAGyC;IAIzC;EAAC;EAAkB;EAAU;EAAmB;EAAG,CAAC,EAGvD,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAG,yBAAyB,aAAa;GAChD,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAG,CAAC,EAGT,QACb,IAEH,EAAS,aAAa,KACtB,EAAS,SAAS,WAAW,IAAqB,IAAI,GAHxB,IAK/B,CAAC,GAAoB,EAAS,SAAS,CAAC,GAQzC,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EACC,uBACA,qEACD;GACG,CAAA;YAGR,kBAAC,GAAD;GACE,aAAa;GACb,SAAQ;GACR,gBAAgB;aAEhB,kBAAC,GAAD;IAAc,GAAI;cAChB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,UAAU;KACS;KACO;KAC1B,CAAA,EACc,CAAA;IACL,CAAA;GACK,CAAA;EACR,CAAA,GA7BT"}
1
+ {"version":3,"file":"AuthRoot.js","names":[],"sources":["../../src/auth/AuthRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo } from \"react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport { useLocation } from \"react-router\";\nimport { ShieldCheck, Laptop, Key, /* Code, */ Building } from \"lucide-react\";\nimport { AuthProvider } from \"./providers/AuthProvider\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { CaptchaProvider } from \"./providers/CaptchaProvider\";\nimport type { NavItem, AuthRootProps } from \"./types\";\nimport { AuthRoutes } from \"./AuthRoutes\";\nimport { useTr } from \"../shared/hooks/useTr\";\n\n/**\n * Root component for the Auth microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { AuthRoot, type AuthRootProps } from '@burdenoff/microfe-auth';\n *\n * function App() {\n * const props: AuthRootProps = {\n * basePath: '/auth',\n * navigate: (path) => router.push(path),\n * apiGatewayUrl: 'http://localhost:4002',\n * authToken: 'token',\n * onAuthSuccess: (user) => shellLogin(user),\n * onLogout: () => shellLogout(),\n * };\n *\n * return <AuthRoot {...props} />;\n * }\n * ```\n */\nexport const AuthRoot: FC<AuthRootProps> = (props) => {\n const {\n registerNavItems,\n registerFooterItems,\n basePath = \"/\",\n // Admin routes (`/auth/users`, `/auth/users/:id`, `/auth/sso`,\n // `/auth/audit-log`) are opt-in: only the admin app shell should pass\n // `enableAdminRoutes={true}`. User-facing product hosts (vibecontrols,\n // workspaces, botlit, healthybowl, etc.) intentionally do not expose\n // these surfaces — gateway RBAC still gates the underlying\n // queries/mutations, but hiding the routes prevents accidental UI\n // discoverability. Must match the corresponding default in\n // `AuthRoutes.tsx`.\n enableAdminRoutes = false,\n bypassEnterprisePlanGate = false,\n } = props;\n const tr = useTr();\n const location = useLocation();\n\n // Normalize basePath (remove trailing slash)\n const normalizedBasePath = useMemo(\n () =>\n basePath && basePath !== \"/\"\n ? basePath.endsWith(\"/\")\n ? basePath.slice(0, -1)\n : basePath\n : \"\",\n [basePath],\n );\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: \"auth-security\",\n label: tr(\"auth.root.navSecurity\", \"Security Settings\"),\n path: joinPath(basePath, \"security\"),\n icon: <ShieldCheck size={20} />,\n order: 10,\n group: \"auth\",\n },\n {\n id: \"auth-sessions\",\n label: tr(\"auth.root.navSessions\", \"Active Sessions\"),\n path: joinPath(basePath, \"sessions\"),\n icon: <Laptop size={20} />,\n order: 20,\n group: \"auth\",\n },\n {\n id: \"auth-mfa\",\n label: tr(\"auth.root.navMfa\", \"Multi-Factor Auth\"),\n path: joinPath(basePath, \"mfa\"),\n icon: <Key size={20} />,\n order: 30,\n group: \"auth\",\n },\n // Hidden — moved to Developer Portal\n // {\n // id: \"auth-api-keys\",\n // label: \"API Keys\",\n // path: joinPath(basePath, \"api-keys\"),\n // icon: <Code size={20} />,\n // order: 40,\n // group: \"auth\",\n // },\n ...(enableAdminRoutes\n ? [\n {\n id: \"auth-sso\",\n label: tr(\"auth.root.navSso\", \"SSO Configuration\"),\n path: joinPath(basePath, \"sso\"),\n icon: <Building size={20} />,\n order: 50,\n group: \"auth\",\n },\n ]\n : []),\n ];\n\n // Register and get cleanup function\n const cleanup = registerNavItems(navItems);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, enableAdminRoutes, tr]);\n\n // Register footer items (example: auth status indicator)\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"auth-status\",\n label: tr(\"auth.root.footerReady\", \"Auth Ready\"),\n type: \"status\" as const,\n order: 10,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n // Check if path matches - must be after all hooks\n const pathMatches = useMemo(() => {\n if (!normalizedBasePath) return true;\n return (\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + \"/\")\n );\n }, [normalizedBasePath, location.pathname]);\n\n // Early return after all hooks are called\n if (!pathMatches) {\n return null;\n }\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n {tr(\n \"auth.root.loadError\",\n \"Something went wrong loading this module. Please refresh the page.\",\n )}\n </div>\n }\n >\n <FeatureFlagProvider\n workspaceId={null}\n gateway=\"global\"\n defaultEnabled={true}\n >\n <AuthProvider {...props}>\n <CaptchaProvider>\n <AuthRoutes\n basePath={normalizedBasePath}\n enableAdminRoutes={enableAdminRoutes}\n bypassEnterprisePlanGate={bypassEnterprisePlanGate}\n />\n </CaptchaProvider>\n </AuthProvider>\n </FeatureFlagProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;AAqCA,IAAa,KAA+B,MAAU;CACpD,IAAM,EACJ,qBACA,wBACA,cAAW,KASX,uBAAoB,IACpB,8BAA2B,OACzB,GACE,IAAK,EAAM,GACX,IAAW,EAAY,GAGvB,IAAqB,QAEvB,KAAY,MAAa,MACrB,EAAS,SAAS,GAAG,IACnB,EAAS,MAAM,GAAG,EAAE,IACpB,IACF,IACN,CAAC,CAAQ,CACX,GAGM,KAAY,GAAc,OACZ,EAAK,SAAS,GAAG,IAAI,EAAK,MAAM,GAAG,EAAE,IAAI,MACzC,EAAK,WAAW,GAAG,IAAI,IAAO,IAAI;CA+FtD,OA1FA,QAAgB;EACT,OAsDL,OAHgB,EAAiB;GAhD/B;IACE,IAAI;IACJ,OAAO,EAAG,yBAAyB,mBAAmB;IACtD,MAAM,EAAS,GAAU,UAAU;IACnC,MAAM,kBAAC,GAAD,EAAa,MAAM,GAAK,CAAA;IAC9B,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAG,yBAAyB,iBAAiB;IACpD,MAAM,EAAS,GAAU,UAAU;IACnC,MAAM,kBAAC,GAAD,EAAQ,MAAM,GAAK,CAAA;IACzB,OAAO;IACP,OAAO;GACT;GACA;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,mBAAmB;IACjD,MAAM,EAAS,GAAU,KAAK;IAC9B,MAAM,kBAAC,GAAD,EAAK,MAAM,GAAK,CAAA;IACtB,OAAO;IACP,OAAO;GACT;GAUA,GAAI,IACA,CACE;IACE,IAAI;IACJ,OAAO,EAAG,oBAAoB,mBAAmB;IACjD,MAAM,EAAS,GAAU,KAAK;IAC9B,MAAM,kBAAC,GAAD,EAAU,MAAM,GAAK,CAAA;IAC3B,OAAO;IACP,OAAO;GACT,CACF,IACA,CAAC;EAI0B,CAG1B;CACT,GAAG;EAAC;EAAkB;EAAU;EAAmB;CAAE,CAAC,GAGtD,QAAgB;EACT,OAaL,OADgB,EAAoB,CATlC;GACE,IAAI;GACJ,OAAO,EAAG,yBAAyB,YAAY;GAC/C,MAAM;GACN,OAAO;GACP,SAAS;EACX,CAGkC,CAC7B;CACT,GAAG,CAAC,GAAqB,CAAE,CAAC,GAGR,QACb,IAEH,EAAS,aAAa,KACtB,EAAS,SAAS,WAAW,IAAqB,GAAG,IAHvB,IAK/B,CAAC,GAAoB,EAAS,QAAQ,CAGpC,IAKH,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EACC,uBACA,oEACF;EACG,CAAA;YAGP,kBAAC,GAAD;GACE,aAAa;GACb,SAAQ;GACR,gBAAgB;aAEhB,kBAAC,GAAD;IAAc,GAAI;cAChB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,UAAU;KACS;KACO;IAC3B,CAAA,EACc,CAAA;GACL,CAAA;EACK,CAAA;CACR,CAAA,IA7BR;AA+BX"}
@@ -24,4 +24,4 @@ export declare function AuthRoutes({ basePath: _basePath, enableAdminRoutes, byp
24
24
  basePath?: string;
25
25
  enableAdminRoutes?: boolean;
26
26
  bypassEnterprisePlanGate?: boolean;
27
- }): import("react").JSX.Element;
27
+ }): import('react').JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"AuthRoutes.js","names":[],"sources":["../../src/auth/AuthRoutes.tsx"],"sourcesContent":["import { lazy, Suspense, useEffect, useState } from \"react\";\nimport {\n useFeatureFlagDetails,\n FeatureGate,\n} from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { Navigate, Route, Routes } from \"react-router\";\nimport { useAuthStore } from \"./store/authStore\";\n\n// Eager imports - these are the most commonly accessed routes\nimport { LoginPage } from \"./pages/LoginPage\";\nimport { SessionBridgePage } from \"./pages/SessionBridgePage\";\nimport { SSORelayPage } from \"./pages/SSORelayPage\";\nimport { SSORelayCallbackPage } from \"./pages/SSORelayCallbackPage\";\nimport { SSODepositPage } from \"./pages/SSODepositPage\";\nimport { SSOClearPage } from \"./pages/SSOClearPage\";\n\n// Lazy-loaded pages - loaded on demand when their routes are accessed\nconst RegisterPage = lazy(() =>\n import(\"./pages/RegisterPage\").then((m) => ({ default: m.RegisterPage })),\n);\nconst PasswordResetPage = lazy(() =>\n import(\"./pages/PasswordResetPage\").then((m) => ({\n default: m.PasswordResetPage,\n })),\n);\nconst EmailVerifyPage = lazy(() =>\n import(\"./pages/EmailVerifyPage\").then((m) => ({\n default: m.EmailVerifyPage,\n })),\n);\nconst MfaVerifyPage = lazy(() =>\n import(\"./pages/MfaVerifyPage\").then((m) => ({ default: m.MfaVerifyPage })),\n);\nconst MagicLinkPage = lazy(() =>\n import(\"./pages/MagicLinkPage\").then((m) => ({ default: m.MagicLinkPage })),\n);\nconst ReactivatePage = lazy(() =>\n import(\"./pages/ReactivatePage\").then((m) => ({ default: m.ReactivatePage })),\n);\nconst SecurityPage = lazy(() =>\n import(\"./pages/SecurityPage\").then((m) => ({ default: m.SecurityPage })),\n);\nconst SessionsPage = lazy(() =>\n import(\"./pages/SessionsPage\").then((m) => ({ default: m.SessionsPage })),\n);\nconst MfaSetupPage = lazy(() =>\n import(\"./pages/MfaSetupPage\").then((m) => ({ default: m.MfaSetupPage })),\n);\nconst AuditLogPage = lazy(() =>\n import(\"./pages/AuditLogPage\").then((m) => ({ default: m.AuditLogPage })),\n);\nconst SsoConfigPage = lazy(() =>\n import(\"./pages/SsoConfigPage\").then((m) => ({ default: m.SsoConfigPage })),\n);\nconst SsoLoginPage = lazy(() =>\n import(\"./pages/SsoLoginPage\").then((m) => ({ default: m.SsoLoginPage })),\n);\nconst SsoCallbackPage = lazy(() =>\n import(\"./pages/SsoCallbackPage\").then((m) => ({\n default: m.SsoCallbackPage,\n })),\n);\nconst OAuthCallbackPage = lazy(() =>\n import(\"./pages/OAuthCallbackPage\").then((m) => ({\n default: m.OAuthCallbackPage,\n })),\n);\nconst UsersPage = lazy(() =>\n import(\"./pages/UsersPage\").then((m) => ({ default: m.UsersPage })),\n);\nconst UserDetailsPage = lazy(() =>\n import(\"./pages/UserDetailsPage\").then((m) => ({\n default: m.UserDetailsPage,\n })),\n);\nconst UserProfilePage = lazy(() =>\n import(\"./pages/UserProfilePage\").then((m) => ({\n default: m.UserProfilePage,\n })),\n);\n/**\n * Simple loading fallback for lazy-loaded pages\n */\nfunction PageLoader() {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"size-8 animate-spin rounded-full border-4 border-primary border-t-transparent\" />\n </div>\n );\n}\n\nfunction decodeJwtExpiry(token: string): number | null {\n try {\n const payload = JSON.parse(\n atob(token.split(\".\")[1].replace(/-/g, \"+\").replace(/_/g, \"/\")),\n ) as { exp?: number };\n\n return typeof payload.exp === \"number\" ? payload.exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\nfunction getStoredSessionSnapshot(): {\n hasValidSession: boolean;\n expiresAt: number | null;\n} {\n try {\n const activeProfileId = sessionStorage.getItem(\"bf-active-profile\");\n if (!activeProfileId) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n const tokensRaw = localStorage.getItem(`bf-p-${activeProfileId}-tokens`);\n if (!tokensRaw) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n const tokens = JSON.parse(tokensRaw) as {\n accessToken?: string;\n expiresAt?: number;\n };\n\n if (!tokens.accessToken) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n const expiresAt =\n typeof tokens.expiresAt === \"number\"\n ? tokens.expiresAt\n : decodeJwtExpiry(tokens.accessToken);\n\n if (!expiresAt) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n return {\n hasValidSession: expiresAt > Date.now(),\n expiresAt,\n };\n } catch {\n return { hasValidSession: false, expiresAt: null };\n }\n}\n\n/**\n * Protected route wrapper\n */\nfunction ProtectedRoute({ children }: { children: React.ReactNode }) {\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const clearAuth = useAuthStore((state) => state.clearAuth);\n const [sessionCheckVersion, setSessionCheckVersion] = useState(0);\n const sessionSnapshot = getStoredSessionSnapshot();\n\n useEffect(() => {\n const handleSessionUpdate = () => {\n setSessionCheckVersion((value) => value + 1);\n };\n\n window.addEventListener(\"bf-profile-storage-change\", handleSessionUpdate);\n window.addEventListener(\"storage\", handleSessionUpdate);\n\n return () => {\n window.removeEventListener(\n \"bf-profile-storage-change\",\n handleSessionUpdate,\n );\n window.removeEventListener(\"storage\", handleSessionUpdate);\n };\n }, []);\n\n useEffect(() => {\n if (!sessionSnapshot.expiresAt) return;\n\n const timeoutMs = Math.max(sessionSnapshot.expiresAt - Date.now(), 0) + 50;\n const timer = window.setTimeout(() => {\n setSessionCheckVersion((value) => value + 1);\n }, timeoutMs);\n\n return () => window.clearTimeout(timer);\n }, [sessionSnapshot.expiresAt, sessionCheckVersion]);\n\n useEffect(() => {\n if (isAuthenticated && !sessionSnapshot.hasValidSession) {\n clearAuth();\n }\n }, [clearAuth, isAuthenticated, sessionSnapshot.hasValidSession]);\n\n if (!sessionSnapshot.hasValidSession) {\n return <Navigate to=\"/auth/login\" replace />;\n }\n\n return <>{children}</>;\n}\n\n/**\n * Internal router for the Auth microfrontend.\n * This component handles routing within the microfrontend using React Router v7.\n *\n * When used within a parent route (e.g., <Route path=\"/auth/*\">), all paths are relative:\n * - login → Login page (accessible at /auth/login)\n * - register → Registration page (accessible at /auth/register)\n * - reset-password → Password reset page (accessible at /auth/reset-password)\n * - verify-email → Email verification page (accessible at /auth/verify-email)\n * - mfa-verify → MFA verification page (accessible at /auth/mfa-verify)\n * - magic-link → Magic link authentication page (accessible at /auth/magic-link)\n * - sso/login → SSO login page (accessible at /auth/sso/login)\n * - sso/callback → SSO callback handler (accessible at /auth/sso/callback)\n * - oauth/callback → OAuth callback handler (accessible at /auth/oauth/callback)\n * - security → Security settings (protected, accessible at /auth/security)\n * - sessions → Active sessions (protected, accessible at /auth/sessions)\n * - mfa → MFA setup (protected, accessible at /auth/mfa)\n * - users → Users management (protected, admin only, accessible at /auth/users)\n * - profile → User profile page (protected, accessible at /auth/profile)\n * - audit-log → Security audit log (protected, accessible at /auth/audit-log)\n * - sso → SSO configuration (protected, admin only, accessible at /auth/sso)\n */\nexport function AuthRoutes({\n basePath: _basePath = \"\",\n // Admin routes (`/auth/users`, `/auth/users/:id`, `/auth/sso`,\n // `/auth/audit-log`) are opt-in: only the admin app shell should pass\n // `enableAdminRoutes={true}`. User-facing product hosts (vibecontrols,\n // workspaces, botlit, healthybowl, etc.) intentionally do not expose\n // these surfaces — the gateway's RBAC directives still gate the\n // underlying queries/mutations, but hiding the routes prevents\n // accidental UI discoverability and reduces the attack surface for\n // misconfigured permissions.\n enableAdminRoutes = false,\n bypassEnterprisePlanGate = false,\n}: {\n basePath?: string;\n enableAdminRoutes?: boolean;\n bypassEnterprisePlanGate?: boolean;\n}) {\n // Note: basePath is kept for backwards compatibility but not used in route paths\n // since React Router v7 uses relative paths when nested inside a parent <Route>\n const auditLogFlag = useFeatureFlagDetails(\"auth.audit-log\");\n const showAuditLog = auditLogFlag?.value === true;\n return (\n <Routes>\n {/* Public routes (no auth required) */}\n {/* LoginPage is eager-loaded as it's the most common entry point */}\n <Route path=\"login\" element={<LoginPage />} />\n <Route\n path=\"register\"\n element={\n <Suspense fallback={<PageLoader />}>\n <RegisterPage />\n </Suspense>\n }\n />\n {/* \"signup\" is the URL most people guess (it's the term this app's own\n copy uses — \"Create your account\" / sign up), but the route has\n always been \"register\" with nothing to catch the alias — it silently\n rendered a blank page. Redirect rather than rename register itself,\n since register is the established/linked path. */}\n <Route path=\"signup\" element={<Navigate to=\"/auth/register\" replace />} />\n <Route\n path=\"reset-password\"\n element={\n <Suspense fallback={<PageLoader />}>\n <PasswordResetPage />\n </Suspense>\n }\n />\n <Route\n path=\"verify-email\"\n element={\n <Suspense fallback={<PageLoader />}>\n <EmailVerifyPage />\n </Suspense>\n }\n />\n <Route\n path=\"mfa-verify\"\n element={\n <Suspense fallback={<PageLoader />}>\n <MfaVerifyPage />\n </Suspense>\n }\n />\n <Route\n path=\"magic-link\"\n element={\n <Suspense fallback={<PageLoader />}>\n <MagicLinkPage />\n </Suspense>\n }\n />\n\n {/* SSO routes (public) */}\n <Route\n path=\"sso/login\"\n element={\n <Suspense fallback={<PageLoader />}>\n <SsoLoginPage />\n </Suspense>\n }\n />\n <Route\n path=\"sso/callback\"\n element={\n <Suspense fallback={<PageLoader />}>\n <SsoCallbackPage />\n </Suspense>\n }\n />\n\n {/* OAuth callback route (public) */}\n <Route\n path=\"oauth/callback\"\n element={\n <Suspense fallback={<PageLoader />}>\n <OAuthCallbackPage />\n </Suspense>\n }\n />\n\n {/* Account reactivation (public) */}\n <Route\n path=\"reactivate\"\n element={\n <Suspense fallback={<PageLoader />}>\n <ReactivatePage />\n </Suspense>\n }\n />\n\n {/* Session bridge (public - embedded as hidden iframe by other app shells) */}\n <Route path=\"session-bridge\" element={<SessionBridgePage />} />\n\n {/* Cross-domain SSO relay (reads local tokens, redirects with them to target) */}\n <Route path=\"sso-relay\" element={<SSORelayPage />} />\n\n {/* Cross-domain SSO callback (receives tokens from relay, stores locally) */}\n <Route path=\"sso-callback\" element={<SSORelayCallbackPage />} />\n\n {/* Cross-domain SSO deposit (bridge host receives tokens on top-level\n redirect right after login on a product origin, writes first-party\n localStorage on the bridge origin so other products can discover\n the session). */}\n <Route path=\"sso-deposit\" element={<SSODepositPage />} />\n\n {/* Cross-domain SLO clear (bridge host clears its central session on\n top-level redirect from a product origin's logout). */}\n <Route path=\"sso-clear\" element={<SSOClearPage />} />\n\n {/* Protected routes (auth required) */}\n <Route\n path=\"security\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.security\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <SecurityPage enableAdminRoutes={enableAdminRoutes} />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n <Route\n path=\"sessions\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.sessions\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <SessionsPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n <Route\n path=\"mfa\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.mfa\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <MfaSetupPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n {enableAdminRoutes && showAuditLog && (\n <Route\n path=\"audit-log\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.audit-log\" defaultValue={false}>\n <Suspense fallback={<PageLoader />}>\n <AuditLogPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n )}\n {!enableAdminRoutes && (\n <Route\n path=\"audit-log\"\n element={<Navigate to=\"/auth/login\" replace />}\n />\n )}\n <Route\n path=\"sso\"\n element={\n enableAdminRoutes ? (\n <ProtectedRoute>\n <FeatureGate flag=\"auth.sso\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <SsoConfigPage\n bypassEnterprisePlanGate={bypassEnterprisePlanGate}\n />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n ) : (\n <Navigate to=\"/auth/login\" replace />\n )\n }\n />\n <Route\n path=\"users\"\n element={\n enableAdminRoutes ? (\n <ProtectedRoute>\n <FeatureGate flag=\"auth.users\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <UsersPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n ) : (\n <Navigate to=\"/auth/login\" replace />\n )\n }\n />\n <Route\n path=\"users/:id\"\n element={\n enableAdminRoutes ? (\n <ProtectedRoute>\n <FeatureGate flag=\"auth.users\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <UserDetailsPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n ) : (\n <Navigate to=\"/auth/login\" replace />\n )\n }\n />\n <Route\n path=\"profile\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.profile\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <UserProfilePage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n\n {/* Default redirect - when visiting /auth or /auth/ with no subpath */}\n <Route index element={<Navigate to=\"login\" replace />} />\n </Routes>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,IAAM,IAAe,QACnB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAoB,QACxB,OAAO,gCAA6B,MAAM,OAAO,EAC/C,SAAS,EAAE,mBACZ,EAAE,CACJ,EACK,IAAkB,QACtB,OAAO,8BAA2B,MAAM,OAAO,EAC7C,SAAS,EAAE,iBACZ,EAAE,CACJ,EACK,IAAgB,QACpB,OAAO,4BAAyB,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAC5E,EACK,IAAgB,QACpB,OAAO,4BAAyB,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAC5E,EACK,IAAiB,QACrB,OAAO,6BAA0B,MAAM,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAC9E,EACK,IAAe,QACnB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAe,QACnB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAe,QACnB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAe,QACnB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAgB,QACpB,OAAO,4BAAyB,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAC5E,EACK,IAAe,QACnB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAkB,QACtB,OAAO,8BAA2B,MAAM,OAAO,EAC7C,SAAS,EAAE,iBACZ,EAAE,CACJ,EACK,IAAoB,QACxB,OAAO,gCAA6B,MAAM,OAAO,EAC/C,SAAS,EAAE,mBACZ,EAAE,CACJ,EACK,IAAY,QAChB,OAAO,wBAAqB,MAAM,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CACpE,EACK,IAAkB,QACtB,OAAO,8BAA2B,MAAM,OAAO,EAC7C,SAAS,EAAE,iBACZ,EAAE,CACJ,EACK,IAAkB,QACtB,OAAO,8BAA2B,MAAM,OAAO,EAC7C,SAAS,EAAE,iBACZ,EAAE,CACJ;AAID,SAAS,IAAa;AACpB,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,iFAAkF,CAAA;EAC7F,CAAA;;AAIV,SAAS,EAAgB,GAA8B;AACrD,KAAI;EACF,IAAM,IAAU,KAAK,MACnB,KAAK,EAAM,MAAM,IAAI,CAAC,GAAG,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI,CAAC,CAChE;AAED,SAAO,OAAO,EAAQ,OAAQ,WAAW,EAAQ,MAAM,MAAO;SACxD;AACN,SAAO;;;AAIX,SAAS,IAGP;AACA,KAAI;EACF,IAAM,IAAkB,eAAe,QAAQ,oBAAoB;AACnE,MAAI,CAAC,EACH,QAAO;GAAE,iBAAiB;GAAO,WAAW;GAAM;EAGpD,IAAM,IAAY,aAAa,QAAQ,QAAQ,EAAgB,SAAS;AACxE,MAAI,CAAC,EACH,QAAO;GAAE,iBAAiB;GAAO,WAAW;GAAM;EAGpD,IAAM,IAAS,KAAK,MAAM,EAAU;AAKpC,MAAI,CAAC,EAAO,YACV,QAAO;GAAE,iBAAiB;GAAO,WAAW;GAAM;EAGpD,IAAM,IACJ,OAAO,EAAO,aAAc,WACxB,EAAO,YACP,EAAgB,EAAO,YAAY;AAMzC,SAJK,IAIE;GACL,iBAAiB,IAAY,KAAK,KAAK;GACvC;GACD,GANQ;GAAE,iBAAiB;GAAO,WAAW;GAAM;SAO9C;AACN,SAAO;GAAE,iBAAiB;GAAO,WAAW;GAAM;;;AAOtD,SAAS,EAAe,EAAE,eAA2C;CACnE,IAAM,IAAkB,GAAc,MAAU,EAAM,gBAAgB,EAChE,IAAY,GAAc,MAAU,EAAM,UAAU,EACpD,CAAC,GAAqB,KAA0B,EAAS,EAAE,EAC3D,IAAkB,GAA0B;AAwClD,QAtCA,QAAgB;EACd,IAAM,UAA4B;AAChC,MAAwB,MAAU,IAAQ,EAAE;;AAM9C,SAHA,OAAO,iBAAiB,6BAA6B,EAAoB,EACzE,OAAO,iBAAiB,WAAW,EAAoB,QAE1C;AAKX,GAJA,OAAO,oBACL,6BACA,EACD,EACD,OAAO,oBAAoB,WAAW,EAAoB;;IAE3D,EAAE,CAAC,EAEN,QAAgB;AACd,MAAI,CAAC,EAAgB,UAAW;EAEhC,IAAM,IAAY,KAAK,IAAI,EAAgB,YAAY,KAAK,KAAK,EAAE,EAAE,GAAG,IAClE,IAAQ,OAAO,iBAAiB;AACpC,MAAwB,MAAU,IAAQ,EAAE;KAC3C,EAAU;AAEb,eAAa,OAAO,aAAa,EAAM;IACtC,CAAC,EAAgB,WAAW,EAAoB,CAAC,EAEpD,QAAgB;AACd,EAAI,KAAmB,CAAC,EAAgB,mBACtC,GAAW;IAEZ;EAAC;EAAW;EAAiB,EAAgB;EAAgB,CAAC,EAE5D,EAAgB,kBAId,kBAAA,GAAA,EAAG,aAAY,CAAA,GAHb,kBAAC,GAAD;EAAU,IAAG;EAAc,SAAA;EAAU,CAAA;;AA4BhD,SAAgB,EAAW,EACzB,UAAU,IAAY,IAStB,uBAAoB,IACpB,8BAA2B,MAK1B;CAID,IAAM,IADe,EAAsB,iBAAiB,EACzB,UAAU;AAC7C,QACE,kBAAC,GAAD,EAAA,UAAA;EAGE,kBAAC,GAAD;GAAO,MAAK;GAAQ,SAAS,kBAAC,GAAD,EAAa,CAAA;GAAI,CAAA;EAC9C,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAgB,CAAA;IACP,CAAA;GAEb,CAAA;EAMF,kBAAC,GAAD;GAAO,MAAK;GAAS,SAAS,kBAAC,GAAD;IAAU,IAAG;IAAiB,SAAA;IAAU,CAAA;GAAI,CAAA;EAC1E,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAqB,CAAA;IACZ,CAAA;GAEb,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAmB,CAAA;IACV,CAAA;GAEb,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAiB,CAAA;IACR,CAAA;GAEb,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAiB,CAAA;IACR,CAAA;GAEb,CAAA;EAGF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAgB,CAAA;IACP,CAAA;GAEb,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAmB,CAAA;IACV,CAAA;GAEb,CAAA;EAGF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAqB,CAAA;IACZ,CAAA;GAEb,CAAA;EAGF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD;IAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;cAChC,kBAAC,GAAD,EAAkB,CAAA;IACT,CAAA;GAEb,CAAA;EAGF,kBAAC,GAAD;GAAO,MAAK;GAAiB,SAAS,kBAAC,GAAD,EAAqB,CAAA;GAAI,CAAA;EAG/D,kBAAC,GAAD;GAAO,MAAK;GAAY,SAAS,kBAAC,GAAD,EAAgB,CAAA;GAAI,CAAA;EAGrD,kBAAC,GAAD;GAAO,MAAK;GAAe,SAAS,kBAAC,GAAD,EAAwB,CAAA;GAAI,CAAA;EAMhE,kBAAC,GAAD;GAAO,MAAK;GAAc,SAAS,kBAAC,GAAD,EAAkB,CAAA;GAAI,CAAA;EAIzD,kBAAC,GAAD;GAAO,MAAK;GAAY,SAAS,kBAAC,GAAD,EAAgB,CAAA;GAAI,CAAA;EAGrD,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAgB,cAAc;cAC9C,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAiC,sBAAqB,CAAA;KAC7C,CAAA;IACC,CAAA,EACC,CAAA;GAEnB,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAgB,cAAc;cAC9C,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAgB,CAAA;KACP,CAAA;IACC,CAAA,EACC,CAAA;GAEnB,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAW,cAAc;cACzC,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAgB,CAAA;KACP,CAAA;IACC,CAAA,EACC,CAAA;GAEnB,CAAA;EACD,KAAqB,KACpB,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAiB,cAAc;cAC/C,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAgB,CAAA;KACP,CAAA;IACC,CAAA,EACC,CAAA;GAEnB,CAAA;EAEH,CAAC,KACA,kBAAC,GAAD;GACE,MAAK;GACL,SAAS,kBAAC,GAAD;IAAU,IAAG;IAAc,SAAA;IAAU,CAAA;GAC9C,CAAA;EAEJ,kBAAC,GAAD;GACE,MAAK;GACL,SACE,IACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAW,cAAc;cACzC,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAC4B,6BAC1B,CAAA;KACO,CAAA;IACC,CAAA,EACC,CAAA,GAEjB,kBAAC,GAAD;IAAU,IAAG;IAAc,SAAA;IAAU,CAAA;GAGzC,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,IACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAa,cAAc;cAC3C,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAa,CAAA;KACJ,CAAA;IACC,CAAA,EACC,CAAA,GAEjB,kBAAC,GAAD;IAAU,IAAG;IAAc,SAAA;IAAU,CAAA;GAGzC,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,IACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAa,cAAc;cAC3C,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAmB,CAAA;KACV,CAAA;IACC,CAAA,EACC,CAAA,GAEjB,kBAAC,GAAD;IAAU,IAAG;IAAc,SAAA;IAAU,CAAA;GAGzC,CAAA;EACF,kBAAC,GAAD;GACE,MAAK;GACL,SACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,MAAK;IAAe,cAAc;cAC7C,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;eAChC,kBAAC,GAAD,EAAmB,CAAA;KACV,CAAA;IACC,CAAA,EACC,CAAA;GAEnB,CAAA;EAGF,kBAAC,GAAD;GAAO,OAAA;GAAM,SAAS,kBAAC,GAAD;IAAU,IAAG;IAAQ,SAAA;IAAU,CAAA;GAAI,CAAA;EAClD,EAAA,CAAA"}
1
+ {"version":3,"file":"AuthRoutes.js","names":[],"sources":["../../src/auth/AuthRoutes.tsx"],"sourcesContent":["import { lazy, Suspense, useEffect, useState } from \"react\";\nimport {\n useFeatureFlagDetails,\n FeatureGate,\n} from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { Navigate, Route, Routes } from \"react-router\";\nimport { useAuthStore } from \"./store/authStore\";\n\n// Eager imports - these are the most commonly accessed routes\nimport { LoginPage } from \"./pages/LoginPage\";\nimport { SessionBridgePage } from \"./pages/SessionBridgePage\";\nimport { SSORelayPage } from \"./pages/SSORelayPage\";\nimport { SSORelayCallbackPage } from \"./pages/SSORelayCallbackPage\";\nimport { SSODepositPage } from \"./pages/SSODepositPage\";\nimport { SSOClearPage } from \"./pages/SSOClearPage\";\n\n// Lazy-loaded pages - loaded on demand when their routes are accessed\nconst RegisterPage = lazy(() =>\n import(\"./pages/RegisterPage\").then((m) => ({ default: m.RegisterPage })),\n);\nconst PasswordResetPage = lazy(() =>\n import(\"./pages/PasswordResetPage\").then((m) => ({\n default: m.PasswordResetPage,\n })),\n);\nconst EmailVerifyPage = lazy(() =>\n import(\"./pages/EmailVerifyPage\").then((m) => ({\n default: m.EmailVerifyPage,\n })),\n);\nconst MfaVerifyPage = lazy(() =>\n import(\"./pages/MfaVerifyPage\").then((m) => ({ default: m.MfaVerifyPage })),\n);\nconst MagicLinkPage = lazy(() =>\n import(\"./pages/MagicLinkPage\").then((m) => ({ default: m.MagicLinkPage })),\n);\nconst ReactivatePage = lazy(() =>\n import(\"./pages/ReactivatePage\").then((m) => ({ default: m.ReactivatePage })),\n);\nconst SecurityPage = lazy(() =>\n import(\"./pages/SecurityPage\").then((m) => ({ default: m.SecurityPage })),\n);\nconst SessionsPage = lazy(() =>\n import(\"./pages/SessionsPage\").then((m) => ({ default: m.SessionsPage })),\n);\nconst MfaSetupPage = lazy(() =>\n import(\"./pages/MfaSetupPage\").then((m) => ({ default: m.MfaSetupPage })),\n);\nconst AuditLogPage = lazy(() =>\n import(\"./pages/AuditLogPage\").then((m) => ({ default: m.AuditLogPage })),\n);\nconst SsoConfigPage = lazy(() =>\n import(\"./pages/SsoConfigPage\").then((m) => ({ default: m.SsoConfigPage })),\n);\nconst SsoLoginPage = lazy(() =>\n import(\"./pages/SsoLoginPage\").then((m) => ({ default: m.SsoLoginPage })),\n);\nconst SsoCallbackPage = lazy(() =>\n import(\"./pages/SsoCallbackPage\").then((m) => ({\n default: m.SsoCallbackPage,\n })),\n);\nconst OAuthCallbackPage = lazy(() =>\n import(\"./pages/OAuthCallbackPage\").then((m) => ({\n default: m.OAuthCallbackPage,\n })),\n);\nconst UsersPage = lazy(() =>\n import(\"./pages/UsersPage\").then((m) => ({ default: m.UsersPage })),\n);\nconst UserDetailsPage = lazy(() =>\n import(\"./pages/UserDetailsPage\").then((m) => ({\n default: m.UserDetailsPage,\n })),\n);\nconst UserProfilePage = lazy(() =>\n import(\"./pages/UserProfilePage\").then((m) => ({\n default: m.UserProfilePage,\n })),\n);\n/**\n * Simple loading fallback for lazy-loaded pages\n */\nfunction PageLoader() {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"size-8 animate-spin rounded-full border-4 border-primary border-t-transparent\" />\n </div>\n );\n}\n\nfunction decodeJwtExpiry(token: string): number | null {\n try {\n const payload = JSON.parse(\n atob(token.split(\".\")[1].replace(/-/g, \"+\").replace(/_/g, \"/\")),\n ) as { exp?: number };\n\n return typeof payload.exp === \"number\" ? payload.exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\nfunction getStoredSessionSnapshot(): {\n hasValidSession: boolean;\n expiresAt: number | null;\n} {\n try {\n const activeProfileId = sessionStorage.getItem(\"bf-active-profile\");\n if (!activeProfileId) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n const tokensRaw = localStorage.getItem(`bf-p-${activeProfileId}-tokens`);\n if (!tokensRaw) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n const tokens = JSON.parse(tokensRaw) as {\n accessToken?: string;\n expiresAt?: number;\n };\n\n if (!tokens.accessToken) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n const expiresAt =\n typeof tokens.expiresAt === \"number\"\n ? tokens.expiresAt\n : decodeJwtExpiry(tokens.accessToken);\n\n if (!expiresAt) {\n return { hasValidSession: false, expiresAt: null };\n }\n\n return {\n hasValidSession: expiresAt > Date.now(),\n expiresAt,\n };\n } catch {\n return { hasValidSession: false, expiresAt: null };\n }\n}\n\n/**\n * Protected route wrapper\n */\nfunction ProtectedRoute({ children }: { children: React.ReactNode }) {\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const clearAuth = useAuthStore((state) => state.clearAuth);\n const [sessionCheckVersion, setSessionCheckVersion] = useState(0);\n const sessionSnapshot = getStoredSessionSnapshot();\n\n useEffect(() => {\n const handleSessionUpdate = () => {\n setSessionCheckVersion((value) => value + 1);\n };\n\n window.addEventListener(\"bf-profile-storage-change\", handleSessionUpdate);\n window.addEventListener(\"storage\", handleSessionUpdate);\n\n return () => {\n window.removeEventListener(\n \"bf-profile-storage-change\",\n handleSessionUpdate,\n );\n window.removeEventListener(\"storage\", handleSessionUpdate);\n };\n }, []);\n\n useEffect(() => {\n if (!sessionSnapshot.expiresAt) return;\n\n const timeoutMs = Math.max(sessionSnapshot.expiresAt - Date.now(), 0) + 50;\n const timer = window.setTimeout(() => {\n setSessionCheckVersion((value) => value + 1);\n }, timeoutMs);\n\n return () => window.clearTimeout(timer);\n }, [sessionSnapshot.expiresAt, sessionCheckVersion]);\n\n useEffect(() => {\n if (isAuthenticated && !sessionSnapshot.hasValidSession) {\n clearAuth();\n }\n }, [clearAuth, isAuthenticated, sessionSnapshot.hasValidSession]);\n\n if (!sessionSnapshot.hasValidSession) {\n return <Navigate to=\"/auth/login\" replace />;\n }\n\n return <>{children}</>;\n}\n\n/**\n * Internal router for the Auth microfrontend.\n * This component handles routing within the microfrontend using React Router v7.\n *\n * When used within a parent route (e.g., <Route path=\"/auth/*\">), all paths are relative:\n * - login → Login page (accessible at /auth/login)\n * - register → Registration page (accessible at /auth/register)\n * - reset-password → Password reset page (accessible at /auth/reset-password)\n * - verify-email → Email verification page (accessible at /auth/verify-email)\n * - mfa-verify → MFA verification page (accessible at /auth/mfa-verify)\n * - magic-link → Magic link authentication page (accessible at /auth/magic-link)\n * - sso/login → SSO login page (accessible at /auth/sso/login)\n * - sso/callback → SSO callback handler (accessible at /auth/sso/callback)\n * - oauth/callback → OAuth callback handler (accessible at /auth/oauth/callback)\n * - security → Security settings (protected, accessible at /auth/security)\n * - sessions → Active sessions (protected, accessible at /auth/sessions)\n * - mfa → MFA setup (protected, accessible at /auth/mfa)\n * - users → Users management (protected, admin only, accessible at /auth/users)\n * - profile → User profile page (protected, accessible at /auth/profile)\n * - audit-log → Security audit log (protected, accessible at /auth/audit-log)\n * - sso → SSO configuration (protected, admin only, accessible at /auth/sso)\n */\nexport function AuthRoutes({\n basePath: _basePath = \"\",\n // Admin routes (`/auth/users`, `/auth/users/:id`, `/auth/sso`,\n // `/auth/audit-log`) are opt-in: only the admin app shell should pass\n // `enableAdminRoutes={true}`. User-facing product hosts (vibecontrols,\n // workspaces, botlit, healthybowl, etc.) intentionally do not expose\n // these surfaces — the gateway's RBAC directives still gate the\n // underlying queries/mutations, but hiding the routes prevents\n // accidental UI discoverability and reduces the attack surface for\n // misconfigured permissions.\n enableAdminRoutes = false,\n bypassEnterprisePlanGate = false,\n}: {\n basePath?: string;\n enableAdminRoutes?: boolean;\n bypassEnterprisePlanGate?: boolean;\n}) {\n // Note: basePath is kept for backwards compatibility but not used in route paths\n // since React Router v7 uses relative paths when nested inside a parent <Route>\n const auditLogFlag = useFeatureFlagDetails(\"auth.audit-log\");\n const showAuditLog = auditLogFlag?.value === true;\n return (\n <Routes>\n {/* Public routes (no auth required) */}\n {/* LoginPage is eager-loaded as it's the most common entry point */}\n <Route path=\"login\" element={<LoginPage />} />\n <Route\n path=\"register\"\n element={\n <Suspense fallback={<PageLoader />}>\n <RegisterPage />\n </Suspense>\n }\n />\n {/* \"signup\" is the URL most people guess (it's the term this app's own\n copy uses — \"Create your account\" / sign up), but the route has\n always been \"register\" with nothing to catch the alias — it silently\n rendered a blank page. Redirect rather than rename register itself,\n since register is the established/linked path. */}\n <Route path=\"signup\" element={<Navigate to=\"/auth/register\" replace />} />\n <Route\n path=\"reset-password\"\n element={\n <Suspense fallback={<PageLoader />}>\n <PasswordResetPage />\n </Suspense>\n }\n />\n <Route\n path=\"verify-email\"\n element={\n <Suspense fallback={<PageLoader />}>\n <EmailVerifyPage />\n </Suspense>\n }\n />\n <Route\n path=\"mfa-verify\"\n element={\n <Suspense fallback={<PageLoader />}>\n <MfaVerifyPage />\n </Suspense>\n }\n />\n <Route\n path=\"magic-link\"\n element={\n <Suspense fallback={<PageLoader />}>\n <MagicLinkPage />\n </Suspense>\n }\n />\n\n {/* SSO routes (public) */}\n <Route\n path=\"sso/login\"\n element={\n <Suspense fallback={<PageLoader />}>\n <SsoLoginPage />\n </Suspense>\n }\n />\n <Route\n path=\"sso/callback\"\n element={\n <Suspense fallback={<PageLoader />}>\n <SsoCallbackPage />\n </Suspense>\n }\n />\n\n {/* OAuth callback route (public) */}\n <Route\n path=\"oauth/callback\"\n element={\n <Suspense fallback={<PageLoader />}>\n <OAuthCallbackPage />\n </Suspense>\n }\n />\n\n {/* Account reactivation (public) */}\n <Route\n path=\"reactivate\"\n element={\n <Suspense fallback={<PageLoader />}>\n <ReactivatePage />\n </Suspense>\n }\n />\n\n {/* Session bridge (public - embedded as hidden iframe by other app shells) */}\n <Route path=\"session-bridge\" element={<SessionBridgePage />} />\n\n {/* Cross-domain SSO relay (reads local tokens, redirects with them to target) */}\n <Route path=\"sso-relay\" element={<SSORelayPage />} />\n\n {/* Cross-domain SSO callback (receives tokens from relay, stores locally) */}\n <Route path=\"sso-callback\" element={<SSORelayCallbackPage />} />\n\n {/* Cross-domain SSO deposit (bridge host receives tokens on top-level\n redirect right after login on a product origin, writes first-party\n localStorage on the bridge origin so other products can discover\n the session). */}\n <Route path=\"sso-deposit\" element={<SSODepositPage />} />\n\n {/* Cross-domain SLO clear (bridge host clears its central session on\n top-level redirect from a product origin's logout). */}\n <Route path=\"sso-clear\" element={<SSOClearPage />} />\n\n {/* Protected routes (auth required) */}\n <Route\n path=\"security\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.security\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <SecurityPage enableAdminRoutes={enableAdminRoutes} />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n <Route\n path=\"sessions\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.sessions\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <SessionsPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n <Route\n path=\"mfa\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.mfa\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <MfaSetupPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n {enableAdminRoutes && showAuditLog && (\n <Route\n path=\"audit-log\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.audit-log\" defaultValue={false}>\n <Suspense fallback={<PageLoader />}>\n <AuditLogPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n )}\n {!enableAdminRoutes && (\n <Route\n path=\"audit-log\"\n element={<Navigate to=\"/auth/login\" replace />}\n />\n )}\n <Route\n path=\"sso\"\n element={\n enableAdminRoutes ? (\n <ProtectedRoute>\n <FeatureGate flag=\"auth.sso\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <SsoConfigPage\n bypassEnterprisePlanGate={bypassEnterprisePlanGate}\n />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n ) : (\n <Navigate to=\"/auth/login\" replace />\n )\n }\n />\n <Route\n path=\"users\"\n element={\n enableAdminRoutes ? (\n <ProtectedRoute>\n <FeatureGate flag=\"auth.users\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <UsersPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n ) : (\n <Navigate to=\"/auth/login\" replace />\n )\n }\n />\n <Route\n path=\"users/:id\"\n element={\n enableAdminRoutes ? (\n <ProtectedRoute>\n <FeatureGate flag=\"auth.users\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <UserDetailsPage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n ) : (\n <Navigate to=\"/auth/login\" replace />\n )\n }\n />\n <Route\n path=\"profile\"\n element={\n <ProtectedRoute>\n <FeatureGate flag=\"auth.profile\" defaultValue={true}>\n <Suspense fallback={<PageLoader />}>\n <UserProfilePage />\n </Suspense>\n </FeatureGate>\n </ProtectedRoute>\n }\n />\n\n {/* Default redirect - when visiting /auth or /auth/ with no subpath */}\n <Route index element={<Navigate to=\"login\" replace />} />\n </Routes>\n );\n}\n"],"mappings":"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"}
@@ -1,16 +1,15 @@
1
1
  import { SVGProps } from 'react';
2
-
3
2
  type IconProps = SVGProps<SVGSVGElement>;
4
- export declare function EmailIcon(props: IconProps): import("react").JSX.Element;
5
- export declare function LockIcon(props: IconProps): import("react").JSX.Element;
6
- export declare function UserIcon(props: IconProps): import("react").JSX.Element;
7
- export declare function EyeIcon(props: IconProps): import("react").JSX.Element;
8
- export declare function EyeOffIcon(props: IconProps): import("react").JSX.Element;
9
- export declare function CheckIcon(props: IconProps): import("react").JSX.Element;
10
- export declare function XIcon(props: IconProps): import("react").JSX.Element;
11
- export declare function AlertIcon(props: IconProps): import("react").JSX.Element;
12
- export declare function SpinnerIcon(props: IconProps): import("react").JSX.Element;
13
- export declare function GoogleIcon(props: IconProps): import("react").JSX.Element;
14
- export declare function GitHubIcon(props: IconProps): import("react").JSX.Element;
15
- export declare function MicrosoftIcon(props: IconProps): import("react").JSX.Element;
3
+ export declare function EmailIcon(props: IconProps): import('react').JSX.Element;
4
+ export declare function LockIcon(props: IconProps): import('react').JSX.Element;
5
+ export declare function UserIcon(props: IconProps): import('react').JSX.Element;
6
+ export declare function EyeIcon(props: IconProps): import('react').JSX.Element;
7
+ export declare function EyeOffIcon(props: IconProps): import('react').JSX.Element;
8
+ export declare function CheckIcon(props: IconProps): import('react').JSX.Element;
9
+ export declare function XIcon(props: IconProps): import('react').JSX.Element;
10
+ export declare function AlertIcon(props: IconProps): import('react').JSX.Element;
11
+ export declare function SpinnerIcon(props: IconProps): import('react').JSX.Element;
12
+ export declare function GoogleIcon(props: IconProps): import('react').JSX.Element;
13
+ export declare function GitHubIcon(props: IconProps): import('react').JSX.Element;
14
+ export declare function MicrosoftIcon(props: IconProps): import('react').JSX.Element;
16
15
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"AuthIcons.js","names":[],"sources":["../../../src/auth/components/AuthIcons.tsx"],"sourcesContent":["import type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nexport function EmailIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75\"\n />\n </svg>\n );\n}\n\nexport function LockIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z\"\n />\n </svg>\n );\n}\n\nexport function UserIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z\"\n />\n </svg>\n );\n}\n\nexport function EyeIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n );\n}\n\nexport function EyeOffIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88\"\n />\n </svg>\n );\n}\n\nexport function CheckIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M4.5 12.75l6 6 9-13.5\"\n />\n </svg>\n );\n}\n\nexport function XIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n );\n}\n\nexport function AlertIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\"\n />\n </svg>\n );\n}\n\nexport function SpinnerIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" {...props}>\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n );\n}\n\n// OAuth Provider Icons\nexport function GoogleIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" {...props}>\n <path\n fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n />\n </svg>\n );\n}\n\nexport function GitHubIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n );\n}\n\nexport function MicrosoftIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" {...props}>\n <path fill=\"#F25022\" d=\"M1 1h10v10H1z\" />\n <path fill=\"#00A4EF\" d=\"M1 13h10v10H1z\" />\n <path fill=\"#7FBA00\" d=\"M13 1h10v10H13z\" />\n <path fill=\"#FFB900\" d=\"M13 13h10v10H13z\" />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AuthIcons.js","names":[],"sources":["../../../src/auth/components/AuthIcons.tsx"],"sourcesContent":["import type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nexport function EmailIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75\"\n />\n </svg>\n );\n}\n\nexport function LockIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z\"\n />\n </svg>\n );\n}\n\nexport function UserIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z\"\n />\n </svg>\n );\n}\n\nexport function EyeIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n );\n}\n\nexport function EyeOffIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88\"\n />\n </svg>\n );\n}\n\nexport function CheckIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M4.5 12.75l6 6 9-13.5\"\n />\n </svg>\n );\n}\n\nexport function XIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n );\n}\n\nexport function AlertIcon(props: IconProps) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n {...props}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\"\n />\n </svg>\n );\n}\n\nexport function SpinnerIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" {...props}>\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n );\n}\n\n// OAuth Provider Icons\nexport function GoogleIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" {...props}>\n <path\n fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n />\n </svg>\n );\n}\n\nexport function GitHubIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <path d=\"M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z\" />\n </svg>\n );\n}\n\nexport function MicrosoftIcon(props: IconProps) {\n return (\n <svg viewBox=\"0 0 24 24\" {...props}>\n <path fill=\"#F25022\" d=\"M1 1h10v10H1z\" />\n <path fill=\"#00A4EF\" d=\"M1 13h10v10H1z\" />\n <path fill=\"#7FBA00\" d=\"M13 1h10v10H13z\" />\n <path fill=\"#FFB900\" d=\"M13 13h10v10H13z\" />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { ReactNode } from 'react';
2
-
3
2
  interface AuthLayoutProps {
4
3
  children: ReactNode;
5
4
  title: string;
@@ -12,5 +11,5 @@ interface AuthLayoutProps {
12
11
  * Left side: Branding with gradient background
13
12
  * Right side: Auth form
14
13
  */
15
- export declare function AuthLayout({ children, title, subtitle, productName, tagline, }: AuthLayoutProps): import("react").JSX.Element;
14
+ export declare function AuthLayout({ children, title, subtitle, productName, tagline, }: AuthLayoutProps): import('react').JSX.Element;
16
15
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"AuthLayout.js","names":[],"sources":["../../../src/auth/components/AuthLayout.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { LanguageSwitcher } from \"@burdenoff/fe-libs/chrome\";\nimport type { Language } from \"@burdenoff/fe-libs/chrome\";\nimport {\n useI18n,\n useAppShell,\n} from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport type { Locale } from \"@burdenoff/fe-libs/shared/providers/shell\";\n\ninterface AuthLayoutProps {\n children: ReactNode;\n title: string;\n subtitle: string;\n productName?: string;\n tagline?: string;\n}\n\n/**\n * Supported languages for the auth pages.\n *\n * Must stay in sync with the locales actually seeded in\n * `i18n_translations` for the consumer products that mount microfe-auth.\n * If a locale is listed here but NOT seeded, selecting it sets\n * `setLocale(<code>)` on the I18nProvider, the next `exportTranslations`\n * call returns zero rows, every `tr()` falls back to its English default,\n * and the user gets an English UI under a non-English flag.\n *\n * Audited 2026-05-31 against alpha `i18n_translations`: only `en/ta/hi/\n * zh/es/ar` have actual translations (vibecontrols 40k+ rows each).\n * `fr` was previously listed but no product seeds it — selecting it\n * produced a half-translated UI. Removed for parity with the dashboard\n * `LanguageSwitcherSlot` (which is data-driven from `i18n_languages`).\n *\n * Adding a new locale requires updating BOTH:\n * - this list\n * - each consumer product's seed (e.g. vibecontrols-app/scripts/\n * build-i18n-bundle.ts + the new `<code>.ts` translation source).\n */\nconst AUTH_LANGUAGES: Language[] = [\n { code: \"en\", name: \"English\", nativeName: \"English\", flag: \"🇺🇸\" },\n { code: \"ta\", name: \"Tamil\", nativeName: \"தமிழ்\", flag: \"🇮🇳\" },\n { code: \"hi\", name: \"Hindi\", nativeName: \"हिन्दी\", flag: \"🇮🇳\" },\n { code: \"zh\", name: \"Chinese\", nativeName: \"中文\", flag: \"🇨🇳\" },\n { code: \"es\", name: \"Spanish\", nativeName: \"Español\", flag: \"🇪🇸\" },\n { code: \"ar\", name: \"Arabic\", nativeName: \"العربية\", flag: \"🇸🇦\" },\n];\n\n/**\n * Brand logo for the auth pages.\n *\n * Renders the host app shell's real product logo served at `/icons/icon.svg`\n * (the same asset the marketing landing page uses) so the login screen and the\n * landing page show an identical mark instead of a generic placeholder glyph.\n * Host shells that don't ship that asset (e.g. admin-app) fall back to a\n * branded initial badge rather than a broken image.\n */\nfunction BrandLogo({ brandInitial }: { brandInitial: string }) {\n const [failed, setFailed] = useState(false);\n\n if (failed) {\n return (\n <div className=\"auth-brand-badge flex size-10 items-center justify-center rounded-xl\">\n <span className=\"text-lg font-bold leading-none text-white\">\n {brandInitial}\n </span>\n </div>\n );\n }\n\n return (\n <img\n src=\"/icons/icon.svg\"\n alt=\"\"\n aria-hidden=\"true\"\n className=\"size-10 rounded-xl object-contain\"\n onError={() => setFailed(true)}\n />\n );\n}\n\n/**\n * Professional auth layout with split-screen design\n * Left side: Branding with gradient background\n * Right side: Auth form\n */\nexport function AuthLayout({\n children,\n title,\n subtitle,\n productName,\n tagline,\n}: AuthLayoutProps) {\n const tr = useTr();\n const shell = useAppShell();\n const displayName = productName || shell.productName || \"Burdenoff\";\n const brandInitial = shell.brandInitial || \"B\";\n const displayTagline = tagline || shell.tagline || \"Enterprise platform\";\n const { locale, setLocale } = useI18n();\n\n const handleLanguageChange = (language: Language) => {\n // AUTH_LANGUAGES intentionally lists locales (e.g. \"ar\") that are seeded\n // in consumer products but not yet present in the fe-libs Locale union.\n // The runtime I18nProvider accepts any locale code, so we cast through\n // unknown to Locale to keep the picker in parity until fe-libs widens the\n // union. Keep AUTH_LANGUAGES in sync with consumer product seeds.\n setLocale(language.code as unknown as Locale);\n };\n\n return (\n <div className=\"min-h-screen flex relative\">\n {/* Left Panel - Branding */}\n <div className=\"auth-brand-panel hidden overflow-hidden lg:flex lg:w-1/2 relative\">\n {/* Decorative Elements */}\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"absolute -top-40 -left-40 size-80 rounded-full bg-accent-blue/20 blur-3xl\" />\n <div className=\"absolute top-1/2 -right-20 size-96 rounded-full bg-accent-indigo/20 blur-3xl\" />\n <div className=\"absolute -bottom-40 left-1/4 size-72 rounded-full bg-accent-purple/20 blur-3xl\" />\n\n {/* Grid Pattern */}\n <div\n className=\"absolute inset-0 opacity-5\"\n style={{\n backgroundImage: `url(\"data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='1'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\")`,\n }}\n />\n </div>\n\n {/* Content */}\n <div className=\"relative z-10 flex flex-col justify-between p-12 w-full\">\n {/* Logo */}\n <div className=\"flex items-center gap-3\">\n <BrandLogo brandInitial={brandInitial} />\n <span className=\"text-xl font-bold text-[var(--color-text-primary)]\">\n {displayName}\n </span>\n </div>\n\n {/* Main Content */}\n <div className=\"max-w-md\">\n <h1 className=\"mb-4 text-4xl font-bold leading-tight text-[var(--color-text-primary)]\">\n {displayTagline}\n </h1>\n <p className=\"auth-brand-copy text-lg leading-relaxed\">\n {tr(\n \"auth.layout.taglineDescription\",\n \"Unify your teams, projects, and workflows in one intelligent workspace. Built for scale with enterprise-grade security, real-time collaboration, and seamless integrations across your entire organization.\",\n )}\n </p>\n\n {/* Features */}\n <div className=\"mt-10 space-y-4\">\n {[\n {\n icon: \"workspace\",\n text: tr(\n \"auth.layout.featureWorkspace\",\n \"Modular workspace architecture\",\n ),\n },\n {\n icon: \"realtime\",\n text: tr(\n \"auth.layout.featureRealtime\",\n \"Real-time collaboration & sync\",\n ),\n },\n {\n icon: \"security\",\n text: tr(\n \"auth.layout.featureSecurity\",\n \"Enterprise-grade security & SSO\",\n ),\n },\n {\n icon: \"scale\",\n text: tr(\n \"auth.layout.featureScale\",\n \"Unlimited scalability & performance\",\n ),\n },\n ].map((feature) => (\n <div key={feature.icon} className=\"flex items-center gap-3\">\n <div className=\"auth-highlight-chip flex size-8 items-center justify-center rounded-lg\">\n {feature.icon === \"workspace\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\"\n />\n </svg>\n )}\n {feature.icon === \"realtime\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z\"\n />\n </svg>\n )}\n {feature.icon === \"security\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z\"\n />\n </svg>\n )}\n {feature.icon === \"scale\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n )}\n </div>\n <span className=\"auth-brand-copy text-sm font-medium\">\n {feature.text}\n </span>\n </div>\n ))}\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"auth-brand-copy-muted text-sm\">\n © {new Date().getFullYear()} Burdenoff. All rights reserved.\n </div>\n </div>\n </div>\n\n {/* Right Panel - Form */}\n <main className=\"auth-shell-gradient relative flex flex-1 items-center justify-center bg-[var(--color-bg-canvas)] p-6 sm:p-12\">\n {/* Language Switcher - Top Right */}\n <div className=\"absolute top-4 right-4 sm:top-6 sm:right-6 z-10\">\n <LanguageSwitcher\n languages={AUTH_LANGUAGES}\n currentLanguage={locale}\n onLanguageChange={handleLanguageChange}\n />\n </div>\n <div className=\"w-full max-w-md\">\n {/* Mobile Logo */}\n <div className=\"lg:hidden flex items-center justify-center gap-3 mb-8\">\n <BrandLogo brandInitial={brandInitial} />\n <span className=\"text-xl font-bold text-[var(--color-text-primary)]\">\n {displayName}\n </span>\n </div>\n\n {/* Header */}\n <div className=\"text-center lg:text-left mb-8\">\n <h2 className=\"text-2xl sm:text-3xl font-bold text-[var(--color-text-primary)] mb-2\">\n {title}\n </h2>\n <p className=\"text-[var(--color-text-secondary)]\">{subtitle}</p>\n </div>\n\n {/* Form Content */}\n {children}\n </div>\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AuthLayout.js","names":[],"sources":["../../../src/auth/components/AuthLayout.tsx"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\nimport { LanguageSwitcher } from \"@burdenoff/fe-libs/chrome\";\nimport type { Language } from \"@burdenoff/fe-libs/chrome\";\nimport {\n useI18n,\n useAppShell,\n} from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport type { Locale } from \"@burdenoff/fe-libs/shared/providers/shell\";\n\ninterface AuthLayoutProps {\n children: ReactNode;\n title: string;\n subtitle: string;\n productName?: string;\n tagline?: string;\n}\n\n/**\n * Supported languages for the auth pages.\n *\n * Must stay in sync with the locales actually seeded in\n * `i18n_translations` for the consumer products that mount microfe-auth.\n * If a locale is listed here but NOT seeded, selecting it sets\n * `setLocale(<code>)` on the I18nProvider, the next `exportTranslations`\n * call returns zero rows, every `tr()` falls back to its English default,\n * and the user gets an English UI under a non-English flag.\n *\n * Audited 2026-05-31 against alpha `i18n_translations`: only `en/ta/hi/\n * zh/es/ar` have actual translations (vibecontrols 40k+ rows each).\n * `fr` was previously listed but no product seeds it — selecting it\n * produced a half-translated UI. Removed for parity with the dashboard\n * `LanguageSwitcherSlot` (which is data-driven from `i18n_languages`).\n *\n * Adding a new locale requires updating BOTH:\n * - this list\n * - each consumer product's seed (e.g. vibecontrols-app/scripts/\n * build-i18n-bundle.ts + the new `<code>.ts` translation source).\n */\nconst AUTH_LANGUAGES: Language[] = [\n { code: \"en\", name: \"English\", nativeName: \"English\", flag: \"🇺🇸\" },\n { code: \"ta\", name: \"Tamil\", nativeName: \"தமிழ்\", flag: \"🇮🇳\" },\n { code: \"hi\", name: \"Hindi\", nativeName: \"हिन्दी\", flag: \"🇮🇳\" },\n { code: \"zh\", name: \"Chinese\", nativeName: \"中文\", flag: \"🇨🇳\" },\n { code: \"es\", name: \"Spanish\", nativeName: \"Español\", flag: \"🇪🇸\" },\n { code: \"ar\", name: \"Arabic\", nativeName: \"العربية\", flag: \"🇸🇦\" },\n];\n\n/**\n * Brand logo for the auth pages.\n *\n * Renders the host app shell's real product logo served at `/icons/icon.svg`\n * (the same asset the marketing landing page uses) so the login screen and the\n * landing page show an identical mark instead of a generic placeholder glyph.\n * Host shells that don't ship that asset (e.g. admin-app) fall back to a\n * branded initial badge rather than a broken image.\n */\nfunction BrandLogo({ brandInitial }: { brandInitial: string }) {\n const [failed, setFailed] = useState(false);\n\n if (failed) {\n return (\n <div className=\"auth-brand-badge flex size-10 items-center justify-center rounded-xl\">\n <span className=\"text-lg font-bold leading-none text-white\">\n {brandInitial}\n </span>\n </div>\n );\n }\n\n return (\n <img\n src=\"/icons/icon.svg\"\n alt=\"\"\n aria-hidden=\"true\"\n className=\"size-10 rounded-xl object-contain\"\n onError={() => setFailed(true)}\n />\n );\n}\n\n/**\n * Professional auth layout with split-screen design\n * Left side: Branding with gradient background\n * Right side: Auth form\n */\nexport function AuthLayout({\n children,\n title,\n subtitle,\n productName,\n tagline,\n}: AuthLayoutProps) {\n const tr = useTr();\n const shell = useAppShell();\n const displayName = productName || shell.productName || \"Burdenoff\";\n const brandInitial = shell.brandInitial || \"B\";\n const displayTagline = tagline || shell.tagline || \"Enterprise platform\";\n const { locale, setLocale } = useI18n();\n\n const handleLanguageChange = (language: Language) => {\n // AUTH_LANGUAGES intentionally lists locales (e.g. \"ar\") that are seeded\n // in consumer products but not yet present in the fe-libs Locale union.\n // The runtime I18nProvider accepts any locale code, so we cast through\n // unknown to Locale to keep the picker in parity until fe-libs widens the\n // union. Keep AUTH_LANGUAGES in sync with consumer product seeds.\n setLocale(language.code as unknown as Locale);\n };\n\n return (\n <div className=\"min-h-screen flex relative\">\n {/* Left Panel - Branding */}\n <div className=\"auth-brand-panel hidden overflow-hidden lg:flex lg:w-1/2 relative\">\n {/* Decorative Elements */}\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"absolute -top-40 -left-40 size-80 rounded-full bg-accent-blue/20 blur-3xl\" />\n <div className=\"absolute top-1/2 -right-20 size-96 rounded-full bg-accent-indigo/20 blur-3xl\" />\n <div className=\"absolute -bottom-40 left-1/4 size-72 rounded-full bg-accent-purple/20 blur-3xl\" />\n\n {/* Grid Pattern */}\n <div\n className=\"absolute inset-0 opacity-5\"\n style={{\n backgroundImage: `url(\"data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='1'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\")`,\n }}\n />\n </div>\n\n {/* Content */}\n <div className=\"relative z-10 flex flex-col justify-between p-12 w-full\">\n {/* Logo */}\n <div className=\"flex items-center gap-3\">\n <BrandLogo brandInitial={brandInitial} />\n <span className=\"text-xl font-bold text-[var(--color-text-primary)]\">\n {displayName}\n </span>\n </div>\n\n {/* Main Content */}\n <div className=\"max-w-md\">\n <h1 className=\"mb-4 text-4xl font-bold leading-tight text-[var(--color-text-primary)]\">\n {displayTagline}\n </h1>\n <p className=\"auth-brand-copy text-lg leading-relaxed\">\n {tr(\n \"auth.layout.taglineDescription\",\n \"Unify your teams, projects, and workflows in one intelligent workspace. Built for scale with enterprise-grade security, real-time collaboration, and seamless integrations across your entire organization.\",\n )}\n </p>\n\n {/* Features */}\n <div className=\"mt-10 space-y-4\">\n {[\n {\n icon: \"workspace\",\n text: tr(\n \"auth.layout.featureWorkspace\",\n \"Modular workspace architecture\",\n ),\n },\n {\n icon: \"realtime\",\n text: tr(\n \"auth.layout.featureRealtime\",\n \"Real-time collaboration & sync\",\n ),\n },\n {\n icon: \"security\",\n text: tr(\n \"auth.layout.featureSecurity\",\n \"Enterprise-grade security & SSO\",\n ),\n },\n {\n icon: \"scale\",\n text: tr(\n \"auth.layout.featureScale\",\n \"Unlimited scalability & performance\",\n ),\n },\n ].map((feature) => (\n <div key={feature.icon} className=\"flex items-center gap-3\">\n <div className=\"auth-highlight-chip flex size-8 items-center justify-center rounded-lg\">\n {feature.icon === \"workspace\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\"\n />\n </svg>\n )}\n {feature.icon === \"realtime\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z\"\n />\n </svg>\n )}\n {feature.icon === \"security\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z\"\n />\n </svg>\n )}\n {feature.icon === \"scale\" && (\n <svg\n className=\"size-4 text-accent-blue\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n )}\n </div>\n <span className=\"auth-brand-copy text-sm font-medium\">\n {feature.text}\n </span>\n </div>\n ))}\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"auth-brand-copy-muted text-sm\">\n © {new Date().getFullYear()} Burdenoff. All rights reserved.\n </div>\n </div>\n </div>\n\n {/* Right Panel - Form */}\n <main className=\"auth-shell-gradient relative flex flex-1 items-center justify-center bg-[var(--color-bg-canvas)] p-6 sm:p-12\">\n {/* Language Switcher - Top Right */}\n <div className=\"absolute top-4 right-4 sm:top-6 sm:right-6 z-10\">\n <LanguageSwitcher\n languages={AUTH_LANGUAGES}\n currentLanguage={locale}\n onLanguageChange={handleLanguageChange}\n />\n </div>\n <div className=\"w-full max-w-md\">\n {/* Mobile Logo */}\n <div className=\"lg:hidden flex items-center justify-center gap-3 mb-8\">\n <BrandLogo brandInitial={brandInitial} />\n <span className=\"text-xl font-bold text-[var(--color-text-primary)]\">\n {displayName}\n </span>\n </div>\n\n {/* Header */}\n <div className=\"text-center lg:text-left mb-8\">\n <h2 className=\"text-2xl sm:text-3xl font-bold text-[var(--color-text-primary)] mb-2\">\n {title}\n </h2>\n <p className=\"text-[var(--color-text-secondary)]\">{subtitle}</p>\n </div>\n\n {/* Form Content */}\n {children}\n </div>\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -21,5 +21,5 @@ interface CaptchaV2Props {
21
21
  * build-time `VITE_CAPTCHA_ENABLED` env for local source-dev. Renders nothing
22
22
  * when disabled and lazily loads the Google reCAPTCHA library only when enabled.
23
23
  */
24
- export declare function CaptchaV2({ onVerify, onExpired, enabled, siteKey, }: CaptchaV2Props): import("react").JSX.Element | null;
24
+ export declare function CaptchaV2({ onVerify, onExpired, enabled, siteKey, }: CaptchaV2Props): import('react').JSX.Element | null;
25
25
  export {};
@@ -3,8 +3,8 @@ import { useTr as n } from "../../shared/hooks/useTr.js";
3
3
  import { Suspense as r, lazy as i, useCallback as a, useState as o } from "react";
4
4
  import { jsx as s } from "react/jsx-runtime";
5
5
  //#region src/auth/components/CaptchaV2.tsx
6
- var c = i(() => import("../../node_modules/react-google-recaptcha/lib/esm/index.js").then((t) => ({ default: function({ onVerify: r, onExpired: i, siteKey: c }) {
7
- let l = n(), u = t.default, [, d] = o(null), f = c ?? e(), p = a((e) => {
6
+ var c = i(() => import("react-google-recaptcha").then((t) => ({ default: function({ onVerify: r, onExpired: i, siteKey: c }) {
7
+ let l = n(), u = t.default, [, d] = o(null), f = c ?? /* @__PURE__ */ e(), p = a((e) => {
8
8
  r(e);
9
9
  }, [r]), m = a(() => {
10
10
  r(null), i?.();
@@ -1 +1 @@
1
- {"version":3,"file":"CaptchaV2.js","names":[],"sources":["../../../src/auth/components/CaptchaV2.tsx"],"sourcesContent":["import { lazy, Suspense, useState, useCallback } from \"react\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport {\n getRecaptchaSiteKey,\n isCaptchaEnabled as getIsCaptchaEnabled,\n} from \"../utils/captchaConfig\";\n\ninterface CaptchaV2Props {\n onVerify: (token: string | null) => void;\n onExpired?: () => void;\n /**\n * Host-driven enable flag. When provided it takes precedence over the\n * build-time env switch (used so a per-product site key can turn the widget\n * on/off without rebuilding). When omitted, falls back to env.\n */\n enabled?: boolean;\n /**\n * reCAPTCHA v2 site key to render with. Overrides the build-time env key.\n * Resolved per-product by the caller (see `useSignupCaptcha`).\n */\n siteKey?: string;\n}\n\ninterface CaptchaWidgetProps {\n onVerify: (token: string | null) => void;\n onExpired?: () => void;\n siteKey?: string;\n}\n\n/**\n * Lazily loaded inner component that imports react-google-recaptcha.\n * Only loaded when captcha is enabled, avoiding import resolution\n * errors in dev environments where the package may not be installed.\n */\nconst LazyCaptchaWidget = lazy(() =>\n import(\"react-google-recaptcha\").then((mod) => ({\n default: function CaptchaWidget({\n onVerify,\n onExpired,\n siteKey: siteKeyProp,\n }: CaptchaWidgetProps) {\n const tr = useTr();\n const ReCAPTCHA = mod.default;\n const [, setRef] = useState<InstanceType<typeof ReCAPTCHA> | null>(null);\n const siteKey = siteKeyProp ?? getRecaptchaSiteKey();\n\n const forwardCaptchaToken = useCallback(\n (token: string | null) => {\n onVerify(token);\n },\n [onVerify],\n );\n\n const clearCaptchaToken = useCallback(() => {\n onVerify(null);\n onExpired?.();\n }, [onVerify, onExpired]);\n\n if (!siteKey) {\n return (\n <div className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {tr(\n \"auth.captcha.siteKeyMissing\",\n \"reCAPTCHA site key is not configured.\",\n )}\n </div>\n );\n }\n\n return (\n <div className=\"flex justify-center\">\n <ReCAPTCHA\n ref={setRef}\n sitekey={siteKey}\n onChange={forwardCaptchaToken}\n onExpired={clearCaptchaToken}\n />\n </div>\n );\n },\n })),\n);\n\n/**\n * reCAPTCHA v2 checkbox component.\n *\n * Enablement is host-driven via the `enabled` prop (resolved per-product from\n * the platform catalog). When `enabled` is omitted it falls back to the\n * build-time `VITE_CAPTCHA_ENABLED` env for local source-dev. Renders nothing\n * when disabled and lazily loads the Google reCAPTCHA library only when enabled.\n */\nexport function CaptchaV2({\n onVerify,\n onExpired,\n enabled,\n siteKey,\n}: CaptchaV2Props) {\n const tr = useTr();\n\n const isEnabled = enabled ?? getIsCaptchaEnabled();\n if (!isEnabled) {\n return null;\n }\n\n return (\n <Suspense\n fallback={\n <div className=\"flex justify-center py-2\">\n {tr(\"auth.captcha.loading\", \"Loading captcha...\")}\n </div>\n }\n >\n <LazyCaptchaWidget\n onVerify={onVerify}\n onExpired={onExpired}\n siteKey={siteKey}\n />\n </Suspense>\n );\n}\n"],"mappings":";;;;;AAkCA,IAAM,IAAoB,QACxB,OAAO,8DAA0B,MAAM,OAAS,EAC9C,SAAS,SAAuB,EAC9B,aACA,cACA,SAAS,KACY;CACrB,IAAM,IAAK,GAAO,EACZ,IAAY,EAAI,SAChB,GAAG,KAAU,EAAgD,KAAK,EAClE,IAAU,KAAe,GAAqB,EAE9C,IAAsB,GACzB,MAAyB;AACxB,IAAS,EAAM;IAEjB,CAAC,EAAS,CACX,EAEK,IAAoB,QAAkB;AAE1C,EADA,EAAS,KAAK,EACd,KAAa;IACZ,CAAC,GAAU,EAAU,CAAC;AAazB,QAXK,IAYH,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,KAAK;GACL,SAAS;GACT,UAAU;GACV,WAAW;GACX,CAAA;EACE,CAAA,GAjBJ,kBAAC,OAAD;EAAK,WAAU;YACZ,EACC,+BACA,wCACD;EACG,CAAA;GAeb,EAAE,CACJ;AAUD,SAAgB,EAAU,EACxB,aACA,cACA,YACA,cACiB;CACjB,IAAM,IAAK,GAAO;AAOlB,QALkB,KAAW,GAAqB,GAMhD,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,wBAAwB,qBAAqB;GAC7C,CAAA;YAGR,kBAAC,GAAD;GACY;GACC;GACF;GACT,CAAA;EACO,CAAA,GAhBJ"}
1
+ {"version":3,"file":"CaptchaV2.js","names":[],"sources":["../../../src/auth/components/CaptchaV2.tsx"],"sourcesContent":["import { lazy, Suspense, useState, useCallback } from \"react\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport {\n getRecaptchaSiteKey,\n isCaptchaEnabled as getIsCaptchaEnabled,\n} from \"../utils/captchaConfig\";\n\ninterface CaptchaV2Props {\n onVerify: (token: string | null) => void;\n onExpired?: () => void;\n /**\n * Host-driven enable flag. When provided it takes precedence over the\n * build-time env switch (used so a per-product site key can turn the widget\n * on/off without rebuilding). When omitted, falls back to env.\n */\n enabled?: boolean;\n /**\n * reCAPTCHA v2 site key to render with. Overrides the build-time env key.\n * Resolved per-product by the caller (see `useSignupCaptcha`).\n */\n siteKey?: string;\n}\n\ninterface CaptchaWidgetProps {\n onVerify: (token: string | null) => void;\n onExpired?: () => void;\n siteKey?: string;\n}\n\n/**\n * Lazily loaded inner component that imports react-google-recaptcha.\n * Only loaded when captcha is enabled, avoiding import resolution\n * errors in dev environments where the package may not be installed.\n */\nconst LazyCaptchaWidget = lazy(() =>\n import(\"react-google-recaptcha\").then((mod) => ({\n default: function CaptchaWidget({\n onVerify,\n onExpired,\n siteKey: siteKeyProp,\n }: CaptchaWidgetProps) {\n const tr = useTr();\n const ReCAPTCHA = mod.default;\n const [, setRef] = useState<InstanceType<typeof ReCAPTCHA> | null>(null);\n const siteKey = siteKeyProp ?? getRecaptchaSiteKey();\n\n const forwardCaptchaToken = useCallback(\n (token: string | null) => {\n onVerify(token);\n },\n [onVerify],\n );\n\n const clearCaptchaToken = useCallback(() => {\n onVerify(null);\n onExpired?.();\n }, [onVerify, onExpired]);\n\n if (!siteKey) {\n return (\n <div className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {tr(\n \"auth.captcha.siteKeyMissing\",\n \"reCAPTCHA site key is not configured.\",\n )}\n </div>\n );\n }\n\n return (\n <div className=\"flex justify-center\">\n <ReCAPTCHA\n ref={setRef}\n sitekey={siteKey}\n onChange={forwardCaptchaToken}\n onExpired={clearCaptchaToken}\n />\n </div>\n );\n },\n })),\n);\n\n/**\n * reCAPTCHA v2 checkbox component.\n *\n * Enablement is host-driven via the `enabled` prop (resolved per-product from\n * the platform catalog). When `enabled` is omitted it falls back to the\n * build-time `VITE_CAPTCHA_ENABLED` env for local source-dev. Renders nothing\n * when disabled and lazily loads the Google reCAPTCHA library only when enabled.\n */\nexport function CaptchaV2({\n onVerify,\n onExpired,\n enabled,\n siteKey,\n}: CaptchaV2Props) {\n const tr = useTr();\n\n const isEnabled = enabled ?? getIsCaptchaEnabled();\n if (!isEnabled) {\n return null;\n }\n\n return (\n <Suspense\n fallback={\n <div className=\"flex justify-center py-2\">\n {tr(\"auth.captcha.loading\", \"Loading captcha...\")}\n </div>\n }\n >\n <LazyCaptchaWidget\n onVerify={onVerify}\n onExpired={onExpired}\n siteKey={siteKey}\n />\n </Suspense>\n );\n}\n"],"mappings":";;;;;AAkCA,IAAM,IAAoB,QACxB,OAAO,0BAA0B,MAAM,OAAS,EAC9C,SAAS,SAAuB,EAC9B,aACA,cACA,SAAS,KACY;CACrB,IAAM,IAAK,EAAM,GACX,IAAY,EAAI,SAChB,GAAG,KAAU,EAAgD,IAAI,GACjE,IAAU,KAAe,kBAAoB,GAE7C,IAAsB,GACzB,MAAyB;EACxB,EAAS,CAAK;CAChB,GACA,CAAC,CAAQ,CACX,GAEM,IAAoB,QAAkB;EAE1C,AADA,EAAS,IAAI,GACb,IAAY;CACd,GAAG,CAAC,GAAU,CAAS,CAAC;CAaxB,OAXK,IAYH,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,KAAK;GACL,SAAS;GACT,UAAU;GACV,WAAW;EACZ,CAAA;CACE,CAAA,IAjBH,kBAAC,OAAD;EAAK,WAAU;YACZ,EACC,+BACA,uCACF;CACG,CAAA;AAcX,EACF,EAAE,CACJ;AAUA,SAAgB,EAAU,EACxB,aACA,cACA,YACA,cACiB;CACjB,IAAM,IAAK,EAAM;CAOjB,OALkB,KAAW,EAAoB,IAM/C,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,wBAAwB,oBAAoB;EAC7C,CAAA;YAGP,kBAAC,GAAD;GACY;GACC;GACF;EACV,CAAA;CACO,CAAA,IAhBH;AAkBX"}
@@ -11,5 +11,5 @@ interface ConfirmActionDialogProps {
11
11
  disabled?: boolean;
12
12
  onConfirm: () => void | Promise<void>;
13
13
  }
14
- export declare function ConfirmActionDialog({ open, onOpenChange, title, description, confirmText, cancelText, variant, isPending, disabled, onConfirm, }: ConfirmActionDialogProps): import("react").JSX.Element;
14
+ export declare function ConfirmActionDialog({ open, onOpenChange, title, description, confirmText, cancelText, variant, isPending, disabled, onConfirm, }: ConfirmActionDialogProps): import('react').JSX.Element;
15
15
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmActionDialog.js","names":[],"sources":["../../../src/auth/components/ConfirmActionDialog.tsx"],"sourcesContent":["import { AlertCircle, AlertTriangle, Info, Loader2 } from \"lucide-react\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useTr } from \"../../shared/hooks/useTr\";\n\ntype ConfirmActionDialogVariant = \"default\" | \"warning\" | \"danger\";\n\ninterface ConfirmActionDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description: string;\n confirmText?: string;\n cancelText?: string;\n variant?: ConfirmActionDialogVariant;\n isPending?: boolean;\n disabled?: boolean;\n onConfirm: () => void | Promise<void>;\n}\n\nconst VARIANT_STYLES: Record<\n ConfirmActionDialogVariant,\n {\n icon: typeof Info;\n iconContainerClassName: string;\n iconClassName: string;\n actionClassName: string;\n }\n> = {\n default: {\n icon: Info,\n iconContainerClassName: \"bg-[var(--color-status-info-bg-subtle)]\",\n iconClassName: \"text-[var(--color-status-info-text)]\",\n actionClassName:\n \"bg-[var(--color-action-primary-bg)] text-[var(--color-action-primary-text)] hover:opacity-90\",\n },\n warning: {\n icon: AlertTriangle,\n iconContainerClassName: \"bg-[var(--color-status-warning-bg-subtle)]\",\n iconClassName: \"text-[var(--color-status-warning-text)]\",\n actionClassName:\n \"bg-[var(--color-status-warning-bg)] text-[var(--color-text-inverse)] hover:opacity-90\",\n },\n danger: {\n icon: AlertCircle,\n iconContainerClassName: \"bg-[var(--color-status-error-bg-subtle)]\",\n iconClassName: \"text-[var(--color-status-error-text)]\",\n actionClassName:\n \"bg-[var(--color-status-error-bg)] text-[var(--color-text-inverse)] hover:opacity-90\",\n },\n};\n\nexport function ConfirmActionDialog({\n open,\n onOpenChange,\n title,\n description,\n confirmText,\n cancelText,\n variant = \"default\",\n isPending = false,\n disabled = false,\n onConfirm,\n}: ConfirmActionDialogProps) {\n const tr = useTr();\n const resolvedConfirmText =\n confirmText || tr(\"auth.confirmDialog.confirm\", \"Confirm\");\n const resolvedCancelText =\n cancelText || tr(\"auth.confirmDialog.cancel\", \"Cancel\");\n const styles = VARIANT_STYLES[variant];\n const Icon = styles.icon;\n\n return (\n <AlertDialog open={open} onOpenChange={onOpenChange}>\n <AlertDialogContent className=\"max-w-md border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)]\">\n <AlertDialogHeader>\n <div className=\"flex items-start gap-4\">\n <div\n className={`flex size-10 shrink-0 items-center justify-center rounded-full ${styles.iconContainerClassName}`}\n >\n <Icon className={`size-5 ${styles.iconClassName}`} />\n </div>\n <div className=\"flex-1\">\n <AlertDialogTitle className=\"text-lg text-[var(--color-text-primary)]\">\n {title}\n </AlertDialogTitle>\n <AlertDialogDescription className=\"mt-2 text-sm text-[var(--color-text-secondary)]\">\n {description}\n </AlertDialogDescription>\n </div>\n </div>\n </AlertDialogHeader>\n\n <AlertDialogFooter className=\"mt-6\">\n <AlertDialogCancel\n disabled={isPending}\n className=\"border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] hover:bg-[var(--color-bg-subtle)]\"\n >\n {resolvedCancelText}\n </AlertDialogCancel>\n <AlertDialogAction\n disabled={disabled || isPending}\n onClick={(event) => {\n event.preventDefault();\n void onConfirm();\n }}\n className={styles.actionClassName}\n >\n {isPending ? <Loader2 className=\"size-4 animate-spin\" /> : null}\n {resolvedConfirmText}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n}\n"],"mappings":";;;;;AA4BA,IAAM,IAQF;CACF,SAAS;EACP,MAAM;EACN,wBAAwB;EACxB,eAAe;EACf,iBACE;EACH;CACD,SAAS;EACP,MAAM;EACN,wBAAwB;EACxB,eAAe;EACf,iBACE;EACH;CACD,QAAQ;EACN,MAAM;EACN,wBAAwB;EACxB,eAAe;EACf,iBACE;EACH;CACF;AAED,SAAgB,EAAoB,EAClC,SACA,iBACA,UACA,gBACA,gBACA,eACA,aAAU,WACV,eAAY,IACZ,cAAW,IACX,gBAC2B;CAC3B,IAAM,IAAK,GAAO,EACZ,IACJ,KAAe,EAAG,8BAA8B,UAAU,EACtD,IACJ,KAAc,EAAG,6BAA6B,SAAS,EACnD,IAAS,EAAe,IACxB,IAAO,EAAO;AAEpB,QACE,kBAAC,GAAD;EAAmB;EAAoB;YACrC,kBAAC,GAAD;GAAoB,WAAU;aAA9B,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KACE,WAAW,kEAAkE,EAAO;eAEpF,kBAAC,GAAD,EAAM,WAAW,UAAU,EAAO,iBAAmB,CAAA;KACjD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAkB,WAAU;gBACzB;MACgB,CAAA,EACnB,kBAAC,GAAD;MAAwB,WAAU;gBAC/B;MACsB,CAAA,CACrB;OACF;OACY,CAAA,EAEpB,kBAAC,GAAD;IAAmB,WAAU;cAA7B,CACE,kBAAC,GAAD;KACE,UAAU;KACV,WAAU;eAET;KACiB,CAAA,EACpB,kBAAC,GAAD;KACE,UAAU,KAAY;KACtB,UAAU,MAAU;AAEb,MADL,EAAM,gBAAgB,EACjB,GAAW;;KAElB,WAAW,EAAO;eANpB,CAQG,IAAY,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,GAAG,MAC1D,EACiB;OACF;MACD;;EACT,CAAA"}
1
+ {"version":3,"file":"ConfirmActionDialog.js","names":[],"sources":["../../../src/auth/components/ConfirmActionDialog.tsx"],"sourcesContent":["import { AlertCircle, AlertTriangle, Info, Loader2 } from \"lucide-react\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useTr } from \"../../shared/hooks/useTr\";\n\ntype ConfirmActionDialogVariant = \"default\" | \"warning\" | \"danger\";\n\ninterface ConfirmActionDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description: string;\n confirmText?: string;\n cancelText?: string;\n variant?: ConfirmActionDialogVariant;\n isPending?: boolean;\n disabled?: boolean;\n onConfirm: () => void | Promise<void>;\n}\n\nconst VARIANT_STYLES: Record<\n ConfirmActionDialogVariant,\n {\n icon: typeof Info;\n iconContainerClassName: string;\n iconClassName: string;\n actionClassName: string;\n }\n> = {\n default: {\n icon: Info,\n iconContainerClassName: \"bg-[var(--color-status-info-bg-subtle)]\",\n iconClassName: \"text-[var(--color-status-info-text)]\",\n actionClassName:\n \"bg-[var(--color-action-primary-bg)] text-[var(--color-action-primary-text)] hover:opacity-90\",\n },\n warning: {\n icon: AlertTriangle,\n iconContainerClassName: \"bg-[var(--color-status-warning-bg-subtle)]\",\n iconClassName: \"text-[var(--color-status-warning-text)]\",\n actionClassName:\n \"bg-[var(--color-status-warning-bg)] text-[var(--color-text-inverse)] hover:opacity-90\",\n },\n danger: {\n icon: AlertCircle,\n iconContainerClassName: \"bg-[var(--color-status-error-bg-subtle)]\",\n iconClassName: \"text-[var(--color-status-error-text)]\",\n actionClassName:\n \"bg-[var(--color-status-error-bg)] text-[var(--color-text-inverse)] hover:opacity-90\",\n },\n};\n\nexport function ConfirmActionDialog({\n open,\n onOpenChange,\n title,\n description,\n confirmText,\n cancelText,\n variant = \"default\",\n isPending = false,\n disabled = false,\n onConfirm,\n}: ConfirmActionDialogProps) {\n const tr = useTr();\n const resolvedConfirmText =\n confirmText || tr(\"auth.confirmDialog.confirm\", \"Confirm\");\n const resolvedCancelText =\n cancelText || tr(\"auth.confirmDialog.cancel\", \"Cancel\");\n const styles = VARIANT_STYLES[variant];\n const Icon = styles.icon;\n\n return (\n <AlertDialog open={open} onOpenChange={onOpenChange}>\n <AlertDialogContent className=\"max-w-md border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)]\">\n <AlertDialogHeader>\n <div className=\"flex items-start gap-4\">\n <div\n className={`flex size-10 shrink-0 items-center justify-center rounded-full ${styles.iconContainerClassName}`}\n >\n <Icon className={`size-5 ${styles.iconClassName}`} />\n </div>\n <div className=\"flex-1\">\n <AlertDialogTitle className=\"text-lg text-[var(--color-text-primary)]\">\n {title}\n </AlertDialogTitle>\n <AlertDialogDescription className=\"mt-2 text-sm text-[var(--color-text-secondary)]\">\n {description}\n </AlertDialogDescription>\n </div>\n </div>\n </AlertDialogHeader>\n\n <AlertDialogFooter className=\"mt-6\">\n <AlertDialogCancel\n disabled={isPending}\n className=\"border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] hover:bg-[var(--color-bg-subtle)]\"\n >\n {resolvedCancelText}\n </AlertDialogCancel>\n <AlertDialogAction\n disabled={disabled || isPending}\n onClick={(event) => {\n event.preventDefault();\n void onConfirm();\n }}\n className={styles.actionClassName}\n >\n {isPending ? <Loader2 className=\"size-4 animate-spin\" /> : null}\n {resolvedConfirmText}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n}\n"],"mappings":";;;;;AA4BA,IAAM,IAQF;CACF,SAAS;EACP,MAAM;EACN,wBAAwB;EACxB,eAAe;EACf,iBACE;CACJ;CACA,SAAS;EACP,MAAM;EACN,wBAAwB;EACxB,eAAe;EACf,iBACE;CACJ;CACA,QAAQ;EACN,MAAM;EACN,wBAAwB;EACxB,eAAe;EACf,iBACE;CACJ;AACF;AAEA,SAAgB,EAAoB,EAClC,SACA,iBACA,UACA,gBACA,gBACA,eACA,aAAU,WACV,eAAY,IACZ,cAAW,IACX,gBAC2B;CAC3B,IAAM,IAAK,EAAM,GACX,IACJ,KAAe,EAAG,8BAA8B,SAAS,GACrD,IACJ,KAAc,EAAG,6BAA6B,QAAQ,GAClD,IAAS,EAAe,IACxB,IAAO,EAAO;CAEpB,OACE,kBAAC,GAAD;EAAmB;EAAoB;YACrC,kBAAC,GAAD;GAAoB,WAAU;aAA9B,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KACE,WAAW,kEAAkE,EAAO;eAEpF,kBAAC,GAAD,EAAM,WAAW,UAAU,EAAO,gBAAkB,CAAA;IACjD,CAAA,GACL,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAkB,WAAU;gBACzB;KACe,CAAA,GAClB,kBAAC,GAAD;MAAwB,WAAU;gBAC/B;KACqB,CAAA,CACrB;MACF;MACY,CAAA,GAEnB,kBAAC,GAAD;IAAmB,WAAU;cAA7B,CACE,kBAAC,GAAD;KACE,UAAU;KACV,WAAU;eAET;IACgB,CAAA,GACnB,kBAAC,GAAD;KACE,UAAU,KAAY;KACtB,UAAU,MAAU;MAElB,AADA,EAAM,eAAe,GACrB,EAAe;KACjB;KACA,WAAW,EAAO;eANpB,CAQG,IAAY,kBAAC,GAAD,EAAS,WAAU,sBAAuB,CAAA,IAAI,MAC1D,CACgB;MACF;KACD;;CACT,CAAA;AAEjB"}
@@ -38,4 +38,4 @@ export interface UserProfileMenuProps {
38
38
  * }
39
39
  * ```
40
40
  */
41
- export declare function UserProfileMenu({ onSwitchWorkspace, onLogout, position, }: UserProfileMenuProps): import("react").JSX.Element | null;
41
+ export declare function UserProfileMenu({ onSwitchWorkspace, onLogout, position, }: UserProfileMenuProps): import('react').JSX.Element | null;
@@ -1 +1 @@
1
- {"version":3,"file":"UserProfileMenu.js","names":[],"sources":["../../../../src/auth/components/profile/UserProfileMenu.tsx"],"sourcesContent":["import { useState, useRef, useEffect } from \"react\";\nimport { useTr } from \"../../../shared/hooks/useTr\";\nimport { LogOut, ChevronDown, Building2, UserPlus } from \"lucide-react\";\nimport { useNavigate } from \"react-router\";\nimport { useAuthStore } from \"../../store/authStore\";\n\nexport interface UserProfileMenuProps {\n /**\n * Callback when workspace switcher should be shown\n */\n onSwitchWorkspace?: () => void;\n\n /**\n * Logout handler (REQUIRED)\n * Should clear auth state and redirect to login\n */\n onLogout: () => void;\n\n /**\n * Position of the dropdown menu\n * @default 'right'\n */\n position?: \"left\" | \"right\";\n}\n\n/**\n * User Profile Menu Component\n *\n * Displays user avatar/icon with dropdown menu containing:\n * - User information\n * - Switch Workspace option\n * - Logout button\n *\n * @example\n * ```tsx\n * import { UserProfileMenu } from '@burdenoff/microfe-auth';\n *\n * function AppHeader() {\n * return (\n * <div className=\"header\">\n * <UserProfileMenu\n * onSwitchWorkspace={() => setShowWorkspaceSwitcher(true)}\n * position=\"right\"\n * />\n * </div>\n * );\n * }\n * ```\n */\nexport function UserProfileMenu({\n onSwitchWorkspace,\n onLogout,\n position = \"right\",\n}: UserProfileMenuProps) {\n const tr = useTr();\n\n const [isOpen, setIsOpen] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const navigate = useNavigate();\n\n const user = useAuthStore((state) => state.user);\n const currentWorkspaceId = useAuthStore((state) => state.currentWorkspaceId);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n }\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }\n }, [isOpen]);\n\n const handleLogout = () => {\n setIsOpen(false);\n onLogout();\n };\n\n const handleSwitchWorkspace = () => {\n setIsOpen(false);\n onSwitchWorkspace?.();\n };\n\n if (!user) {\n return null;\n }\n\n // Get user initials for avatar\n const getInitials = () => {\n if (user.firstName && user.lastName) {\n return `${user.firstName[0]}${user.lastName[0]}`.toUpperCase();\n }\n if (user.name) {\n const parts = user.name.split(\" \");\n if (parts.length >= 2) {\n return `${parts[0][0]}${parts[1][0]}`.toUpperCase();\n }\n return user.name.substring(0, 2).toUpperCase();\n }\n if (user.username) {\n return user.username.substring(0, 2).toUpperCase();\n }\n return user.email.substring(0, 2).toUpperCase();\n };\n\n const displayName =\n user.name ||\n `${user.firstName || \"\"} ${user.lastName || \"\"}`.trim() ||\n user.username;\n\n return (\n <div className=\"relative\" ref={menuRef}>\n {/* Profile Button */}\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-bg-sunken transition-colors\"\n aria-label={tr(\"auth.profileMenu.userMenu\", \"User menu\")}\n aria-expanded={isOpen}\n >\n {/* Avatar */}\n <div className=\"size-8 rounded-full bg-accent-blue flex items-center justify-center text-white text-sm font-medium overflow-hidden\">\n {user.avatar ? (\n <img\n src={user.avatar}\n alt={tr(\"auth.profileMenu.avatarAlt\", \"Profile picture\")}\n className=\"size-full object-cover\"\n />\n ) : (\n getInitials()\n )}\n </div>\n\n {/* User Name (optional, hide on small screens) */}\n <span className=\"hidden sm:block text-sm font-medium text-text-secondary\">\n {displayName}\n </span>\n\n {/* Chevron */}\n <ChevronDown\n className={`size-4 text-text-secondary transition-transform ${\n isOpen ? \"rotate-180\" : \"\"\n }`}\n />\n </button>\n\n {/* Dropdown Menu */}\n {isOpen && (\n <div\n className={`absolute top-full mt-2 w-64 bg-bg-surface rounded-lg shadow-lg border border-border-subtle py-2 z-50 ${\n position === \"right\" ? \"right-0\" : \"left-0\"\n }`}\n >\n {/* User Info Section */}\n <div className=\"px-4 py-3 border-b border-border-subtle\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {displayName}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">{user.email}</p>\n {currentWorkspaceId && (\n <p className=\"text-xs text-text-tertiary mt-1 truncate\">\n {tr(\"auth.profileMenu.workspaceLabel\", \"Workspace:\")}{\" \"}\n {currentWorkspaceId.substring(0, 8)}...\n </p>\n )}\n </div>\n\n {/* Menu Items */}\n <div className=\"py-1\">\n {/* Switch Workspace */}\n {onSwitchWorkspace && (\n <button\n type=\"button\"\n onClick={handleSwitchWorkspace}\n className=\"w-full flex items-center gap-3 px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken transition-colors\"\n >\n <Building2 className=\"size-4\" />\n <span>\n {tr(\"auth.profileMenu.switchWorkspace\", \"Switch Workspace\")}\n </span>\n </button>\n )}\n\n {/* Add Account */}\n <button\n type=\"button\"\n onClick={() => {\n setIsOpen(false);\n const returnTo = encodeURIComponent(\n window.location.pathname + window.location.search,\n );\n navigate(`/auth/login?mode=add-account&returnTo=${returnTo}`);\n }}\n className=\"w-full flex items-center gap-3 px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken transition-colors\"\n >\n <UserPlus className=\"size-4\" />\n <span>{tr(\"auth.profileMenu.addAccount\", \"Add account\")}</span>\n </button>\n\n {/* Logout */}\n <button\n type=\"button\"\n onClick={handleLogout}\n className=\"w-full flex items-center gap-3 px-4 py-2 text-sm text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <LogOut className=\"size-4\" />\n <span>{tr(\"auth.profileMenu.logout\", \"Logout\")}</span>\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"UserProfileMenu.js","names":[],"sources":["../../../../src/auth/components/profile/UserProfileMenu.tsx"],"sourcesContent":["import { useState, useRef, useEffect } from \"react\";\nimport { useTr } from \"../../../shared/hooks/useTr\";\nimport { LogOut, ChevronDown, Building2, UserPlus } from \"lucide-react\";\nimport { useNavigate } from \"react-router\";\nimport { useAuthStore } from \"../../store/authStore\";\n\nexport interface UserProfileMenuProps {\n /**\n * Callback when workspace switcher should be shown\n */\n onSwitchWorkspace?: () => void;\n\n /**\n * Logout handler (REQUIRED)\n * Should clear auth state and redirect to login\n */\n onLogout: () => void;\n\n /**\n * Position of the dropdown menu\n * @default 'right'\n */\n position?: \"left\" | \"right\";\n}\n\n/**\n * User Profile Menu Component\n *\n * Displays user avatar/icon with dropdown menu containing:\n * - User information\n * - Switch Workspace option\n * - Logout button\n *\n * @example\n * ```tsx\n * import { UserProfileMenu } from '@burdenoff/microfe-auth';\n *\n * function AppHeader() {\n * return (\n * <div className=\"header\">\n * <UserProfileMenu\n * onSwitchWorkspace={() => setShowWorkspaceSwitcher(true)}\n * position=\"right\"\n * />\n * </div>\n * );\n * }\n * ```\n */\nexport function UserProfileMenu({\n onSwitchWorkspace,\n onLogout,\n position = \"right\",\n}: UserProfileMenuProps) {\n const tr = useTr();\n\n const [isOpen, setIsOpen] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const navigate = useNavigate();\n\n const user = useAuthStore((state) => state.user);\n const currentWorkspaceId = useAuthStore((state) => state.currentWorkspaceId);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n }\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }\n }, [isOpen]);\n\n const handleLogout = () => {\n setIsOpen(false);\n onLogout();\n };\n\n const handleSwitchWorkspace = () => {\n setIsOpen(false);\n onSwitchWorkspace?.();\n };\n\n if (!user) {\n return null;\n }\n\n // Get user initials for avatar\n const getInitials = () => {\n if (user.firstName && user.lastName) {\n return `${user.firstName[0]}${user.lastName[0]}`.toUpperCase();\n }\n if (user.name) {\n const parts = user.name.split(\" \");\n if (parts.length >= 2) {\n return `${parts[0][0]}${parts[1][0]}`.toUpperCase();\n }\n return user.name.substring(0, 2).toUpperCase();\n }\n if (user.username) {\n return user.username.substring(0, 2).toUpperCase();\n }\n return user.email.substring(0, 2).toUpperCase();\n };\n\n const displayName =\n user.name ||\n `${user.firstName || \"\"} ${user.lastName || \"\"}`.trim() ||\n user.username;\n\n return (\n <div className=\"relative\" ref={menuRef}>\n {/* Profile Button */}\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-bg-sunken transition-colors\"\n aria-label={tr(\"auth.profileMenu.userMenu\", \"User menu\")}\n aria-expanded={isOpen}\n >\n {/* Avatar */}\n <div className=\"size-8 rounded-full bg-accent-blue flex items-center justify-center text-white text-sm font-medium overflow-hidden\">\n {user.avatar ? (\n <img\n src={user.avatar}\n alt={tr(\"auth.profileMenu.avatarAlt\", \"Profile picture\")}\n className=\"size-full object-cover\"\n />\n ) : (\n getInitials()\n )}\n </div>\n\n {/* User Name (optional, hide on small screens) */}\n <span className=\"hidden sm:block text-sm font-medium text-text-secondary\">\n {displayName}\n </span>\n\n {/* Chevron */}\n <ChevronDown\n className={`size-4 text-text-secondary transition-transform ${\n isOpen ? \"rotate-180\" : \"\"\n }`}\n />\n </button>\n\n {/* Dropdown Menu */}\n {isOpen && (\n <div\n className={`absolute top-full mt-2 w-64 bg-bg-surface rounded-lg shadow-lg border border-border-subtle py-2 z-50 ${\n position === \"right\" ? \"right-0\" : \"left-0\"\n }`}\n >\n {/* User Info Section */}\n <div className=\"px-4 py-3 border-b border-border-subtle\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {displayName}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">{user.email}</p>\n {currentWorkspaceId && (\n <p className=\"text-xs text-text-tertiary mt-1 truncate\">\n {tr(\"auth.profileMenu.workspaceLabel\", \"Workspace:\")}{\" \"}\n {currentWorkspaceId.substring(0, 8)}...\n </p>\n )}\n </div>\n\n {/* Menu Items */}\n <div className=\"py-1\">\n {/* Switch Workspace */}\n {onSwitchWorkspace && (\n <button\n type=\"button\"\n onClick={handleSwitchWorkspace}\n className=\"w-full flex items-center gap-3 px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken transition-colors\"\n >\n <Building2 className=\"size-4\" />\n <span>\n {tr(\"auth.profileMenu.switchWorkspace\", \"Switch Workspace\")}\n </span>\n </button>\n )}\n\n {/* Add Account */}\n <button\n type=\"button\"\n onClick={() => {\n setIsOpen(false);\n const returnTo = encodeURIComponent(\n window.location.pathname + window.location.search,\n );\n navigate(`/auth/login?mode=add-account&returnTo=${returnTo}`);\n }}\n className=\"w-full flex items-center gap-3 px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken transition-colors\"\n >\n <UserPlus className=\"size-4\" />\n <span>{tr(\"auth.profileMenu.addAccount\", \"Add account\")}</span>\n </button>\n\n {/* Logout */}\n <button\n type=\"button\"\n onClick={handleLogout}\n className=\"w-full flex items-center gap-3 px-4 py-2 text-sm text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <LogOut className=\"size-4\" />\n <span>{tr(\"auth.profileMenu.logout\", \"Logout\")}</span>\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAiDA,SAAgB,EAAgB,EAC9B,sBACA,aACA,cAAW,WACY;CACvB,IAAM,IAAK,EAAM,GAEX,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,IAAU,EAAuB,IAAI,GACrC,IAAW,EAAY,GAEvB,IAAO,GAAc,MAAU,EAAM,IAAI,GACzC,IAAqB,GAAc,MAAU,EAAM,kBAAkB;CAG3E,QAAgB;EACd,SAAS,EAAmB,GAAmB;GAC7C,AAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,MAAc,KACnE,EAAU,EAAK;EAEnB;EAEA,IAAI,GAEF,OADA,SAAS,iBAAiB,aAAa,CAAkB,SAEvD,SAAS,oBAAoB,aAAa,CAAkB;CAElE,GAAG,CAAC,CAAM,CAAC;CAEX,IAAM,UAAqB;EAEzB,AADA,EAAU,EAAK,GACf,EAAS;CACX,GAEM,UAA8B;EAElC,AADA,EAAU,EAAK,GACf,IAAoB;CACtB;CAEA,IAAI,CAAC,GACH,OAAO;CAIT,IAAM,UAAoB;EACxB,IAAI,EAAK,aAAa,EAAK,UACzB,OAAO,GAAG,EAAK,UAAU,KAAK,EAAK,SAAS,KAAK,YAAY;EAE/D,IAAI,EAAK,MAAM;GACb,IAAM,IAAQ,EAAK,KAAK,MAAM,GAAG;GAIjC,OAHI,EAAM,UAAU,IACX,GAAG,EAAM,GAAG,KAAK,EAAM,GAAG,KAAK,YAAY,IAE7C,EAAK,KAAK,UAAU,GAAG,CAAC,EAAE,YAAY;EAC/C;EAIA,OAHI,EAAK,WACA,EAAK,SAAS,UAAU,GAAG,CAAC,EAAE,YAAY,IAE5C,EAAK,MAAM,UAAU,GAAG,CAAC,EAAE,YAAY;CAChD,GAEM,IACJ,EAAK,QACL,GAAG,EAAK,aAAa,GAAG,GAAG,EAAK,YAAY,KAAK,KAAK,KACtD,EAAK;CAEP,OACE,kBAAC,OAAD;EAAK,WAAU;EAAW,KAAK;YAA/B,CAEE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAU,CAAC,CAAM;GAChC,WAAU;GACV,cAAY,EAAG,6BAA6B,WAAW;GACvD,iBAAe;aALjB;IAQE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,SACJ,kBAAC,OAAD;MACE,KAAK,EAAK;MACV,KAAK,EAAG,8BAA8B,iBAAiB;MACvD,WAAU;KACX,CAAA,IAED,EAAY;IAEX,CAAA;IAGL,kBAAC,QAAD;KAAM,WAAU;eACb;IACG,CAAA;IAGN,kBAAC,GAAD,EACE,WAAW,mDACT,IAAS,eAAe,KAE3B,CAAA;GACK;MAGP,KACC,kBAAC,OAAD;GACE,WAAW,wGACT,MAAa,UAAU,YAAY;aAFvC,CAME,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,KAAD;MAAG,WAAU;gBACV;KACA,CAAA;KACH,kBAAC,KAAD;MAAG,WAAU;gBAAwC,EAAK;KAAS,CAAA;KAClE,KACC,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAG,mCAAmC,YAAY;OAAG;OACrD,EAAmB,UAAU,GAAG,CAAC;OAAE;MACnC;;IAEF;OAGL,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEG,KACC,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,SAAU,CAAA,GAC/B,kBAAC,QAAD,EAAA,UACG,EAAG,oCAAoC,kBAAkB,EACtD,CAAA,CACA;;KAIV,kBAAC,UAAD;MACE,MAAK;MACL,eAAe;OAKb,AAJA,EAAU,EAAK,GAIf,EAAS,yCAHQ,mBACf,OAAO,SAAS,WAAW,OAAO,SAAS,MAEK,GAAU;MAC9D;MACA,WAAU;gBATZ,CAWE,kBAAC,GAAD,EAAU,WAAU,SAAU,CAAA,GAC9B,kBAAC,QAAD,EAAA,UAAO,EAAG,+BAA+B,aAAa,EAAQ,CAAA,CACxD;;KAGR,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,SAAU,CAAA,GAC5B,kBAAC,QAAD,EAAA,UAAO,EAAG,2BAA2B,QAAQ,EAAQ,CAAA,CAC/C;;IACL;KACF;IAEJ;;AAET"}
@@ -1,5 +1,4 @@
1
1
  import { Workspace } from '../../types';
2
-
3
2
  /**
4
3
  * Organization interface (grouped from workspaces)
5
4
  */
@@ -46,4 +45,4 @@ export interface WorkspaceSelectorProps {
46
45
  */
47
46
  error?: string | null;
48
47
  }
49
- export declare function WorkspaceSelector({ isOpen, onClose, workspaces, projects, onSelect, isLoading, error, }: WorkspaceSelectorProps): import("react").JSX.Element | null;
48
+ export declare function WorkspaceSelector({ isOpen, onClose, workspaces, projects, onSelect, isLoading, error, }: WorkspaceSelectorProps): import('react').JSX.Element | null;