@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,786 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.standardizedApi = exports.ApiNetworkError = exports.ApiValidationError = exports.ApiBusinessLogicError = exports.ApiResponseFormatError = void 0;
|
|
38
|
+
exports.isApiSuccess = isApiSuccess;
|
|
39
|
+
exports.isApiPagedSuccess = isApiPagedSuccess;
|
|
40
|
+
exports.isApiError = isApiError;
|
|
41
|
+
exports.extractApiData = extractApiData;
|
|
42
|
+
exports.extractApiItems = extractApiItems;
|
|
43
|
+
// ========================================================================================
|
|
44
|
+
// BULLETPROOF STANDARDIZED CLIENT API - ZERO TOLERANCE FOR BAD RESPONSES
|
|
45
|
+
// ========================================================================================
|
|
46
|
+
// This client API ENFORCES the standardized response format
|
|
47
|
+
// It will BREAK if APIs don't return the expected structure
|
|
48
|
+
// NO MORE GUESSING data.data.data.data - EVER AGAIN!
|
|
49
|
+
// ========================================================================================
|
|
50
|
+
const react_1 = require("next-auth/react");
|
|
51
|
+
const api_responses_1 = require("./types/api-responses");
|
|
52
|
+
// ========================================================================================
|
|
53
|
+
// CLIENT API ERROR TYPES
|
|
54
|
+
// ========================================================================================
|
|
55
|
+
/**
|
|
56
|
+
* ERROR THROWN WHEN API RESPONSE FORMAT IS INVALID
|
|
57
|
+
* This means the API is NOT following our standardized format
|
|
58
|
+
*/
|
|
59
|
+
class ApiResponseFormatError extends Error {
|
|
60
|
+
endpoint;
|
|
61
|
+
rawResponse;
|
|
62
|
+
constructor(message, endpoint, rawResponse) {
|
|
63
|
+
super(`API_FORMAT_ERROR: ${message}`);
|
|
64
|
+
this.endpoint = endpoint;
|
|
65
|
+
this.rawResponse = rawResponse;
|
|
66
|
+
this.name = 'ApiResponseFormatError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.ApiResponseFormatError = ApiResponseFormatError;
|
|
70
|
+
/**
|
|
71
|
+
* ERROR THROWN WHEN API RETURNS A STANDARDIZED ERROR RESPONSE
|
|
72
|
+
* This is a properly formatted error from the API
|
|
73
|
+
*/
|
|
74
|
+
class ApiBusinessLogicError extends Error {
|
|
75
|
+
errorCode;
|
|
76
|
+
operation;
|
|
77
|
+
details;
|
|
78
|
+
constructor(errorCode, message, operation, details) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.errorCode = errorCode;
|
|
81
|
+
this.operation = operation;
|
|
82
|
+
this.details = details;
|
|
83
|
+
this.name = 'ApiBusinessLogicError';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.ApiBusinessLogicError = ApiBusinessLogicError;
|
|
87
|
+
/**
|
|
88
|
+
* ERROR THROWN WHEN VALIDATION FAILS
|
|
89
|
+
* This is a properly formatted validation error from the API
|
|
90
|
+
*/
|
|
91
|
+
class ApiValidationError extends Error {
|
|
92
|
+
operation;
|
|
93
|
+
validationErrors;
|
|
94
|
+
invalidValue;
|
|
95
|
+
primaryField;
|
|
96
|
+
constructor(message, operation, validationErrors, invalidValue, primaryField) {
|
|
97
|
+
super(message);
|
|
98
|
+
this.operation = operation;
|
|
99
|
+
this.validationErrors = validationErrors;
|
|
100
|
+
this.invalidValue = invalidValue;
|
|
101
|
+
this.primaryField = primaryField;
|
|
102
|
+
this.name = 'ApiValidationError';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.ApiValidationError = ApiValidationError;
|
|
106
|
+
/**
|
|
107
|
+
* ERROR THROWN WHEN NETWORK/HTTP ISSUES OCCUR
|
|
108
|
+
*/
|
|
109
|
+
class ApiNetworkError extends Error {
|
|
110
|
+
status;
|
|
111
|
+
endpoint;
|
|
112
|
+
constructor(message, status, endpoint) {
|
|
113
|
+
super(`NETWORK_ERROR: ${message}`);
|
|
114
|
+
this.status = status;
|
|
115
|
+
this.endpoint = endpoint;
|
|
116
|
+
this.name = 'ApiNetworkError';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.ApiNetworkError = ApiNetworkError;
|
|
120
|
+
// ========================================================================================
|
|
121
|
+
// AUTHENTICATION STATE MANAGEMENT
|
|
122
|
+
// ========================================================================================
|
|
123
|
+
// Coordinate client-side refresh to avoid duplicate refresh calls racing with
|
|
124
|
+
// server-side middleware or other tabs. Only one refresh runs at a time.
|
|
125
|
+
let refreshInFlight = null;
|
|
126
|
+
// Enhanced redirect logic with grace period and retry attempts
|
|
127
|
+
let authRedirectScheduled = false;
|
|
128
|
+
let lastAuthFailureTime = 0;
|
|
129
|
+
let consecutiveAuthFailures = 0;
|
|
130
|
+
const AUTH_FAILURE_GRACE_PERIOD = 2000; // 2 seconds grace period
|
|
131
|
+
const MAX_AUTH_FAILURES_BEFORE_REDIRECT = 2; // Allow 2 failures before redirect
|
|
132
|
+
const AUTH_FAILURE_RESET_WINDOW = 30000; // Reset failure count after 30 seconds
|
|
133
|
+
// Helper: detect pre-2FA session (session exists, requires 2FA and not completed)
|
|
134
|
+
function isPreTwoFactorSession(session) {
|
|
135
|
+
return !!(session?.user?.requiresTwoFactor && !session?.user?.twoFactorSessionVerified);
|
|
136
|
+
}
|
|
137
|
+
// Reset auth failure state on successful requests
|
|
138
|
+
function resetAuthFailureState() {
|
|
139
|
+
if (consecutiveAuthFailures > 0) {
|
|
140
|
+
console.log(`✅ Resetting auth failure state (was ${consecutiveAuthFailures} failures)`);
|
|
141
|
+
consecutiveAuthFailures = 0;
|
|
142
|
+
lastAuthFailureTime = 0;
|
|
143
|
+
authRedirectScheduled = false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function scheduleLoginRedirect(isImmediate = false) {
|
|
147
|
+
if (authRedirectScheduled)
|
|
148
|
+
return;
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
// Reset consecutive failures if enough time has passed
|
|
151
|
+
if (now - lastAuthFailureTime > AUTH_FAILURE_RESET_WINDOW) {
|
|
152
|
+
consecutiveAuthFailures = 0;
|
|
153
|
+
}
|
|
154
|
+
consecutiveAuthFailures++;
|
|
155
|
+
lastAuthFailureTime = now;
|
|
156
|
+
console.warn(`🔴 Auth failure #${consecutiveAuthFailures}, immediate: ${isImmediate}`);
|
|
157
|
+
// Only redirect if we've had multiple failures or if explicitly requested
|
|
158
|
+
if (!isImmediate && consecutiveAuthFailures < MAX_AUTH_FAILURES_BEFORE_REDIRECT) {
|
|
159
|
+
console.log(`⏳ Delaying redirect - only ${consecutiveAuthFailures} failures so far`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
authRedirectScheduled = true;
|
|
163
|
+
const redirectFunction = () => {
|
|
164
|
+
try {
|
|
165
|
+
const returnUrl = encodeURIComponent(`${window.location.pathname}${window.location.search}`);
|
|
166
|
+
console.warn(`🔄 Redirecting to login with return URL: ${returnUrl}`);
|
|
167
|
+
window.location.href = `/account-auth/login?returnUrl=${returnUrl}`;
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error('❌ Error during login redirect:', error);
|
|
171
|
+
// Final fallback
|
|
172
|
+
try {
|
|
173
|
+
window.location.href = '/account-auth/login';
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// no-op if window is not available
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
if (isImmediate) {
|
|
181
|
+
// Immediate redirect for critical auth failures
|
|
182
|
+
redirectFunction();
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// Small delay to allow any pending requests to complete
|
|
186
|
+
console.log(`⏳ Scheduling redirect with ${AUTH_FAILURE_GRACE_PERIOD}ms grace period`);
|
|
187
|
+
setTimeout(redirectFunction, AUTH_FAILURE_GRACE_PERIOD);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// ========================================================================================
|
|
191
|
+
// BULLETPROOF CLIENT API SERVICE
|
|
192
|
+
// ========================================================================================
|
|
193
|
+
class StandardizedClientApiService {
|
|
194
|
+
baseUrl;
|
|
195
|
+
constructor() {
|
|
196
|
+
this.baseUrl = '';
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* MAKES HTTP REQUEST AND VALIDATES RESPONSE FORMAT
|
|
200
|
+
* This method ENFORCES standardized response format compliance
|
|
201
|
+
* Will throw ApiResponseFormatError if format is invalid
|
|
202
|
+
*/
|
|
203
|
+
async makeRequest(endpoint, options = {}, sessionToken) {
|
|
204
|
+
const fullEndpoint = `${this.baseUrl}${endpoint}`;
|
|
205
|
+
try {
|
|
206
|
+
// Use provided token or get from NextAuth session
|
|
207
|
+
const currentSession = await (0, react_1.getSession)();
|
|
208
|
+
let token = sessionToken || currentSession?.accessToken;
|
|
209
|
+
// Preflight freshness check: if token is near expiry, coordinate refresh BEFORE making request
|
|
210
|
+
const pre2FA = isPreTwoFactorSession(currentSession);
|
|
211
|
+
const hasRefresh = !!currentSession?.refreshToken;
|
|
212
|
+
if (!pre2FA && hasRefresh) {
|
|
213
|
+
try {
|
|
214
|
+
let timeLeft = null;
|
|
215
|
+
if (currentSession?.accessTokenExpires) {
|
|
216
|
+
timeLeft = currentSession.accessTokenExpires - Date.now();
|
|
217
|
+
}
|
|
218
|
+
else if (token) {
|
|
219
|
+
// Fallback decode only if session did not include expiry
|
|
220
|
+
const { jwtDecode } = await Promise.resolve().then(() => __importStar(require('./jwt-decode-client')));
|
|
221
|
+
const decoded = jwtDecode(token);
|
|
222
|
+
const expMs = decoded?.exp ? decoded.exp * 1000 : 0;
|
|
223
|
+
timeLeft = expMs - Date.now();
|
|
224
|
+
}
|
|
225
|
+
// Refresh if <= 60s remaining (or already expired)
|
|
226
|
+
if (timeLeft !== null && !Number.isNaN(timeLeft) && timeLeft <= 60000) {
|
|
227
|
+
console.log(`⏳ Access token expiring soon (${Math.floor(timeLeft / 1000)}s). Coordinating refresh before request...`);
|
|
228
|
+
if (!refreshInFlight) {
|
|
229
|
+
refreshInFlight = (async () => {
|
|
230
|
+
const reqId = crypto.randomUUID();
|
|
231
|
+
const rr = await fetch('/api/auth/refresh', {
|
|
232
|
+
method: 'POST',
|
|
233
|
+
credentials: 'include',
|
|
234
|
+
headers: { 'X-Request-ID': reqId },
|
|
235
|
+
});
|
|
236
|
+
if (rr.ok || rr.status === 409) {
|
|
237
|
+
// ok or in-progress; give it a beat in case of 409
|
|
238
|
+
if (rr.status === 409)
|
|
239
|
+
await new Promise(r => setTimeout(r, 1200));
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
if (rr.status === 401 || rr.status === 403) {
|
|
243
|
+
scheduleLoginRedirect();
|
|
244
|
+
throw new ApiNetworkError('Authentication failed - unable to refresh session', rr.status, endpoint);
|
|
245
|
+
}
|
|
246
|
+
const et = await rr.text();
|
|
247
|
+
throw new ApiNetworkError(et || 'Token refresh failed', rr.status, endpoint);
|
|
248
|
+
})().finally(() => { refreshInFlight = null; });
|
|
249
|
+
}
|
|
250
|
+
await refreshInFlight;
|
|
251
|
+
const newSessionAfter = await (0, react_1.getSession)();
|
|
252
|
+
token = newSessionAfter?.accessToken || token;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (preErr) {
|
|
256
|
+
console.warn('Preflight token freshness check failed (continuing to attempt request):', preErr);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// Elegantly skip preflight refresh in pre-2FA window or when no refresh token exists
|
|
261
|
+
if (pre2FA) {
|
|
262
|
+
console.log('⏭️ Skipping preflight refresh: 2FA not complete (no refresh allowed yet)');
|
|
263
|
+
}
|
|
264
|
+
else if (!hasRefresh) {
|
|
265
|
+
console.log('⏭️ Skipping preflight refresh: no refresh token present');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const config = {
|
|
269
|
+
...options,
|
|
270
|
+
headers: {
|
|
271
|
+
'Content-Type': 'application/json',
|
|
272
|
+
...(token && { 'Authorization': `Bearer ${token}` }),
|
|
273
|
+
...options.headers,
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
console.log(`🔄 API Request: ${options.method || 'GET'} ${fullEndpoint}`);
|
|
277
|
+
const response = await fetch(fullEndpoint, config);
|
|
278
|
+
if (!response.ok) {
|
|
279
|
+
// Handle coordination blocking (503) with auto-retry
|
|
280
|
+
if (response.status === 503) {
|
|
281
|
+
console.log('🔄 Got 503 Service Unavailable, attempting auto-retry for coordination...');
|
|
282
|
+
// Parse Retry-After header (in seconds)
|
|
283
|
+
const retryAfterHeader = response.headers.get('Retry-After');
|
|
284
|
+
let retryAfterSeconds = 1; // Default to 1 second
|
|
285
|
+
if (retryAfterHeader && /^\d+$/.test(retryAfterHeader)) {
|
|
286
|
+
retryAfterSeconds = parseInt(retryAfterHeader, 10);
|
|
287
|
+
}
|
|
288
|
+
const baseDelayMs = retryAfterSeconds * 1000;
|
|
289
|
+
const maxRetries = 3;
|
|
290
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
291
|
+
// Add jitter to prevent thundering herd
|
|
292
|
+
const jitterMs = Math.floor(Math.random() * 300) - 150; // ±150ms jitter
|
|
293
|
+
const exponentialBackoff = Math.pow(1.5, attempt - 1); // Mild exponential backoff
|
|
294
|
+
const delayMs = Math.max(100, baseDelayMs * exponentialBackoff + jitterMs);
|
|
295
|
+
console.log(`🔄 503 retry attempt ${attempt}/${maxRetries}, waiting ${delayMs}ms...`);
|
|
296
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
297
|
+
try {
|
|
298
|
+
const retryResponse = await fetch(fullEndpoint, config);
|
|
299
|
+
if (retryResponse.ok) {
|
|
300
|
+
console.log(`✅ 503 retry attempt ${attempt} succeeded`);
|
|
301
|
+
const rawData = await retryResponse.json();
|
|
302
|
+
resetAuthFailureState();
|
|
303
|
+
// COMPATIBILITY MODE: Handle both formats
|
|
304
|
+
if (rawData && typeof rawData === 'object' && 'success' in rawData) {
|
|
305
|
+
const validatedResponse = (0, api_responses_1.validateStandardizedResponse)(rawData, endpoint);
|
|
306
|
+
return this.convertToApiResult(validatedResponse);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
// New format - raw data
|
|
310
|
+
const wrappedResponse = {
|
|
311
|
+
success: true,
|
|
312
|
+
data: rawData,
|
|
313
|
+
message: 'Success',
|
|
314
|
+
operation_code: 'RAW_RESPONSE',
|
|
315
|
+
timestamp: new Date().toISOString()
|
|
316
|
+
};
|
|
317
|
+
return wrappedResponse;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
// If we get another 503, continue retrying
|
|
321
|
+
if (retryResponse.status === 503) {
|
|
322
|
+
console.log(`🔄 503 retry attempt ${attempt} got another 503, will retry...`);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
// If we get a different error, break and handle it normally
|
|
326
|
+
console.log(`❌ 503 retry attempt ${attempt} got ${retryResponse.status}, stopping retries`);
|
|
327
|
+
// Fall through to handle the retry response error
|
|
328
|
+
const errorText = await retryResponse.text();
|
|
329
|
+
let errorData;
|
|
330
|
+
try {
|
|
331
|
+
errorData = JSON.parse(errorText);
|
|
332
|
+
if (errorData && typeof errorData === 'object' && 'success' in errorData) {
|
|
333
|
+
// Detect PayEz canonical error envelope and map accordingly
|
|
334
|
+
if (errorData.error && typeof errorData.error === 'object') {
|
|
335
|
+
const reqIdHeader = retryResponse.headers.get('X-Request-ID') || retryResponse.headers.get('X-Correlation-ID');
|
|
336
|
+
const reqIdBody = errorData?.request_id || errorData?.requestId;
|
|
337
|
+
const errorResult = {
|
|
338
|
+
success: false,
|
|
339
|
+
error_code: errorData?.error?.code || errorData?.error_code || errorData?.code || `HTTP_${retryResponse.status}`,
|
|
340
|
+
message: errorData?.error?.message || errorData?.message || `Request failed with status ${retryResponse.status}`,
|
|
341
|
+
operation: endpoint,
|
|
342
|
+
details: (errorData?.error?.details ?? errorData?.details) || undefined,
|
|
343
|
+
...(reqIdBody || reqIdHeader ? { request_id: (reqIdBody || reqIdHeader) } : {})
|
|
344
|
+
};
|
|
345
|
+
return errorResult;
|
|
346
|
+
}
|
|
347
|
+
// Otherwise attempt to validate as our standardized error shape
|
|
348
|
+
const validatedError = (0, api_responses_1.validateStandardizedResponse)(errorData, endpoint);
|
|
349
|
+
return this.convertToApiResult(validatedError);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
// New/unknown error format - best-effort mapping
|
|
353
|
+
const reqIdHeader = retryResponse.headers.get('X-Request-ID') || retryResponse.headers.get('X-Correlation-ID');
|
|
354
|
+
const reqIdBody = errorData?.request_id || errorData?.requestId;
|
|
355
|
+
const errorResult = {
|
|
356
|
+
success: false,
|
|
357
|
+
error_code: errorData?.error_code || errorData?.code || `HTTP_${retryResponse.status}`,
|
|
358
|
+
message: errorData?.message || (typeof errorData?.error === 'string' ? errorData.error : errorData?.error?.message) || errorText || `Request failed with status ${retryResponse.status}`,
|
|
359
|
+
operation: endpoint,
|
|
360
|
+
details: (errorData?.error?.details ?? errorData?.details) || undefined,
|
|
361
|
+
...(reqIdBody || reqIdHeader ? { request_id: (reqIdBody || reqIdHeader) } : {})
|
|
362
|
+
};
|
|
363
|
+
return errorResult;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
const reqIdHeader2 = retryResponse.headers.get('X-Request-ID') || retryResponse.headers.get('X-Correlation-ID');
|
|
368
|
+
const errorResult = {
|
|
369
|
+
success: false,
|
|
370
|
+
error_code: `HTTP_${retryResponse.status}`,
|
|
371
|
+
message: errorText || `Request failed with status ${retryResponse.status}`,
|
|
372
|
+
operation: endpoint,
|
|
373
|
+
...(reqIdHeader2 ? { request_id: reqIdHeader2 } : {})
|
|
374
|
+
};
|
|
375
|
+
return errorResult;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
catch (retryError) {
|
|
379
|
+
console.log(`❌ 503 retry attempt ${attempt} failed with network error:`, retryError);
|
|
380
|
+
if (attempt === maxRetries) {
|
|
381
|
+
// If all retries failed with network errors, throw the original error
|
|
382
|
+
throw new ApiNetworkError('Service temporarily unavailable after retries', 503, endpoint);
|
|
383
|
+
}
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// If we got here, all retries failed - fall through to normal error handling
|
|
388
|
+
console.log('❌ All 503 retry attempts exhausted, treating as error');
|
|
389
|
+
}
|
|
390
|
+
// Handle authentication errors with a single refresh+retry
|
|
391
|
+
if (response.status === 401) {
|
|
392
|
+
console.log('🔑 Got 401, checking if we have a session to refresh...');
|
|
393
|
+
// CRITICAL FIX: Check if we actually have a session before attempting refresh
|
|
394
|
+
const currentSession = await (0, react_1.getSession)();
|
|
395
|
+
if (!currentSession || !currentSession.accessToken) {
|
|
396
|
+
console.log('🚫 No valid session found, redirecting to login instead of refresh');
|
|
397
|
+
scheduleLoginRedirect(true); // Immediate redirect
|
|
398
|
+
throw new ApiNetworkError('Authentication required - no valid session', 401, endpoint);
|
|
399
|
+
}
|
|
400
|
+
// Elegantly gate refresh during pre-2FA or when no refresh token exists
|
|
401
|
+
const pre2FA_now = isPreTwoFactorSession(currentSession);
|
|
402
|
+
const hasRefresh_now = !!currentSession?.refreshToken;
|
|
403
|
+
if (pre2FA_now || !hasRefresh_now) {
|
|
404
|
+
console.log('⏭️ Skipping 401-driven refresh:', {
|
|
405
|
+
reason: pre2FA_now ? 'pre-2FA session' : 'no refresh token',
|
|
406
|
+
requiresTwoFactor: currentSession?.user?.requiresTwoFactor,
|
|
407
|
+
twoFactorVerified: currentSession?.user?.twoFactorSessionVerified,
|
|
408
|
+
hasRefreshToken: hasRefresh_now
|
|
409
|
+
});
|
|
410
|
+
// CRITICAL: Redirect to login immediately if refresh is impossible
|
|
411
|
+
console.log('🚫 Cannot refresh session, redirecting to login');
|
|
412
|
+
scheduleLoginRedirect(true); // Immediate redirect
|
|
413
|
+
throw new ApiNetworkError(pre2FA_now
|
|
414
|
+
? 'Two-factor authentication required'
|
|
415
|
+
: 'Session expired - refresh token unavailable', 401, endpoint);
|
|
416
|
+
}
|
|
417
|
+
console.log('🔑 Valid session found, attempting token refresh...');
|
|
418
|
+
// Try to refresh the token, but coordinate to avoid double refresh
|
|
419
|
+
if (!refreshInFlight) {
|
|
420
|
+
refreshInFlight = (async () => {
|
|
421
|
+
const reqId = crypto.randomUUID();
|
|
422
|
+
const refreshResponse = await fetch('/api/auth/refresh', {
|
|
423
|
+
method: 'POST',
|
|
424
|
+
credentials: 'include',
|
|
425
|
+
headers: { 'X-Request-ID': reqId },
|
|
426
|
+
});
|
|
427
|
+
if (refreshResponse.ok) {
|
|
428
|
+
console.log('✅ Token refreshed successfully (client-side coordinator)');
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
// If refresh is already in progress server-side, wait briefly and allow retry
|
|
432
|
+
if (refreshResponse.status === 409) {
|
|
433
|
+
console.log('↪️ Refresh in progress server-side (409). Waiting for completion...');
|
|
434
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
// For auth failures, schedule redirect; for others, throw
|
|
438
|
+
if (refreshResponse.status === 401 || refreshResponse.status === 403) {
|
|
439
|
+
scheduleLoginRedirect();
|
|
440
|
+
throw new ApiNetworkError('Authentication failed - unable to refresh session', refreshResponse.status, endpoint);
|
|
441
|
+
}
|
|
442
|
+
const errorText = await refreshResponse.text();
|
|
443
|
+
throw new ApiNetworkError(errorText || 'Token refresh failed', refreshResponse.status, endpoint);
|
|
444
|
+
})().finally(() => { refreshInFlight = null; });
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
await refreshInFlight;
|
|
448
|
+
}
|
|
449
|
+
catch (e) {
|
|
450
|
+
throw e; // bubble up to caller handling
|
|
451
|
+
}
|
|
452
|
+
console.log('🔁 Retrying original request after coordinated refresh...');
|
|
453
|
+
// Get the new session and retry the original request
|
|
454
|
+
const newSession = await (0, react_1.getSession)();
|
|
455
|
+
const newToken = newSession?.accessToken;
|
|
456
|
+
const retryConfig = {
|
|
457
|
+
...options,
|
|
458
|
+
headers: {
|
|
459
|
+
'Content-Type': 'application/json',
|
|
460
|
+
...(newToken && { 'Authorization': `Bearer ${newToken}` }),
|
|
461
|
+
...options.headers,
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
const retryResponse = await fetch(fullEndpoint, retryConfig);
|
|
465
|
+
if (retryResponse.ok) {
|
|
466
|
+
const rawData = await retryResponse.json();
|
|
467
|
+
// Reset auth failure state on successful retry
|
|
468
|
+
resetAuthFailureState();
|
|
469
|
+
// COMPATIBILITY MODE: Handle both formats in retry as well
|
|
470
|
+
if (rawData && typeof rawData === 'object' && 'success' in rawData) {
|
|
471
|
+
const validatedResponse = (0, api_responses_1.validateStandardizedResponse)(rawData, endpoint);
|
|
472
|
+
return this.convertToApiResult(validatedResponse);
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
// New format - raw data
|
|
476
|
+
console.log(`🔄 Converting raw retry response to standardized format for ${endpoint}`);
|
|
477
|
+
const wrappedResponse = {
|
|
478
|
+
success: true,
|
|
479
|
+
data: rawData,
|
|
480
|
+
message: 'Success',
|
|
481
|
+
operation_code: 'RAW_RESPONSE',
|
|
482
|
+
timestamp: new Date().toISOString()
|
|
483
|
+
};
|
|
484
|
+
return wrappedResponse;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
// If retry still 401, schedule redirect
|
|
489
|
+
if (retryResponse.status === 401) {
|
|
490
|
+
scheduleLoginRedirect();
|
|
491
|
+
}
|
|
492
|
+
const errorText = await retryResponse.text();
|
|
493
|
+
let errorData;
|
|
494
|
+
try {
|
|
495
|
+
errorData = JSON.parse(errorText);
|
|
496
|
+
// Check if it has the success field (old format)
|
|
497
|
+
if (errorData && typeof errorData === 'object' && 'success' in errorData) {
|
|
498
|
+
// Detect PayEz canonical error envelope and map accordingly
|
|
499
|
+
if (errorData.error && typeof errorData.error === 'object') {
|
|
500
|
+
const reqIdHeader = retryResponse.headers.get('X-Request-ID') || retryResponse.headers.get('X-Correlation-ID');
|
|
501
|
+
const reqIdBody = errorData?.request_id || errorData?.requestId;
|
|
502
|
+
const errorResult = {
|
|
503
|
+
success: false,
|
|
504
|
+
error_code: errorData?.error?.code || errorData?.error_code || errorData?.code || `HTTP_${retryResponse.status}`,
|
|
505
|
+
message: errorData?.error?.message || errorData?.message || `Request failed with status ${retryResponse.status}`,
|
|
506
|
+
operation: endpoint,
|
|
507
|
+
details: (errorData?.error?.details ?? errorData?.details) || undefined,
|
|
508
|
+
...(reqIdBody || reqIdHeader ? { request_id: (reqIdBody || reqIdHeader) } : {})
|
|
509
|
+
};
|
|
510
|
+
return errorResult;
|
|
511
|
+
}
|
|
512
|
+
const validatedError = (0, api_responses_1.validateStandardizedResponse)(errorData, endpoint);
|
|
513
|
+
return this.convertToApiResult(validatedError);
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
// New format - convert raw error to standardized format
|
|
517
|
+
const reqIdHeader = retryResponse.headers.get('X-Request-ID') || retryResponse.headers.get('X-Correlation-ID');
|
|
518
|
+
const reqIdBody = errorData?.request_id || errorData?.requestId;
|
|
519
|
+
const errorResult = {
|
|
520
|
+
success: false,
|
|
521
|
+
error_code: errorData?.error_code || errorData?.code || `HTTP_${retryResponse.status}`,
|
|
522
|
+
message: errorData?.message || (typeof errorData?.error === 'string' ? errorData.error : errorData?.error?.message) || errorText || `Request failed with status ${retryResponse.status}`,
|
|
523
|
+
operation: endpoint,
|
|
524
|
+
details: (errorData?.error?.details ?? errorData?.details) || undefined,
|
|
525
|
+
...(reqIdBody || reqIdHeader ? { request_id: (reqIdBody || reqIdHeader) } : {})
|
|
526
|
+
};
|
|
527
|
+
return errorResult;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
// If we can't parse the error, create a generic error response
|
|
532
|
+
const reqIdHeader = retryResponse.headers.get('X-Request-ID') || retryResponse.headers.get('X-Correlation-ID');
|
|
533
|
+
const errorResult = {
|
|
534
|
+
success: false,
|
|
535
|
+
error_code: `HTTP_${retryResponse.status}`,
|
|
536
|
+
message: errorText || `Request failed with status ${retryResponse.status}`,
|
|
537
|
+
operation: endpoint,
|
|
538
|
+
...(reqIdHeader ? { request_id: reqIdHeader } : {})
|
|
539
|
+
};
|
|
540
|
+
return errorResult;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
// Non-401 error: try to parse as standardized error response
|
|
545
|
+
const errorText = await response.text();
|
|
546
|
+
let errorData;
|
|
547
|
+
try {
|
|
548
|
+
errorData = JSON.parse(errorText);
|
|
549
|
+
// Check if it has the success field (old format)
|
|
550
|
+
if (errorData && typeof errorData === 'object' && 'success' in errorData) {
|
|
551
|
+
// Detect PayEz canonical error envelope and map accordingly
|
|
552
|
+
if (errorData.error && typeof errorData.error === 'object') {
|
|
553
|
+
const reqIdHeader = response.headers.get('X-Request-ID') || response.headers.get('X-Correlation-ID');
|
|
554
|
+
const reqIdBody = errorData?.request_id || errorData?.requestId;
|
|
555
|
+
const errorResult = {
|
|
556
|
+
success: false,
|
|
557
|
+
error_code: errorData?.error?.code || errorData?.error_code || errorData?.code || `HTTP_${response.status}`,
|
|
558
|
+
message: errorData?.error?.message || errorData?.message || `Request failed with status ${response.status}`,
|
|
559
|
+
operation: endpoint,
|
|
560
|
+
details: (errorData?.error?.details ?? errorData?.details) || undefined,
|
|
561
|
+
validation_errors: errorData?.validation_errors || undefined,
|
|
562
|
+
...(reqIdBody || reqIdHeader ? { request_id: (reqIdBody || reqIdHeader) } : {})
|
|
563
|
+
};
|
|
564
|
+
return errorResult;
|
|
565
|
+
}
|
|
566
|
+
const validatedError = (0, api_responses_1.validateStandardizedResponse)(errorData, endpoint);
|
|
567
|
+
return this.convertToApiResult(validatedError);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
// New format - convert raw error to standardized format
|
|
571
|
+
const reqIdHeader = response.headers.get('X-Request-ID') || response.headers.get('X-Correlation-ID');
|
|
572
|
+
const reqIdBody = errorData?.request_id || errorData?.requestId;
|
|
573
|
+
const errorResult = {
|
|
574
|
+
success: false,
|
|
575
|
+
error_code: errorData?.error_code || errorData?.code || `HTTP_${response.status}`,
|
|
576
|
+
message: errorData?.message || (typeof errorData?.error === 'string' ? errorData.error : errorData?.error?.message) || errorText || `Request failed with status ${response.status}`,
|
|
577
|
+
operation: endpoint,
|
|
578
|
+
details: (errorData?.error?.details ?? errorData?.details) || undefined,
|
|
579
|
+
validation_errors: errorData?.validation_errors || undefined,
|
|
580
|
+
...(reqIdBody || reqIdHeader ? { request_id: (reqIdBody || reqIdHeader) } : {})
|
|
581
|
+
};
|
|
582
|
+
return errorResult;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
catch (parseError) {
|
|
586
|
+
// If we can't parse the error, create a generic error response
|
|
587
|
+
const reqIdHeader = response.headers.get('X-Request-ID') || response.headers.get('X-Correlation-ID');
|
|
588
|
+
const errorResult = {
|
|
589
|
+
success: false,
|
|
590
|
+
error_code: `HTTP_${response.status}`,
|
|
591
|
+
message: errorText || `Request failed with status ${response.status}`,
|
|
592
|
+
operation: endpoint,
|
|
593
|
+
details: undefined,
|
|
594
|
+
...(reqIdHeader ? { request_id: reqIdHeader } : {})
|
|
595
|
+
};
|
|
596
|
+
return errorResult;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// SUCCESS PATH: Parse and validate response
|
|
600
|
+
const rawData = await response.json();
|
|
601
|
+
// Reset auth failure state on successful request
|
|
602
|
+
resetAuthFailureState();
|
|
603
|
+
// COMPATIBILITY MODE: Handle both old envelope format and new raw format
|
|
604
|
+
try {
|
|
605
|
+
// First check if it's the old standardized format with success field
|
|
606
|
+
if (rawData && typeof rawData === 'object' && 'success' in rawData) {
|
|
607
|
+
// Old format - validate as standardized response
|
|
608
|
+
const validatedResponse = (0, api_responses_1.validateStandardizedResponse)(rawData, endpoint);
|
|
609
|
+
return this.convertToApiResult(validatedResponse);
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
// New format - raw data, wrap it in success envelope for compatibility
|
|
613
|
+
console.log(`🔄 Converting raw response to standardized format for ${endpoint}`);
|
|
614
|
+
const wrappedResponse = {
|
|
615
|
+
success: true,
|
|
616
|
+
data: rawData,
|
|
617
|
+
message: 'Success',
|
|
618
|
+
operation_code: 'RAW_RESPONSE',
|
|
619
|
+
timestamp: new Date().toISOString()
|
|
620
|
+
};
|
|
621
|
+
return wrappedResponse;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
catch (validationError) {
|
|
625
|
+
// If response format is invalid, this is a CRITICAL error
|
|
626
|
+
throw new ApiResponseFormatError(validationError instanceof Error ? validationError.message : 'Response format validation failed', endpoint, rawData);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
// Re-throw our custom errors as-is
|
|
631
|
+
if (error instanceof ApiResponseFormatError ||
|
|
632
|
+
error instanceof ApiBusinessLogicError ||
|
|
633
|
+
error instanceof ApiValidationError ||
|
|
634
|
+
error instanceof ApiNetworkError) {
|
|
635
|
+
throw error;
|
|
636
|
+
}
|
|
637
|
+
// Wrap unknown errors as network errors
|
|
638
|
+
console.error('❌ API request failed:', error);
|
|
639
|
+
throw new ApiNetworkError(error instanceof Error ? error.message : 'Network error', 0, endpoint);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* CONVERTS VALIDATED STANDARDIZED RESPONSE TO CLIENT RESULT
|
|
644
|
+
* This normalizes the response for client consumption
|
|
645
|
+
*/
|
|
646
|
+
convertToApiResult(validatedResponse) {
|
|
647
|
+
if ((0, api_responses_1.isSuccessResponse)(validatedResponse)) {
|
|
648
|
+
return {
|
|
649
|
+
success: true,
|
|
650
|
+
data: validatedResponse.data,
|
|
651
|
+
message: validatedResponse.message,
|
|
652
|
+
operation_code: validatedResponse.operation_code,
|
|
653
|
+
timestamp: validatedResponse.timestamp
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
if ((0, api_responses_1.isPagedResponse)(validatedResponse)) {
|
|
657
|
+
return {
|
|
658
|
+
success: true,
|
|
659
|
+
items: validatedResponse.data,
|
|
660
|
+
message: validatedResponse.message,
|
|
661
|
+
operation_code: validatedResponse.operation_code,
|
|
662
|
+
pagination: validatedResponse.pagination,
|
|
663
|
+
timestamp: validatedResponse.timestamp
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
if ((0, api_responses_1.isErrorResponse)(validatedResponse)) {
|
|
667
|
+
const reqId = validatedResponse?.request_id || validatedResponse?.requestId;
|
|
668
|
+
if (validatedResponse.error_code === 'VALIDATION_ERROR') {
|
|
669
|
+
// Handle validation error
|
|
670
|
+
const valError = validatedResponse;
|
|
671
|
+
return {
|
|
672
|
+
success: false,
|
|
673
|
+
error_code: validatedResponse.error_code,
|
|
674
|
+
message: validatedResponse.message,
|
|
675
|
+
operation: validatedResponse.operation,
|
|
676
|
+
details: validatedResponse.details,
|
|
677
|
+
validation_errors: valError.payload?.validation_errors,
|
|
678
|
+
...(reqId ? { request_id: reqId } : {})
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
// Handle regular error
|
|
683
|
+
return {
|
|
684
|
+
success: false,
|
|
685
|
+
error_code: validatedResponse.error_code,
|
|
686
|
+
message: validatedResponse.message,
|
|
687
|
+
operation: validatedResponse.operation,
|
|
688
|
+
details: validatedResponse.details,
|
|
689
|
+
...(reqId ? { request_id: reqId } : {})
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
// This should never happen due to validation, but TypeScript requires it
|
|
694
|
+
throw new ApiResponseFormatError('Unknown response type after validation', 'unknown', validatedResponse);
|
|
695
|
+
}
|
|
696
|
+
// ========================================================================================
|
|
697
|
+
// HTTP METHOD WRAPPERS - PUBLIC API
|
|
698
|
+
// ========================================================================================
|
|
699
|
+
/**
|
|
700
|
+
* GET REQUEST - Returns typed result with direct data access
|
|
701
|
+
*/
|
|
702
|
+
async get(endpoint, sessionToken) {
|
|
703
|
+
return this.makeRequest(endpoint, { method: 'GET' }, sessionToken);
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* POST REQUEST - Returns typed result with direct data access
|
|
707
|
+
*/
|
|
708
|
+
async post(endpoint, data, sessionToken) {
|
|
709
|
+
return this.makeRequest(endpoint, {
|
|
710
|
+
method: 'POST',
|
|
711
|
+
body: data ? JSON.stringify(data) : undefined,
|
|
712
|
+
}, sessionToken);
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* PUT REQUEST - Returns typed result with direct data access
|
|
716
|
+
*/
|
|
717
|
+
async put(endpoint, data, sessionToken) {
|
|
718
|
+
return this.makeRequest(endpoint, {
|
|
719
|
+
method: 'PUT',
|
|
720
|
+
body: data ? JSON.stringify(data) : undefined,
|
|
721
|
+
}, sessionToken);
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* DELETE REQUEST - Returns typed result with direct data access
|
|
725
|
+
*/
|
|
726
|
+
async delete(endpoint) {
|
|
727
|
+
return this.makeRequest(endpoint, { method: 'DELETE' });
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
// ========================================================================================
|
|
731
|
+
// SINGLETON INSTANCE - READY TO USE
|
|
732
|
+
// ========================================================================================
|
|
733
|
+
exports.standardizedApi = new StandardizedClientApiService();
|
|
734
|
+
// ========================================================================================
|
|
735
|
+
// CONVENIENCE HELPER FUNCTIONS
|
|
736
|
+
// ========================================================================================
|
|
737
|
+
/**
|
|
738
|
+
* TYPE-SAFE SUCCESS CHECK
|
|
739
|
+
* Use this to check if API call was successful with proper type narrowing
|
|
740
|
+
*/
|
|
741
|
+
function isApiSuccess(result) {
|
|
742
|
+
return result.success === true && 'data' in result;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* TYPE-SAFE PAGED SUCCESS CHECK
|
|
746
|
+
* Use this to check if API call was successful paged response with proper type narrowing
|
|
747
|
+
*/
|
|
748
|
+
function isApiPagedSuccess(result) {
|
|
749
|
+
return result.success === true && 'items' in result;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* TYPE-SAFE ERROR CHECK
|
|
753
|
+
* Use this to check if API call failed with proper type narrowing
|
|
754
|
+
*/
|
|
755
|
+
function isApiError(result) {
|
|
756
|
+
return result.success === false;
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* EXTRACT DATA FROM SUCCESS RESULT
|
|
760
|
+
* Use this to get the data from a successful API call
|
|
761
|
+
* Will throw if result is not successful
|
|
762
|
+
*/
|
|
763
|
+
function extractApiData(result) {
|
|
764
|
+
if (isApiSuccess(result)) {
|
|
765
|
+
return result.data;
|
|
766
|
+
}
|
|
767
|
+
if (isApiPagedSuccess(result)) {
|
|
768
|
+
return result.items;
|
|
769
|
+
}
|
|
770
|
+
throw new ApiBusinessLogicError(result.error_code, result.message, result.operation, result.details);
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* EXTRACT ITEMS FROM PAGED SUCCESS RESULT
|
|
774
|
+
* Use this to get the items array from a successful paged API call
|
|
775
|
+
* Will throw if result is not successful paged response
|
|
776
|
+
*/
|
|
777
|
+
function extractApiItems(result) {
|
|
778
|
+
if (isApiPagedSuccess(result)) {
|
|
779
|
+
return result.items;
|
|
780
|
+
}
|
|
781
|
+
if (isApiSuccess(result)) {
|
|
782
|
+
// If it's a regular success but expected paged, data should be array
|
|
783
|
+
return result.data;
|
|
784
|
+
}
|
|
785
|
+
throw new ApiBusinessLogicError(result.error_code, result.message, result.operation, result.details);
|
|
786
|
+
}
|