@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,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Token Lifecycle Management for @payez/next-mvp
|
|
4
|
+
*
|
|
5
|
+
* Ensures tokens are fresh before making API calls.
|
|
6
|
+
* Checks expiration and triggers refresh if needed.
|
|
7
|
+
*
|
|
8
|
+
* Pattern: Check first, refresh if needed, fail gracefully if refresh fails.
|
|
9
|
+
*
|
|
10
|
+
* HANDLES CONCURRENT REFRESH: When multiple API calls arrive simultaneously
|
|
11
|
+
* with expired tokens, only one will actually perform the refresh. Others
|
|
12
|
+
* receive 409 (conflict) and wait for the refresh to complete, then use
|
|
13
|
+
* the freshly refreshed tokens.
|
|
14
|
+
*
|
|
15
|
+
* REQUIRED: Your app must expose the refresh route:
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // app/api/auth/refresh/route.ts
|
|
18
|
+
* export { POST } from '@payez/next-mvp/routes/auth/refresh';
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @version 2.0.0
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.ensureFreshToken = ensureFreshToken;
|
|
25
|
+
exports.getFreshAuthHeader = getFreshAuthHeader;
|
|
26
|
+
const jwt_1 = require("next-auth/jwt");
|
|
27
|
+
const session_store_1 = require("./session-store");
|
|
28
|
+
const app_slug_1 = require("./app-slug");
|
|
29
|
+
const idp_client_config_1 = require("./idp-client-config");
|
|
30
|
+
// 5 minute threshold for "needs refresh" - matches refresh handler pattern
|
|
31
|
+
const REFRESH_THRESHOLD_MS = 5 * 60 * 1000;
|
|
32
|
+
// Concurrent refresh handling configuration
|
|
33
|
+
const CONCURRENT_REFRESH_POLL_INTERVAL_MS = 200; // How often to poll session during concurrent refresh
|
|
34
|
+
const CONCURRENT_REFRESH_MAX_WAIT_MS = 8000; // Max time to wait for concurrent refresh to complete
|
|
35
|
+
const REFRESH_RETRY_DELAY_MS = 500; // Delay before retrying after failed concurrent refresh
|
|
36
|
+
const KEY_PROPAGATION_DELAY_MS = 150; // Delay after refresh to allow JWKS cache updates in downstream services
|
|
37
|
+
/**
|
|
38
|
+
* Check if token needs refresh based on expiration time
|
|
39
|
+
*/
|
|
40
|
+
function needsRefresh(accessTokenExpires) {
|
|
41
|
+
if (!accessTokenExpires)
|
|
42
|
+
return true;
|
|
43
|
+
const timeUntilExpiry = accessTokenExpires - Date.now();
|
|
44
|
+
return timeUntilExpiry <= REFRESH_THRESHOLD_MS;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Helper to delay execution
|
|
48
|
+
*/
|
|
49
|
+
function delay(ms) {
|
|
50
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Wait for a concurrent refresh to complete by polling the session.
|
|
54
|
+
* Returns true if session becomes fresh, false if timeout reached.
|
|
55
|
+
*/
|
|
56
|
+
async function waitForConcurrentRefresh(sessionToken, maxWaitMs = CONCURRENT_REFRESH_MAX_WAIT_MS) {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
59
|
+
await delay(CONCURRENT_REFRESH_POLL_INTERVAL_MS);
|
|
60
|
+
const sessionData = await (0, session_store_1.getSession)(sessionToken);
|
|
61
|
+
if (!sessionData) {
|
|
62
|
+
return { success: false };
|
|
63
|
+
}
|
|
64
|
+
// Check if token is now fresh
|
|
65
|
+
if (!needsRefresh(sessionData.idpAccessTokenExpires)) {
|
|
66
|
+
return { success: true, sessionData };
|
|
67
|
+
}
|
|
68
|
+
// Check if session has a new access token (even if still within threshold)
|
|
69
|
+
if (sessionData.idpAccessToken && sessionData.idpAccessTokenExpires &&
|
|
70
|
+
sessionData.idpAccessTokenExpires > Date.now()) {
|
|
71
|
+
return { success: true, sessionData };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { success: false };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the internal API URL for making internal service calls.
|
|
78
|
+
* INTERNAL_API_URL is REQUIRED - no fallbacks.
|
|
79
|
+
*/
|
|
80
|
+
function getInternalApiUrl(request) {
|
|
81
|
+
const internalUrl = process.env.INTERNAL_API_URL;
|
|
82
|
+
if (!internalUrl) {
|
|
83
|
+
throw new Error('[INTERNAL_API_URL] FATAL: INTERNAL_API_URL environment variable is REQUIRED. ' +
|
|
84
|
+
'Set it to this app\'s internal K8s service URL (e.g., http://myapp.namespace.svc.cluster.local:80) ' +
|
|
85
|
+
'or http://localhost:3000 for local development.');
|
|
86
|
+
}
|
|
87
|
+
return internalUrl;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Trigger a token refresh via the refresh API endpoint.
|
|
91
|
+
*
|
|
92
|
+
* HANDLES CONCURRENT REFRESH (409):
|
|
93
|
+
* When another request is already refreshing the token, this function
|
|
94
|
+
* waits for that refresh to complete instead of failing immediately.
|
|
95
|
+
* This prevents race conditions where multiple parallel API calls
|
|
96
|
+
* could cause unnecessary refresh failures.
|
|
97
|
+
*
|
|
98
|
+
* TERMINAL STATES:
|
|
99
|
+
* Returns { success: false, terminal: true } when the session cannot be
|
|
100
|
+
* recovered (e.g., no refresh token). Callers should redirect to login.
|
|
101
|
+
*/
|
|
102
|
+
async function triggerRefresh(request, sessionToken, retryCount = 0) {
|
|
103
|
+
const maxRetries = 2;
|
|
104
|
+
try {
|
|
105
|
+
const baseUrl = getInternalApiUrl(request);
|
|
106
|
+
const requestId = `refresh_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
107
|
+
const response = await fetch(`${baseUrl}/api/auth/refresh`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: {
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
'Cookie': request.headers.get('cookie') || '',
|
|
112
|
+
'X-Session-Token': sessionToken,
|
|
113
|
+
'X-Request-Id': requestId,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
// Handle 409 Conflict - another refresh is in progress
|
|
117
|
+
if (response.status === 409) {
|
|
118
|
+
// Wait for the concurrent refresh to complete
|
|
119
|
+
const waitResult = await waitForConcurrentRefresh(sessionToken);
|
|
120
|
+
if (waitResult.success) {
|
|
121
|
+
return { success: true };
|
|
122
|
+
}
|
|
123
|
+
// Concurrent refresh didn't produce a fresh token - try again if we have retries left
|
|
124
|
+
if (retryCount < maxRetries) {
|
|
125
|
+
await delay(REFRESH_RETRY_DELAY_MS);
|
|
126
|
+
return triggerRefresh(request, sessionToken, retryCount + 1);
|
|
127
|
+
}
|
|
128
|
+
return { success: false };
|
|
129
|
+
}
|
|
130
|
+
// Handle other non-OK responses
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
// Parse response body to check for terminal errors
|
|
133
|
+
let responseData = {};
|
|
134
|
+
try {
|
|
135
|
+
responseData = await response.json();
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Ignore parse errors
|
|
139
|
+
}
|
|
140
|
+
// Log the failure for debugging
|
|
141
|
+
console.warn('[TOKEN_LIFECYCLE] Refresh request failed:', {
|
|
142
|
+
status: response.status,
|
|
143
|
+
statusText: response.statusText,
|
|
144
|
+
baseUrl,
|
|
145
|
+
retryCount,
|
|
146
|
+
code: responseData.code,
|
|
147
|
+
terminal: responseData.terminal
|
|
148
|
+
});
|
|
149
|
+
// CHECK FOR TERMINAL STATE: No refresh token = session is dead
|
|
150
|
+
// Don't retry - user must re-authenticate
|
|
151
|
+
if (responseData.code === 'NO_REFRESH_TOKEN' || responseData.terminal === true) {
|
|
152
|
+
console.error('[TOKEN_LIFECYCLE] TERMINAL: Session has no refresh token - user must re-login');
|
|
153
|
+
return { success: false, terminal: true, code: responseData.code };
|
|
154
|
+
}
|
|
155
|
+
// For other 401s, check if maybe session was refreshed by another request
|
|
156
|
+
if (response.status === 401 && retryCount < maxRetries) {
|
|
157
|
+
await delay(REFRESH_RETRY_DELAY_MS);
|
|
158
|
+
const sessionData = await (0, session_store_1.getSession)(sessionToken);
|
|
159
|
+
if (sessionData && !needsRefresh(sessionData.idpAccessTokenExpires)) {
|
|
160
|
+
return { success: true };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return { success: false, code: responseData.code };
|
|
164
|
+
}
|
|
165
|
+
const result = await response.json();
|
|
166
|
+
const success = result.refreshed === true || result.reason === 'already_fresh';
|
|
167
|
+
return { success };
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
// Log network errors for debugging
|
|
171
|
+
console.error('[TOKEN_LIFECYCLE] Refresh network error:', {
|
|
172
|
+
error: error instanceof Error ? error.message : String(error),
|
|
173
|
+
retryCount
|
|
174
|
+
});
|
|
175
|
+
// On network error, check if maybe another request refreshed the token
|
|
176
|
+
if (retryCount < maxRetries) {
|
|
177
|
+
await delay(REFRESH_RETRY_DELAY_MS);
|
|
178
|
+
const sessionData = await (0, session_store_1.getSession)(sessionToken);
|
|
179
|
+
if (sessionData && !needsRefresh(sessionData.idpAccessTokenExpires)) {
|
|
180
|
+
return { success: true };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { success: false };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Ensures we have a fresh access token before making API calls.
|
|
188
|
+
*
|
|
189
|
+
* This utility checks token expiration and triggers a refresh if needed,
|
|
190
|
+
* preventing 401 errors from expired tokens being sent to downstream APIs.
|
|
191
|
+
*
|
|
192
|
+
* @param request - The incoming NextRequest
|
|
193
|
+
* @returns TokenResult with accessToken and sessionData, or TokenError
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* import { ensureFreshToken } from '@payez/next-mvp/lib/token-lifecycle';
|
|
198
|
+
*
|
|
199
|
+
* export async function GET(request: NextRequest) {
|
|
200
|
+
* const tokenResult = await ensureFreshToken(request);
|
|
201
|
+
* if (!tokenResult.success) {
|
|
202
|
+
* return NextResponse.json({ error: tokenResult.error }, { status: 401 });
|
|
203
|
+
* }
|
|
204
|
+
*
|
|
205
|
+
* // Use tokenResult.accessToken for downstream API calls
|
|
206
|
+
* const response = await fetch('https://api.example.com/data', {
|
|
207
|
+
* headers: { 'Authorization': `Bearer ${tokenResult.accessToken}` }
|
|
208
|
+
* });
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
/**
|
|
213
|
+
* Get NextAuth secret from IDP config (cached).
|
|
214
|
+
* NEVER use process.env.NEXTAUTH_SECRET directly - it may not be set.
|
|
215
|
+
*/
|
|
216
|
+
async function getNextAuthSecret() {
|
|
217
|
+
const config = await (0, idp_client_config_1.getIDPClientConfig)();
|
|
218
|
+
return config.nextAuthSecret || '';
|
|
219
|
+
}
|
|
220
|
+
async function ensureFreshToken(request) {
|
|
221
|
+
try {
|
|
222
|
+
// 1. Get NextAuth JWT to extract sessionToken
|
|
223
|
+
// Use IDP config to get the secret (same as viability.ts)
|
|
224
|
+
const secret = await getNextAuthSecret();
|
|
225
|
+
if (!secret) {
|
|
226
|
+
console.error('[TOKEN_LIFECYCLE] NEXTAUTH_SECRET not available from IDP config');
|
|
227
|
+
return { success: false, error: 'NO_SESSION', message: 'Auth not configured' };
|
|
228
|
+
}
|
|
229
|
+
const cookieName = (0, app_slug_1.getJwtCookieName)();
|
|
230
|
+
const token = await (0, jwt_1.getToken)({
|
|
231
|
+
req: request,
|
|
232
|
+
secret,
|
|
233
|
+
cookieName,
|
|
234
|
+
});
|
|
235
|
+
// Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
|
|
236
|
+
const sessionTokenFromJwt = (token?.sessionToken || token?.redisSessionId);
|
|
237
|
+
if (!sessionTokenFromJwt) {
|
|
238
|
+
// Debug: log what we got including cookie presence and value info
|
|
239
|
+
const cookieHeader = request.headers.get('cookie') || '';
|
|
240
|
+
const hasCookie = cookieHeader.includes(cookieName);
|
|
241
|
+
// Extract the actual cookie value to check if it's empty
|
|
242
|
+
const cookieMatch = cookieHeader.match(new RegExp(`${cookieName}=([^;]*)`));
|
|
243
|
+
const cookieValue = cookieMatch ? cookieMatch[1] : null;
|
|
244
|
+
const cookieValueLength = cookieValue?.length || 0;
|
|
245
|
+
console.warn('[TOKEN_LIFECYCLE] NO_SESSION -', {
|
|
246
|
+
token: token ? 'exists but no sessionToken/redisSessionId' : 'null',
|
|
247
|
+
cookieName,
|
|
248
|
+
hasCookie,
|
|
249
|
+
cookieValueLength,
|
|
250
|
+
cookieValuePreview: cookieValue ? cookieValue.substring(0, 20) + '...' : 'EMPTY',
|
|
251
|
+
cookieHeaderLength: cookieHeader.length,
|
|
252
|
+
secretLength: secret.length,
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
success: false,
|
|
256
|
+
error: 'NO_SESSION',
|
|
257
|
+
message: 'No session available',
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const sessionToken = sessionTokenFromJwt;
|
|
261
|
+
// 2. Get session data from Redis
|
|
262
|
+
let sessionData = await (0, session_store_1.getSession)(sessionToken);
|
|
263
|
+
if (!sessionData) {
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
error: 'NO_SESSION',
|
|
267
|
+
message: 'Session expired or not found',
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
// DEBUG: Log session data before refresh check
|
|
271
|
+
const tokenExpiresStr = sessionData.idpAccessTokenExpires
|
|
272
|
+
? new Date(sessionData.idpAccessTokenExpires).toISOString()
|
|
273
|
+
: 'undefined';
|
|
274
|
+
let needsRefreshNow = needsRefresh(sessionData.idpAccessTokenExpires);
|
|
275
|
+
// VALIDATION: Check if the actual JWT token's exp matches what Redis claims
|
|
276
|
+
// This catches cases where accessTokenExpires was updated but accessToken wasn't
|
|
277
|
+
let tokenMismatch = false;
|
|
278
|
+
if (sessionData.idpAccessToken && !needsRefreshNow) {
|
|
279
|
+
try {
|
|
280
|
+
const tokenParts = sessionData.idpAccessToken.split('.');
|
|
281
|
+
if (tokenParts.length === 3) {
|
|
282
|
+
const payload = JSON.parse(Buffer.from(tokenParts[1], 'base64url').toString());
|
|
283
|
+
const jwtExpMs = (payload.exp || 0) * 1000;
|
|
284
|
+
const now = Date.now();
|
|
285
|
+
// If the JWT is actually expired, force a refresh regardless of what Redis says
|
|
286
|
+
if (jwtExpMs < now) {
|
|
287
|
+
console.warn('[TOKEN_LIFECYCLE] Token mismatch detected! JWT expired but Redis claims valid', {
|
|
288
|
+
jwtExp: new Date(jwtExpMs).toISOString(),
|
|
289
|
+
redisAccessTokenExpires: tokenExpiresStr,
|
|
290
|
+
now: new Date(now).toISOString(),
|
|
291
|
+
mismatchMs: sessionData.idpAccessTokenExpires ? sessionData.idpAccessTokenExpires - jwtExpMs : 'N/A'
|
|
292
|
+
});
|
|
293
|
+
needsRefreshNow = true;
|
|
294
|
+
tokenMismatch = true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
// If we can't decode, proceed with normal logic
|
|
300
|
+
console.warn('[TOKEN_LIFECYCLE] Could not validate JWT exp claim:', e);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
console.log('[TOKEN_LIFECYCLE] ensureFreshToken check:', {
|
|
304
|
+
sessionToken: sessionToken.substring(0, 8) + '...',
|
|
305
|
+
accessTokenExpires: tokenExpiresStr,
|
|
306
|
+
now: new Date().toISOString(),
|
|
307
|
+
needsRefresh: needsRefreshNow,
|
|
308
|
+
tokenMismatch,
|
|
309
|
+
hasRefreshToken: !!sessionData.idpRefreshToken
|
|
310
|
+
});
|
|
311
|
+
// 3. Check if token needs refresh
|
|
312
|
+
if (needsRefreshNow) {
|
|
313
|
+
// 4. Trigger refresh
|
|
314
|
+
console.log('[TOKEN_LIFECYCLE] Triggering refresh...');
|
|
315
|
+
const refreshResult = await triggerRefresh(request, sessionToken);
|
|
316
|
+
if (!refreshResult.success) {
|
|
317
|
+
// Check for terminal state - session cannot be recovered
|
|
318
|
+
if (refreshResult.terminal) {
|
|
319
|
+
console.error('[TOKEN_LIFECYCLE] TERMINAL: Session expired with no refresh token - redirect to login');
|
|
320
|
+
return {
|
|
321
|
+
success: false,
|
|
322
|
+
error: 'SESSION_EXPIRED_NO_REFRESH',
|
|
323
|
+
message: 'Session expired. Please sign in again.',
|
|
324
|
+
terminal: true,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
console.warn('[TOKEN_LIFECYCLE] Refresh failed');
|
|
328
|
+
return {
|
|
329
|
+
success: false,
|
|
330
|
+
error: 'REFRESH_FAILED',
|
|
331
|
+
message: 'Token refresh failed',
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
// 5. Re-fetch session data after refresh
|
|
335
|
+
sessionData = await (0, session_store_1.getSession)(sessionToken);
|
|
336
|
+
console.log('[TOKEN_LIFECYCLE] After refresh:', {
|
|
337
|
+
hasAccessToken: !!sessionData?.idpAccessToken,
|
|
338
|
+
newAccessTokenExpires: sessionData?.idpAccessTokenExpires
|
|
339
|
+
? new Date(sessionData.idpAccessTokenExpires).toISOString()
|
|
340
|
+
: 'undefined'
|
|
341
|
+
});
|
|
342
|
+
if (!sessionData?.idpAccessToken) {
|
|
343
|
+
return {
|
|
344
|
+
success: false,
|
|
345
|
+
error: 'REFRESH_FAILED',
|
|
346
|
+
message: 'No access token after refresh',
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
// 5.5. Key propagation delay - allow downstream services (like Vibe) to cache new JWKS
|
|
350
|
+
// This is critical when IDP rotates signing keys - the new token's kid may not be
|
|
351
|
+
// immediately available in Vibe's JWKS cache
|
|
352
|
+
await delay(KEY_PROPAGATION_DELAY_MS);
|
|
353
|
+
}
|
|
354
|
+
// 6. Validate we have a token
|
|
355
|
+
if (!sessionData.idpAccessToken) {
|
|
356
|
+
return {
|
|
357
|
+
success: false,
|
|
358
|
+
error: 'NO_TOKEN',
|
|
359
|
+
message: 'No access token available',
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
success: true,
|
|
364
|
+
accessToken: sessionData.idpAccessToken,
|
|
365
|
+
sessionData,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
console.error('[TOKEN_LIFECYCLE] Error:', error);
|
|
370
|
+
return {
|
|
371
|
+
success: false,
|
|
372
|
+
error: 'NO_SESSION',
|
|
373
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Get authorization header from fresh token.
|
|
379
|
+
* Convenience wrapper for API routes.
|
|
380
|
+
*
|
|
381
|
+
* @param request - The incoming NextRequest
|
|
382
|
+
* @returns Authorization header string or null if token unavailable
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```typescript
|
|
386
|
+
* const authHeader = await getFreshAuthHeader(request);
|
|
387
|
+
* if (!authHeader) {
|
|
388
|
+
* return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
389
|
+
* }
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
async function getFreshAuthHeader(request) {
|
|
393
|
+
const result = await ensureFreshToken(request);
|
|
394
|
+
if (!result.success) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return `Bearer ${result.accessToken}`;
|
|
398
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BASE STANDARDIZED RESPONSE FORMAT
|
|
3
|
+
* This is THE ONLY acceptable response format from our APIs
|
|
4
|
+
*/
|
|
5
|
+
export interface StandardizedApiResponse<TData = unknown> {
|
|
6
|
+
/** REQUIRED: Operation success status */
|
|
7
|
+
success: true;
|
|
8
|
+
/** REQUIRED: The actual data payload */
|
|
9
|
+
data: TData;
|
|
10
|
+
/** REQUIRED: Human-readable success message */
|
|
11
|
+
message: string;
|
|
12
|
+
/** REQUIRED: Unique operation code for tracking */
|
|
13
|
+
operation_code: string;
|
|
14
|
+
/** Optional: Server timestamp */
|
|
15
|
+
timestamp?: string;
|
|
16
|
+
/** Optional: Request ID for tracing */
|
|
17
|
+
request_id?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* STANDARDIZED ERROR RESPONSE FORMAT
|
|
21
|
+
* This is THE ONLY acceptable error format from our APIs
|
|
22
|
+
*/
|
|
23
|
+
export interface StandardizedErrorResponse {
|
|
24
|
+
/** REQUIRED: Always false for errors */
|
|
25
|
+
success: false;
|
|
26
|
+
/** REQUIRED: Standard error code */
|
|
27
|
+
error_code: string;
|
|
28
|
+
/** REQUIRED: Human-readable error message */
|
|
29
|
+
message: string;
|
|
30
|
+
/** REQUIRED: Operation that failed */
|
|
31
|
+
operation: string;
|
|
32
|
+
/** Optional: Additional error details - can be any structure from IDP */
|
|
33
|
+
details?: unknown;
|
|
34
|
+
/** Optional: Validation errors */
|
|
35
|
+
validation_errors?: Record<string, string[]>;
|
|
36
|
+
/** Optional: Server timestamp */
|
|
37
|
+
timestamp?: string;
|
|
38
|
+
/** Optional: Request ID for tracing */
|
|
39
|
+
request_id?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* STANDARDIZED PAGINATED RESPONSE FORMAT
|
|
43
|
+
* For endpoints that return paged data
|
|
44
|
+
*/
|
|
45
|
+
export interface StandardizedPagedResponse<TData = unknown> {
|
|
46
|
+
/** REQUIRED: Always true for success */
|
|
47
|
+
success: true;
|
|
48
|
+
/** REQUIRED: Array of data items */
|
|
49
|
+
data: TData[];
|
|
50
|
+
/** REQUIRED: Human-readable success message */
|
|
51
|
+
message: string;
|
|
52
|
+
/** REQUIRED: Unique operation code */
|
|
53
|
+
operation_code: string;
|
|
54
|
+
/** REQUIRED: Pagination metadata */
|
|
55
|
+
pagination: {
|
|
56
|
+
/** Current page number (1-based) */
|
|
57
|
+
current_page: number;
|
|
58
|
+
/** Total number of pages */
|
|
59
|
+
total_pages: number;
|
|
60
|
+
/** Number of items per page */
|
|
61
|
+
page_size: number;
|
|
62
|
+
/** Total number of items across all pages */
|
|
63
|
+
total_items: number;
|
|
64
|
+
/** True if there are more pages after current */
|
|
65
|
+
has_next_page: boolean;
|
|
66
|
+
/** True if there are pages before current */
|
|
67
|
+
has_previous_page: boolean;
|
|
68
|
+
};
|
|
69
|
+
/** Optional: Server timestamp */
|
|
70
|
+
timestamp?: string;
|
|
71
|
+
/** Optional: Request ID for tracing */
|
|
72
|
+
request_id?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* VALIDATION ERROR RESPONSE FORMAT
|
|
76
|
+
* For input validation failures
|
|
77
|
+
*/
|
|
78
|
+
export interface StandardizedValidationResponse {
|
|
79
|
+
/** REQUIRED: Always false for validation errors */
|
|
80
|
+
success: false;
|
|
81
|
+
/** REQUIRED: Always 'VALIDATION_ERROR' */
|
|
82
|
+
error_code: 'VALIDATION_ERROR';
|
|
83
|
+
/** REQUIRED: Summary message */
|
|
84
|
+
message: string;
|
|
85
|
+
/** REQUIRED: Operation that failed */
|
|
86
|
+
operation: string;
|
|
87
|
+
/** REQUIRED: Field-specific validation errors */
|
|
88
|
+
payload: {
|
|
89
|
+
/** Field name mapped to array of error messages */
|
|
90
|
+
validation_errors: Record<string, string[]>;
|
|
91
|
+
/** The invalid value that caused the error */
|
|
92
|
+
invalid_value?: unknown;
|
|
93
|
+
/** The field that caused the primary error */
|
|
94
|
+
primary_field?: string;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** ALL POSSIBLE STANDARDIZED RESPONSES */
|
|
98
|
+
export type StandardizedResponse<TData = unknown> = StandardizedApiResponse<TData> | StandardizedPagedResponse<TData> | StandardizedErrorResponse | StandardizedValidationResponse;
|
|
99
|
+
/**
|
|
100
|
+
* Type guard to check if response is a success response
|
|
101
|
+
* THROWS if response doesn't match standardized format
|
|
102
|
+
*/
|
|
103
|
+
export declare function isSuccessResponse<TData = unknown>(response: unknown): response is StandardizedApiResponse<TData>;
|
|
104
|
+
/**
|
|
105
|
+
* Type guard to check if response is a paged success response
|
|
106
|
+
* THROWS if response doesn't match standardized format
|
|
107
|
+
*/
|
|
108
|
+
export declare function isPagedResponse<TData = unknown>(response: unknown): response is StandardizedPagedResponse<TData>;
|
|
109
|
+
/**
|
|
110
|
+
* Type guard to check if response is an error response
|
|
111
|
+
* THROWS if response doesn't match standardized format
|
|
112
|
+
*/
|
|
113
|
+
export declare function isErrorResponse(response: unknown): response is StandardizedErrorResponse;
|
|
114
|
+
/**
|
|
115
|
+
* Type guard to check if response is a validation error
|
|
116
|
+
* THROWS if response doesn't match standardized format
|
|
117
|
+
*/
|
|
118
|
+
export declare function isValidationErrorResponse(response: unknown): response is StandardizedValidationResponse;
|
|
119
|
+
/**
|
|
120
|
+
* VALIDATES AND NORMALIZES API RESPONSES
|
|
121
|
+
* This function BREAKS THE BUILD if responses don't match our standard
|
|
122
|
+
* NO EXCEPTIONS - ZERO TOLERANCE FOR BAD RESPONSES
|
|
123
|
+
*/
|
|
124
|
+
export declare function validateStandardizedResponse<TData = unknown>(response: unknown, endpoint?: string): StandardizedResponse<TData>;
|
|
125
|
+
/** Extract the data type from a standardized response */
|
|
126
|
+
export type ExtractResponseData<T> = T extends StandardizedApiResponse<infer U> ? U : T extends StandardizedPagedResponse<infer U> ? U[] : never;
|
|
127
|
+
/** Extract the error code from an error response */
|
|
128
|
+
export type ExtractErrorCode<T> = T extends StandardizedErrorResponse ? T['error_code'] : T extends StandardizedValidationResponse ? T['error_code'] : never;
|