@burdenoff/microfe-auth 2026.510.127
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/auth/AuthRoot.d.ts +30 -0
- package/dist/auth/AuthRoot.d.ts.map +1 -0
- package/dist/auth/AuthRoot.js +82 -0
- package/dist/auth/AuthRoot.js.map +1 -0
- package/dist/auth/AuthRoutes.d.ts +29 -0
- package/dist/auth/AuthRoutes.d.ts.map +1 -0
- package/dist/auth/AuthRoutes.js +271 -0
- package/dist/auth/AuthRoutes.js.map +1 -0
- package/dist/auth/components/AuthIcons.d.ts +17 -0
- package/dist/auth/components/AuthIcons.d.ts.map +1 -0
- package/dist/auth/components/AuthIcons.js +197 -0
- package/dist/auth/components/AuthIcons.js.map +1 -0
- package/dist/auth/components/AuthLayout.d.ts +17 -0
- package/dist/auth/components/AuthLayout.d.ts.map +1 -0
- package/dist/auth/components/AuthLayout.js +237 -0
- package/dist/auth/components/AuthLayout.js.map +1 -0
- package/dist/auth/components/CaptchaV2.d.ts +16 -0
- package/dist/auth/components/CaptchaV2.d.ts.map +1 -0
- package/dist/auth/components/CaptchaV2.js +47 -0
- package/dist/auth/components/CaptchaV2.js.map +1 -0
- package/dist/auth/components/ConfirmActionDialog.d.ts +16 -0
- package/dist/auth/components/ConfirmActionDialog.d.ts.map +1 -0
- package/dist/auth/components/ConfirmActionDialog.js +68 -0
- package/dist/auth/components/ConfirmActionDialog.js.map +1 -0
- package/dist/auth/components/index.d.ts +4 -0
- package/dist/auth/components/index.d.ts.map +1 -0
- package/dist/auth/components/profile/UserProfileMenu.d.ts +42 -0
- package/dist/auth/components/profile/UserProfileMenu.d.ts.map +1 -0
- package/dist/auth/components/profile/UserProfileMenu.js +91 -0
- package/dist/auth/components/profile/UserProfileMenu.js.map +1 -0
- package/dist/auth/components/workspace/WorkspaceSelector.d.ts +76 -0
- package/dist/auth/components/workspace/WorkspaceSelector.d.ts.map +1 -0
- package/dist/auth/components/workspace/WorkspaceSelector.js +240 -0
- package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -0
- package/dist/auth/constants/permissions.d.ts +30 -0
- package/dist/auth/constants/permissions.d.ts.map +1 -0
- package/dist/auth/constants/permissions.js +18 -0
- package/dist/auth/constants/permissions.js.map +1 -0
- package/dist/auth/constants/sessionKeys.d.ts +18 -0
- package/dist/auth/constants/sessionKeys.d.ts.map +1 -0
- package/dist/auth/constants/sessionKeys.js +6 -0
- package/dist/auth/constants/sessionKeys.js.map +1 -0
- package/dist/auth/hooks/index.d.ts +18 -0
- package/dist/auth/hooks/index.d.ts.map +1 -0
- package/dist/auth/hooks/index.js +16 -0
- package/dist/auth/hooks/useAccountOperations.d.ts +19 -0
- package/dist/auth/hooks/useAccountOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useAccountOperations.js +52 -0
- package/dist/auth/hooks/useAccountOperations.js.map +1 -0
- package/dist/auth/hooks/useApiKeyOperations.d.ts +22 -0
- package/dist/auth/hooks/useApiKeyOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useApiKeyOperations.js +4 -0
- package/dist/auth/hooks/useAppOperations.d.ts +26 -0
- package/dist/auth/hooks/useAppOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useAppOperations.js +4 -0
- package/dist/auth/hooks/useAuthOperations.d.ts +57 -0
- package/dist/auth/hooks/useAuthOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useAuthOperations.js +236 -0
- package/dist/auth/hooks/useAuthOperations.js.map +1 -0
- package/dist/auth/hooks/useAuthPermissions.d.ts +20 -0
- package/dist/auth/hooks/useAuthPermissions.d.ts.map +1 -0
- package/dist/auth/hooks/useAuthPermissions.js +22 -0
- package/dist/auth/hooks/useAuthPermissions.js.map +1 -0
- package/dist/auth/hooks/useCaptchaV3.d.ts +13 -0
- package/dist/auth/hooks/useCaptchaV3.d.ts.map +1 -0
- package/dist/auth/hooks/useCaptchaV3.js +19 -0
- package/dist/auth/hooks/useCaptchaV3.js.map +1 -0
- package/dist/auth/hooks/useContextSwitcherData.d.ts +106 -0
- package/dist/auth/hooks/useContextSwitcherData.d.ts.map +1 -0
- package/dist/auth/hooks/useContextSwitcherData.js +466 -0
- package/dist/auth/hooks/useContextSwitcherData.js.map +1 -0
- package/dist/auth/hooks/useDelegationOperations.d.ts +25 -0
- package/dist/auth/hooks/useDelegationOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useDelegationOperations.js +4 -0
- package/dist/auth/hooks/useMfaOperations.d.ts +18 -0
- package/dist/auth/hooks/useMfaOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useMfaOperations.js +103 -0
- package/dist/auth/hooks/useMfaOperations.js.map +1 -0
- package/dist/auth/hooks/useMyWorkspaces.d.ts +45 -0
- package/dist/auth/hooks/useMyWorkspaces.d.ts.map +1 -0
- package/dist/auth/hooks/useMyWorkspaces.js +140 -0
- package/dist/auth/hooks/useMyWorkspaces.js.map +1 -0
- package/dist/auth/hooks/useOAuthOperations.d.ts +19 -0
- package/dist/auth/hooks/useOAuthOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useOAuthOperations.js +103 -0
- package/dist/auth/hooks/useOAuthOperations.js.map +1 -0
- package/dist/auth/hooks/usePasswordOperations.d.ts +13 -0
- package/dist/auth/hooks/usePasswordOperations.d.ts.map +1 -0
- package/dist/auth/hooks/usePasswordOperations.js +56 -0
- package/dist/auth/hooks/usePasswordOperations.js.map +1 -0
- package/dist/auth/hooks/useSessionOperations.d.ts +41 -0
- package/dist/auth/hooks/useSessionOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useSessionOperations.js +59 -0
- package/dist/auth/hooks/useSessionOperations.js.map +1 -0
- package/dist/auth/hooks/useSsoOperations.d.ts +65 -0
- package/dist/auth/hooks/useSsoOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useSsoOperations.js +236 -0
- package/dist/auth/hooks/useSsoOperations.js.map +1 -0
- package/dist/auth/hooks/useTokenRefresh.d.ts +56 -0
- package/dist/auth/hooks/useTokenRefresh.d.ts.map +1 -0
- package/dist/auth/hooks/useTokenRefresh.js +53 -0
- package/dist/auth/hooks/useTokenRefresh.js.map +1 -0
- package/dist/auth/hooks/useUserOperations.d.ts +32 -0
- package/dist/auth/hooks/useUserOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useUserOperations.js +100 -0
- package/dist/auth/hooks/useUserOperations.js.map +1 -0
- package/dist/auth/hooks/useWorkspaceOperations.d.ts +35 -0
- package/dist/auth/hooks/useWorkspaceOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useWorkspaceOperations.js +35 -0
- package/dist/auth/hooks/useWorkspaceOperations.js.map +1 -0
- package/dist/auth/hooks/useWorkspaceToken.d.ts +56 -0
- package/dist/auth/hooks/useWorkspaceToken.d.ts.map +1 -0
- package/dist/auth/hooks/useWorkspaceToken.js +94 -0
- package/dist/auth/hooks/useWorkspaceToken.js.map +1 -0
- package/dist/auth/index.d.ts +63 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +18 -0
- package/dist/auth/pages/ApiKeysPage.d.ts +5 -0
- package/dist/auth/pages/ApiKeysPage.d.ts.map +1 -0
- package/dist/auth/pages/AppsPage.d.ts +5 -0
- package/dist/auth/pages/AppsPage.d.ts.map +1 -0
- package/dist/auth/pages/AuditLogPage.d.ts +5 -0
- package/dist/auth/pages/AuditLogPage.d.ts.map +1 -0
- package/dist/auth/pages/AuditLogPage.js +129 -0
- package/dist/auth/pages/AuditLogPage.js.map +1 -0
- package/dist/auth/pages/DelegationsPage.d.ts +5 -0
- package/dist/auth/pages/DelegationsPage.d.ts.map +1 -0
- package/dist/auth/pages/EmailVerifyPage.d.ts +5 -0
- package/dist/auth/pages/EmailVerifyPage.d.ts.map +1 -0
- package/dist/auth/pages/EmailVerifyPage.js +166 -0
- package/dist/auth/pages/EmailVerifyPage.js.map +1 -0
- package/dist/auth/pages/LoginPage.d.ts +6 -0
- package/dist/auth/pages/LoginPage.d.ts.map +1 -0
- package/dist/auth/pages/LoginPage.js +575 -0
- package/dist/auth/pages/LoginPage.js.map +1 -0
- package/dist/auth/pages/MagicLinkPage.d.ts +6 -0
- package/dist/auth/pages/MagicLinkPage.d.ts.map +1 -0
- package/dist/auth/pages/MagicLinkPage.js +219 -0
- package/dist/auth/pages/MagicLinkPage.js.map +1 -0
- package/dist/auth/pages/MfaSetupPage.d.ts +5 -0
- package/dist/auth/pages/MfaSetupPage.d.ts.map +1 -0
- package/dist/auth/pages/MfaSetupPage.js +341 -0
- package/dist/auth/pages/MfaSetupPage.js.map +1 -0
- package/dist/auth/pages/MfaVerifyPage.d.ts +7 -0
- package/dist/auth/pages/MfaVerifyPage.d.ts.map +1 -0
- package/dist/auth/pages/MfaVerifyPage.js +189 -0
- package/dist/auth/pages/MfaVerifyPage.js.map +1 -0
- package/dist/auth/pages/OAuthCallbackPage.d.ts +7 -0
- package/dist/auth/pages/OAuthCallbackPage.d.ts.map +1 -0
- package/dist/auth/pages/OAuthCallbackPage.js +100 -0
- package/dist/auth/pages/OAuthCallbackPage.js.map +1 -0
- package/dist/auth/pages/PasswordResetPage.d.ts +6 -0
- package/dist/auth/pages/PasswordResetPage.d.ts.map +1 -0
- package/dist/auth/pages/PasswordResetPage.js +352 -0
- package/dist/auth/pages/PasswordResetPage.js.map +1 -0
- package/dist/auth/pages/ReactivatePage.d.ts +6 -0
- package/dist/auth/pages/ReactivatePage.d.ts.map +1 -0
- package/dist/auth/pages/ReactivatePage.js +217 -0
- package/dist/auth/pages/ReactivatePage.js.map +1 -0
- package/dist/auth/pages/RegisterPage.d.ts +5 -0
- package/dist/auth/pages/RegisterPage.d.ts.map +1 -0
- package/dist/auth/pages/RegisterPage.js +439 -0
- package/dist/auth/pages/RegisterPage.js.map +1 -0
- package/dist/auth/pages/SSORelayCallbackPage.d.ts +8 -0
- package/dist/auth/pages/SSORelayCallbackPage.d.ts.map +1 -0
- package/dist/auth/pages/SSORelayCallbackPage.js +48 -0
- package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -0
- package/dist/auth/pages/SSORelayPage.d.ts +18 -0
- package/dist/auth/pages/SSORelayPage.d.ts.map +1 -0
- package/dist/auth/pages/SSORelayPage.js +134 -0
- package/dist/auth/pages/SSORelayPage.js.map +1 -0
- package/dist/auth/pages/SecurityPage.d.ts +5 -0
- package/dist/auth/pages/SecurityPage.d.ts.map +1 -0
- package/dist/auth/pages/SecurityPage.js +587 -0
- package/dist/auth/pages/SecurityPage.js.map +1 -0
- package/dist/auth/pages/SessionBridgePage.d.ts +14 -0
- package/dist/auth/pages/SessionBridgePage.d.ts.map +1 -0
- package/dist/auth/pages/SessionBridgePage.js +231 -0
- package/dist/auth/pages/SessionBridgePage.js.map +1 -0
- package/dist/auth/pages/SessionsPage.d.ts +5 -0
- package/dist/auth/pages/SessionsPage.d.ts.map +1 -0
- package/dist/auth/pages/SessionsPage.js +258 -0
- package/dist/auth/pages/SessionsPage.js.map +1 -0
- package/dist/auth/pages/SsoCallbackPage.d.ts +8 -0
- package/dist/auth/pages/SsoCallbackPage.d.ts.map +1 -0
- package/dist/auth/pages/SsoCallbackPage.js +188 -0
- package/dist/auth/pages/SsoCallbackPage.js.map +1 -0
- package/dist/auth/pages/SsoConfigPage.d.ts +6 -0
- package/dist/auth/pages/SsoConfigPage.d.ts.map +1 -0
- package/dist/auth/pages/SsoConfigPage.js +1144 -0
- package/dist/auth/pages/SsoConfigPage.js.map +1 -0
- package/dist/auth/pages/SsoLoginPage.d.ts +7 -0
- package/dist/auth/pages/SsoLoginPage.d.ts.map +1 -0
- package/dist/auth/pages/SsoLoginPage.js +236 -0
- package/dist/auth/pages/SsoLoginPage.js.map +1 -0
- package/dist/auth/pages/UserDetailsPage.d.ts +11 -0
- package/dist/auth/pages/UserDetailsPage.d.ts.map +1 -0
- package/dist/auth/pages/UserDetailsPage.js +338 -0
- package/dist/auth/pages/UserDetailsPage.js.map +1 -0
- package/dist/auth/pages/UserProfilePage.d.ts +5 -0
- package/dist/auth/pages/UserProfilePage.d.ts.map +1 -0
- package/dist/auth/pages/UserProfilePage.js +445 -0
- package/dist/auth/pages/UserProfilePage.js.map +1 -0
- package/dist/auth/pages/UsersPage.d.ts +5 -0
- package/dist/auth/pages/UsersPage.d.ts.map +1 -0
- package/dist/auth/pages/UsersPage.js +899 -0
- package/dist/auth/pages/UsersPage.js.map +1 -0
- package/dist/auth/providers/AuthProvider.d.ts +18 -0
- package/dist/auth/providers/AuthProvider.d.ts.map +1 -0
- package/dist/auth/providers/AuthProvider.js +36 -0
- package/dist/auth/providers/AuthProvider.js.map +1 -0
- package/dist/auth/providers/CaptchaProvider.d.ts +13 -0
- package/dist/auth/providers/CaptchaProvider.d.ts.map +1 -0
- package/dist/auth/providers/CaptchaProvider.js +21 -0
- package/dist/auth/providers/CaptchaProvider.js.map +1 -0
- package/dist/auth/store/authStore.d.ts +91 -0
- package/dist/auth/store/authStore.d.ts.map +1 -0
- package/dist/auth/store/authStore.js +314 -0
- package/dist/auth/store/authStore.js.map +1 -0
- package/dist/auth/types/index.d.ts +636 -0
- package/dist/auth/types/index.d.ts.map +1 -0
- package/dist/auth/utils/captchaConfig.d.ts +4 -0
- package/dist/auth/utils/captchaConfig.d.ts.map +1 -0
- package/dist/auth/utils/captchaConfig.js +13 -0
- package/dist/auth/utils/captchaConfig.js.map +1 -0
- package/dist/auth/utils/formatters.d.ts +37 -0
- package/dist/auth/utils/formatters.d.ts.map +1 -0
- package/dist/auth/utils/formatters.js +48 -0
- package/dist/auth/utils/formatters.js.map +1 -0
- package/dist/auth/utils/gatewayBaseUrls.d.ts +6 -0
- package/dist/auth/utils/gatewayBaseUrls.d.ts.map +1 -0
- package/dist/auth/utils/gatewayBaseUrls.js +18 -0
- package/dist/auth/utils/gatewayBaseUrls.js.map +1 -0
- package/dist/auth/utils/index.d.ts +3 -0
- package/dist/auth/utils/index.d.ts.map +1 -0
- package/dist/auth/utils/validation.d.ts +30 -0
- package/dist/auth/utils/validation.d.ts.map +1 -0
- package/dist/auth/utils/validation.js +15 -0
- package/dist/auth/utils/validation.js.map +1 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2978 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-operations.js +944 -0
- package/dist/generated/global-operations.js.map +1 -0
- package/dist/generated/global-types.d.ts +21253 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +55214 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/microfe-auth.css +3 -0
- package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js +70 -0
- package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js.map +1 -0
- package/dist/node_modules/object-assign/index.js +41 -0
- package/dist/node_modules/object-assign/index.js.map +1 -0
- package/dist/node_modules/prop-types/checkPropTypes.js +46 -0
- package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -0
- package/dist/node_modules/prop-types/factoryWithThrowingShims.js +49 -0
- package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -0
- package/dist/node_modules/prop-types/factoryWithTypeCheckers.js +272 -0
- package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -0
- package/dist/node_modules/prop-types/index.js +16 -0
- package/dist/node_modules/prop-types/index.js.map +1 -0
- package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js +10 -0
- package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -0
- package/dist/node_modules/prop-types/lib/has.js +10 -0
- package/dist/node_modules/prop-types/lib/has.js.map +1 -0
- package/dist/node_modules/qrcode.react/lib/esm/index.js +959 -0
- package/dist/node_modules/qrcode.react/lib/esm/index.js.map +1 -0
- package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js +114 -0
- package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/index.js +8 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/index.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js +20 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js +148 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js +445 -0
- package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js.map +1 -0
- package/dist/node_modules/react-is/cjs/react-is.development.js +84 -0
- package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -0
- package/dist/node_modules/react-is/cjs/react-is.production.min.js +64 -0
- package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -0
- package/dist/node_modules/react-is/index.js +12 -0
- package/dist/node_modules/react-is/index.js.map +1 -0
- package/dist/shared/hooks/index.d.ts +7 -0
- package/dist/shared/hooks/index.d.ts.map +1 -0
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/types/index.d.ts +109 -0
- package/dist/shared/types/index.d.ts.map +1 -0
- package/dist/utils/nativeBridge.d.ts +3 -0
- package/dist/utils/nativeBridge.d.ts.map +1 -0
- package/dist/utils/nativeBridge.js +2 -0
- package/package.json +114 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWorkspaceToken.js","names":[],"sources":["../../../src/auth/hooks/useWorkspaceToken.ts"],"sourcesContent":["import { useState, useCallback } from \"react\";\nimport { graphqlFetch } from \"@burdenoff/fe-libs/shared/graphql/fetch\";\nimport { useAuthStore } from \"../store/authStore\";\n\n/**\n * Workspace token management hook\n *\n * Provides functions to issue, refresh, and verify workspace tokens.\n * Automatically updates the auth store with new tokens.\n *\n * API Flow:\n * - Calls workspace gateway (https://gw-wspace.local.burdenoff.com/workspaces/graphql)\n * - Gateway federates wspace-auth-svc which handles token operations\n * - Auth token (from global-auth-svc) goes in Authorization header\n *\n * Usage:\n * ```tsx\n * const { issueToken, refreshToken, verifyToken, isLoading, error } = useWorkspaceToken({\n * workspaceGatewayUrl: 'https://gw-wspace.local.burdenoff.com/workspaces/graphql'\n * });\n *\n * // After login and organization/workspace selection\n * await issueToken(organizationId, workspaceId);\n *\n * // Refresh token before expiry (uses stored org/workspace IDs)\n * await refreshToken();\n * ```\n */\nexport interface UseWorkspaceTokenOptions {\n /**\n * URL of workspace gateway GraphQL endpoint\n * Default: https://gw-wspace.local.burdenoff.com/workspaces/graphql\n *\n * Note: This should point to the workspace gateway, NOT directly to wspace-auth-svc.\n * The gateway federates wspace-auth-svc and handles routing.\n */\n workspaceGatewayUrl?: string;\n}\n\nexport interface WorkspaceTokenPayload {\n sub: string; // User ID\n workspaceId: string;\n tenantId?: string;\n email?: string;\n username?: string;\n role?: string;\n scopes: string[];\n iat: number;\n exp: number;\n}\n\nexport function useWorkspaceToken(options: UseWorkspaceTokenOptions = {}) {\n const {\n workspaceGatewayUrl = \"https://gw-wspace.local.burdenoff.com/workspaces/graphql\",\n } = options;\n\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Issue a new workspace token for the given workspace\n *\n * @param organizationId - Organization ID (required)\n * @param workspaceId - Workspace ID (optional, auto-resolves to first accessible)\n * @param projectId - Project ID (optional, auto-resolves to first accessible)\n * @param scopes - Requested scopes (optional, defaults to full access)\n */\n const issueToken = useCallback(\n async (\n organizationId: string,\n workspaceId?: string,\n projectId?: string,\n scopes?: string[],\n ): Promise<string> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const accessToken = useAuthStore.getState().accessToken;\n\n if (!accessToken) {\n throw new Error(\"No access token available. Please login first.\");\n }\n\n const response = await graphqlFetch<{\n issueWorkspaceToken: {\n success: boolean;\n token: string;\n expiresAt: string;\n organizationId: string;\n workspaceId: string;\n projectId?: string;\n scopes: string[];\n error?: { code?: string; message?: string };\n };\n }>({\n gateway: \"workspace\",\n query: `\n mutation IssueWorkspaceToken($input: IssueWorkspaceTokenInput!) {\n issueWorkspaceToken(input: $input) {\n success\n token\n expiresAt\n organizationId\n workspaceId\n projectId\n scopes\n error {\n code\n message\n }\n }\n }\n `,\n variables: {\n input: {\n organizationId,\n ...(workspaceId && { workspaceId }),\n ...(projectId && { projectId }),\n ...(scopes && { scopes }),\n },\n },\n authToken: accessToken,\n });\n\n const result = response.data?.issueWorkspaceToken;\n\n if (!result?.success || !result?.token) {\n const errorMsg =\n typeof result?.error?.message === \"string\"\n ? result.error.message\n : typeof result?.error === \"string\"\n ? result.error\n : \"Failed to issue workspace token\";\n throw new Error(errorMsg);\n }\n\n useAuthStore.getState().setWorkspaceToken(result.token);\n useAuthStore.getState().setCurrentWorkspaceId(result.workspaceId);\n\n setIsLoading(false);\n return result.token;\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"Unknown error occurred\";\n console.error(\"[useWorkspaceToken] Error issuing token:\", errorMessage);\n setError(errorMessage);\n setIsLoading(false);\n throw err;\n }\n },\n [workspaceGatewayUrl],\n );\n\n /**\n * Verify a workspace token\n *\n * @param token - Optional token to verify (uses stored token if not provided)\n */\n const verifyToken = useCallback(\n async (token?: string): Promise<WorkspaceTokenPayload> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { workspaceToken } = useAuthStore.getState();\n const tokenToVerify = token || workspaceToken;\n\n if (!tokenToVerify) {\n throw new Error(\"No workspace token available to verify\");\n }\n\n const response = await graphqlFetch<{\n verifyWorkspaceToken: {\n valid: boolean;\n payload?: WorkspaceTokenPayload;\n error?: { code?: string; message?: string };\n };\n }>({\n gateway: \"workspace\",\n query: `\n query VerifyWorkspaceToken($token: String!) {\n verifyWorkspaceToken(token: $token) {\n valid\n payload {\n sub\n workspaceId\n tenantId\n email\n username\n role\n scopes\n iat\n exp\n }\n error {\n code\n message\n }\n }\n }\n `,\n variables: { token: tokenToVerify },\n });\n\n const result = response.data?.verifyWorkspaceToken;\n\n if (!result?.valid) {\n const errorMsg =\n typeof result?.error?.message === \"string\"\n ? result.error.message\n : typeof result?.error === \"string\"\n ? result.error\n : \"Token verification failed\";\n throw new Error(errorMsg);\n }\n\n setIsLoading(false);\n return result.payload!;\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"Unknown error occurred\";\n console.error(\n \"[useWorkspaceToken] Error verifying token:\",\n errorMessage,\n );\n setError(errorMessage);\n setIsLoading(false);\n throw err;\n }\n },\n [workspaceGatewayUrl],\n );\n\n /**\n * Refresh the workspace token\n */\n const refreshToken = useCallback(async (): Promise<string> => {\n const { currentOrganizationId, currentWorkspaceId } =\n useAuthStore.getState();\n if (!currentOrganizationId) {\n throw new Error(\"No organization ID in store. Please login first.\");\n }\n return issueToken(currentOrganizationId, currentWorkspaceId ?? undefined);\n }, [issueToken]);\n\n /**\n * Decode a JWT token to get its payload (client-side only, no verification)\n */\n const decodeToken = useCallback((token: string): WorkspaceTokenPayload => {\n try {\n const base64Url = token.split(\".\")[1];\n const base64 = base64Url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split(\"\")\n .map((c) => \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2))\n .join(\"\"),\n );\n return JSON.parse(jsonPayload);\n } catch {\n throw new Error(\"Failed to decode token\");\n }\n }, []);\n\n /**\n * Check if a token is expired (client-side check)\n */\n const isTokenExpired = useCallback(\n (token?: string): boolean => {\n try {\n const { workspaceToken } = useAuthStore.getState();\n const tokenToCheck = token || workspaceToken;\n\n if (!tokenToCheck) return true;\n\n const payload = decodeToken(tokenToCheck);\n const now = Math.floor(Date.now() / 1000);\n\n return payload.exp < now;\n } catch {\n return true;\n }\n },\n [decodeToken],\n );\n\n /**\n * Get time until token expiry in milliseconds\n */\n const getTimeUntilExpiry = useCallback(\n (token?: string): number => {\n try {\n const { workspaceToken } = useAuthStore.getState();\n const tokenToCheck = token || workspaceToken;\n\n if (!tokenToCheck) return 0;\n\n const payload = decodeToken(tokenToCheck);\n const now = Math.floor(Date.now() / 1000);\n const timeUntilExpiry = (payload.exp - now) * 1000; // Convert to ms\n\n return Math.max(0, timeUntilExpiry);\n } catch {\n return 0;\n }\n },\n [decodeToken],\n );\n\n return {\n issueToken,\n refreshToken,\n verifyToken,\n decodeToken,\n isTokenExpired,\n getTimeUntilExpiry,\n isLoading,\n error,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Microfrontend
|
|
3
|
+
*
|
|
4
|
+
* Provides authentication, security settings, and account management interface
|
|
5
|
+
* for the Burdenoff multi-tenant platform.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - User authentication (signIn, signUp, signOut, refreshToken)
|
|
9
|
+
* - MFA (TOTP, SMS, Email, WebAuthn)
|
|
10
|
+
* - OAuth and SAML SSO
|
|
11
|
+
* - Magic Link authentication
|
|
12
|
+
* - Workspace token management
|
|
13
|
+
* - User management (admin)
|
|
14
|
+
*
|
|
15
|
+
* Note: API Key management, App management, and App-user delegations
|
|
16
|
+
* have been consolidated into microfe-devportal.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { AuthRoot, type AuthRootProps } from '@burdenoff/microfe-auth';
|
|
21
|
+
*
|
|
22
|
+
* function App() {
|
|
23
|
+
* const props: AuthRootProps = {
|
|
24
|
+
* basePath: '/auth',
|
|
25
|
+
* navigate: (path) => router.push(path),
|
|
26
|
+
* apiGatewayUrl: 'https://gw-global.local.burdenoff.com',
|
|
27
|
+
* authToken: 'token',
|
|
28
|
+
* onAuthSuccess: (user) => shellLogin(user),
|
|
29
|
+
* onLogout: () => shellLogout(),
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* return <AuthRoot {...props} />;
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export { AuthRoot } from './AuthRoot';
|
|
37
|
+
export type { AuthRootProps, User, UserRole, UserStatus, UserConnection, UserFilterInput, PaginationInput, } from './types';
|
|
38
|
+
export type { AuthType, AuthMethod, AuthMethodConfig, AuthStrategyHealth, AuthPayload, AuthResult, SignInInput, SignUpInput, ChangePasswordInput, } from './types';
|
|
39
|
+
export type { MFAMethod, MFASetupResult, MFAVerifyInput } from './types';
|
|
40
|
+
export type { OAuthInput, SAMLInput, SAMLRequestResult } from './types';
|
|
41
|
+
export type { AuthContext, MagicLinkSendResult } from './types';
|
|
42
|
+
export type { Organization, OrganizationConnection } from './types';
|
|
43
|
+
export type { Project, ProjectStatus, ProjectConnection } from './types';
|
|
44
|
+
export type { Workspace, WorkspaceSecretStatus, WorkspaceSecretInfo, WorkspaceTokenResponse, GenerateWorkspaceTokenInput, RotateWorkspaceSecretInput, SecretRotationResponse, } from './types';
|
|
45
|
+
export type { TokenValidationError, TokenValidationResponse, ValidateTokensInput, } from './types';
|
|
46
|
+
export type { EmailVerificationResult, ResendVerificationResult, PasswordResetRequestResult, DeleteUserResult, } from './types';
|
|
47
|
+
export type { Session, MfaDevice, OAuthAccount, SecurityAudit, OAuthProvider, SecurityEventType, TrustedDevice, SSOConfig, PasswordStrength, } from './types';
|
|
48
|
+
export { useAuth } from './providers/AuthProvider';
|
|
49
|
+
export { useAuthOperations, useMfaOperations, useSessionOperations, usePasswordOperations, useAuthStore, } from './hooks';
|
|
50
|
+
export { useWorkspaceOperations } from './hooks';
|
|
51
|
+
export { useUserOperations } from './hooks';
|
|
52
|
+
export { useWorkspaceToken } from './hooks/useWorkspaceToken';
|
|
53
|
+
export { useTokenRefresh } from './hooks/useTokenRefresh';
|
|
54
|
+
export { useContextSwitcherData, useWorkspaceSyncEffect, useProjectSyncEffect, } from './hooks';
|
|
55
|
+
export { useMyWorkspaces } from './hooks';
|
|
56
|
+
export type { UseContextSwitcherDataOptions } from './hooks';
|
|
57
|
+
export { WorkspaceSelector } from './components/workspace/WorkspaceSelector';
|
|
58
|
+
export type { WorkspaceSelectorProps } from './components/workspace/WorkspaceSelector';
|
|
59
|
+
export { UserProfileMenu } from './components/profile/UserProfileMenu';
|
|
60
|
+
export type { UserProfileMenuProps } from './components/profile/UserProfileMenu';
|
|
61
|
+
export { SSORelayPage } from './pages/SSORelayPage';
|
|
62
|
+
export { SSORelayCallbackPage } from './pages/SSORelayCallbackPage';
|
|
63
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,YAAY,EACV,aAAa,EACb,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAC;AAGjB,YAAY,EACV,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGzE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGxE,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGhE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGpE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGzE,YAAY,EACV,SAAS,EACT,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAGjB,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAGjB,YAAY,EACV,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,YAAY,EACV,OAAO,EACP,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAGnD,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,GACb,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EAAE,6BAA6B,EAAE,MAAM,SAAS,CAAC;AAG7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAC7E,YAAY,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAGvF,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,YAAY,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAGjF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./providers/AuthProvider.js";
|
|
2
|
+
import "./store/authStore.js";
|
|
3
|
+
import "./hooks/useAuthOperations.js";
|
|
4
|
+
import "./hooks/useMfaOperations.js";
|
|
5
|
+
import "./hooks/usePasswordOperations.js";
|
|
6
|
+
import "./hooks/useSessionOperations.js";
|
|
7
|
+
import "./hooks/useWorkspaceOperations.js";
|
|
8
|
+
import "./hooks/useMyWorkspaces.js";
|
|
9
|
+
import "./hooks/useContextSwitcherData.js";
|
|
10
|
+
import "./hooks/useUserOperations.js";
|
|
11
|
+
import "./hooks/index.js";
|
|
12
|
+
import "./pages/SSORelayPage.js";
|
|
13
|
+
import "./pages/SSORelayCallbackPage.js";
|
|
14
|
+
import "./AuthRoot.js";
|
|
15
|
+
import "./hooks/useWorkspaceToken.js";
|
|
16
|
+
import "./hooks/useTokenRefresh.js";
|
|
17
|
+
import "./components/workspace/WorkspaceSelector.js";
|
|
18
|
+
import "./components/profile/UserProfileMenu.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiKeysPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/ApiKeysPage.tsx"],"names":[],"mappings":"AAwCA;;GAEG;AACH,wBAAgB,WAAW,4CA0e1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppsPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/AppsPage.tsx"],"names":[],"mappings":"AAyCA;;GAEG;AACH,wBAAgB,QAAQ,4CAkjCvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuditLogPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/AuditLogPage.tsx"],"names":[],"mappings":"AAiCA;;GAEG;AACH,wBAAgB,YAAY,4CA8H3B"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { AlertIcon as e } from "../components/AuthIcons.js";
|
|
2
|
+
import { formatDateTime as t } from "../utils/formatters.js";
|
|
3
|
+
import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
import { useFeatureFlagDetails as a } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
6
|
+
import { useQuery as o } from "@apollo/client/react";
|
|
7
|
+
import { gql as s } from "@apollo/client";
|
|
8
|
+
//#region src/auth/pages/AuditLogPage.tsx
|
|
9
|
+
var c = s`
|
|
10
|
+
query AuthAuditLogs($pagination: PaginationInput) {
|
|
11
|
+
authAuditLogs(pagination: $pagination) {
|
|
12
|
+
id
|
|
13
|
+
action
|
|
14
|
+
description
|
|
15
|
+
ipAddress
|
|
16
|
+
userAgent
|
|
17
|
+
createdAt
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
function l() {
|
|
22
|
+
let { t: s } = n(), l = (e, t) => {
|
|
23
|
+
let n = s(e);
|
|
24
|
+
return n === e ? t : n;
|
|
25
|
+
}, u = a("auth.audit-log")?.value === !0, { data: d, loading: f, error: p } = o(c, {
|
|
26
|
+
skip: !u,
|
|
27
|
+
fetchPolicy: "cache-and-network",
|
|
28
|
+
variables: { pagination: {
|
|
29
|
+
limit: 50,
|
|
30
|
+
offset: 0
|
|
31
|
+
} }
|
|
32
|
+
}), m = d?.authAuditLogs ?? [];
|
|
33
|
+
if (!u) return /* @__PURE__ */ r("div", {
|
|
34
|
+
className: "max-w-4xl mx-auto p-6",
|
|
35
|
+
children: /* @__PURE__ */ i("div", {
|
|
36
|
+
className: "text-center py-16 border-2 border-dashed border-border-subtle rounded-xl",
|
|
37
|
+
children: [
|
|
38
|
+
/* @__PURE__ */ r("div", {
|
|
39
|
+
className: "w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center",
|
|
40
|
+
children: /* @__PURE__ */ r(e, { className: "w-8 h-8 text-status-warning-text" })
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ r("h2", {
|
|
43
|
+
className: "text-xl font-semibold text-text-primary mb-2",
|
|
44
|
+
children: l("auth.auditLog.notAvailable", "Page Not Available")
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ r("p", {
|
|
47
|
+
className: "text-text-secondary",
|
|
48
|
+
children: l("auth.auditLog.notEnabled", "The Security Audit Log is not enabled for your account.")
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
})
|
|
52
|
+
});
|
|
53
|
+
let h = (e) => {
|
|
54
|
+
switch (e) {
|
|
55
|
+
case "LOGIN_SUCCESS": return "OK";
|
|
56
|
+
case "LOGIN_FAILURE": return "ER";
|
|
57
|
+
case "LOGOUT": return "LO";
|
|
58
|
+
case "PASSWORD_CHANGE": return "PW";
|
|
59
|
+
case "MFA_ENABLED":
|
|
60
|
+
case "MFA_VERIFIED": return "MF";
|
|
61
|
+
case "ANOMALY_DETECTED": return "AL";
|
|
62
|
+
default: return "AU";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
return /* @__PURE__ */ i("div", {
|
|
66
|
+
className: "max-w-4xl mx-auto p-6",
|
|
67
|
+
children: [/* @__PURE__ */ r("h1", {
|
|
68
|
+
className: "text-3xl font-semibold text-text-primary mb-8",
|
|
69
|
+
children: l("auth.auditLog.title", "Security Audit Log")
|
|
70
|
+
}), f ? /* @__PURE__ */ r("div", {
|
|
71
|
+
className: "text-center py-12",
|
|
72
|
+
children: /* @__PURE__ */ r("p", {
|
|
73
|
+
className: "text-text-secondary",
|
|
74
|
+
children: l("auth.auditLog.loading", "Loading audit events...")
|
|
75
|
+
})
|
|
76
|
+
}) : p ? /* @__PURE__ */ r("div", {
|
|
77
|
+
className: "text-center py-12 border border-status-error-border rounded-xl bg-status-error-bg-subtle",
|
|
78
|
+
children: /* @__PURE__ */ r("p", {
|
|
79
|
+
className: "text-status-error-text",
|
|
80
|
+
children: l("auth.auditLog.error", "Unable to load audit events")
|
|
81
|
+
})
|
|
82
|
+
}) : m.length === 0 ? /* @__PURE__ */ r("div", {
|
|
83
|
+
className: "text-center py-12",
|
|
84
|
+
children: /* @__PURE__ */ r("p", {
|
|
85
|
+
className: "text-text-secondary",
|
|
86
|
+
children: l("auth.auditLog.noEvents", "No security events recorded")
|
|
87
|
+
})
|
|
88
|
+
}) : /* @__PURE__ */ r("div", {
|
|
89
|
+
className: "space-y-4",
|
|
90
|
+
children: m.map((e) => /* @__PURE__ */ r("div", {
|
|
91
|
+
className: "p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm",
|
|
92
|
+
children: /* @__PURE__ */ i("div", {
|
|
93
|
+
className: "flex items-start gap-4",
|
|
94
|
+
children: [
|
|
95
|
+
/* @__PURE__ */ r("div", {
|
|
96
|
+
className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-bg-muted text-xs font-semibold text-text-secondary",
|
|
97
|
+
children: h(e.action)
|
|
98
|
+
}),
|
|
99
|
+
/* @__PURE__ */ i("div", {
|
|
100
|
+
className: "flex-1",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ r("h3", {
|
|
103
|
+
className: "text-lg font-medium text-text-primary mb-1",
|
|
104
|
+
children: e.action.replace(/_/g, " ")
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ r("p", {
|
|
107
|
+
className: "text-sm text-text-secondary mb-2",
|
|
108
|
+
children: t(e.createdAt)
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ i("p", {
|
|
111
|
+
className: "text-sm text-text-secondary",
|
|
112
|
+
children: [e.description ?? l("auth.auditLog.defaultDescription", "Authentication event"), e.ipAddress && ` • ${e.ipAddress}`]
|
|
113
|
+
})
|
|
114
|
+
]
|
|
115
|
+
}),
|
|
116
|
+
e.action.includes("FAILURE") && /* @__PURE__ */ r("span", {
|
|
117
|
+
className: "px-3 py-1 rounded-full bg-status-error-bg-subtle text-status-error-text text-sm font-medium",
|
|
118
|
+
children: l("auth.auditLog.failed", "Failed")
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
})
|
|
122
|
+
}, e.id))
|
|
123
|
+
})]
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { l as AuditLogPage };
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=AuditLogPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuditLogPage.js","names":[],"sources":["../../../src/auth/pages/AuditLogPage.tsx"],"sourcesContent":["import { gql } from \"@apollo/client\";\nimport { useQuery } from \"@apollo/client/react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useFeatureFlagDetails } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { formatDateTime } from \"../utils\";\nimport { AlertIcon } from \"../components/AuthIcons\";\n\ninterface AuthAuditLogEntry {\n id: string;\n action: string;\n description?: string | null;\n ipAddress?: string | null;\n userAgent?: string | null;\n createdAt: string;\n}\n\ninterface AuthAuditLogsQueryResult {\n authAuditLogs: AuthAuditLogEntry[];\n}\n\nconst AUTH_AUDIT_LOGS_QUERY = gql`\n query AuthAuditLogs($pagination: PaginationInput) {\n authAuditLogs(pagination: $pagination) {\n id\n action\n description\n ipAddress\n userAgent\n createdAt\n }\n }\n`;\n\n/**\n * Security audit log page\n */\nexport function AuditLogPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n // Default-deny: only show when the flag is explicitly enabled in the system.\n // useFeatureFlag uses default-allow (returns true when not found), so we use\n // useFeatureFlagDetails + explicit value check instead.\n const auditLogFlag = useFeatureFlagDetails(\"auth.audit-log\");\n const showAuditLog = auditLogFlag?.value === true;\n const { data, loading, error } = useQuery<AuthAuditLogsQueryResult>(\n AUTH_AUDIT_LOGS_QUERY,\n {\n skip: !showAuditLog,\n fetchPolicy: \"cache-and-network\",\n variables: { pagination: { limit: 50, offset: 0 } },\n },\n );\n const auditLogs = data?.authAuditLogs ?? [];\n\n if (!showAuditLog) {\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center\">\n <AlertIcon className=\"w-8 h-8 text-status-warning-text\" />\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.auditLog.notAvailable\", \"Page Not Available\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.auditLog.notEnabled\",\n \"The Security Audit Log is not enabled for your account.\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const getEventMarker = (eventType: string) => {\n switch (eventType) {\n case \"LOGIN_SUCCESS\":\n return \"OK\";\n case \"LOGIN_FAILURE\":\n return \"ER\";\n case \"LOGOUT\":\n return \"LO\";\n case \"PASSWORD_CHANGE\":\n return \"PW\";\n case \"MFA_ENABLED\":\n case \"MFA_VERIFIED\":\n return \"MF\";\n case \"ANOMALY_DETECTED\":\n return \"AL\";\n default:\n return \"AU\";\n }\n };\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n <h1 className=\"text-3xl font-semibold text-text-primary mb-8\">\n {tr(\"auth.auditLog.title\", \"Security Audit Log\")}\n </h1>\n\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-text-secondary\">\n {tr(\"auth.auditLog.loading\", \"Loading audit events...\")}\n </p>\n </div>\n ) : error ? (\n <div className=\"text-center py-12 border border-status-error-border rounded-xl bg-status-error-bg-subtle\">\n <p className=\"text-status-error-text\">\n {tr(\"auth.auditLog.error\", \"Unable to load audit events\")}\n </p>\n </div>\n ) : auditLogs.length === 0 ? (\n <div className=\"text-center py-12\">\n <p className=\"text-text-secondary\">\n {tr(\"auth.auditLog.noEvents\", \"No security events recorded\")}\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {auditLogs.map((event) => (\n <div\n key={event.id}\n className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\"\n >\n <div className=\"flex items-start gap-4\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-bg-muted text-xs font-semibold text-text-secondary\">\n {getEventMarker(event.action)}\n </div>\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-medium text-text-primary mb-1\">\n {event.action.replace(/_/g, \" \")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-2\">\n {formatDateTime(event.createdAt)}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {event.description ??\n tr(\n \"auth.auditLog.defaultDescription\",\n \"Authentication event\",\n )}\n {event.ipAddress && ` • ${event.ipAddress}`}\n </p>\n </div>\n {event.action.includes(\"FAILURE\") && (\n <span className=\"px-3 py-1 rounded-full bg-status-error-bg-subtle text-status-error-text text-sm font-medium\">\n {tr(\"auth.auditLog.failed\", \"Failed\")}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAoBA,IAAM,IAAwB,CAAG;;;;;;;;;;;;AAgBjC,SAAgB,IAAe;CAC7B,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAOnC,IADe,EAAsB,iBAAiB,EACzB,UAAU,IACvC,EAAE,SAAM,YAAS,aAAU,EAC/B,GACA;EACE,MAAM,CAAC;EACP,aAAa;EACb,WAAW,EAAE,YAAY;GAAE,OAAO;GAAI,QAAQ;GAAG,EAAE;EACpD,CACF,EACK,IAAY,GAAM,iBAAiB,EAAE;AAE3C,KAAI,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAW,WAAU,oCAAqC,CAAA;KACtD,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,8BAA8B,qBAAqB;KACpD,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,4BACA,0DACD;KACC,CAAA;IACA;;EACF,CAAA;CAIV,IAAM,KAAkB,MAAsB;AAC5C,UAAQ,GAAR;GACE,KAAK,gBACH,QAAO;GACT,KAAK,gBACH,QAAO;GACT,KAAK,SACH,QAAO;GACT,KAAK,kBACH,QAAO;GACT,KAAK;GACL,KAAK,eACH,QAAO;GACT,KAAK,mBACH,QAAO;GACT,QACE,QAAO;;;AAIb,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,MAAD;GAAI,WAAU;aACX,EAAG,uBAAuB,qBAAqB;GAC7C,CAAA,EAEJ,IACC,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,yBAAyB,0BAA0B;IACrD,CAAA;GACA,CAAA,GACJ,IACF,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,uBAAuB,8BAA8B;IACvD,CAAA;GACA,CAAA,GACJ,EAAU,WAAW,IACvB,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,0BAA0B,8BAA8B;IAC1D,CAAA;GACA,CAAA,GAEN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAU,KAAK,MACd,kBAAC,OAAD;IAEE,WAAU;cAEV,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAe,EAAM,OAAO;OACzB,CAAA;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAM,OAAO,QAAQ,MAAM,IAAI;SAC7B,CAAA;QACL,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAe,EAAM,UAAU;SAC9B,CAAA;QACJ,kBAAC,KAAD;SAAG,WAAU;mBAAb,CACG,EAAM,eACL,EACE,oCACA,uBACD,EACF,EAAM,aAAa,MAAM,EAAM,YAC9B;;QACA;;MACL,EAAM,OAAO,SAAS,UAAU,IAC/B,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAG,wBAAwB,SAAS;OAChC,CAAA;MAEL;;IACF,EA7BC,EAAM,GA6BP,CACN;GACE,CAAA,CAEJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DelegationsPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/DelegationsPage.tsx"],"names":[],"mappings":"AAiIA;;GAEG;AACH,wBAAgB,eAAe,4CAwkB9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailVerifyPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/EmailVerifyPage.tsx"],"names":[],"mappings":"AAoBA;;GAEG;AACH,wBAAgB,eAAe,4CAqP9B"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { useAuthStore as e } from "../store/authStore.js";
|
|
2
|
+
import { useAuthOperations as t } from "../hooks/useAuthOperations.js";
|
|
3
|
+
import "../hooks/index.js";
|
|
4
|
+
import { AuthLayout as n } from "../components/AuthLayout.js";
|
|
5
|
+
import { SpinnerIcon as r } from "../components/AuthIcons.js";
|
|
6
|
+
import { useCallback as i, useEffect as a, useRef as o, useState as s } from "react";
|
|
7
|
+
import { useSearchParams as c } from "react-router-dom";
|
|
8
|
+
import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
9
|
+
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
10
|
+
//#region src/auth/pages/EmailVerifyPage.tsx
|
|
11
|
+
var p = 5;
|
|
12
|
+
function m(e) {
|
|
13
|
+
let t = "/auth/login", n = e ? `${t}?email=${encodeURIComponent(e)}` : t;
|
|
14
|
+
window.location.href = n;
|
|
15
|
+
}
|
|
16
|
+
function h() {
|
|
17
|
+
let { t: h } = l(), g = (e, t) => {
|
|
18
|
+
let n = h(e);
|
|
19
|
+
return n === e ? t : n;
|
|
20
|
+
}, [_] = c(), v = _.get("token"), y = _.get("email"), { verifyEmail: b, resendVerification: x } = t(), S = e((e) => e.user), [C, w] = s("verifying"), [T, E] = s(y || void 0), [D, O] = s(!1), [k, A] = s(!1), [j, M] = s(p), N = o(!1);
|
|
21
|
+
a(() => {
|
|
22
|
+
if (!v || N.current) return;
|
|
23
|
+
let e = `auth:verifyEmail:inflight:${v}`;
|
|
24
|
+
if (!(typeof window < "u" && window.sessionStorage.getItem(e))) {
|
|
25
|
+
N.current = !0;
|
|
26
|
+
try {
|
|
27
|
+
window.sessionStorage.setItem(e, "1");
|
|
28
|
+
} catch {}
|
|
29
|
+
b(v).then((e) => {
|
|
30
|
+
e.success ? (w("success"), e.email && E(e.email)) : w("error");
|
|
31
|
+
}).catch(() => w("error"));
|
|
32
|
+
}
|
|
33
|
+
}, [v]), a(() => {
|
|
34
|
+
if (C !== "success") return;
|
|
35
|
+
let e = setInterval(() => {
|
|
36
|
+
M((t) => t <= 1 ? (clearInterval(e), m(T), 0) : t - 1);
|
|
37
|
+
}, 1e3);
|
|
38
|
+
return () => clearInterval(e);
|
|
39
|
+
}, [C, T]);
|
|
40
|
+
let P = async () => {
|
|
41
|
+
let e = y || S?.email;
|
|
42
|
+
if (!e) {
|
|
43
|
+
console.error("No email available for resend");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
O(!0);
|
|
47
|
+
try {
|
|
48
|
+
await x(e), A(!0);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.error("Failed to resend verification:", e);
|
|
51
|
+
} finally {
|
|
52
|
+
O(!1);
|
|
53
|
+
}
|
|
54
|
+
}, F = i(() => {
|
|
55
|
+
m(T);
|
|
56
|
+
}, [T]), I = i(() => {
|
|
57
|
+
m();
|
|
58
|
+
}, []);
|
|
59
|
+
return C === "verifying" ? /* @__PURE__ */ d(n, {
|
|
60
|
+
title: g("auth.emailVerify.verifyingTitle", "Verifying your email"),
|
|
61
|
+
subtitle: g("auth.emailVerify.verifyingSubtitle", "Please wait while we confirm your email address"),
|
|
62
|
+
children: /* @__PURE__ */ f("div", {
|
|
63
|
+
className: "flex flex-col items-center justify-center py-12",
|
|
64
|
+
children: [/* @__PURE__ */ d("div", {
|
|
65
|
+
className: "w-16 h-16 rounded-full bg-[var(--color-bg-accent)] flex items-center justify-center mb-6",
|
|
66
|
+
children: /* @__PURE__ */ d(r, { className: "w-8 h-8 text-[var(--color-text-link)] animate-spin" })
|
|
67
|
+
}), /* @__PURE__ */ d("p", {
|
|
68
|
+
className: "text-[var(--color-text-secondary)]",
|
|
69
|
+
children: g("auth.emailVerify.moment", "This will only take a moment...")
|
|
70
|
+
})]
|
|
71
|
+
})
|
|
72
|
+
}) : C === "success" ? /* @__PURE__ */ d(n, {
|
|
73
|
+
title: g("auth.emailVerify.verifiedTitle", "Email verified!"),
|
|
74
|
+
subtitle: g("auth.emailVerify.verifiedSubtitle", "Your email address has been confirmed"),
|
|
75
|
+
children: /* @__PURE__ */ f("div", {
|
|
76
|
+
className: "flex flex-col items-center justify-center py-6",
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ d("div", {
|
|
79
|
+
className: "w-20 h-20 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center mb-6",
|
|
80
|
+
children: /* @__PURE__ */ d("svg", {
|
|
81
|
+
className: "w-10 h-10 text-[var(--color-status-success-text)]",
|
|
82
|
+
fill: "none",
|
|
83
|
+
viewBox: "0 0 24 24",
|
|
84
|
+
stroke: "currentColor",
|
|
85
|
+
children: /* @__PURE__ */ d("path", {
|
|
86
|
+
strokeLinecap: "round",
|
|
87
|
+
strokeLinejoin: "round",
|
|
88
|
+
strokeWidth: 2,
|
|
89
|
+
d: "M5 13l4 4L19 7"
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
}),
|
|
93
|
+
/* @__PURE__ */ d("p", {
|
|
94
|
+
className: "text-center text-[var(--color-text-secondary)] mb-6",
|
|
95
|
+
children: g("auth.emailVerify.successMessage", "Your email has been successfully verified. You can now sign in to access all features.")
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ f("p", {
|
|
98
|
+
className: "text-center text-sm text-[var(--color-text-tertiary)] mb-6",
|
|
99
|
+
children: [
|
|
100
|
+
g("auth.emailVerify.redirecting", "Redirecting to sign in in"),
|
|
101
|
+
" ",
|
|
102
|
+
/* @__PURE__ */ d("span", {
|
|
103
|
+
className: "font-semibold text-[var(--color-text-primary)]",
|
|
104
|
+
children: j
|
|
105
|
+
}),
|
|
106
|
+
" ",
|
|
107
|
+
g("auth.emailVerify.seconds", "seconds...")
|
|
108
|
+
]
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ d("button", {
|
|
111
|
+
onClick: F,
|
|
112
|
+
className: "auth-primary-button w-full px-4 py-3 font-semibold",
|
|
113
|
+
children: g("auth.emailVerify.continueSignIn", "Continue to sign in now")
|
|
114
|
+
})
|
|
115
|
+
]
|
|
116
|
+
})
|
|
117
|
+
}) : /* @__PURE__ */ d(n, {
|
|
118
|
+
title: g("auth.emailVerify.failedTitle", "Verification failed"),
|
|
119
|
+
subtitle: g("auth.emailVerify.failedSubtitle", "We couldn't verify your email address"),
|
|
120
|
+
children: /* @__PURE__ */ f("div", {
|
|
121
|
+
className: "flex flex-col items-center justify-center py-6",
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ d("div", {
|
|
124
|
+
className: "w-20 h-20 rounded-full bg-[var(--color-status-error-bg-subtle)] flex items-center justify-center mb-6",
|
|
125
|
+
children: /* @__PURE__ */ d("svg", {
|
|
126
|
+
className: "w-10 h-10 text-[var(--color-status-error-text)]",
|
|
127
|
+
fill: "none",
|
|
128
|
+
viewBox: "0 0 24 24",
|
|
129
|
+
stroke: "currentColor",
|
|
130
|
+
children: /* @__PURE__ */ d("path", {
|
|
131
|
+
strokeLinecap: "round",
|
|
132
|
+
strokeLinejoin: "round",
|
|
133
|
+
strokeWidth: 2,
|
|
134
|
+
d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
}),
|
|
138
|
+
/* @__PURE__ */ d("p", {
|
|
139
|
+
className: "text-center text-[var(--color-text-secondary)] mb-8",
|
|
140
|
+
children: g("auth.emailVerify.invalidLink", "The verification link is invalid or has expired. Please request a new verification email.")
|
|
141
|
+
}),
|
|
142
|
+
k ? /* @__PURE__ */ d("div", {
|
|
143
|
+
className: "w-full p-4 rounded-xl bg-[var(--color-status-success-bg-subtle)] border border-[var(--color-status-success-border)] text-center mb-4",
|
|
144
|
+
children: /* @__PURE__ */ d("p", {
|
|
145
|
+
className: "text-sm text-[var(--color-status-success-text)]",
|
|
146
|
+
children: g("auth.emailVerify.emailSent", "Verification email sent! Please check your inbox.")
|
|
147
|
+
})
|
|
148
|
+
}) : /* @__PURE__ */ d("button", {
|
|
149
|
+
onClick: P,
|
|
150
|
+
disabled: D,
|
|
151
|
+
className: "auth-primary-button mb-4 flex w-full items-center justify-center gap-2 px-4 py-3 font-semibold",
|
|
152
|
+
children: D ? /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(r, { className: "w-5 h-5 animate-spin" }), /* @__PURE__ */ d("span", { children: "Sending..." })] }) : g("auth.emailVerify.resend", "Resend verification email")
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ d("button", {
|
|
155
|
+
onClick: I,
|
|
156
|
+
className: "w-full py-3 px-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] font-medium hover:bg-[var(--color-bg-sunken)] transition-all",
|
|
157
|
+
children: g("auth.emailVerify.backToSignIn", "Back to sign in")
|
|
158
|
+
})
|
|
159
|
+
]
|
|
160
|
+
})
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
164
|
+
export { h as EmailVerifyPage };
|
|
165
|
+
|
|
166
|
+
//# sourceMappingURL=EmailVerifyPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailVerifyPage.js","names":[],"sources":["../../../src/auth/pages/EmailVerifyPage.tsx"],"sourcesContent":["import { useEffect, useState, useCallback, useRef } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useSearchParams } from \"react-router-dom\";\nimport { useAuthOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { SpinnerIcon } from \"../components/AuthIcons\";\n\nconst REDIRECT_DELAY = 5; // seconds\n\n/**\n * Navigate to login page with optional email pre-fill\n * Uses window.location.href for reliable navigation (works in new tabs)\n */\nfunction navigateToLogin(email?: string) {\n const baseUrl = \"/auth/login\";\n const url = email ? `${baseUrl}?email=${encodeURIComponent(email)}` : baseUrl;\n window.location.href = url;\n}\n\n/**\n * Email verification page with professional design\n */\nexport function EmailVerifyPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const [searchParams] = useSearchParams();\n const token = searchParams.get(\"token\");\n const urlEmail = searchParams.get(\"email\");\n const { verifyEmail, resendVerification } = useAuthOperations();\n const user = useAuthStore((state) => state.user);\n const [status, setStatus] = useState<\"verifying\" | \"success\" | \"error\">(\n \"verifying\",\n );\n const [verifiedEmail, setVerifiedEmail] = useState<string | undefined>(\n urlEmail || undefined,\n );\n const [isResending, setIsResending] = useState(false);\n const [resendSuccess, setResendSuccess] = useState(false);\n const [countdown, setCountdown] = useState(REDIRECT_DELAY);\n\n // Guard against duplicate calls. useRef alone resets across remounts\n // (StrictMode, Suspense resolution of the lazy Auth root, HMR), so we\n // additionally key on the token via sessionStorage — any remount for the\n // same token short-circuits instead of firing a second mutation.\n const verificationInitiatedRef = useRef(false);\n\n useEffect(() => {\n if (!token || verificationInitiatedRef.current) return;\n\n const storageKey = `auth:verifyEmail:inflight:${token}`;\n if (\n typeof window !== \"undefined\" &&\n window.sessionStorage.getItem(storageKey)\n ) {\n return;\n }\n verificationInitiatedRef.current = true;\n try {\n window.sessionStorage.setItem(storageKey, \"1\");\n } catch {\n // sessionStorage unavailable (private mode, SSR); ref guard still applies.\n }\n\n verifyEmail(token)\n .then((result) => {\n if (result.success) {\n setStatus(\"success\");\n if (result.email) setVerifiedEmail(result.email);\n } else {\n setStatus(\"error\");\n }\n })\n .catch(() => setStatus(\"error\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [token]);\n\n // Auto-redirect countdown after successful verification\n useEffect(() => {\n if (status !== \"success\") return;\n\n const timer = setInterval(() => {\n setCountdown((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n navigateToLogin(verifiedEmail);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [status, verifiedEmail]);\n\n const handleResend = async () => {\n const resendEmail = urlEmail || user?.email;\n if (!resendEmail) {\n console.error(\"No email available for resend\");\n return;\n }\n setIsResending(true);\n try {\n await resendVerification(resendEmail);\n setResendSuccess(true);\n } catch (err) {\n console.error(\"Failed to resend verification:\", err);\n } finally {\n setIsResending(false);\n }\n };\n\n const handleContinueToLogin = useCallback(() => {\n navigateToLogin(verifiedEmail);\n }, [verifiedEmail]);\n\n const handleBackToLogin = useCallback(() => {\n navigateToLogin();\n }, []);\n\n if (status === \"verifying\") {\n return (\n <AuthLayout\n title={tr(\"auth.emailVerify.verifyingTitle\", \"Verifying your email\")}\n subtitle={tr(\n \"auth.emailVerify.verifyingSubtitle\",\n \"Please wait while we confirm your email address\",\n )}\n >\n {/* Loading Spinner */}\n <div className=\"flex flex-col items-center justify-center py-12\">\n <div className=\"w-16 h-16 rounded-full bg-[var(--color-bg-accent)] flex items-center justify-center mb-6\">\n <SpinnerIcon className=\"w-8 h-8 text-[var(--color-text-link)] animate-spin\" />\n </div>\n <p className=\"text-[var(--color-text-secondary)]\">\n {tr(\"auth.emailVerify.moment\", \"This will only take a moment...\")}\n </p>\n </div>\n </AuthLayout>\n );\n }\n\n if (status === \"success\") {\n return (\n <AuthLayout\n title={tr(\"auth.emailVerify.verifiedTitle\", \"Email verified!\")}\n subtitle={tr(\n \"auth.emailVerify.verifiedSubtitle\",\n \"Your email address has been confirmed\",\n )}\n >\n {/* Success Icon */}\n <div className=\"flex flex-col items-center justify-center py-6\">\n <div className=\"w-20 h-20 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center mb-6\">\n <svg\n className=\"w-10 h-10 text-[var(--color-status-success-text)]\"\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=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n\n <p className=\"text-center text-[var(--color-text-secondary)] mb-6\">\n {tr(\n \"auth.emailVerify.successMessage\",\n \"Your email has been successfully verified. You can now sign in to access all features.\",\n )}\n </p>\n\n <p className=\"text-center text-sm text-[var(--color-text-tertiary)] mb-6\">\n {tr(\"auth.emailVerify.redirecting\", \"Redirecting to sign in in\")}{\" \"}\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {countdown}\n </span>{\" \"}\n {tr(\"auth.emailVerify.seconds\", \"seconds...\")}\n </p>\n\n <button\n onClick={handleContinueToLogin}\n className=\"auth-primary-button w-full px-4 py-3 font-semibold\"\n >\n {tr(\"auth.emailVerify.continueSignIn\", \"Continue to sign in now\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n // Error state\n return (\n <AuthLayout\n title={tr(\"auth.emailVerify.failedTitle\", \"Verification failed\")}\n subtitle={tr(\n \"auth.emailVerify.failedSubtitle\",\n \"We couldn't verify your email address\",\n )}\n >\n <div className=\"flex flex-col items-center justify-center py-6\">\n {/* Error Icon */}\n <div className=\"w-20 h-20 rounded-full bg-[var(--color-status-error-bg-subtle)] flex items-center justify-center mb-6\">\n <svg\n className=\"w-10 h-10 text-[var(--color-status-error-text)]\"\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=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n\n <p className=\"text-center text-[var(--color-text-secondary)] mb-8\">\n {tr(\n \"auth.emailVerify.invalidLink\",\n \"The verification link is invalid or has expired. Please request a new verification email.\",\n )}\n </p>\n\n {resendSuccess ? (\n <div className=\"w-full p-4 rounded-xl bg-[var(--color-status-success-bg-subtle)] border border-[var(--color-status-success-border)] text-center mb-4\">\n <p className=\"text-sm text-[var(--color-status-success-text)]\">\n {tr(\n \"auth.emailVerify.emailSent\",\n \"Verification email sent! Please check your inbox.\",\n )}\n </p>\n </div>\n ) : (\n <button\n onClick={handleResend}\n disabled={isResending}\n className=\"auth-primary-button mb-4 flex w-full items-center justify-center gap-2 px-4 py-3 font-semibold\"\n >\n {isResending ? (\n <>\n <SpinnerIcon className=\"w-5 h-5 animate-spin\" />\n <span>Sending...</span>\n </>\n ) : (\n tr(\"auth.emailVerify.resend\", \"Resend verification email\")\n )}\n </button>\n )}\n\n <button\n onClick={handleBackToLogin}\n className=\"w-full py-3 px-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] font-medium hover:bg-[var(--color-bg-sunken)] transition-all\"\n >\n {tr(\"auth.emailVerify.backToSignIn\", \"Back to sign in\")}\n </button>\n </div>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/LoginPage.tsx"],"names":[],"mappings":"AA0DA;;;GAGG;AACH,wBAAgB,SAAS,4CAsgCxB"}
|