@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,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Auth Settings Route
|
|
3
|
+
*
|
|
4
|
+
* Returns client auth settings for pre-login pages (signup, login).
|
|
5
|
+
* Does NOT require authentication - these are public client settings.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextResponse } from 'next/server';
|
|
9
|
+
import { getIDPClientConfig } from '../../lib/idp-client-config';
|
|
10
|
+
|
|
11
|
+
export interface PublicAuthSettings {
|
|
12
|
+
// OAuth providers enabled for this client
|
|
13
|
+
enabledProviders: string[];
|
|
14
|
+
|
|
15
|
+
// Registration settings
|
|
16
|
+
allowPublicRegistration: boolean;
|
|
17
|
+
allowSocialLogin: boolean;
|
|
18
|
+
|
|
19
|
+
// Password settings
|
|
20
|
+
enablePasswordReset: boolean;
|
|
21
|
+
|
|
22
|
+
// 2FA settings (public - no secrets)
|
|
23
|
+
require2FA: boolean;
|
|
24
|
+
allowed2FAMethods: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* GET /api/auth/settings
|
|
29
|
+
*
|
|
30
|
+
* Returns public auth settings for the current client.
|
|
31
|
+
* Used by login/signup pages to determine what options to show.
|
|
32
|
+
*/
|
|
33
|
+
export async function GET() {
|
|
34
|
+
try {
|
|
35
|
+
const config = await getIDPClientConfig();
|
|
36
|
+
|
|
37
|
+
const settings: PublicAuthSettings = {
|
|
38
|
+
// Get enabled OAuth provider names
|
|
39
|
+
enabledProviders: config.oauthProviders
|
|
40
|
+
?.filter(p => p.enabled)
|
|
41
|
+
.map(p => p.provider) ?? [],
|
|
42
|
+
|
|
43
|
+
// Registration - default to true if not specified
|
|
44
|
+
allowPublicRegistration: true, // Could come from config.authSettings in future
|
|
45
|
+
allowSocialLogin: config.oauthProviders?.some(p => p.enabled) ?? false,
|
|
46
|
+
|
|
47
|
+
// Password reset
|
|
48
|
+
enablePasswordReset: true, // Could come from config.authSettings in future
|
|
49
|
+
|
|
50
|
+
// 2FA
|
|
51
|
+
require2FA: config.authSettings?.require2FA ?? true,
|
|
52
|
+
allowed2FAMethods: config.authSettings?.allowed2FAMethods ?? ['email', 'sms'],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return NextResponse.json({
|
|
56
|
+
success: true,
|
|
57
|
+
data: settings,
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('[AUTH_SETTINGS] Failed to get settings:', error);
|
|
61
|
+
|
|
62
|
+
// Return safe defaults on error
|
|
63
|
+
return NextResponse.json({
|
|
64
|
+
success: true,
|
|
65
|
+
data: {
|
|
66
|
+
enabledProviders: [],
|
|
67
|
+
allowPublicRegistration: true,
|
|
68
|
+
allowSocialLogin: false,
|
|
69
|
+
enablePasswordReset: true,
|
|
70
|
+
require2FA: true,
|
|
71
|
+
allowed2FAMethods: ['email', 'sms'],
|
|
72
|
+
} as PublicAuthSettings,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ready-to-Use Session Viability Route
|
|
3
|
+
*
|
|
4
|
+
* Checks if the current session is viable (valid and not expired).
|
|
5
|
+
* Used by client-side code to determine if a refresh is needed.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // app/api/session/viability/route.ts
|
|
10
|
+
* export { GET } from '@payez/next-mvp/routes/auth/viability';
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @version 2.0.0
|
|
14
|
+
* @since auth-ready-v2
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
18
|
+
import { getToken } from 'next-auth/jwt';
|
|
19
|
+
import { getSession } from '../../lib/session-store';
|
|
20
|
+
import { getJwtCookieName } from '../../lib/app-slug';
|
|
21
|
+
import { getIDPClientConfig } from '../../lib/idp-client-config';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get NextAuth secret from IDP config (cached).
|
|
25
|
+
* NEVER use process.env.NEXTAUTH_SECRET at module level - it may not be set yet.
|
|
26
|
+
*/
|
|
27
|
+
async function getNextAuthSecret(): Promise<string> {
|
|
28
|
+
const config = await getIDPClientConfig();
|
|
29
|
+
return config.nextAuthSecret || '';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get tenant-wide 2FA requirement from cached client config (from broker handshake)
|
|
34
|
+
*/
|
|
35
|
+
async function getTenantRequiresTwoFactor(): Promise<boolean> {
|
|
36
|
+
try {
|
|
37
|
+
const config = await getIDPClientConfig();
|
|
38
|
+
return config.authSettings?.require2FA ?? true; // Default to true for security
|
|
39
|
+
} catch {
|
|
40
|
+
console.warn('[VIABILITY] Could not get client config, defaulting tenantRequiresTwoFactor to true');
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* GET /api/session/viability - Check if session is viable
|
|
47
|
+
*
|
|
48
|
+
* Returns:
|
|
49
|
+
* - viable: boolean - Whether the session can be used
|
|
50
|
+
* - needsRefresh: boolean - Whether a refresh is recommended
|
|
51
|
+
* - expiresIn: number - Seconds until token expires
|
|
52
|
+
*/
|
|
53
|
+
export async function GET(req: NextRequest) {
|
|
54
|
+
try {
|
|
55
|
+
const cookieName = getJwtCookieName();
|
|
56
|
+
const secret = await getNextAuthSecret();
|
|
57
|
+
const token = await getToken({ req, secret, cookieName });
|
|
58
|
+
|
|
59
|
+
if (!token) {
|
|
60
|
+
return NextResponse.json({
|
|
61
|
+
viable: false,
|
|
62
|
+
needsRefresh: false,
|
|
63
|
+
authenticated: false,
|
|
64
|
+
reason: 'No session found'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
|
|
69
|
+
const sessionToken = (token as any).sessionToken || (token as any).redisSessionId;
|
|
70
|
+
const session = sessionToken ? await getSession(sessionToken) : null;
|
|
71
|
+
|
|
72
|
+
// CRITICAL: Detect stale cookie state (JWT exists but Redis session missing)
|
|
73
|
+
if (sessionToken && !session) {
|
|
74
|
+
console.warn('[VIABILITY] Stale cookie detected - session not in Redis');
|
|
75
|
+
return NextResponse.json({
|
|
76
|
+
viable: false,
|
|
77
|
+
needsRefresh: false,
|
|
78
|
+
authenticated: false,
|
|
79
|
+
sessionToken, // Return sessionToken so middleware can detect and clear stale cookie
|
|
80
|
+
reason: 'Stale session - cookie exists but session not found in Redis'
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check access token expiry
|
|
85
|
+
const now = Math.floor(Date.now() / 1000);
|
|
86
|
+
const accessTokenExpires = (token as any).accessTokenExpires || token.exp;
|
|
87
|
+
|
|
88
|
+
if (!accessTokenExpires) {
|
|
89
|
+
// No expiry info, assume viable but recommend refresh
|
|
90
|
+
const tenantRequiresTwoFactor = await getTenantRequiresTwoFactor();
|
|
91
|
+
|
|
92
|
+
// CRITICAL: Check if MFA has expired (2FA TTL enforcement)
|
|
93
|
+
const mfaExpiresAt = session?.mfaExpiresAt || 0;
|
|
94
|
+
const mfaExpired = mfaExpiresAt > 0 && mfaExpiresAt < Date.now();
|
|
95
|
+
// Check mfaVerified (normalized name) with fallback to twoFactorComplete for compatibility
|
|
96
|
+
const mfaVerifiedInSession = session?.mfaVerified ?? (session as any)?.twoFactorComplete ?? false;
|
|
97
|
+
|
|
98
|
+
// User has completed 2FA requirements if: they verified AND it hasn't expired
|
|
99
|
+
const userHasCompletedTenantTwoFactorRequirements = mfaVerifiedInSession && !mfaExpired;
|
|
100
|
+
|
|
101
|
+
// userStillNeedsTwoFactor = inverse of completed (matches session callback logic)
|
|
102
|
+
const userStillNeedsTwoFactor = !userHasCompletedTenantTwoFactorRequirements;
|
|
103
|
+
|
|
104
|
+
return NextResponse.json({
|
|
105
|
+
viable: true,
|
|
106
|
+
needsRefresh: true,
|
|
107
|
+
authenticated: true,
|
|
108
|
+
sessionToken,
|
|
109
|
+
// Clear names for middleware decision-making
|
|
110
|
+
tenantRequiresTwoFactor,
|
|
111
|
+
userHasCompletedTenantTwoFactorRequirements,
|
|
112
|
+
userStillNeedsTwoFactor,
|
|
113
|
+
// Legacy field names for backwards compatibility
|
|
114
|
+
requires2FA: tenantRequiresTwoFactor,
|
|
115
|
+
twoFactorComplete: userHasCompletedTenantTwoFactorRequirements,
|
|
116
|
+
accessTokenExpired: false,
|
|
117
|
+
reason: 'No expiry information'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Convert to seconds if needed
|
|
122
|
+
const expiryTime = accessTokenExpires > 1000000000000
|
|
123
|
+
? Math.floor(accessTokenExpires / 1000)
|
|
124
|
+
: accessTokenExpires;
|
|
125
|
+
|
|
126
|
+
const expiresIn = expiryTime - now;
|
|
127
|
+
const isExpired = expiresIn <= 0;
|
|
128
|
+
const needsRefresh = expiresIn <= 300; // 5 minutes buffer
|
|
129
|
+
|
|
130
|
+
// Check if we have refresh capability (check normalized field name first)
|
|
131
|
+
const hasRefreshToken = !!(session?.idpRefreshToken || (session as any)?.refreshToken || (token as any).refreshToken);
|
|
132
|
+
|
|
133
|
+
// CLEAR NAMING: Tenant-wide 2FA requirement from client config
|
|
134
|
+
const tenantRequiresTwoFactor = await getTenantRequiresTwoFactor();
|
|
135
|
+
|
|
136
|
+
// CRITICAL: Check if MFA has expired (2FA TTL enforcement)
|
|
137
|
+
// The session may have mfaVerified=true from days ago, but if mfaExpiresAt
|
|
138
|
+
// has passed, we must treat 2FA as incomplete to force re-verification.
|
|
139
|
+
const mfaExpiresAt = session?.mfaExpiresAt || 0;
|
|
140
|
+
const mfaExpired = mfaExpiresAt > 0 && mfaExpiresAt < Date.now();
|
|
141
|
+
// Check mfaVerified (normalized name) with fallback to twoFactorComplete for compatibility
|
|
142
|
+
const mfaVerifiedInSession = session?.mfaVerified ?? (session as any)?.twoFactorComplete ?? false;
|
|
143
|
+
|
|
144
|
+
// DEBUG: Log what we're reading from the session
|
|
145
|
+
console.log('[VIABILITY] Session 2FA state:', {
|
|
146
|
+
sessionToken: sessionToken?.substring(0, 8) + '...',
|
|
147
|
+
'session.mfaVerified': session?.mfaVerified,
|
|
148
|
+
'session.twoFactorComplete': (session as any)?.twoFactorComplete,
|
|
149
|
+
mfaVerifiedInSession,
|
|
150
|
+
mfaExpiresAt,
|
|
151
|
+
mfaExpired,
|
|
152
|
+
hasRefreshToken,
|
|
153
|
+
'session.idpRefreshToken': !!session?.idpRefreshToken,
|
|
154
|
+
'session.refreshToken': !!(session as any)?.refreshToken,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// CLEAR NAMING: User has completed 2FA requirements if: they verified AND it hasn't expired
|
|
158
|
+
const userHasCompletedTenantTwoFactorRequirements = mfaVerifiedInSession && !mfaExpired;
|
|
159
|
+
|
|
160
|
+
// userStillNeedsTwoFactor = inverse of completed (matches session callback logic)
|
|
161
|
+
const userStillNeedsTwoFactor = !userHasCompletedTenantTwoFactorRequirements;
|
|
162
|
+
|
|
163
|
+
if (mfaExpired && mfaVerifiedInSession) {
|
|
164
|
+
console.warn('[VIABILITY] MFA expired - forcing 2FA re-verification');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (isExpired) {
|
|
168
|
+
return NextResponse.json({
|
|
169
|
+
viable: false,
|
|
170
|
+
needsRefresh: hasRefreshToken,
|
|
171
|
+
expiresIn: 0,
|
|
172
|
+
hasRefreshToken,
|
|
173
|
+
authenticated: true,
|
|
174
|
+
sessionToken,
|
|
175
|
+
// Clear names
|
|
176
|
+
tenantRequiresTwoFactor,
|
|
177
|
+
userHasCompletedTenantTwoFactorRequirements,
|
|
178
|
+
userStillNeedsTwoFactor,
|
|
179
|
+
// Legacy names for backwards compatibility
|
|
180
|
+
requires2FA: tenantRequiresTwoFactor,
|
|
181
|
+
twoFactorComplete: userHasCompletedTenantTwoFactorRequirements,
|
|
182
|
+
accessTokenExpired: true,
|
|
183
|
+
reason: 'Token expired',
|
|
184
|
+
// RBAC fields
|
|
185
|
+
roles: session?.roles || [],
|
|
186
|
+
clientId: session?.idpClientId || process.env.IDP_CLIENT_ID || '',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return NextResponse.json({
|
|
191
|
+
viable: true,
|
|
192
|
+
needsRefresh,
|
|
193
|
+
expiresIn,
|
|
194
|
+
hasRefreshToken,
|
|
195
|
+
authenticated: true,
|
|
196
|
+
sessionToken,
|
|
197
|
+
// Clear names
|
|
198
|
+
tenantRequiresTwoFactor,
|
|
199
|
+
userHasCompletedTenantTwoFactorRequirements,
|
|
200
|
+
userStillNeedsTwoFactor,
|
|
201
|
+
// Legacy names for backwards compatibility
|
|
202
|
+
requires2FA: tenantRequiresTwoFactor,
|
|
203
|
+
twoFactorComplete: userHasCompletedTenantTwoFactorRequirements,
|
|
204
|
+
accessTokenExpired: false,
|
|
205
|
+
expiresAt: new Date(expiryTime * 1000).toISOString(),
|
|
206
|
+
// RBAC fields
|
|
207
|
+
roles: session?.roles || [],
|
|
208
|
+
clientId: session?.idpClientId || process.env.IDP_CLIENT_ID || '',
|
|
209
|
+
});
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error('[VIABILITY_ROUTE] Error checking session viability:', error);
|
|
212
|
+
return NextResponse.json({
|
|
213
|
+
viable: false,
|
|
214
|
+
needsRefresh: false,
|
|
215
|
+
authenticated: false,
|
|
216
|
+
error: 'Failed to check session',
|
|
217
|
+
details: error instanceof Error ? error.message : 'Unknown error'
|
|
218
|
+
}, { status: 500 });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @payez/next-mvp Route Module Exports
|
|
3
|
+
*
|
|
4
|
+
* Ready-to-use route handlers for quick integration
|
|
5
|
+
*
|
|
6
|
+
* @version 2.3.0
|
|
7
|
+
* @since auth-ready-v2
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Export auth routes
|
|
11
|
+
export * from './auth';
|
|
12
|
+
|
|
13
|
+
// Export account/2FA routes
|
|
14
|
+
export * from './account';
|
|
15
|
+
|
|
16
|
+
// Namespace exports for cleaner imports
|
|
17
|
+
export * as auth from './auth';
|
|
18
|
+
export * as account from './account';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ready-to-Use Refresh Viability Route
|
|
3
|
+
*
|
|
4
|
+
* Checks if a session has a valid refresh token for automatic refresh.
|
|
5
|
+
* Used by middleware to decide whether to attempt refresh or redirect to login.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // app/api/session/refresh-viability/route.ts
|
|
10
|
+
* export { GET } from '@payez/next-mvp/routes/session/refresh-viability';
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @version 2.0.0
|
|
14
|
+
* @since auth-ready-v2
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export { GET } from '../../api-handlers/session/refresh-viability';
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import * as signalR from '@microsoft/signalr';
|
|
2
|
+
|
|
3
|
+
export interface HealthStatus {
|
|
4
|
+
isHealthy: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
lastHeartbeat: Date | null;
|
|
7
|
+
connectionId: string | null | undefined;
|
|
8
|
+
responseTime?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type HealthStatusCallback = (status: HealthStatus) => void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* SignalR-based health service following Occam's Razor principle:
|
|
15
|
+
* - If SignalR connection is alive = Service is working
|
|
16
|
+
* - If SignalR connection is dead = Service is not working
|
|
17
|
+
* - No complex orchestration, just connection state monitoring
|
|
18
|
+
*/
|
|
19
|
+
class SignalRActivityService {
|
|
20
|
+
private connection: signalR.HubConnection | null = null;
|
|
21
|
+
private subscribers: Set<HealthStatusCallback> = new Set();
|
|
22
|
+
private currentStatus: HealthStatus = {
|
|
23
|
+
isHealthy: false,
|
|
24
|
+
message: 'Disconnected',
|
|
25
|
+
lastHeartbeat: null,
|
|
26
|
+
connectionId: null
|
|
27
|
+
};
|
|
28
|
+
private heartbeatTimeout: NodeJS.Timeout | null = null;
|
|
29
|
+
private readonly heartbeatTimeoutMs = 45000; // 45 seconds (server sends every 30s)
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Start the health monitoring connection
|
|
33
|
+
* @param idpBaseUrl - The base URL of the IDP server (e.g., 'http://localhost:32785')
|
|
34
|
+
*/
|
|
35
|
+
async start(idpBaseUrl: string): Promise<void> {
|
|
36
|
+
// If we already have a connected or connecting connection, don't start again
|
|
37
|
+
if (this.connection &&
|
|
38
|
+
(this.connection.state === signalR.HubConnectionState.Connected ||
|
|
39
|
+
this.connection.state === signalR.HubConnectionState.Connecting)) {
|
|
40
|
+
console.info('[SignalRHealth] Connection already active, skipping start');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Stop existing connection if it exists
|
|
45
|
+
if (this.connection) {
|
|
46
|
+
await this.stop();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
if (!idpBaseUrl) {
|
|
51
|
+
throw new Error('IDP base URL is required for health monitoring');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Construct absolute hub URL safely
|
|
55
|
+
const activityHubUrl = new URL('/healthHub', idpBaseUrl).toString();
|
|
56
|
+
console.info('[SignalRHealth] Using hub URL:', activityHubUrl);
|
|
57
|
+
|
|
58
|
+
this.connection = new signalR.HubConnectionBuilder()
|
|
59
|
+
.withUrl(activityHubUrl, {
|
|
60
|
+
withCredentials: false,
|
|
61
|
+
transport: signalR.HttpTransportType.WebSockets | signalR.HttpTransportType.ServerSentEvents | signalR.HttpTransportType.LongPolling,
|
|
62
|
+
})
|
|
63
|
+
.withAutomaticReconnect({
|
|
64
|
+
nextRetryDelayInMilliseconds: (retryContext) => {
|
|
65
|
+
// More conservative backoff: 5s, 15s, 45s, then stop trying
|
|
66
|
+
const delays = [5000, 15000, 45000];
|
|
67
|
+
if (retryContext.previousRetryCount >= delays.length) {
|
|
68
|
+
return null; // Stop automatic reconnection
|
|
69
|
+
}
|
|
70
|
+
return delays[retryContext.previousRetryCount];
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
.configureLogging(signalR.LogLevel.Critical) // Only critical errors, hide connection noise
|
|
74
|
+
.build();
|
|
75
|
+
|
|
76
|
+
// Handle connection events
|
|
77
|
+
this.connection.onclose(() => {
|
|
78
|
+
this.updateStatus({
|
|
79
|
+
isHealthy: false,
|
|
80
|
+
message: 'Service unavailable',
|
|
81
|
+
lastHeartbeat: null,
|
|
82
|
+
connectionId: null
|
|
83
|
+
});
|
|
84
|
+
this.clearHeartbeatTimeout();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
this.connection.onreconnecting(() => {
|
|
88
|
+
this.updateStatus({
|
|
89
|
+
isHealthy: false,
|
|
90
|
+
message: 'Service unavailable',
|
|
91
|
+
lastHeartbeat: this.currentStatus.lastHeartbeat,
|
|
92
|
+
connectionId: null
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this.connection.onreconnected((connectionId) => {
|
|
97
|
+
this.updateStatus({
|
|
98
|
+
isHealthy: true,
|
|
99
|
+
message: 'Service operational',
|
|
100
|
+
lastHeartbeat: new Date(),
|
|
101
|
+
connectionId
|
|
102
|
+
});
|
|
103
|
+
this.resetHeartbeatTimeout();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Handle heartbeat messages - this is the core health indicator
|
|
107
|
+
this.connection.on('Heartbeat', (data) => {
|
|
108
|
+
this.updateStatus({
|
|
109
|
+
isHealthy: true,
|
|
110
|
+
message: 'Service operational',
|
|
111
|
+
lastHeartbeat: new Date(),
|
|
112
|
+
connectionId: this.connection?.connectionId || null
|
|
113
|
+
});
|
|
114
|
+
this.resetHeartbeatTimeout();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Handle initial health status
|
|
118
|
+
this.connection.on('HealthStatus', (data) => {
|
|
119
|
+
this.updateStatus({
|
|
120
|
+
isHealthy: data.status === 'healthy',
|
|
121
|
+
message: data.message || 'Service connected',
|
|
122
|
+
lastHeartbeat: new Date(),
|
|
123
|
+
connectionId: this.connection?.connectionId || null
|
|
124
|
+
});
|
|
125
|
+
this.resetHeartbeatTimeout();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Start the connection
|
|
129
|
+
await this.connection.start();
|
|
130
|
+
console.info('[SignalRHealth] Connection started, connectionId:', this.connection.connectionId);
|
|
131
|
+
|
|
132
|
+
this.updateStatus({
|
|
133
|
+
isHealthy: true,
|
|
134
|
+
message: 'Service connected',
|
|
135
|
+
lastHeartbeat: new Date(),
|
|
136
|
+
connectionId: this.connection.connectionId
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
this.resetHeartbeatTimeout();
|
|
140
|
+
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// Reduce console noise for expected connection failures
|
|
143
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
144
|
+
console.warn('[SignalRHealth] Connection start failed:', errorMessage);
|
|
145
|
+
const isConnectionRefused = errorMessage.includes('ERR_CONNECTION_REFUSED') ||
|
|
146
|
+
errorMessage.includes('Failed to fetch') ||
|
|
147
|
+
errorMessage.includes('Failed to complete negotiation');
|
|
148
|
+
|
|
149
|
+
if (isConnectionRefused) {
|
|
150
|
+
// Service is down - this is expected, log at info level
|
|
151
|
+
console.info('SignalR Health Service: Backend service unavailable');
|
|
152
|
+
} else {
|
|
153
|
+
// Unexpected error - log as error
|
|
154
|
+
console.error('SignalR Health Service failed to start:', error);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
this.updateStatus({
|
|
158
|
+
isHealthy: false,
|
|
159
|
+
message: 'Service unavailable',
|
|
160
|
+
lastHeartbeat: null,
|
|
161
|
+
connectionId: null
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Stop the health monitoring connection
|
|
168
|
+
*/
|
|
169
|
+
async stop(): Promise<void> {
|
|
170
|
+
this.clearHeartbeatTimeout();
|
|
171
|
+
|
|
172
|
+
if (this.connection) {
|
|
173
|
+
try {
|
|
174
|
+
// Check if connection is in a state that can be stopped
|
|
175
|
+
if (this.connection.state !== signalR.HubConnectionState.Disconnected) {
|
|
176
|
+
await this.connection.stop();
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
// Ignore "connection was stopped before the hub handshake could complete" errors
|
|
180
|
+
// as these are expected during rapid start/stop cycles
|
|
181
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
182
|
+
if (!errorMessage.includes('stopped before the hub handshake could complete')) {
|
|
183
|
+
console.error('Error stopping SignalR health connection:', error);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
this.connection = null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.updateStatus({
|
|
190
|
+
isHealthy: false,
|
|
191
|
+
message: 'Disconnected',
|
|
192
|
+
lastHeartbeat: null,
|
|
193
|
+
connectionId: null
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Subscribe to health status changes
|
|
199
|
+
*/
|
|
200
|
+
subscribe(callback: HealthStatusCallback): () => void {
|
|
201
|
+
this.subscribers.add(callback);
|
|
202
|
+
|
|
203
|
+
// Immediately notify with current status
|
|
204
|
+
callback(this.currentStatus);
|
|
205
|
+
|
|
206
|
+
// Return unsubscribe function
|
|
207
|
+
return () => {
|
|
208
|
+
this.subscribers.delete(callback);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get current health status
|
|
214
|
+
*/
|
|
215
|
+
getCurrentStatus(): HealthStatus {
|
|
216
|
+
return { ...this.currentStatus };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private updateStatus(newStatus: HealthStatus): void {
|
|
220
|
+
this.currentStatus = newStatus;
|
|
221
|
+
this.notifySubscribers();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private notifySubscribers(): void {
|
|
225
|
+
this.subscribers.forEach(callback => {
|
|
226
|
+
try {
|
|
227
|
+
callback(this.currentStatus);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error('Error in health status subscriber:', error);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private resetHeartbeatTimeout(): void {
|
|
235
|
+
this.clearHeartbeatTimeout();
|
|
236
|
+
|
|
237
|
+
// If we don't receive a heartbeat within the timeout period, consider service unhealthy
|
|
238
|
+
this.heartbeatTimeout = setTimeout(() => {
|
|
239
|
+
this.updateStatus({
|
|
240
|
+
isHealthy: false,
|
|
241
|
+
message: 'Service unavailable',
|
|
242
|
+
lastHeartbeat: this.currentStatus.lastHeartbeat,
|
|
243
|
+
connectionId: this.currentStatus.connectionId
|
|
244
|
+
});
|
|
245
|
+
}, this.heartbeatTimeoutMs);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private clearHeartbeatTimeout(): void {
|
|
249
|
+
if (this.heartbeatTimeout) {
|
|
250
|
+
clearTimeout(this.heartbeatTimeout);
|
|
251
|
+
this.heartbeatTimeout = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Export singleton instance
|
|
258
|
+
export const signalRActivityService = new SignalRActivityService();
|