@payez/next-mvp 3.0.0
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 +782 -0
- package/dist/api/auth-handler.d.ts +67 -0
- package/dist/api/auth-handler.js +397 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +19 -0
- package/dist/api-handlers/account/change-password.d.ts +9 -0
- package/dist/api-handlers/account/change-password.js +112 -0
- package/dist/api-handlers/account/masked-info.d.ts +2 -0
- package/dist/api-handlers/account/masked-info.js +41 -0
- package/dist/api-handlers/account/profile.d.ts +3 -0
- package/dist/api-handlers/account/profile.js +63 -0
- package/dist/api-handlers/account/recovery/initiate.d.ts +2 -0
- package/dist/api-handlers/account/recovery/initiate.js +26 -0
- package/dist/api-handlers/account/recovery/send-code.d.ts +2 -0
- package/dist/api-handlers/account/recovery/send-code.js +28 -0
- package/dist/api-handlers/account/recovery/verify-code.d.ts +2 -0
- package/dist/api-handlers/account/recovery/verify-code.js +28 -0
- package/dist/api-handlers/account/reset-password.d.ts +2 -0
- package/dist/api-handlers/account/reset-password.js +26 -0
- package/dist/api-handlers/account/send-code.d.ts +24 -0
- package/dist/api-handlers/account/send-code.js +60 -0
- package/dist/api-handlers/account/update-phone.d.ts +27 -0
- package/dist/api-handlers/account/update-phone.js +64 -0
- package/dist/api-handlers/account/validate-password.d.ts +17 -0
- package/dist/api-handlers/account/validate-password.js +81 -0
- package/dist/api-handlers/account/verify-email.d.ts +26 -0
- package/dist/api-handlers/account/verify-email.js +106 -0
- package/dist/api-handlers/account/verify-sms.d.ts +26 -0
- package/dist/api-handlers/account/verify-sms.js +106 -0
- package/dist/api-handlers/admin/analytics.d.ts +20 -0
- package/dist/api-handlers/admin/analytics.js +379 -0
- package/dist/api-handlers/admin/audit.d.ts +20 -0
- package/dist/api-handlers/admin/audit.js +214 -0
- package/dist/api-handlers/admin/index.d.ts +21 -0
- package/dist/api-handlers/admin/index.js +41 -0
- package/dist/api-handlers/admin/redis-sessions.d.ts +36 -0
- package/dist/api-handlers/admin/redis-sessions.js +204 -0
- package/dist/api-handlers/admin/sessions.d.ts +21 -0
- package/dist/api-handlers/admin/sessions.js +284 -0
- package/dist/api-handlers/admin/site-logs.d.ts +46 -0
- package/dist/api-handlers/admin/site-logs.js +318 -0
- package/dist/api-handlers/admin/users.d.ts +20 -0
- package/dist/api-handlers/admin/users.js +222 -0
- package/dist/api-handlers/admin/vibe-data.d.ts +80 -0
- package/dist/api-handlers/admin/vibe-data.js +268 -0
- package/dist/api-handlers/anon/preferences.d.ts +37 -0
- package/dist/api-handlers/anon/preferences.js +96 -0
- package/dist/api-handlers/auth/jwks.d.ts +2 -0
- package/dist/api-handlers/auth/jwks.js +24 -0
- package/dist/api-handlers/auth/login.d.ts +42 -0
- package/dist/api-handlers/auth/login.js +178 -0
- package/dist/api-handlers/auth/refresh.d.ts +74 -0
- package/dist/api-handlers/auth/refresh.js +635 -0
- package/dist/api-handlers/auth/signout.d.ts +37 -0
- package/dist/api-handlers/auth/signout.js +187 -0
- package/dist/api-handlers/auth/status.d.ts +8 -0
- package/dist/api-handlers/auth/status.js +26 -0
- package/dist/api-handlers/auth/update-session.d.ts +37 -0
- package/dist/api-handlers/auth/update-session.js +95 -0
- package/dist/api-handlers/auth/validate.d.ts +6 -0
- package/dist/api-handlers/auth/validate.js +43 -0
- package/dist/api-handlers/auth/verify-code.d.ts +43 -0
- package/dist/api-handlers/auth/verify-code.js +94 -0
- package/dist/api-handlers/session/refresh-viability.d.ts +14 -0
- package/dist/api-handlers/session/refresh-viability.js +39 -0
- package/dist/api-handlers/session/viability.d.ts +13 -0
- package/dist/api-handlers/session/viability.js +146 -0
- package/dist/api-handlers/test/force-expire.d.ts +23 -0
- package/dist/api-handlers/test/force-expire.js +65 -0
- package/dist/auth/auth-decision.d.ts +39 -0
- package/dist/auth/auth-decision.js +182 -0
- package/dist/auth/auth-options.d.ts +57 -0
- package/dist/auth/auth-options.js +213 -0
- package/dist/auth/callbacks/index.d.ts +6 -0
- package/dist/auth/callbacks/index.js +12 -0
- package/dist/auth/callbacks/jwt.d.ts +45 -0
- package/dist/auth/callbacks/jwt.js +305 -0
- package/dist/auth/callbacks/session.d.ts +60 -0
- package/dist/auth/callbacks/session.js +170 -0
- package/dist/auth/callbacks/signin.d.ts +23 -0
- package/dist/auth/callbacks/signin.js +44 -0
- package/dist/auth/events/index.d.ts +4 -0
- package/dist/auth/events/index.js +8 -0
- package/dist/auth/events/signout.d.ts +17 -0
- package/dist/auth/events/signout.js +32 -0
- package/dist/auth/providers/credentials.d.ts +32 -0
- package/dist/auth/providers/credentials.js +223 -0
- package/dist/auth/providers/index.d.ts +5 -0
- package/dist/auth/providers/index.js +21 -0
- package/dist/auth/providers/oauth.d.ts +26 -0
- package/dist/auth/providers/oauth.js +105 -0
- package/dist/auth/route-config.d.ts +66 -0
- package/dist/auth/route-config.js +190 -0
- package/dist/auth/types/auth-types.d.ts +417 -0
- package/dist/auth/types/auth-types.js +53 -0
- package/dist/auth/types/index.d.ts +6 -0
- package/dist/auth/types/index.js +22 -0
- package/dist/auth/unauthenticated-routes.d.ts +1 -0
- package/dist/auth/unauthenticated-routes.js +19 -0
- package/dist/auth/utils/idp-client.d.ts +94 -0
- package/dist/auth/utils/idp-client.js +383 -0
- package/dist/auth/utils/index.d.ts +5 -0
- package/dist/auth/utils/index.js +21 -0
- package/dist/auth/utils/token-utils.d.ts +84 -0
- package/dist/auth/utils/token-utils.js +219 -0
- package/dist/client/AuthContext.d.ts +19 -0
- package/dist/client/AuthContext.js +112 -0
- package/dist/client/fetch-with-auth.d.ts +11 -0
- package/dist/client/fetch-with-auth.js +44 -0
- package/dist/client/fetchWithSession.d.ts +3 -0
- package/dist/client/fetchWithSession.js +24 -0
- package/dist/client/index.d.ts +9 -0
- package/dist/client/index.js +20 -0
- package/dist/client/useAnonSession.d.ts +36 -0
- package/dist/client/useAnonSession.js +99 -0
- package/dist/components/SessionSync.d.ts +13 -0
- package/dist/components/SessionSync.js +119 -0
- package/dist/components/SignalRHealthCheck.d.ts +10 -0
- package/dist/components/SignalRHealthCheck.js +97 -0
- package/dist/components/account/UserAvatarMenu.d.ts +20 -0
- package/dist/components/account/UserAvatarMenu.js +80 -0
- package/dist/components/account/index.d.ts +7 -0
- package/dist/components/account/index.js +10 -0
- package/dist/components/admin/AlertSettingsTab.d.ts +48 -0
- package/dist/components/admin/AlertSettingsTab.js +351 -0
- package/dist/components/admin/AnalyticsTab.d.ts +22 -0
- package/dist/components/admin/AnalyticsTab.js +167 -0
- package/dist/components/admin/DataBrowserTab.d.ts +19 -0
- package/dist/components/admin/DataBrowserTab.js +252 -0
- package/dist/components/admin/LoggingSettingsTab.d.ts +73 -0
- package/dist/components/admin/LoggingSettingsTab.js +339 -0
- package/dist/components/admin/SessionsTab.d.ts +37 -0
- package/dist/components/admin/SessionsTab.js +165 -0
- package/dist/components/admin/StatsTab.d.ts +53 -0
- package/dist/components/admin/StatsTab.js +161 -0
- package/dist/components/admin/VibeAdminContext.d.ts +32 -0
- package/dist/components/admin/VibeAdminContext.js +38 -0
- package/dist/components/admin/VibeAdminLayout.d.ts +11 -0
- package/dist/components/admin/VibeAdminLayout.js +69 -0
- package/dist/components/admin/index.d.ts +29 -0
- package/dist/components/admin/index.js +44 -0
- package/dist/components/auth/FederatedAuthSection.d.ts +8 -0
- package/dist/components/auth/FederatedAuthSection.js +45 -0
- package/dist/components/auth/ModeAwareLoginPage.d.ts +10 -0
- package/dist/components/auth/ModeAwareLoginPage.js +42 -0
- package/dist/components/auth/ModeAwareSignupPage.d.ts +9 -0
- package/dist/components/auth/ModeAwareSignupPage.js +78 -0
- package/dist/components/auth/TraditionalAuthSection.d.ts +14 -0
- package/dist/components/auth/TraditionalAuthSection.js +20 -0
- package/dist/components/recovery/CompleteStep.d.ts +5 -0
- package/dist/components/recovery/CompleteStep.js +8 -0
- package/dist/components/recovery/InitiateRecoveryStep.d.ts +8 -0
- package/dist/components/recovery/InitiateRecoveryStep.js +20 -0
- package/dist/components/recovery/SelectMethodStep.d.ts +8 -0
- package/dist/components/recovery/SelectMethodStep.js +8 -0
- package/dist/components/recovery/SetPasswordStep.d.ts +6 -0
- package/dist/components/recovery/SetPasswordStep.js +20 -0
- package/dist/components/recovery/VerifyCodeStep.d.ts +10 -0
- package/dist/components/recovery/VerifyCodeStep.js +24 -0
- package/dist/components/reserved/ReservedRecoveryWarning.d.ts +38 -0
- package/dist/components/reserved/ReservedRecoveryWarning.js +92 -0
- package/dist/components/reserved/ReservedStatusBox.d.ts +30 -0
- package/dist/components/reserved/ReservedStatusBox.js +71 -0
- package/dist/components/ui/BetaBadge.d.ts +29 -0
- package/dist/components/ui/BetaBadge.js +38 -0
- package/dist/components/ui/Footer.d.ts +37 -0
- package/dist/components/ui/Footer.js +41 -0
- package/dist/config/env.d.ts +66 -0
- package/dist/config/env.js +57 -0
- package/dist/config/logger.d.ts +57 -0
- package/dist/config/logger.js +73 -0
- package/dist/config/logging-config.d.ts +30 -0
- package/dist/config/logging-config.js +122 -0
- package/dist/config/unauthenticated-routes.d.ts +17 -0
- package/dist/config/unauthenticated-routes.js +24 -0
- package/dist/config/vibe-log-transport.d.ts +79 -0
- package/dist/config/vibe-log-transport.js +203 -0
- package/dist/edge/internal-api-url.d.ts +53 -0
- package/dist/edge/internal-api-url.js +63 -0
- package/dist/edge/middleware.d.ts +14 -0
- package/dist/edge/middleware.js +32 -0
- package/dist/hooks/useAuth.d.ts +23 -0
- package/dist/hooks/useAuth.js +81 -0
- package/dist/hooks/useAuthSettings.d.ts +59 -0
- package/dist/hooks/useAuthSettings.js +93 -0
- package/dist/hooks/useAvailableProviders.d.ts +45 -0
- package/dist/hooks/useAvailableProviders.js +108 -0
- package/dist/hooks/usePasswordValidation.d.ts +27 -0
- package/dist/hooks/usePasswordValidation.js +102 -0
- package/dist/hooks/useProfile.d.ts +15 -0
- package/dist/hooks/useProfile.js +59 -0
- package/dist/hooks/usePublicAuthSettings.d.ts +56 -0
- package/dist/hooks/usePublicAuthSettings.js +131 -0
- package/dist/hooks/useSessionExpiration.d.ts +57 -0
- package/dist/hooks/useSessionExpiration.js +72 -0
- package/dist/hooks/useViabilitySession.d.ts +75 -0
- package/dist/hooks/useViabilitySession.js +268 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +54 -0
- package/dist/lib/anon-session.d.ts +74 -0
- package/dist/lib/anon-session.js +169 -0
- package/dist/lib/api-handler.d.ts +123 -0
- package/dist/lib/api-handler.js +478 -0
- package/dist/lib/app-slug.d.ts +95 -0
- package/dist/lib/app-slug.js +172 -0
- package/dist/lib/demo-mode.d.ts +6 -0
- package/dist/lib/demo-mode.js +16 -0
- package/dist/lib/geolocation.d.ts +64 -0
- package/dist/lib/geolocation.js +235 -0
- package/dist/lib/idp-client-config.d.ts +75 -0
- package/dist/lib/idp-client-config.js +351 -0
- package/dist/lib/idp-fetch.d.ts +14 -0
- package/dist/lib/idp-fetch.js +91 -0
- package/dist/lib/internal-api.d.ts +87 -0
- package/dist/lib/internal-api.js +122 -0
- package/dist/lib/jwt-decode-client.d.ts +10 -0
- package/dist/lib/jwt-decode-client.js +46 -0
- package/dist/lib/jwt-decode.d.ts +48 -0
- package/dist/lib/jwt-decode.js +57 -0
- package/dist/lib/nextauth-secret.d.ts +10 -0
- package/dist/lib/nextauth-secret.js +104 -0
- package/dist/lib/rate-limit-service.d.ts +23 -0
- package/dist/lib/rate-limit-service.js +6 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.js +28 -0
- package/dist/lib/refresh-token-validator.d.ts +13 -0
- package/dist/lib/refresh-token-validator.js +117 -0
- package/dist/lib/roles.d.ts +145 -0
- package/dist/lib/roles.js +168 -0
- package/dist/lib/secret-validation.d.ts +4 -0
- package/dist/lib/secret-validation.js +14 -0
- package/dist/lib/session-store.d.ts +166 -0
- package/dist/lib/session-store.js +537 -0
- package/dist/lib/session.d.ts +21 -0
- package/dist/lib/session.js +26 -0
- package/dist/lib/site-logger.d.ts +214 -0
- package/dist/lib/site-logger.js +210 -0
- package/dist/lib/standardized-client-api.d.ts +161 -0
- package/dist/lib/standardized-client-api.js +786 -0
- package/dist/lib/startup-init.d.ts +40 -0
- package/dist/lib/startup-init.js +261 -0
- package/dist/lib/test-aware-get-token.d.ts +2 -0
- package/dist/lib/test-aware-get-token.js +81 -0
- package/dist/lib/token-expiry.d.ts +14 -0
- package/dist/lib/token-expiry.js +39 -0
- package/dist/lib/token-lifecycle.d.ts +52 -0
- package/dist/lib/token-lifecycle.js +398 -0
- package/dist/lib/types/api-responses.d.ts +128 -0
- package/dist/lib/types/api-responses.js +171 -0
- package/dist/lib/user-agent-parser.d.ts +50 -0
- package/dist/lib/user-agent-parser.js +220 -0
- package/dist/logging/api/admin-analytics.d.ts +3 -0
- package/dist/logging/api/admin-analytics.js +45 -0
- package/dist/logging/api/audit-log.d.ts +3 -0
- package/dist/logging/api/audit-log.js +52 -0
- package/dist/logging/components/AdminAnalyticsLayout.d.ts +10 -0
- package/dist/logging/components/AdminAnalyticsLayout.js +11 -0
- package/dist/logging/components/AuditLogViewer.d.ts +7 -0
- package/dist/logging/components/AuditLogViewer.js +51 -0
- package/dist/logging/components/ErrorMetricsCard.d.ts +7 -0
- package/dist/logging/components/ErrorMetricsCard.js +16 -0
- package/dist/logging/components/HealthMetricsCard.d.ts +7 -0
- package/dist/logging/components/HealthMetricsCard.js +19 -0
- package/dist/logging/hooks/useAdminAnalytics.d.ts +24 -0
- package/dist/logging/hooks/useAdminAnalytics.js +22 -0
- package/dist/logging/hooks/useAuditLog.d.ts +6 -0
- package/dist/logging/hooks/useAuditLog.js +25 -0
- package/dist/logging/hooks/useErrorMetrics.d.ts +6 -0
- package/dist/logging/hooks/useErrorMetrics.js +38 -0
- package/dist/logging/hooks/useHealthMetrics.d.ts +6 -0
- package/dist/logging/hooks/useHealthMetrics.js +41 -0
- package/dist/logging/index.d.ts +11 -0
- package/dist/logging/index.js +40 -0
- package/dist/logging/types/analytics.d.ts +68 -0
- package/dist/logging/types/analytics.js +3 -0
- package/dist/logging/types/audit.d.ts +29 -0
- package/dist/logging/types/audit.js +2 -0
- package/dist/logging/types/index.d.ts +2 -0
- package/dist/logging/types/index.js +19 -0
- package/dist/middleware/auth-decision.d.ts +33 -0
- package/dist/middleware/auth-decision.js +65 -0
- package/dist/middleware/create-middleware.d.ts +100 -0
- package/dist/middleware/create-middleware.js +445 -0
- package/dist/middleware/rbac-check.d.ts +44 -0
- package/dist/middleware/rbac-check.js +191 -0
- package/dist/middleware/twofa-presets.d.ts +134 -0
- package/dist/middleware/twofa-presets.js +175 -0
- package/dist/models/DecodedAccessToken.d.ts +17 -0
- package/dist/models/DecodedAccessToken.js +2 -0
- package/dist/models/SessionModel.d.ts +122 -0
- package/dist/models/SessionModel.js +136 -0
- package/dist/pages/admin-login/page.d.ts +31 -0
- package/dist/pages/admin-login/page.js +83 -0
- package/dist/pages/admin-roles/RolesAdminPage.d.ts +15 -0
- package/dist/pages/admin-roles/RolesAdminPage.js +78 -0
- package/dist/pages/admin-roles/index.d.ts +8 -0
- package/dist/pages/admin-roles/index.js +15 -0
- package/dist/pages/admin-roles/modals.d.ts +72 -0
- package/dist/pages/admin-roles/modals.js +154 -0
- package/dist/pages/client-admin/ClientSiteAdminPage.d.ts +79 -0
- package/dist/pages/client-admin/ClientSiteAdminPage.js +177 -0
- package/dist/pages/client-admin/index.d.ts +32 -0
- package/dist/pages/client-admin/index.js +37 -0
- package/dist/pages/login/page.d.ts +22 -0
- package/dist/pages/login/page.js +239 -0
- package/dist/pages/profile/EnhancedProfilePage.d.ts +13 -0
- package/dist/pages/profile/EnhancedProfilePage.js +150 -0
- package/dist/pages/profile/index.d.ts +8 -0
- package/dist/pages/profile/index.js +16 -0
- package/dist/pages/profile/page.d.ts +19 -0
- package/dist/pages/profile/page.js +47 -0
- package/dist/pages/profile/profile-patch.d.ts +1 -0
- package/dist/pages/profile/profile-patch.js +281 -0
- package/dist/pages/recovery/page.d.ts +1 -0
- package/dist/pages/recovery/page.js +142 -0
- package/dist/pages/roles/MyRolesPage.d.ts +24 -0
- package/dist/pages/roles/MyRolesPage.js +71 -0
- package/dist/pages/roles/components.d.ts +63 -0
- package/dist/pages/roles/components.js +108 -0
- package/dist/pages/roles/index.d.ts +8 -0
- package/dist/pages/roles/index.js +19 -0
- package/dist/pages/security/EnhancedSecurityPage.d.ts +14 -0
- package/dist/pages/security/EnhancedSecurityPage.js +248 -0
- package/dist/pages/security/index.d.ts +8 -0
- package/dist/pages/security/index.js +16 -0
- package/dist/pages/security/page.d.ts +21 -0
- package/dist/pages/security/page.js +212 -0
- package/dist/pages/security/security-patch.d.ts +1 -0
- package/dist/pages/security/security-patch.js +302 -0
- package/dist/pages/settings/EnhancedSettingsPage.d.ts +46 -0
- package/dist/pages/settings/EnhancedSettingsPage.js +231 -0
- package/dist/pages/settings/index.d.ts +8 -0
- package/dist/pages/settings/index.js +16 -0
- package/dist/pages/settings/page.d.ts +7 -0
- package/dist/pages/settings/page.js +26 -0
- package/dist/pages/showcase/ShowcasePage.d.ts +13 -0
- package/dist/pages/showcase/ShowcasePage.js +140 -0
- package/dist/pages/showcase/index.d.ts +12 -0
- package/dist/pages/showcase/index.js +17 -0
- package/dist/pages/test-env/EmergencyLogoutPage.d.ts +14 -0
- package/dist/pages/test-env/EmergencyLogoutPage.js +98 -0
- package/dist/pages/test-env/JwtInspectPage.d.ts +14 -0
- package/dist/pages/test-env/JwtInspectPage.js +114 -0
- package/dist/pages/test-env/RefreshTokenPage.d.ts +15 -0
- package/dist/pages/test-env/RefreshTokenPage.js +91 -0
- package/dist/pages/test-env/TestEnvPage.d.ts +13 -0
- package/dist/pages/test-env/TestEnvPage.js +49 -0
- package/dist/pages/test-env/index.d.ts +24 -0
- package/dist/pages/test-env/index.js +32 -0
- package/dist/pages/verify-code/page.d.ts +30 -0
- package/dist/pages/verify-code/page.js +408 -0
- package/dist/routes/account/index.d.ts +28 -0
- package/dist/routes/account/index.js +71 -0
- package/dist/routes/account/masked-info.d.ts +33 -0
- package/dist/routes/account/masked-info.js +39 -0
- package/dist/routes/account/send-code.d.ts +37 -0
- package/dist/routes/account/send-code.js +42 -0
- package/dist/routes/account/update-phone.d.ts +13 -0
- package/dist/routes/account/update-phone.js +17 -0
- package/dist/routes/account/verify-email.d.ts +38 -0
- package/dist/routes/account/verify-email.js +43 -0
- package/dist/routes/account/verify-sms.d.ts +38 -0
- package/dist/routes/account/verify-sms.js +43 -0
- package/dist/routes/auth/index.d.ts +19 -0
- package/dist/routes/auth/index.js +64 -0
- package/dist/routes/auth/logout.d.ts +31 -0
- package/dist/routes/auth/logout.js +113 -0
- package/dist/routes/auth/nextauth.d.ts +19 -0
- package/dist/routes/auth/nextauth.js +72 -0
- package/dist/routes/auth/refresh.d.ts +30 -0
- package/dist/routes/auth/refresh.js +51 -0
- package/dist/routes/auth/session.d.ts +72 -0
- package/dist/routes/auth/session.js +180 -0
- package/dist/routes/auth/settings.d.ts +25 -0
- package/dist/routes/auth/settings.js +55 -0
- package/dist/routes/auth/viability.d.ts +52 -0
- package/dist/routes/auth/viability.js +201 -0
- package/dist/routes/index.d.ts +12 -0
- package/dist/routes/index.js +54 -0
- package/dist/routes/session/index.d.ts +6 -0
- package/dist/routes/session/index.js +10 -0
- package/dist/routes/session/refresh-viability.d.ts +16 -0
- package/dist/routes/session/refresh-viability.js +20 -0
- package/dist/services/signalrActivityService.d.ts +44 -0
- package/dist/services/signalrActivityService.js +257 -0
- package/dist/stores/authStore.d.ts +154 -0
- package/dist/stores/authStore.js +1531 -0
- package/dist/theme/ThemeProvider.d.ts +14 -0
- package/dist/theme/ThemeProvider.js +28 -0
- package/dist/theme/default.d.ts +8 -0
- package/dist/theme/default.js +33 -0
- package/dist/theme/index.d.ts +15 -0
- package/dist/theme/index.js +25 -0
- package/dist/theme/types.d.ts +56 -0
- package/dist/theme/types.js +8 -0
- package/dist/theme/useTheme.d.ts +60 -0
- package/dist/theme/useTheme.js +63 -0
- package/dist/theme/utils.d.ts +13 -0
- package/dist/theme/utils.js +39 -0
- package/dist/types/api.d.ts +134 -0
- package/dist/types/api.js +44 -0
- package/dist/types/auth.d.ts +19 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/logging.d.ts +42 -0
- package/dist/types/logging.js +2 -0
- package/dist/types/recovery.d.ts +48 -0
- package/dist/types/recovery.js +2 -0
- package/dist/types/security.d.ts +1 -0
- package/dist/types/security.js +2 -0
- package/dist/utils/api.d.ts +85 -0
- package/dist/utils/api.js +287 -0
- package/dist/utils/circuitBreaker.d.ts +43 -0
- package/dist/utils/circuitBreaker.js +91 -0
- package/dist/utils/error-message.d.ts +1 -0
- package/dist/utils/error-message.js +103 -0
- package/dist/utils/layout/reservedSpace.d.ts +59 -0
- package/dist/utils/layout/reservedSpace.js +102 -0
- package/dist/utils/logout.d.ts +14 -0
- package/dist/utils/logout.js +32 -0
- package/dist/vibe/client.d.ts +261 -0
- package/dist/vibe/client.js +445 -0
- package/dist/vibe/errors.d.ts +83 -0
- package/dist/vibe/errors.js +146 -0
- package/dist/vibe/generic.d.ts +234 -0
- package/dist/vibe/generic.js +369 -0
- package/dist/vibe/hooks/index.d.ts +169 -0
- package/dist/vibe/hooks/index.js +252 -0
- package/dist/vibe/index.d.ts +23 -0
- package/dist/vibe/index.js +67 -0
- package/dist/vibe/sessions.d.ts +161 -0
- package/dist/vibe/sessions.js +391 -0
- package/dist/vibe/types.d.ts +353 -0
- package/dist/vibe/types.js +315 -0
- package/package.json +855 -0
- package/scripts/check-internal-url-usage.sh +73 -0
- package/scripts/dev-broker.ps1 +35 -0
- package/scripts/dev-local.ps1 +45 -0
- package/src/api/auth-handler.ts +550 -0
- package/src/api/index.ts +18 -0
- package/src/api-handlers/account/change-password.ts +145 -0
- package/src/api-handlers/account/masked-info.ts +45 -0
- package/src/api-handlers/account/profile.ts +80 -0
- package/src/api-handlers/account/recovery/initiate.ts +23 -0
- package/src/api-handlers/account/recovery/send-code.ts +25 -0
- package/src/api-handlers/account/recovery/verify-code.ts +25 -0
- package/src/api-handlers/account/reset-password.ts +23 -0
- package/src/api-handlers/account/send-code.ts +76 -0
- package/src/api-handlers/account/update-phone.ts +79 -0
- package/src/api-handlers/account/validate-password.ts +118 -0
- package/src/api-handlers/account/verify-email.ts +125 -0
- package/src/api-handlers/account/verify-sms.ts +125 -0
- package/src/api-handlers/admin/analytics.ts +445 -0
- package/src/api-handlers/admin/audit.ts +225 -0
- package/src/api-handlers/admin/index.ts +59 -0
- package/src/api-handlers/admin/redis-sessions.ts +253 -0
- package/src/api-handlers/admin/sessions.ts +320 -0
- package/src/api-handlers/admin/site-logs.ts +367 -0
- package/src/api-handlers/admin/users.ts +244 -0
- package/src/api-handlers/admin/vibe-data.ts +326 -0
- package/src/api-handlers/anon/preferences.ts +123 -0
- package/src/api-handlers/auth/jwks.ts +20 -0
- package/src/api-handlers/auth/login.ts +240 -0
- package/src/api-handlers/auth/refresh.ts +687 -0
- package/src/api-handlers/auth/signout.ts +212 -0
- package/src/api-handlers/auth/status.ts +23 -0
- package/src/api-handlers/auth/update-session.ts +125 -0
- package/src/api-handlers/auth/validate.ts +44 -0
- package/src/api-handlers/auth/verify-code.ts +129 -0
- package/src/api-handlers/session/refresh-viability.ts +36 -0
- package/src/api-handlers/session/viability.ts +166 -0
- package/src/api-handlers/test/force-expire.ts +67 -0
- package/src/auth/auth-decision.ts +230 -0
- package/src/auth/auth-options.ts +237 -0
- package/src/auth/callbacks/index.ts +7 -0
- package/src/auth/callbacks/jwt.ts +382 -0
- package/src/auth/callbacks/session.ts +243 -0
- package/src/auth/callbacks/signin.ts +56 -0
- package/src/auth/events/index.ts +5 -0
- package/src/auth/events/signout.ts +33 -0
- package/src/auth/providers/credentials.ts +256 -0
- package/src/auth/providers/index.ts +6 -0
- package/src/auth/providers/oauth.ts +114 -0
- package/src/auth/route-config.ts +220 -0
- package/src/auth/types/auth-types.ts +555 -0
- package/src/auth/types/index.ts +7 -0
- package/src/auth/unauthenticated-routes.ts +3 -0
- package/src/auth/utils/idp-client.ts +444 -0
- package/src/auth/utils/index.ts +6 -0
- package/src/auth/utils/token-utils.ts +244 -0
- package/src/client/AuthContext.tsx +140 -0
- package/src/client/fetch-with-auth.ts +48 -0
- package/src/client/fetchWithSession.ts +21 -0
- package/src/client/index.ts +13 -0
- package/src/client/useAnonSession.ts +131 -0
- package/src/components/SessionSync.tsx +137 -0
- package/src/components/SignalRHealthCheck.tsx +131 -0
- package/src/components/account/UserAvatarMenu.tsx +217 -0
- package/src/components/account/index.ts +8 -0
- package/src/components/admin/AlertSettingsTab.tsx +728 -0
- package/src/components/admin/AnalyticsTab.tsx +703 -0
- package/src/components/admin/DataBrowserTab.tsx +505 -0
- package/src/components/admin/LoggingSettingsTab.tsx +665 -0
- package/src/components/admin/SessionsTab.tsx +414 -0
- package/src/components/admin/StatsTab.tsx +379 -0
- package/src/components/admin/VibeAdminContext.tsx +87 -0
- package/src/components/admin/VibeAdminLayout.tsx +185 -0
- package/src/components/admin/index.ts +59 -0
- package/src/components/auth/FederatedAuthSection.tsx +95 -0
- package/src/components/auth/ModeAwareLoginPage.tsx +135 -0
- package/src/components/auth/ModeAwareSignupPage.tsx +267 -0
- package/src/components/auth/TraditionalAuthSection.tsx +99 -0
- package/src/components/recovery/CompleteStep.tsx +36 -0
- package/src/components/recovery/InitiateRecoveryStep.tsx +68 -0
- package/src/components/recovery/SelectMethodStep.tsx +73 -0
- package/src/components/recovery/SetPasswordStep.tsx +97 -0
- package/src/components/recovery/VerifyCodeStep.tsx +90 -0
- package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -0
- package/src/components/reserved/ReservedStatusBox.tsx +118 -0
- package/src/components/ui/BetaBadge.tsx +58 -0
- package/src/components/ui/Footer.tsx +93 -0
- package/src/config/env.ts +57 -0
- package/src/config/logger.ts +62 -0
- package/src/config/logging-config.ts +82 -0
- package/src/config/unauthenticated-routes.ts +19 -0
- package/src/config/vibe-log-transport.ts +250 -0
- package/src/edge/internal-api-url.ts +65 -0
- package/src/edge/middleware.ts +42 -0
- package/src/hooks/useAuth.ts +115 -0
- package/src/hooks/useAuthSettings.ts +97 -0
- package/src/hooks/useAvailableProviders.ts +118 -0
- package/src/hooks/usePasswordValidation.ts +127 -0
- package/src/hooks/useProfile.ts +75 -0
- package/src/hooks/usePublicAuthSettings.ts +149 -0
- package/src/hooks/useSessionExpiration.ts +102 -0
- package/src/hooks/useViabilitySession.ts +335 -0
- package/src/index.ts +63 -0
- package/src/lib/anon-session.ts +213 -0
- package/src/lib/api-handler.ts +625 -0
- package/src/lib/app-slug.ts +178 -0
- package/src/lib/demo-mode.ts +13 -0
- package/src/lib/geolocation.ts +265 -0
- package/src/lib/idp-client-config.ts +442 -0
- package/src/lib/idp-fetch.ts +101 -0
- package/src/lib/internal-api.ts +171 -0
- package/src/lib/jwt-decode-client.ts +45 -0
- package/src/lib/jwt-decode.ts +83 -0
- package/src/lib/nextauth-secret.ts +126 -0
- package/src/lib/rate-limit-service.ts +9 -0
- package/src/lib/redis.ts +27 -0
- package/src/lib/refresh-token-validator.ts +64 -0
- package/src/lib/roles.ts +177 -0
- package/src/lib/secret-validation.ts +8 -0
- package/src/lib/session-store.ts +637 -0
- package/src/lib/session.ts +34 -0
- package/src/lib/site-logger.ts +245 -0
- package/src/lib/standardized-client-api.ts +896 -0
- package/src/lib/startup-init.ts +247 -0
- package/src/lib/test-aware-get-token.ts +30 -0
- package/src/lib/token-expiry.ts +40 -0
- package/src/lib/token-lifecycle.ts +477 -0
- package/src/lib/types/api-responses.ts +336 -0
- package/src/lib/user-agent-parser.ts +252 -0
- package/src/logging/api/admin-analytics.ts +51 -0
- package/src/logging/api/audit-log.ts +53 -0
- package/src/logging/components/AdminAnalyticsLayout.tsx +49 -0
- package/src/logging/components/AuditLogViewer.tsx +125 -0
- package/src/logging/components/ErrorMetricsCard.tsx +98 -0
- package/src/logging/components/HealthMetricsCard.tsx +70 -0
- package/src/logging/hooks/useAdminAnalytics.ts +22 -0
- package/src/logging/hooks/useAuditLog.ts +24 -0
- package/src/logging/hooks/useErrorMetrics.ts +40 -0
- package/src/logging/hooks/useHealthMetrics.ts +44 -0
- package/src/logging/index.ts +18 -0
- package/src/logging/types/analytics.ts +81 -0
- package/src/logging/types/audit.ts +31 -0
- package/src/logging/types/index.ts +3 -0
- package/src/middleware/auth-decision.ts +43 -0
- package/src/middleware/create-middleware.ts +626 -0
- package/src/middleware/rbac-check.ts +244 -0
- package/src/middleware/twofa-presets.ts +224 -0
- package/src/models/DecodedAccessToken.ts +17 -0
- package/src/models/SessionModel.ts +258 -0
- package/src/pages/admin-login/page.tsx +229 -0
- package/src/pages/admin-roles/RolesAdminPage.tsx +357 -0
- package/src/pages/admin-roles/index.ts +9 -0
- package/src/pages/admin-roles/modals.tsx +469 -0
- package/src/pages/client-admin/ClientSiteAdminPage.tsx +380 -0
- package/src/pages/client-admin/index.ts +33 -0
- package/src/pages/login/page.tsx +463 -0
- package/src/pages/profile/EnhancedProfilePage.tsx +479 -0
- package/src/pages/profile/index.ts +9 -0
- package/src/pages/profile/page.tsx +166 -0
- package/src/pages/recovery/page.tsx +234 -0
- package/src/pages/roles/MyRolesPage.tsx +211 -0
- package/src/pages/roles/components.tsx +294 -0
- package/src/pages/roles/index.ts +17 -0
- package/src/pages/security/EnhancedSecurityPage.tsx +574 -0
- package/src/pages/security/index.ts +9 -0
- package/src/pages/security/page.tsx +507 -0
- package/src/pages/settings/EnhancedSettingsPage.tsx +642 -0
- package/src/pages/settings/index.ts +9 -0
- package/src/pages/settings/page.tsx +47 -0
- package/src/pages/showcase/ShowcasePage.tsx +530 -0
- package/src/pages/showcase/index.ts +13 -0
- package/src/pages/test-env/EmergencyLogoutPage.tsx +179 -0
- package/src/pages/test-env/JwtInspectPage.tsx +418 -0
- package/src/pages/test-env/RefreshTokenPage.tsx +155 -0
- package/src/pages/test-env/TestEnvPage.tsx +116 -0
- package/src/pages/test-env/index.ts +25 -0
- package/src/pages/verify-code/page.tsx +648 -0
- package/src/routes/account/index.ts +32 -0
- package/src/routes/account/masked-info.ts +37 -0
- package/src/routes/account/send-code.ts +40 -0
- package/src/routes/account/update-phone.ts +13 -0
- package/src/routes/account/verify-email.ts +41 -0
- package/src/routes/account/verify-sms.ts +41 -0
- package/src/routes/auth/index.ts +23 -0
- package/src/routes/auth/logout.ts +127 -0
- package/src/routes/auth/nextauth.ts +71 -0
- package/src/routes/auth/refresh.ts +54 -0
- package/src/routes/auth/session.ts +193 -0
- package/src/routes/auth/settings.ts +75 -0
- package/src/routes/auth/viability.ts +220 -0
- package/src/routes/index.ts +18 -0
- package/src/routes/session/index.ts +7 -0
- package/src/routes/session/refresh-viability.ts +17 -0
- package/src/services/signalrActivityService.ts +258 -0
- package/src/stores/authStore.ts +1904 -0
- package/src/templates/instrumentation.ts +41 -0
- package/src/theme/ThemeProvider.tsx +39 -0
- package/src/theme/default.ts +33 -0
- package/src/theme/index.ts +31 -0
- package/src/theme/types.ts +69 -0
- package/src/theme/useTheme.ts +57 -0
- package/src/theme/utils.ts +40 -0
- package/src/types/api.ts +13 -0
- package/src/types/auth.d.ts +15 -0
- package/src/types/auth.ts +22 -0
- package/src/types/logging.ts +11 -0
- package/src/types/next-auth.d.ts +15 -0
- package/src/types/recovery.ts +54 -0
- package/src/types/security.ts +1 -0
- package/src/utils/api.ts +353 -0
- package/src/utils/circuitBreaker.ts +40 -0
- package/src/utils/error-message.ts +108 -0
- package/src/utils/layout/reservedSpace.ts +124 -0
- package/src/utils/logout.ts +30 -0
- package/src/vibe/client.ts +590 -0
- package/src/vibe/errors.ts +185 -0
- package/src/vibe/generic.ts +429 -0
- package/src/vibe/hooks/index.ts +367 -0
- package/src/vibe/index.ts +121 -0
- package/src/vibe/sessions.ts +551 -0
- package/src/vibe/types.ts +577 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext, ReactNode, useState, useEffect } from 'react';
|
|
4
|
+
import { getProviders } from 'next-auth/react';
|
|
5
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
6
|
+
import { AuthConfig, AuthMode, FederatedProvider } from '@/types/auth';
|
|
7
|
+
|
|
8
|
+
const AuthContext = createContext<AuthConfig | null>(null);
|
|
9
|
+
|
|
10
|
+
const defaultConfig: AuthConfig = {
|
|
11
|
+
mode: 'traditional',
|
|
12
|
+
providers: [],
|
|
13
|
+
enableRecovery: true,
|
|
14
|
+
enableEmailSignup: true,
|
|
15
|
+
allowPasswordReset: true,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Map NextAuth provider IDs to our FederatedProvider type
|
|
19
|
+
const PROVIDER_MAP: Record<string, FederatedProvider> = {
|
|
20
|
+
'google': 'google',
|
|
21
|
+
'apple': 'apple',
|
|
22
|
+
'facebook': 'facebook',
|
|
23
|
+
'github': 'github',
|
|
24
|
+
'azure-ad': 'microsoft',
|
|
25
|
+
'microsoft-entra-id': 'microsoft',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// OAuth providers we support in UI (excludes credentials)
|
|
29
|
+
const OAUTH_PROVIDER_IDS = ['google', 'apple', 'facebook', 'github', 'azure-ad', 'microsoft-entra-id'];
|
|
30
|
+
|
|
31
|
+
interface AuthProviderProps {
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
config?: Partial<AuthConfig>;
|
|
34
|
+
/**
|
|
35
|
+
* If true, providers will be fetched dynamically from NextAuth
|
|
36
|
+
* instead of using the static providers array from config.
|
|
37
|
+
* Defaults to true for dynamic provider loading from IDP.
|
|
38
|
+
*/
|
|
39
|
+
useDynamicProviders?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function AuthProvider({ children, config, useDynamicProviders = true }: AuthProviderProps) {
|
|
43
|
+
const [dynamicProviders, setDynamicProviders] = useState<FederatedProvider[]>([]);
|
|
44
|
+
const [providersLoaded, setProvidersLoaded] = useState(!useDynamicProviders);
|
|
45
|
+
|
|
46
|
+
// Create QueryClient instance for React Query - used internally by MVP hooks
|
|
47
|
+
const [queryClient] = useState(() => new QueryClient({
|
|
48
|
+
defaultOptions: {
|
|
49
|
+
queries: {
|
|
50
|
+
staleTime: 60 * 1000, // 1 minute
|
|
51
|
+
retry: 1,
|
|
52
|
+
refetchOnWindowFocus: false,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
// Fetch dynamic providers from NextAuth on mount
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!useDynamicProviders) return;
|
|
60
|
+
|
|
61
|
+
let mounted = true;
|
|
62
|
+
|
|
63
|
+
async function fetchDynamicProviders() {
|
|
64
|
+
try {
|
|
65
|
+
const result = await getProviders();
|
|
66
|
+
|
|
67
|
+
if (!mounted) return;
|
|
68
|
+
|
|
69
|
+
if (result) {
|
|
70
|
+
// Filter to OAuth providers only and map to FederatedProvider type
|
|
71
|
+
const oauthProviders = Object.keys(result)
|
|
72
|
+
.filter(id => OAUTH_PROVIDER_IDS.includes(id))
|
|
73
|
+
.map(id => PROVIDER_MAP[id])
|
|
74
|
+
.filter((p): p is FederatedProvider => p !== undefined);
|
|
75
|
+
|
|
76
|
+
setDynamicProviders(oauthProviders);
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// Fall back to static config providers on error
|
|
80
|
+
} finally {
|
|
81
|
+
if (mounted) {
|
|
82
|
+
setProvidersLoaded(true);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fetchDynamicProviders();
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
mounted = false;
|
|
91
|
+
};
|
|
92
|
+
}, [useDynamicProviders]);
|
|
93
|
+
|
|
94
|
+
// Determine final providers list
|
|
95
|
+
const providers = useDynamicProviders && providersLoaded
|
|
96
|
+
? dynamicProviders
|
|
97
|
+
: (config?.providers ?? defaultConfig.providers);
|
|
98
|
+
|
|
99
|
+
const authConfig: AuthConfig = {
|
|
100
|
+
...defaultConfig,
|
|
101
|
+
...config,
|
|
102
|
+
providers, // Override with dynamic providers if enabled
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<QueryClientProvider client={queryClient}>
|
|
107
|
+
<AuthContext.Provider value={authConfig}>
|
|
108
|
+
{children}
|
|
109
|
+
</AuthContext.Provider>
|
|
110
|
+
</QueryClientProvider>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function useAuthConfig(): AuthConfig {
|
|
115
|
+
const context = useContext(AuthContext);
|
|
116
|
+
if (!context) {
|
|
117
|
+
return defaultConfig;
|
|
118
|
+
}
|
|
119
|
+
return context;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function useAuthMode(): AuthMode {
|
|
123
|
+
const config = useAuthConfig();
|
|
124
|
+
return config.mode;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function useFederatedProviders(): FederatedProvider[] {
|
|
128
|
+
const config = useAuthConfig();
|
|
129
|
+
return config.providers;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function useFederatedAuthEnabled(): boolean {
|
|
133
|
+
const config = useAuthConfig();
|
|
134
|
+
return config.mode === 'federated' && config.providers.length > 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function useTraditionalAuthEnabled(): boolean {
|
|
138
|
+
const config = useAuthConfig();
|
|
139
|
+
return config.mode === 'traditional';
|
|
140
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/client/fetch-with-auth.ts
|
|
2
|
+
import { getSession } from 'next-auth/react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A wrapper for the `fetch` API that automatically injects the session's
|
|
6
|
+
* accessToken into the Authorization header and handles 401 Unauthorized
|
|
7
|
+
* responses by redirecting the user to the login page.
|
|
8
|
+
*
|
|
9
|
+
* @param url The URL to fetch.
|
|
10
|
+
* @param options The standard `fetch` options.
|
|
11
|
+
* @returns A `Promise` that resolves to the `Response` object.
|
|
12
|
+
* @throws An 'UNAUTHORIZED_REDIRECT' error after initiating the redirect to halt further execution.
|
|
13
|
+
*/
|
|
14
|
+
export async function fetchWithAuth(url: string, options: RequestInit = {}): Promise<Response> {
|
|
15
|
+
// 1. Retrieve the client-side session to get the accessToken.
|
|
16
|
+
const session = await getSession();
|
|
17
|
+
|
|
18
|
+
// 2. Inject the accessToken into the Authorization header.
|
|
19
|
+
const headers = new Headers(options.headers);
|
|
20
|
+
if (session?.accessToken) {
|
|
21
|
+
headers.set('Authorization', `Bearer ${session.accessToken}`);
|
|
22
|
+
}
|
|
23
|
+
options.headers = headers;
|
|
24
|
+
|
|
25
|
+
const response = await fetch(url, options);
|
|
26
|
+
|
|
27
|
+
// 3. Handle the 401 response intelligently.
|
|
28
|
+
if (response.status === 401) {
|
|
29
|
+
// If we have a valid session, this is likely a claim/permission error, not an auth error
|
|
30
|
+
if (session?.accessToken) {
|
|
31
|
+
console.warn('API returned 401 despite valid session. Likely insufficient claims or permissions.');
|
|
32
|
+
// Don't redirect - let the calling code handle the error gracefully
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// No valid session - this is a real authentication failure
|
|
37
|
+
console.error('Unauthorized API call (no valid session). Redirecting to login.');
|
|
38
|
+
// SAFEGUARD: Never use auth pages as callback URLs to prevent redirect loops
|
|
39
|
+
const pathname = window.location.pathname;
|
|
40
|
+
const safeCallbackUrl = pathname.startsWith('/account-auth/') ? '/' : pathname;
|
|
41
|
+
window.location.href = `/account-auth/login?callbackUrl=${encodeURIComponent(safeCallbackUrl)}`;
|
|
42
|
+
|
|
43
|
+
// Throw a specific error to signal that a redirect has been initiated.
|
|
44
|
+
throw new Error('UNAUTHORIZED_REDIRECT');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return response;
|
|
48
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export async function fetchWithSession(input: RequestInfo | URL, init: RequestInit = {}, opts: { retry?: number } = {}): Promise<Response> {
|
|
4
|
+
const retry = opts.retry ?? 1;
|
|
5
|
+
const doFetch = async (): Promise<Response> => {
|
|
6
|
+
const res = await fetch(input, { ...init, credentials: 'include' });
|
|
7
|
+
if (res.ok) return res;
|
|
8
|
+
if (res.status === 401 && retry > 0) {
|
|
9
|
+
const rf = await fetch('/api/auth/refresh', { method: 'POST', headers: { 'Accept': 'application/json' }, credentials: 'include' });
|
|
10
|
+
if (rf.ok) return fetchWithSession(input, init, { retry: retry - 1 });
|
|
11
|
+
}
|
|
12
|
+
if ((res.status === 409 || res.status === 503) && retry > 0) {
|
|
13
|
+
const retryAfter = res.headers.get('Retry-After');
|
|
14
|
+
const waitMs = retryAfter ? parseInt(retryAfter) * 1000 : 1000;
|
|
15
|
+
await new Promise(r => setTimeout(r, Math.min(waitMs, 3000)));
|
|
16
|
+
return fetchWithSession(input, init, { retry: retry - 1 });
|
|
17
|
+
}
|
|
18
|
+
return res;
|
|
19
|
+
};
|
|
20
|
+
return doFetch();
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-Side Exports
|
|
3
|
+
*
|
|
4
|
+
* This module exports only client-safe code for use in browser environments.
|
|
5
|
+
* Server-only utilities and Node.js dependencies are excluded.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Client-side fetch utility
|
|
9
|
+
export { fetchWithAuth } from './fetch-with-auth';
|
|
10
|
+
|
|
11
|
+
// Authentication context and hooks
|
|
12
|
+
export { AuthProvider, useAuthConfig, useAuthMode, useFederatedProviders, useFederatedAuthEnabled, useTraditionalAuthEnabled } from './AuthContext';
|
|
13
|
+
export type { AuthConfig } from '../types/auth';
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAnonSession - React hook for anonymous session management
|
|
3
|
+
*
|
|
4
|
+
* Provides access to anonymous session preferences stored in Redis.
|
|
5
|
+
* Works before user logs in, preferences persist across visits.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use client';
|
|
9
|
+
|
|
10
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
11
|
+
|
|
12
|
+
export interface AnonPreferences {
|
|
13
|
+
theme?: string;
|
|
14
|
+
locale?: string;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface AnonMetrics {
|
|
19
|
+
resumeGenerationCount?: number;
|
|
20
|
+
firstVisit?: number;
|
|
21
|
+
lastVisit?: number;
|
|
22
|
+
visitCount?: number;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AnonSession {
|
|
27
|
+
id: string;
|
|
28
|
+
preferences: AnonPreferences;
|
|
29
|
+
metrics: AnonMetrics;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UseAnonSessionReturn {
|
|
33
|
+
session: AnonSession | null;
|
|
34
|
+
isLoading: boolean;
|
|
35
|
+
error: string | null;
|
|
36
|
+
updatePreferences: (preferences: Partial<AnonPreferences>) => Promise<void>;
|
|
37
|
+
setTheme: (theme: string) => Promise<void>;
|
|
38
|
+
refresh: () => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Hook to manage anonymous session state
|
|
43
|
+
*/
|
|
44
|
+
export function useAnonSession(): UseAnonSessionReturn {
|
|
45
|
+
const [session, setSession] = useState<AnonSession | null>(null);
|
|
46
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
47
|
+
const [error, setError] = useState<string | null>(null);
|
|
48
|
+
|
|
49
|
+
// Fetch session on mount
|
|
50
|
+
const fetchSession = useCallback(async () => {
|
|
51
|
+
try {
|
|
52
|
+
setIsLoading(true);
|
|
53
|
+
setError(null);
|
|
54
|
+
|
|
55
|
+
const response = await fetch('/api/anon/preferences', {
|
|
56
|
+
method: 'GET',
|
|
57
|
+
credentials: 'include', // Important for cookies
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
throw new Error('Failed to fetch preferences');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
if (data.success && data.data) {
|
|
66
|
+
setSession({
|
|
67
|
+
id: data.data.id,
|
|
68
|
+
preferences: data.data.preferences || {},
|
|
69
|
+
metrics: data.data.metrics || {},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.error('[useAnonSession] Error fetching session:', err);
|
|
74
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
75
|
+
} finally {
|
|
76
|
+
setIsLoading(false);
|
|
77
|
+
}
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
fetchSession();
|
|
82
|
+
}, [fetchSession]);
|
|
83
|
+
|
|
84
|
+
// Update preferences
|
|
85
|
+
const updatePreferences = useCallback(async (preferences: Partial<AnonPreferences>) => {
|
|
86
|
+
try {
|
|
87
|
+
setError(null);
|
|
88
|
+
|
|
89
|
+
const response = await fetch('/api/anon/preferences', {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
credentials: 'include',
|
|
92
|
+
headers: {
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify({ preferences }),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
throw new Error('Failed to update preferences');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const data = await response.json();
|
|
103
|
+
if (data.success && data.data) {
|
|
104
|
+
setSession(prev => prev ? {
|
|
105
|
+
...prev,
|
|
106
|
+
preferences: data.data.preferences,
|
|
107
|
+
} : null);
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error('[useAnonSession] Error updating preferences:', err);
|
|
111
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
}, []);
|
|
115
|
+
|
|
116
|
+
// Convenience method to set theme
|
|
117
|
+
const setTheme = useCallback(async (theme: string) => {
|
|
118
|
+
await updatePreferences({ theme });
|
|
119
|
+
}, [updatePreferences]);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
session,
|
|
123
|
+
isLoading,
|
|
124
|
+
error,
|
|
125
|
+
updatePreferences,
|
|
126
|
+
setTheme,
|
|
127
|
+
refresh: fetchSession,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default useAnonSession;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import { useSession, signOut } from 'next-auth/react';
|
|
5
|
+
import type { Session } from 'next-auth';
|
|
6
|
+
import { useAuthStore } from '../stores/authStore';
|
|
7
|
+
import { isValidSession } from '../lib/session';
|
|
8
|
+
import {
|
|
9
|
+
getSecureSessionCookieName,
|
|
10
|
+
getSecureCsrfCookieName,
|
|
11
|
+
getCallbackUrlCookieName
|
|
12
|
+
} from '../lib/app-slug';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sanitize sensitive data for logging
|
|
16
|
+
* Never log full user IDs or emails in any environment
|
|
17
|
+
*/
|
|
18
|
+
function sanitizeForLog(value: string | undefined, type: 'email' | 'userId'): string {
|
|
19
|
+
if (!value) return '(empty)';
|
|
20
|
+
|
|
21
|
+
if (type === 'email') {
|
|
22
|
+
return '***@***'; // Never log emails
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (type === 'userId') {
|
|
26
|
+
// Only show first 8 chars in development
|
|
27
|
+
if (process.env.NODE_ENV === 'development') {
|
|
28
|
+
return value.substring(0, 8) + '...';
|
|
29
|
+
}
|
|
30
|
+
return '***'; // Fully redact in production
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return '***';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* SessionSync - Bridges NextAuth session with Zustand auth store
|
|
38
|
+
*
|
|
39
|
+
* CRITICAL: This component enforces strict session validation. If NextAuth
|
|
40
|
+
* reports an authenticated status but the session data is invalid (empty user ID,
|
|
41
|
+
* empty email, or missing access token), it forces a sign-out to prevent
|
|
42
|
+
* contradictory state like "hasSession: true, userId: ''"
|
|
43
|
+
*
|
|
44
|
+
* This ensures the app NEVER shows authenticated UI with empty/invalid session data.
|
|
45
|
+
*/
|
|
46
|
+
export function SessionSync({ children }: { children: React.ReactNode }) {
|
|
47
|
+
const { data: session, status } = useSession();
|
|
48
|
+
const { setSession, clearSession } = useAuthStore();
|
|
49
|
+
|
|
50
|
+
// Guard against duplicate sign-out calls
|
|
51
|
+
const isSigningOutRef = useRef(false);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
let isMounted = true;
|
|
55
|
+
|
|
56
|
+
// Only process when NextAuth has finished loading
|
|
57
|
+
if (status === 'loading') {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Strict validation: Check if session is actually valid
|
|
62
|
+
const isValid = isValidSession(session);
|
|
63
|
+
|
|
64
|
+
// CRITICAL FIX: If NextAuth says "authenticated" but session is invalid,
|
|
65
|
+
// this is a broken state that must be fixed immediately
|
|
66
|
+
if (status === 'authenticated' && !isValid) {
|
|
67
|
+
// GUARD: Prevent duplicate sign-out
|
|
68
|
+
if (isSigningOutRef.current) {
|
|
69
|
+
console.warn('[SessionSync] Sign-out already in progress, skipping');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
isSigningOutRef.current = true;
|
|
73
|
+
|
|
74
|
+
console.error('[SessionSync] CRITICAL: Invalid session detected despite authenticated status!');
|
|
75
|
+
console.error('[SessionSync] This indicates a session with empty user data - forcing sign-out');
|
|
76
|
+
|
|
77
|
+
// Log diagnostic info with PII redaction
|
|
78
|
+
// Note: session is typed as Session | null from NextAuth, but may have invalid/partial data
|
|
79
|
+
const sessionData = session as any; // Explicit cast needed for error logging
|
|
80
|
+
console.error('[SessionSync] Session data:', {
|
|
81
|
+
hasSessionObject: !!sessionData,
|
|
82
|
+
hasUser: !!sessionData?.user,
|
|
83
|
+
userId: sanitizeForLog(sessionData?.user?.id, 'userId'),
|
|
84
|
+
userEmail: sanitizeForLog(sessionData?.user?.email, 'email'),
|
|
85
|
+
hasAccessToken: !!sessionData?.accessToken,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Clear the auth store immediately
|
|
89
|
+
clearSession();
|
|
90
|
+
|
|
91
|
+
// FIX: Force clear all auth cookies including stale provisional tokens (app-slug prefixed)
|
|
92
|
+
// This prevents infinite loop when provisional token exists but session is invalid
|
|
93
|
+
// Root cause: OAuth creates provisional token before Redis session exists
|
|
94
|
+
try {
|
|
95
|
+
const secureSession = getSecureSessionCookieName();
|
|
96
|
+
const secureCsrf = getSecureCsrfCookieName();
|
|
97
|
+
const callbackUrl = getCallbackUrlCookieName();
|
|
98
|
+
document.cookie = `${secureSession}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; Secure; SameSite=Lax`;
|
|
99
|
+
document.cookie = `${secureCsrf}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; SameSite=Lax`;
|
|
100
|
+
document.cookie = `__Secure-${callbackUrl}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; Secure; SameSite=Lax`;
|
|
101
|
+
} catch (e) {
|
|
102
|
+
// Cookie clearing failed - non-critical, continue with signout
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Force NextAuth to sign out (this will clear cookies and trigger redirect)
|
|
106
|
+
signOut({ redirect: false })
|
|
107
|
+
.then(() => {
|
|
108
|
+
if (isMounted) {
|
|
109
|
+
// Use generic error code instead of implementation details
|
|
110
|
+
window.location.href = '/account-auth/login?error=SessionExpired&code=1001';
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
.catch((err) => {
|
|
114
|
+
console.error('[SessionSync] Error during forced signout:', err);
|
|
115
|
+
if (isMounted) {
|
|
116
|
+
window.location.href = '/account-auth/login?error=SessionExpired&code=1001';
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Normal flow: Update store based on valid session status
|
|
124
|
+
if (status === 'authenticated' && isValid) {
|
|
125
|
+
setSession(session);
|
|
126
|
+
} else if (status === 'unauthenticated') {
|
|
127
|
+
clearSession();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Cleanup function to prevent post-unmount updates
|
|
131
|
+
return () => {
|
|
132
|
+
isMounted = false;
|
|
133
|
+
};
|
|
134
|
+
}, [session, status, setSession, clearSession]);
|
|
135
|
+
|
|
136
|
+
return <>{children}</>;
|
|
137
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { signalRActivityService, type HealthStatus } from '../services/signalrActivityService';
|
|
5
|
+
|
|
6
|
+
interface SignalRHealthCheckProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
idpBaseUrl: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Simple health check component using SignalR connection state
|
|
13
|
+
* Following Occam's Razor: Connection alive = Service healthy, Connection dead = Service unhealthy
|
|
14
|
+
*/
|
|
15
|
+
export default function SignalRHealthCheck({ className = '', idpBaseUrl }: SignalRHealthCheckProps) {
|
|
16
|
+
// Allow disabling via env for noisy environments (e.g., production demos)
|
|
17
|
+
if (process.env.NEXT_PUBLIC_DISABLE_HEALTH_MONITOR === 'true') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const [healthStatus, setHealthStatus] = useState<HealthStatus>({
|
|
22
|
+
isHealthy: false,
|
|
23
|
+
message: 'Initializing...',
|
|
24
|
+
lastHeartbeat: null,
|
|
25
|
+
connectionId: null
|
|
26
|
+
});
|
|
27
|
+
const [isInitializing, setIsInitializing] = useState(true);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
let unsubscribe: (() => void) | null = null;
|
|
31
|
+
|
|
32
|
+
const initializeHealthService = async () => {
|
|
33
|
+
try {
|
|
34
|
+
// Subscribe to health status changes
|
|
35
|
+
unsubscribe = signalRActivityService.subscribe((status) => {
|
|
36
|
+
setHealthStatus(status);
|
|
37
|
+
setIsInitializing(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Start the health monitoring
|
|
41
|
+
await signalRActivityService.start(idpBaseUrl);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// Handle service unavailable gracefully without console spam
|
|
44
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
45
|
+
const isServiceDown = errorMessage.includes('ERR_CONNECTION_REFUSED') ||
|
|
46
|
+
errorMessage.includes('Failed to fetch');
|
|
47
|
+
|
|
48
|
+
if (isServiceDown) {
|
|
49
|
+
console.info('Health monitoring: Backend service unavailable');
|
|
50
|
+
setHealthStatus({
|
|
51
|
+
isHealthy: false,
|
|
52
|
+
message: 'Backend service offline',
|
|
53
|
+
lastHeartbeat: null,
|
|
54
|
+
connectionId: null
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
console.error('Failed to initialize SignalR health service:', error);
|
|
58
|
+
setHealthStatus({
|
|
59
|
+
isHealthy: false,
|
|
60
|
+
message: 'Failed to initialize health monitoring',
|
|
61
|
+
lastHeartbeat: null,
|
|
62
|
+
connectionId: null
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
setIsInitializing(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
initializeHealthService();
|
|
70
|
+
|
|
71
|
+
// Cleanup on unmount
|
|
72
|
+
return () => {
|
|
73
|
+
if (unsubscribe) {
|
|
74
|
+
unsubscribe();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}, [idpBaseUrl]);
|
|
78
|
+
|
|
79
|
+
const getStatusColor = () => {
|
|
80
|
+
if (isInitializing) return 'text-yellow-600';
|
|
81
|
+
return healthStatus.isHealthy ? 'text-green-600' : 'text-orange-600'; // Orange instead of alarming red
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const getStatusIcon = () => {
|
|
85
|
+
if (isInitializing) return '🔄';
|
|
86
|
+
return healthStatus.isHealthy ? '✅' : '🔶'; // Orange diamond instead of scary red X
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const getStatusMessage = () => {
|
|
90
|
+
if (isInitializing) return 'Connecting to service...';
|
|
91
|
+
return healthStatus.message;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const formatLastHeartbeat = () => {
|
|
95
|
+
if (!healthStatus.lastHeartbeat) return null;
|
|
96
|
+
const now = new Date();
|
|
97
|
+
const diff = Math.floor((now.getTime() - healthStatus.lastHeartbeat.getTime()) / 1000);
|
|
98
|
+
|
|
99
|
+
if (diff < 60) return `${diff}s ago`;
|
|
100
|
+
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
|
|
101
|
+
return `${Math.floor(diff / 3600)}h ago`;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className={`flex items-center space-x-2 ${className}`}>
|
|
106
|
+
<span className="text-lg" role="img" aria-label="status">
|
|
107
|
+
{getStatusIcon()}
|
|
108
|
+
</span>
|
|
109
|
+
|
|
110
|
+
<div className="flex flex-col">
|
|
111
|
+
<span className={`text-sm font-medium ${getStatusColor()}`}>
|
|
112
|
+
{getStatusMessage()}
|
|
113
|
+
</span>
|
|
114
|
+
|
|
115
|
+
{healthStatus.lastHeartbeat && (
|
|
116
|
+
<span className="text-xs text-gray-500">
|
|
117
|
+
Last heartbeat: {formatLastHeartbeat()}
|
|
118
|
+
</span>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
{/* Uncomment for SignalR debugging:
|
|
122
|
+
{process.env.NODE_ENV === 'development' && healthStatus.connectionId && (
|
|
123
|
+
<span className="text-xs text-gray-400 font-mono">
|
|
124
|
+
Connection: {healthStatus.connectionId.substring(0, 8)}...
|
|
125
|
+
</span>
|
|
126
|
+
)}
|
|
127
|
+
*/}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|