@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.
Files changed (654) hide show
  1. package/README.md +782 -0
  2. package/dist/api/auth-handler.d.ts +67 -0
  3. package/dist/api/auth-handler.js +397 -0
  4. package/dist/api/index.d.ts +10 -0
  5. package/dist/api/index.js +19 -0
  6. package/dist/api-handlers/account/change-password.d.ts +9 -0
  7. package/dist/api-handlers/account/change-password.js +112 -0
  8. package/dist/api-handlers/account/masked-info.d.ts +2 -0
  9. package/dist/api-handlers/account/masked-info.js +41 -0
  10. package/dist/api-handlers/account/profile.d.ts +3 -0
  11. package/dist/api-handlers/account/profile.js +63 -0
  12. package/dist/api-handlers/account/recovery/initiate.d.ts +2 -0
  13. package/dist/api-handlers/account/recovery/initiate.js +26 -0
  14. package/dist/api-handlers/account/recovery/send-code.d.ts +2 -0
  15. package/dist/api-handlers/account/recovery/send-code.js +28 -0
  16. package/dist/api-handlers/account/recovery/verify-code.d.ts +2 -0
  17. package/dist/api-handlers/account/recovery/verify-code.js +28 -0
  18. package/dist/api-handlers/account/reset-password.d.ts +2 -0
  19. package/dist/api-handlers/account/reset-password.js +26 -0
  20. package/dist/api-handlers/account/send-code.d.ts +24 -0
  21. package/dist/api-handlers/account/send-code.js +60 -0
  22. package/dist/api-handlers/account/update-phone.d.ts +27 -0
  23. package/dist/api-handlers/account/update-phone.js +64 -0
  24. package/dist/api-handlers/account/validate-password.d.ts +17 -0
  25. package/dist/api-handlers/account/validate-password.js +81 -0
  26. package/dist/api-handlers/account/verify-email.d.ts +26 -0
  27. package/dist/api-handlers/account/verify-email.js +106 -0
  28. package/dist/api-handlers/account/verify-sms.d.ts +26 -0
  29. package/dist/api-handlers/account/verify-sms.js +106 -0
  30. package/dist/api-handlers/admin/analytics.d.ts +20 -0
  31. package/dist/api-handlers/admin/analytics.js +379 -0
  32. package/dist/api-handlers/admin/audit.d.ts +20 -0
  33. package/dist/api-handlers/admin/audit.js +214 -0
  34. package/dist/api-handlers/admin/index.d.ts +21 -0
  35. package/dist/api-handlers/admin/index.js +41 -0
  36. package/dist/api-handlers/admin/redis-sessions.d.ts +36 -0
  37. package/dist/api-handlers/admin/redis-sessions.js +204 -0
  38. package/dist/api-handlers/admin/sessions.d.ts +21 -0
  39. package/dist/api-handlers/admin/sessions.js +284 -0
  40. package/dist/api-handlers/admin/site-logs.d.ts +46 -0
  41. package/dist/api-handlers/admin/site-logs.js +318 -0
  42. package/dist/api-handlers/admin/users.d.ts +20 -0
  43. package/dist/api-handlers/admin/users.js +222 -0
  44. package/dist/api-handlers/admin/vibe-data.d.ts +80 -0
  45. package/dist/api-handlers/admin/vibe-data.js +268 -0
  46. package/dist/api-handlers/anon/preferences.d.ts +37 -0
  47. package/dist/api-handlers/anon/preferences.js +96 -0
  48. package/dist/api-handlers/auth/jwks.d.ts +2 -0
  49. package/dist/api-handlers/auth/jwks.js +24 -0
  50. package/dist/api-handlers/auth/login.d.ts +42 -0
  51. package/dist/api-handlers/auth/login.js +178 -0
  52. package/dist/api-handlers/auth/refresh.d.ts +74 -0
  53. package/dist/api-handlers/auth/refresh.js +635 -0
  54. package/dist/api-handlers/auth/signout.d.ts +37 -0
  55. package/dist/api-handlers/auth/signout.js +187 -0
  56. package/dist/api-handlers/auth/status.d.ts +8 -0
  57. package/dist/api-handlers/auth/status.js +26 -0
  58. package/dist/api-handlers/auth/update-session.d.ts +37 -0
  59. package/dist/api-handlers/auth/update-session.js +95 -0
  60. package/dist/api-handlers/auth/validate.d.ts +6 -0
  61. package/dist/api-handlers/auth/validate.js +43 -0
  62. package/dist/api-handlers/auth/verify-code.d.ts +43 -0
  63. package/dist/api-handlers/auth/verify-code.js +94 -0
  64. package/dist/api-handlers/session/refresh-viability.d.ts +14 -0
  65. package/dist/api-handlers/session/refresh-viability.js +39 -0
  66. package/dist/api-handlers/session/viability.d.ts +13 -0
  67. package/dist/api-handlers/session/viability.js +146 -0
  68. package/dist/api-handlers/test/force-expire.d.ts +23 -0
  69. package/dist/api-handlers/test/force-expire.js +65 -0
  70. package/dist/auth/auth-decision.d.ts +39 -0
  71. package/dist/auth/auth-decision.js +182 -0
  72. package/dist/auth/auth-options.d.ts +57 -0
  73. package/dist/auth/auth-options.js +213 -0
  74. package/dist/auth/callbacks/index.d.ts +6 -0
  75. package/dist/auth/callbacks/index.js +12 -0
  76. package/dist/auth/callbacks/jwt.d.ts +45 -0
  77. package/dist/auth/callbacks/jwt.js +305 -0
  78. package/dist/auth/callbacks/session.d.ts +60 -0
  79. package/dist/auth/callbacks/session.js +170 -0
  80. package/dist/auth/callbacks/signin.d.ts +23 -0
  81. package/dist/auth/callbacks/signin.js +44 -0
  82. package/dist/auth/events/index.d.ts +4 -0
  83. package/dist/auth/events/index.js +8 -0
  84. package/dist/auth/events/signout.d.ts +17 -0
  85. package/dist/auth/events/signout.js +32 -0
  86. package/dist/auth/providers/credentials.d.ts +32 -0
  87. package/dist/auth/providers/credentials.js +223 -0
  88. package/dist/auth/providers/index.d.ts +5 -0
  89. package/dist/auth/providers/index.js +21 -0
  90. package/dist/auth/providers/oauth.d.ts +26 -0
  91. package/dist/auth/providers/oauth.js +105 -0
  92. package/dist/auth/route-config.d.ts +66 -0
  93. package/dist/auth/route-config.js +190 -0
  94. package/dist/auth/types/auth-types.d.ts +417 -0
  95. package/dist/auth/types/auth-types.js +53 -0
  96. package/dist/auth/types/index.d.ts +6 -0
  97. package/dist/auth/types/index.js +22 -0
  98. package/dist/auth/unauthenticated-routes.d.ts +1 -0
  99. package/dist/auth/unauthenticated-routes.js +19 -0
  100. package/dist/auth/utils/idp-client.d.ts +94 -0
  101. package/dist/auth/utils/idp-client.js +383 -0
  102. package/dist/auth/utils/index.d.ts +5 -0
  103. package/dist/auth/utils/index.js +21 -0
  104. package/dist/auth/utils/token-utils.d.ts +84 -0
  105. package/dist/auth/utils/token-utils.js +219 -0
  106. package/dist/client/AuthContext.d.ts +19 -0
  107. package/dist/client/AuthContext.js +112 -0
  108. package/dist/client/fetch-with-auth.d.ts +11 -0
  109. package/dist/client/fetch-with-auth.js +44 -0
  110. package/dist/client/fetchWithSession.d.ts +3 -0
  111. package/dist/client/fetchWithSession.js +24 -0
  112. package/dist/client/index.d.ts +9 -0
  113. package/dist/client/index.js +20 -0
  114. package/dist/client/useAnonSession.d.ts +36 -0
  115. package/dist/client/useAnonSession.js +99 -0
  116. package/dist/components/SessionSync.d.ts +13 -0
  117. package/dist/components/SessionSync.js +119 -0
  118. package/dist/components/SignalRHealthCheck.d.ts +10 -0
  119. package/dist/components/SignalRHealthCheck.js +97 -0
  120. package/dist/components/account/UserAvatarMenu.d.ts +20 -0
  121. package/dist/components/account/UserAvatarMenu.js +80 -0
  122. package/dist/components/account/index.d.ts +7 -0
  123. package/dist/components/account/index.js +10 -0
  124. package/dist/components/admin/AlertSettingsTab.d.ts +48 -0
  125. package/dist/components/admin/AlertSettingsTab.js +351 -0
  126. package/dist/components/admin/AnalyticsTab.d.ts +22 -0
  127. package/dist/components/admin/AnalyticsTab.js +167 -0
  128. package/dist/components/admin/DataBrowserTab.d.ts +19 -0
  129. package/dist/components/admin/DataBrowserTab.js +252 -0
  130. package/dist/components/admin/LoggingSettingsTab.d.ts +73 -0
  131. package/dist/components/admin/LoggingSettingsTab.js +339 -0
  132. package/dist/components/admin/SessionsTab.d.ts +37 -0
  133. package/dist/components/admin/SessionsTab.js +165 -0
  134. package/dist/components/admin/StatsTab.d.ts +53 -0
  135. package/dist/components/admin/StatsTab.js +161 -0
  136. package/dist/components/admin/VibeAdminContext.d.ts +32 -0
  137. package/dist/components/admin/VibeAdminContext.js +38 -0
  138. package/dist/components/admin/VibeAdminLayout.d.ts +11 -0
  139. package/dist/components/admin/VibeAdminLayout.js +69 -0
  140. package/dist/components/admin/index.d.ts +29 -0
  141. package/dist/components/admin/index.js +44 -0
  142. package/dist/components/auth/FederatedAuthSection.d.ts +8 -0
  143. package/dist/components/auth/FederatedAuthSection.js +45 -0
  144. package/dist/components/auth/ModeAwareLoginPage.d.ts +10 -0
  145. package/dist/components/auth/ModeAwareLoginPage.js +42 -0
  146. package/dist/components/auth/ModeAwareSignupPage.d.ts +9 -0
  147. package/dist/components/auth/ModeAwareSignupPage.js +78 -0
  148. package/dist/components/auth/TraditionalAuthSection.d.ts +14 -0
  149. package/dist/components/auth/TraditionalAuthSection.js +20 -0
  150. package/dist/components/recovery/CompleteStep.d.ts +5 -0
  151. package/dist/components/recovery/CompleteStep.js +8 -0
  152. package/dist/components/recovery/InitiateRecoveryStep.d.ts +8 -0
  153. package/dist/components/recovery/InitiateRecoveryStep.js +20 -0
  154. package/dist/components/recovery/SelectMethodStep.d.ts +8 -0
  155. package/dist/components/recovery/SelectMethodStep.js +8 -0
  156. package/dist/components/recovery/SetPasswordStep.d.ts +6 -0
  157. package/dist/components/recovery/SetPasswordStep.js +20 -0
  158. package/dist/components/recovery/VerifyCodeStep.d.ts +10 -0
  159. package/dist/components/recovery/VerifyCodeStep.js +24 -0
  160. package/dist/components/reserved/ReservedRecoveryWarning.d.ts +38 -0
  161. package/dist/components/reserved/ReservedRecoveryWarning.js +92 -0
  162. package/dist/components/reserved/ReservedStatusBox.d.ts +30 -0
  163. package/dist/components/reserved/ReservedStatusBox.js +71 -0
  164. package/dist/components/ui/BetaBadge.d.ts +29 -0
  165. package/dist/components/ui/BetaBadge.js +38 -0
  166. package/dist/components/ui/Footer.d.ts +37 -0
  167. package/dist/components/ui/Footer.js +41 -0
  168. package/dist/config/env.d.ts +66 -0
  169. package/dist/config/env.js +57 -0
  170. package/dist/config/logger.d.ts +57 -0
  171. package/dist/config/logger.js +73 -0
  172. package/dist/config/logging-config.d.ts +30 -0
  173. package/dist/config/logging-config.js +122 -0
  174. package/dist/config/unauthenticated-routes.d.ts +17 -0
  175. package/dist/config/unauthenticated-routes.js +24 -0
  176. package/dist/config/vibe-log-transport.d.ts +79 -0
  177. package/dist/config/vibe-log-transport.js +203 -0
  178. package/dist/edge/internal-api-url.d.ts +53 -0
  179. package/dist/edge/internal-api-url.js +63 -0
  180. package/dist/edge/middleware.d.ts +14 -0
  181. package/dist/edge/middleware.js +32 -0
  182. package/dist/hooks/useAuth.d.ts +23 -0
  183. package/dist/hooks/useAuth.js +81 -0
  184. package/dist/hooks/useAuthSettings.d.ts +59 -0
  185. package/dist/hooks/useAuthSettings.js +93 -0
  186. package/dist/hooks/useAvailableProviders.d.ts +45 -0
  187. package/dist/hooks/useAvailableProviders.js +108 -0
  188. package/dist/hooks/usePasswordValidation.d.ts +27 -0
  189. package/dist/hooks/usePasswordValidation.js +102 -0
  190. package/dist/hooks/useProfile.d.ts +15 -0
  191. package/dist/hooks/useProfile.js +59 -0
  192. package/dist/hooks/usePublicAuthSettings.d.ts +56 -0
  193. package/dist/hooks/usePublicAuthSettings.js +131 -0
  194. package/dist/hooks/useSessionExpiration.d.ts +57 -0
  195. package/dist/hooks/useSessionExpiration.js +72 -0
  196. package/dist/hooks/useViabilitySession.d.ts +75 -0
  197. package/dist/hooks/useViabilitySession.js +268 -0
  198. package/dist/index.d.ts +12 -0
  199. package/dist/index.js +54 -0
  200. package/dist/lib/anon-session.d.ts +74 -0
  201. package/dist/lib/anon-session.js +169 -0
  202. package/dist/lib/api-handler.d.ts +123 -0
  203. package/dist/lib/api-handler.js +478 -0
  204. package/dist/lib/app-slug.d.ts +95 -0
  205. package/dist/lib/app-slug.js +172 -0
  206. package/dist/lib/demo-mode.d.ts +6 -0
  207. package/dist/lib/demo-mode.js +16 -0
  208. package/dist/lib/geolocation.d.ts +64 -0
  209. package/dist/lib/geolocation.js +235 -0
  210. package/dist/lib/idp-client-config.d.ts +75 -0
  211. package/dist/lib/idp-client-config.js +351 -0
  212. package/dist/lib/idp-fetch.d.ts +14 -0
  213. package/dist/lib/idp-fetch.js +91 -0
  214. package/dist/lib/internal-api.d.ts +87 -0
  215. package/dist/lib/internal-api.js +122 -0
  216. package/dist/lib/jwt-decode-client.d.ts +10 -0
  217. package/dist/lib/jwt-decode-client.js +46 -0
  218. package/dist/lib/jwt-decode.d.ts +48 -0
  219. package/dist/lib/jwt-decode.js +57 -0
  220. package/dist/lib/nextauth-secret.d.ts +10 -0
  221. package/dist/lib/nextauth-secret.js +104 -0
  222. package/dist/lib/rate-limit-service.d.ts +23 -0
  223. package/dist/lib/rate-limit-service.js +6 -0
  224. package/dist/lib/redis.d.ts +5 -0
  225. package/dist/lib/redis.js +28 -0
  226. package/dist/lib/refresh-token-validator.d.ts +13 -0
  227. package/dist/lib/refresh-token-validator.js +117 -0
  228. package/dist/lib/roles.d.ts +145 -0
  229. package/dist/lib/roles.js +168 -0
  230. package/dist/lib/secret-validation.d.ts +4 -0
  231. package/dist/lib/secret-validation.js +14 -0
  232. package/dist/lib/session-store.d.ts +166 -0
  233. package/dist/lib/session-store.js +537 -0
  234. package/dist/lib/session.d.ts +21 -0
  235. package/dist/lib/session.js +26 -0
  236. package/dist/lib/site-logger.d.ts +214 -0
  237. package/dist/lib/site-logger.js +210 -0
  238. package/dist/lib/standardized-client-api.d.ts +161 -0
  239. package/dist/lib/standardized-client-api.js +786 -0
  240. package/dist/lib/startup-init.d.ts +40 -0
  241. package/dist/lib/startup-init.js +261 -0
  242. package/dist/lib/test-aware-get-token.d.ts +2 -0
  243. package/dist/lib/test-aware-get-token.js +81 -0
  244. package/dist/lib/token-expiry.d.ts +14 -0
  245. package/dist/lib/token-expiry.js +39 -0
  246. package/dist/lib/token-lifecycle.d.ts +52 -0
  247. package/dist/lib/token-lifecycle.js +398 -0
  248. package/dist/lib/types/api-responses.d.ts +128 -0
  249. package/dist/lib/types/api-responses.js +171 -0
  250. package/dist/lib/user-agent-parser.d.ts +50 -0
  251. package/dist/lib/user-agent-parser.js +220 -0
  252. package/dist/logging/api/admin-analytics.d.ts +3 -0
  253. package/dist/logging/api/admin-analytics.js +45 -0
  254. package/dist/logging/api/audit-log.d.ts +3 -0
  255. package/dist/logging/api/audit-log.js +52 -0
  256. package/dist/logging/components/AdminAnalyticsLayout.d.ts +10 -0
  257. package/dist/logging/components/AdminAnalyticsLayout.js +11 -0
  258. package/dist/logging/components/AuditLogViewer.d.ts +7 -0
  259. package/dist/logging/components/AuditLogViewer.js +51 -0
  260. package/dist/logging/components/ErrorMetricsCard.d.ts +7 -0
  261. package/dist/logging/components/ErrorMetricsCard.js +16 -0
  262. package/dist/logging/components/HealthMetricsCard.d.ts +7 -0
  263. package/dist/logging/components/HealthMetricsCard.js +19 -0
  264. package/dist/logging/hooks/useAdminAnalytics.d.ts +24 -0
  265. package/dist/logging/hooks/useAdminAnalytics.js +22 -0
  266. package/dist/logging/hooks/useAuditLog.d.ts +6 -0
  267. package/dist/logging/hooks/useAuditLog.js +25 -0
  268. package/dist/logging/hooks/useErrorMetrics.d.ts +6 -0
  269. package/dist/logging/hooks/useErrorMetrics.js +38 -0
  270. package/dist/logging/hooks/useHealthMetrics.d.ts +6 -0
  271. package/dist/logging/hooks/useHealthMetrics.js +41 -0
  272. package/dist/logging/index.d.ts +11 -0
  273. package/dist/logging/index.js +40 -0
  274. package/dist/logging/types/analytics.d.ts +68 -0
  275. package/dist/logging/types/analytics.js +3 -0
  276. package/dist/logging/types/audit.d.ts +29 -0
  277. package/dist/logging/types/audit.js +2 -0
  278. package/dist/logging/types/index.d.ts +2 -0
  279. package/dist/logging/types/index.js +19 -0
  280. package/dist/middleware/auth-decision.d.ts +33 -0
  281. package/dist/middleware/auth-decision.js +65 -0
  282. package/dist/middleware/create-middleware.d.ts +100 -0
  283. package/dist/middleware/create-middleware.js +445 -0
  284. package/dist/middleware/rbac-check.d.ts +44 -0
  285. package/dist/middleware/rbac-check.js +191 -0
  286. package/dist/middleware/twofa-presets.d.ts +134 -0
  287. package/dist/middleware/twofa-presets.js +175 -0
  288. package/dist/models/DecodedAccessToken.d.ts +17 -0
  289. package/dist/models/DecodedAccessToken.js +2 -0
  290. package/dist/models/SessionModel.d.ts +122 -0
  291. package/dist/models/SessionModel.js +136 -0
  292. package/dist/pages/admin-login/page.d.ts +31 -0
  293. package/dist/pages/admin-login/page.js +83 -0
  294. package/dist/pages/admin-roles/RolesAdminPage.d.ts +15 -0
  295. package/dist/pages/admin-roles/RolesAdminPage.js +78 -0
  296. package/dist/pages/admin-roles/index.d.ts +8 -0
  297. package/dist/pages/admin-roles/index.js +15 -0
  298. package/dist/pages/admin-roles/modals.d.ts +72 -0
  299. package/dist/pages/admin-roles/modals.js +154 -0
  300. package/dist/pages/client-admin/ClientSiteAdminPage.d.ts +79 -0
  301. package/dist/pages/client-admin/ClientSiteAdminPage.js +177 -0
  302. package/dist/pages/client-admin/index.d.ts +32 -0
  303. package/dist/pages/client-admin/index.js +37 -0
  304. package/dist/pages/login/page.d.ts +22 -0
  305. package/dist/pages/login/page.js +239 -0
  306. package/dist/pages/profile/EnhancedProfilePage.d.ts +13 -0
  307. package/dist/pages/profile/EnhancedProfilePage.js +150 -0
  308. package/dist/pages/profile/index.d.ts +8 -0
  309. package/dist/pages/profile/index.js +16 -0
  310. package/dist/pages/profile/page.d.ts +19 -0
  311. package/dist/pages/profile/page.js +47 -0
  312. package/dist/pages/profile/profile-patch.d.ts +1 -0
  313. package/dist/pages/profile/profile-patch.js +281 -0
  314. package/dist/pages/recovery/page.d.ts +1 -0
  315. package/dist/pages/recovery/page.js +142 -0
  316. package/dist/pages/roles/MyRolesPage.d.ts +24 -0
  317. package/dist/pages/roles/MyRolesPage.js +71 -0
  318. package/dist/pages/roles/components.d.ts +63 -0
  319. package/dist/pages/roles/components.js +108 -0
  320. package/dist/pages/roles/index.d.ts +8 -0
  321. package/dist/pages/roles/index.js +19 -0
  322. package/dist/pages/security/EnhancedSecurityPage.d.ts +14 -0
  323. package/dist/pages/security/EnhancedSecurityPage.js +248 -0
  324. package/dist/pages/security/index.d.ts +8 -0
  325. package/dist/pages/security/index.js +16 -0
  326. package/dist/pages/security/page.d.ts +21 -0
  327. package/dist/pages/security/page.js +212 -0
  328. package/dist/pages/security/security-patch.d.ts +1 -0
  329. package/dist/pages/security/security-patch.js +302 -0
  330. package/dist/pages/settings/EnhancedSettingsPage.d.ts +46 -0
  331. package/dist/pages/settings/EnhancedSettingsPage.js +231 -0
  332. package/dist/pages/settings/index.d.ts +8 -0
  333. package/dist/pages/settings/index.js +16 -0
  334. package/dist/pages/settings/page.d.ts +7 -0
  335. package/dist/pages/settings/page.js +26 -0
  336. package/dist/pages/showcase/ShowcasePage.d.ts +13 -0
  337. package/dist/pages/showcase/ShowcasePage.js +140 -0
  338. package/dist/pages/showcase/index.d.ts +12 -0
  339. package/dist/pages/showcase/index.js +17 -0
  340. package/dist/pages/test-env/EmergencyLogoutPage.d.ts +14 -0
  341. package/dist/pages/test-env/EmergencyLogoutPage.js +98 -0
  342. package/dist/pages/test-env/JwtInspectPage.d.ts +14 -0
  343. package/dist/pages/test-env/JwtInspectPage.js +114 -0
  344. package/dist/pages/test-env/RefreshTokenPage.d.ts +15 -0
  345. package/dist/pages/test-env/RefreshTokenPage.js +91 -0
  346. package/dist/pages/test-env/TestEnvPage.d.ts +13 -0
  347. package/dist/pages/test-env/TestEnvPage.js +49 -0
  348. package/dist/pages/test-env/index.d.ts +24 -0
  349. package/dist/pages/test-env/index.js +32 -0
  350. package/dist/pages/verify-code/page.d.ts +30 -0
  351. package/dist/pages/verify-code/page.js +408 -0
  352. package/dist/routes/account/index.d.ts +28 -0
  353. package/dist/routes/account/index.js +71 -0
  354. package/dist/routes/account/masked-info.d.ts +33 -0
  355. package/dist/routes/account/masked-info.js +39 -0
  356. package/dist/routes/account/send-code.d.ts +37 -0
  357. package/dist/routes/account/send-code.js +42 -0
  358. package/dist/routes/account/update-phone.d.ts +13 -0
  359. package/dist/routes/account/update-phone.js +17 -0
  360. package/dist/routes/account/verify-email.d.ts +38 -0
  361. package/dist/routes/account/verify-email.js +43 -0
  362. package/dist/routes/account/verify-sms.d.ts +38 -0
  363. package/dist/routes/account/verify-sms.js +43 -0
  364. package/dist/routes/auth/index.d.ts +19 -0
  365. package/dist/routes/auth/index.js +64 -0
  366. package/dist/routes/auth/logout.d.ts +31 -0
  367. package/dist/routes/auth/logout.js +113 -0
  368. package/dist/routes/auth/nextauth.d.ts +19 -0
  369. package/dist/routes/auth/nextauth.js +72 -0
  370. package/dist/routes/auth/refresh.d.ts +30 -0
  371. package/dist/routes/auth/refresh.js +51 -0
  372. package/dist/routes/auth/session.d.ts +72 -0
  373. package/dist/routes/auth/session.js +180 -0
  374. package/dist/routes/auth/settings.d.ts +25 -0
  375. package/dist/routes/auth/settings.js +55 -0
  376. package/dist/routes/auth/viability.d.ts +52 -0
  377. package/dist/routes/auth/viability.js +201 -0
  378. package/dist/routes/index.d.ts +12 -0
  379. package/dist/routes/index.js +54 -0
  380. package/dist/routes/session/index.d.ts +6 -0
  381. package/dist/routes/session/index.js +10 -0
  382. package/dist/routes/session/refresh-viability.d.ts +16 -0
  383. package/dist/routes/session/refresh-viability.js +20 -0
  384. package/dist/services/signalrActivityService.d.ts +44 -0
  385. package/dist/services/signalrActivityService.js +257 -0
  386. package/dist/stores/authStore.d.ts +154 -0
  387. package/dist/stores/authStore.js +1531 -0
  388. package/dist/theme/ThemeProvider.d.ts +14 -0
  389. package/dist/theme/ThemeProvider.js +28 -0
  390. package/dist/theme/default.d.ts +8 -0
  391. package/dist/theme/default.js +33 -0
  392. package/dist/theme/index.d.ts +15 -0
  393. package/dist/theme/index.js +25 -0
  394. package/dist/theme/types.d.ts +56 -0
  395. package/dist/theme/types.js +8 -0
  396. package/dist/theme/useTheme.d.ts +60 -0
  397. package/dist/theme/useTheme.js +63 -0
  398. package/dist/theme/utils.d.ts +13 -0
  399. package/dist/theme/utils.js +39 -0
  400. package/dist/types/api.d.ts +134 -0
  401. package/dist/types/api.js +44 -0
  402. package/dist/types/auth.d.ts +19 -0
  403. package/dist/types/auth.js +2 -0
  404. package/dist/types/logging.d.ts +42 -0
  405. package/dist/types/logging.js +2 -0
  406. package/dist/types/recovery.d.ts +48 -0
  407. package/dist/types/recovery.js +2 -0
  408. package/dist/types/security.d.ts +1 -0
  409. package/dist/types/security.js +2 -0
  410. package/dist/utils/api.d.ts +85 -0
  411. package/dist/utils/api.js +287 -0
  412. package/dist/utils/circuitBreaker.d.ts +43 -0
  413. package/dist/utils/circuitBreaker.js +91 -0
  414. package/dist/utils/error-message.d.ts +1 -0
  415. package/dist/utils/error-message.js +103 -0
  416. package/dist/utils/layout/reservedSpace.d.ts +59 -0
  417. package/dist/utils/layout/reservedSpace.js +102 -0
  418. package/dist/utils/logout.d.ts +14 -0
  419. package/dist/utils/logout.js +32 -0
  420. package/dist/vibe/client.d.ts +261 -0
  421. package/dist/vibe/client.js +445 -0
  422. package/dist/vibe/errors.d.ts +83 -0
  423. package/dist/vibe/errors.js +146 -0
  424. package/dist/vibe/generic.d.ts +234 -0
  425. package/dist/vibe/generic.js +369 -0
  426. package/dist/vibe/hooks/index.d.ts +169 -0
  427. package/dist/vibe/hooks/index.js +252 -0
  428. package/dist/vibe/index.d.ts +23 -0
  429. package/dist/vibe/index.js +67 -0
  430. package/dist/vibe/sessions.d.ts +161 -0
  431. package/dist/vibe/sessions.js +391 -0
  432. package/dist/vibe/types.d.ts +353 -0
  433. package/dist/vibe/types.js +315 -0
  434. package/package.json +855 -0
  435. package/scripts/check-internal-url-usage.sh +73 -0
  436. package/scripts/dev-broker.ps1 +35 -0
  437. package/scripts/dev-local.ps1 +45 -0
  438. package/src/api/auth-handler.ts +550 -0
  439. package/src/api/index.ts +18 -0
  440. package/src/api-handlers/account/change-password.ts +145 -0
  441. package/src/api-handlers/account/masked-info.ts +45 -0
  442. package/src/api-handlers/account/profile.ts +80 -0
  443. package/src/api-handlers/account/recovery/initiate.ts +23 -0
  444. package/src/api-handlers/account/recovery/send-code.ts +25 -0
  445. package/src/api-handlers/account/recovery/verify-code.ts +25 -0
  446. package/src/api-handlers/account/reset-password.ts +23 -0
  447. package/src/api-handlers/account/send-code.ts +76 -0
  448. package/src/api-handlers/account/update-phone.ts +79 -0
  449. package/src/api-handlers/account/validate-password.ts +118 -0
  450. package/src/api-handlers/account/verify-email.ts +125 -0
  451. package/src/api-handlers/account/verify-sms.ts +125 -0
  452. package/src/api-handlers/admin/analytics.ts +445 -0
  453. package/src/api-handlers/admin/audit.ts +225 -0
  454. package/src/api-handlers/admin/index.ts +59 -0
  455. package/src/api-handlers/admin/redis-sessions.ts +253 -0
  456. package/src/api-handlers/admin/sessions.ts +320 -0
  457. package/src/api-handlers/admin/site-logs.ts +367 -0
  458. package/src/api-handlers/admin/users.ts +244 -0
  459. package/src/api-handlers/admin/vibe-data.ts +326 -0
  460. package/src/api-handlers/anon/preferences.ts +123 -0
  461. package/src/api-handlers/auth/jwks.ts +20 -0
  462. package/src/api-handlers/auth/login.ts +240 -0
  463. package/src/api-handlers/auth/refresh.ts +687 -0
  464. package/src/api-handlers/auth/signout.ts +212 -0
  465. package/src/api-handlers/auth/status.ts +23 -0
  466. package/src/api-handlers/auth/update-session.ts +125 -0
  467. package/src/api-handlers/auth/validate.ts +44 -0
  468. package/src/api-handlers/auth/verify-code.ts +129 -0
  469. package/src/api-handlers/session/refresh-viability.ts +36 -0
  470. package/src/api-handlers/session/viability.ts +166 -0
  471. package/src/api-handlers/test/force-expire.ts +67 -0
  472. package/src/auth/auth-decision.ts +230 -0
  473. package/src/auth/auth-options.ts +237 -0
  474. package/src/auth/callbacks/index.ts +7 -0
  475. package/src/auth/callbacks/jwt.ts +382 -0
  476. package/src/auth/callbacks/session.ts +243 -0
  477. package/src/auth/callbacks/signin.ts +56 -0
  478. package/src/auth/events/index.ts +5 -0
  479. package/src/auth/events/signout.ts +33 -0
  480. package/src/auth/providers/credentials.ts +256 -0
  481. package/src/auth/providers/index.ts +6 -0
  482. package/src/auth/providers/oauth.ts +114 -0
  483. package/src/auth/route-config.ts +220 -0
  484. package/src/auth/types/auth-types.ts +555 -0
  485. package/src/auth/types/index.ts +7 -0
  486. package/src/auth/unauthenticated-routes.ts +3 -0
  487. package/src/auth/utils/idp-client.ts +444 -0
  488. package/src/auth/utils/index.ts +6 -0
  489. package/src/auth/utils/token-utils.ts +244 -0
  490. package/src/client/AuthContext.tsx +140 -0
  491. package/src/client/fetch-with-auth.ts +48 -0
  492. package/src/client/fetchWithSession.ts +21 -0
  493. package/src/client/index.ts +13 -0
  494. package/src/client/useAnonSession.ts +131 -0
  495. package/src/components/SessionSync.tsx +137 -0
  496. package/src/components/SignalRHealthCheck.tsx +131 -0
  497. package/src/components/account/UserAvatarMenu.tsx +217 -0
  498. package/src/components/account/index.ts +8 -0
  499. package/src/components/admin/AlertSettingsTab.tsx +728 -0
  500. package/src/components/admin/AnalyticsTab.tsx +703 -0
  501. package/src/components/admin/DataBrowserTab.tsx +505 -0
  502. package/src/components/admin/LoggingSettingsTab.tsx +665 -0
  503. package/src/components/admin/SessionsTab.tsx +414 -0
  504. package/src/components/admin/StatsTab.tsx +379 -0
  505. package/src/components/admin/VibeAdminContext.tsx +87 -0
  506. package/src/components/admin/VibeAdminLayout.tsx +185 -0
  507. package/src/components/admin/index.ts +59 -0
  508. package/src/components/auth/FederatedAuthSection.tsx +95 -0
  509. package/src/components/auth/ModeAwareLoginPage.tsx +135 -0
  510. package/src/components/auth/ModeAwareSignupPage.tsx +267 -0
  511. package/src/components/auth/TraditionalAuthSection.tsx +99 -0
  512. package/src/components/recovery/CompleteStep.tsx +36 -0
  513. package/src/components/recovery/InitiateRecoveryStep.tsx +68 -0
  514. package/src/components/recovery/SelectMethodStep.tsx +73 -0
  515. package/src/components/recovery/SetPasswordStep.tsx +97 -0
  516. package/src/components/recovery/VerifyCodeStep.tsx +90 -0
  517. package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -0
  518. package/src/components/reserved/ReservedStatusBox.tsx +118 -0
  519. package/src/components/ui/BetaBadge.tsx +58 -0
  520. package/src/components/ui/Footer.tsx +93 -0
  521. package/src/config/env.ts +57 -0
  522. package/src/config/logger.ts +62 -0
  523. package/src/config/logging-config.ts +82 -0
  524. package/src/config/unauthenticated-routes.ts +19 -0
  525. package/src/config/vibe-log-transport.ts +250 -0
  526. package/src/edge/internal-api-url.ts +65 -0
  527. package/src/edge/middleware.ts +42 -0
  528. package/src/hooks/useAuth.ts +115 -0
  529. package/src/hooks/useAuthSettings.ts +97 -0
  530. package/src/hooks/useAvailableProviders.ts +118 -0
  531. package/src/hooks/usePasswordValidation.ts +127 -0
  532. package/src/hooks/useProfile.ts +75 -0
  533. package/src/hooks/usePublicAuthSettings.ts +149 -0
  534. package/src/hooks/useSessionExpiration.ts +102 -0
  535. package/src/hooks/useViabilitySession.ts +335 -0
  536. package/src/index.ts +63 -0
  537. package/src/lib/anon-session.ts +213 -0
  538. package/src/lib/api-handler.ts +625 -0
  539. package/src/lib/app-slug.ts +178 -0
  540. package/src/lib/demo-mode.ts +13 -0
  541. package/src/lib/geolocation.ts +265 -0
  542. package/src/lib/idp-client-config.ts +442 -0
  543. package/src/lib/idp-fetch.ts +101 -0
  544. package/src/lib/internal-api.ts +171 -0
  545. package/src/lib/jwt-decode-client.ts +45 -0
  546. package/src/lib/jwt-decode.ts +83 -0
  547. package/src/lib/nextauth-secret.ts +126 -0
  548. package/src/lib/rate-limit-service.ts +9 -0
  549. package/src/lib/redis.ts +27 -0
  550. package/src/lib/refresh-token-validator.ts +64 -0
  551. package/src/lib/roles.ts +177 -0
  552. package/src/lib/secret-validation.ts +8 -0
  553. package/src/lib/session-store.ts +637 -0
  554. package/src/lib/session.ts +34 -0
  555. package/src/lib/site-logger.ts +245 -0
  556. package/src/lib/standardized-client-api.ts +896 -0
  557. package/src/lib/startup-init.ts +247 -0
  558. package/src/lib/test-aware-get-token.ts +30 -0
  559. package/src/lib/token-expiry.ts +40 -0
  560. package/src/lib/token-lifecycle.ts +477 -0
  561. package/src/lib/types/api-responses.ts +336 -0
  562. package/src/lib/user-agent-parser.ts +252 -0
  563. package/src/logging/api/admin-analytics.ts +51 -0
  564. package/src/logging/api/audit-log.ts +53 -0
  565. package/src/logging/components/AdminAnalyticsLayout.tsx +49 -0
  566. package/src/logging/components/AuditLogViewer.tsx +125 -0
  567. package/src/logging/components/ErrorMetricsCard.tsx +98 -0
  568. package/src/logging/components/HealthMetricsCard.tsx +70 -0
  569. package/src/logging/hooks/useAdminAnalytics.ts +22 -0
  570. package/src/logging/hooks/useAuditLog.ts +24 -0
  571. package/src/logging/hooks/useErrorMetrics.ts +40 -0
  572. package/src/logging/hooks/useHealthMetrics.ts +44 -0
  573. package/src/logging/index.ts +18 -0
  574. package/src/logging/types/analytics.ts +81 -0
  575. package/src/logging/types/audit.ts +31 -0
  576. package/src/logging/types/index.ts +3 -0
  577. package/src/middleware/auth-decision.ts +43 -0
  578. package/src/middleware/create-middleware.ts +626 -0
  579. package/src/middleware/rbac-check.ts +244 -0
  580. package/src/middleware/twofa-presets.ts +224 -0
  581. package/src/models/DecodedAccessToken.ts +17 -0
  582. package/src/models/SessionModel.ts +258 -0
  583. package/src/pages/admin-login/page.tsx +229 -0
  584. package/src/pages/admin-roles/RolesAdminPage.tsx +357 -0
  585. package/src/pages/admin-roles/index.ts +9 -0
  586. package/src/pages/admin-roles/modals.tsx +469 -0
  587. package/src/pages/client-admin/ClientSiteAdminPage.tsx +380 -0
  588. package/src/pages/client-admin/index.ts +33 -0
  589. package/src/pages/login/page.tsx +463 -0
  590. package/src/pages/profile/EnhancedProfilePage.tsx +479 -0
  591. package/src/pages/profile/index.ts +9 -0
  592. package/src/pages/profile/page.tsx +166 -0
  593. package/src/pages/recovery/page.tsx +234 -0
  594. package/src/pages/roles/MyRolesPage.tsx +211 -0
  595. package/src/pages/roles/components.tsx +294 -0
  596. package/src/pages/roles/index.ts +17 -0
  597. package/src/pages/security/EnhancedSecurityPage.tsx +574 -0
  598. package/src/pages/security/index.ts +9 -0
  599. package/src/pages/security/page.tsx +507 -0
  600. package/src/pages/settings/EnhancedSettingsPage.tsx +642 -0
  601. package/src/pages/settings/index.ts +9 -0
  602. package/src/pages/settings/page.tsx +47 -0
  603. package/src/pages/showcase/ShowcasePage.tsx +530 -0
  604. package/src/pages/showcase/index.ts +13 -0
  605. package/src/pages/test-env/EmergencyLogoutPage.tsx +179 -0
  606. package/src/pages/test-env/JwtInspectPage.tsx +418 -0
  607. package/src/pages/test-env/RefreshTokenPage.tsx +155 -0
  608. package/src/pages/test-env/TestEnvPage.tsx +116 -0
  609. package/src/pages/test-env/index.ts +25 -0
  610. package/src/pages/verify-code/page.tsx +648 -0
  611. package/src/routes/account/index.ts +32 -0
  612. package/src/routes/account/masked-info.ts +37 -0
  613. package/src/routes/account/send-code.ts +40 -0
  614. package/src/routes/account/update-phone.ts +13 -0
  615. package/src/routes/account/verify-email.ts +41 -0
  616. package/src/routes/account/verify-sms.ts +41 -0
  617. package/src/routes/auth/index.ts +23 -0
  618. package/src/routes/auth/logout.ts +127 -0
  619. package/src/routes/auth/nextauth.ts +71 -0
  620. package/src/routes/auth/refresh.ts +54 -0
  621. package/src/routes/auth/session.ts +193 -0
  622. package/src/routes/auth/settings.ts +75 -0
  623. package/src/routes/auth/viability.ts +220 -0
  624. package/src/routes/index.ts +18 -0
  625. package/src/routes/session/index.ts +7 -0
  626. package/src/routes/session/refresh-viability.ts +17 -0
  627. package/src/services/signalrActivityService.ts +258 -0
  628. package/src/stores/authStore.ts +1904 -0
  629. package/src/templates/instrumentation.ts +41 -0
  630. package/src/theme/ThemeProvider.tsx +39 -0
  631. package/src/theme/default.ts +33 -0
  632. package/src/theme/index.ts +31 -0
  633. package/src/theme/types.ts +69 -0
  634. package/src/theme/useTheme.ts +57 -0
  635. package/src/theme/utils.ts +40 -0
  636. package/src/types/api.ts +13 -0
  637. package/src/types/auth.d.ts +15 -0
  638. package/src/types/auth.ts +22 -0
  639. package/src/types/logging.ts +11 -0
  640. package/src/types/next-auth.d.ts +15 -0
  641. package/src/types/recovery.ts +54 -0
  642. package/src/types/security.ts +1 -0
  643. package/src/utils/api.ts +353 -0
  644. package/src/utils/circuitBreaker.ts +40 -0
  645. package/src/utils/error-message.ts +108 -0
  646. package/src/utils/layout/reservedSpace.ts +124 -0
  647. package/src/utils/logout.ts +30 -0
  648. package/src/vibe/client.ts +590 -0
  649. package/src/vibe/errors.ts +185 -0
  650. package/src/vibe/generic.ts +429 -0
  651. package/src/vibe/hooks/index.ts +367 -0
  652. package/src/vibe/index.ts +121 -0
  653. package/src/vibe/sessions.ts +551 -0
  654. package/src/vibe/types.ts +577 -0
@@ -0,0 +1,442 @@
1
+ /**
2
+ * IDP Client Configuration
3
+ *
4
+ * Fetches full client configuration from IDP including:
5
+ * - OAuth provider credentials (from Key Vault)
6
+ * - 2FA/MFA settings
7
+ * - Session configuration
8
+ * - NextAuth secret
9
+ * - Branding
10
+ *
11
+ * CACHING STRATEGY:
12
+ * 1. In-memory cache (fastest, but lost on module reload in dev)
13
+ * 2. Redis cache (survives module reloads, shared across instances)
14
+ * 3. IDP fetch (when both caches miss)
15
+ *
16
+ * NO FALLBACKS. If IDP doesn't respond correctly, we fail loud.
17
+ *
18
+ * @version 2.0.0 - Added Redis-backed caching
19
+ */
20
+
21
+ import 'server-only';
22
+ import { randomUUID } from 'crypto';
23
+ import redis from './redis';
24
+
25
+ // ============================================================================
26
+ // Types
27
+ // ============================================================================
28
+
29
+ export interface OAuthProviderConfig {
30
+ provider: string;
31
+ enabled: boolean;
32
+ clientId: string;
33
+ clientSecret: string;
34
+ scopes?: string;
35
+ additionalParams?: Record<string, any>;
36
+ }
37
+
38
+ export interface AuthSettings {
39
+ require2FA: boolean;
40
+ allowed2FAMethods: string[];
41
+ mfaGracePeriodHours: number;
42
+ mfaRememberDeviceDays: number;
43
+ sessionTimeoutMinutes: number;
44
+ idleTimeoutMinutes: number;
45
+ allowRememberMe: boolean;
46
+ rememberMeDays: number;
47
+ lockoutThreshold: number;
48
+ lockoutDurationMinutes: number;
49
+ }
50
+
51
+ export interface BrandingConfig {
52
+ theme?: string;
53
+ primaryColor?: string;
54
+ secondaryColor?: string;
55
+ logoUrl?: string;
56
+ }
57
+
58
+ export interface IDPClientConfig {
59
+ clientId: number;
60
+ clientSlug: string;
61
+ nextAuthSecret: string;
62
+ configCacheTtlSeconds: number;
63
+ oauthProviders: OAuthProviderConfig[];
64
+ authSettings: AuthSettings;
65
+ branding: BrandingConfig;
66
+ baseClientUrl?: string; // Public base URL - sets IDENTITY_CLIENT_BASE_EXTERNAL_URL
67
+ }
68
+
69
+ // ============================================================================
70
+ // Cache & Fetch Deduplication
71
+ // ============================================================================
72
+
73
+ let cachedConfig: IDPClientConfig | null = null;
74
+ let cacheExpiry: number = 0;
75
+ let pendingFetch: Promise<IDPClientConfig> | null = null; // Prevents parallel fetches
76
+
77
+ // ============================================================================
78
+ // Redis Cache Configuration
79
+ // ============================================================================
80
+
81
+ const REDIS_CONFIG_KEY_PREFIX = 'idp_config:';
82
+
83
+ function getRedisConfigKey(): string {
84
+ const clientId = process.env.CLIENT_ID || process.env.NEXT_PUBLIC_CLIENT_ID || 'default';
85
+ return `${REDIS_CONFIG_KEY_PREFIX}${clientId}`;
86
+ }
87
+
88
+ interface RedisCachedConfig {
89
+ config: IDPClientConfig;
90
+ expiresAt: number;
91
+ }
92
+
93
+ async function getConfigFromRedis(): Promise<IDPClientConfig | null> {
94
+ try {
95
+ const key = getRedisConfigKey();
96
+ const cached = await redis.get(key);
97
+ if (!cached) return null;
98
+
99
+ const parsed: RedisCachedConfig = JSON.parse(cached);
100
+ if (Date.now() >= parsed.expiresAt) {
101
+ // Expired, delete it
102
+ await redis.del(key);
103
+ return null;
104
+ }
105
+
106
+ return parsed.config;
107
+ } catch (error) {
108
+ console.warn('[IDP_CONFIG] Failed to read from Redis cache:', error);
109
+ return null;
110
+ }
111
+ }
112
+
113
+ async function setConfigInRedis(config: IDPClientConfig): Promise<void> {
114
+ try {
115
+ const key = getRedisConfigKey();
116
+ const ttlSeconds = config.configCacheTtlSeconds || 300;
117
+ const data: RedisCachedConfig = {
118
+ config,
119
+ expiresAt: Date.now() + (ttlSeconds * 1000)
120
+ };
121
+ // Store with TTL slightly longer than the logical expiry to allow for clock skew
122
+ await redis.set(key, JSON.stringify(data), 'EX', ttlSeconds + 10);
123
+ } catch (error) {
124
+ console.warn('[IDP_CONFIG] Failed to write to Redis cache:', error);
125
+ }
126
+ }
127
+
128
+ // ============================================================================
129
+ // Circuit Breaker & Backoff State
130
+ // ============================================================================
131
+
132
+ let consecutiveFailures = 0;
133
+ let lastFailureTime = 0;
134
+ const MAX_FAILURES = 3;
135
+ const CIRCUIT_OPEN_MS = 300000; // 5 minutes
136
+ const MAX_BACKOFF_MS = 30000; // 30 seconds max backoff
137
+
138
+ // ============================================================================
139
+ // Main Functions
140
+ // ============================================================================
141
+
142
+ /**
143
+ * Get IDP client configuration with multi-tier caching.
144
+ *
145
+ * Caching layers (checked in order):
146
+ * 1. In-memory cache (fastest, lost on module reload in dev)
147
+ * 2. Redis cache (survives module reloads)
148
+ * 3. IDP fetch (when both caches miss)
149
+ *
150
+ * THROWS if IDP is unavailable or misconfigured. No fallbacks.
151
+ */
152
+ export async function getIDPClientConfig(forceRefresh: boolean = false): Promise<IDPClientConfig> {
153
+ const now = Date.now();
154
+
155
+ // Layer 1: Return in-memory cached if still valid (skip if forceRefresh)
156
+ if (!forceRefresh && cachedConfig && now < cacheExpiry) {
157
+ return cachedConfig;
158
+ }
159
+
160
+ // If a fetch is already in progress, wait for it instead of starting another
161
+ if (pendingFetch) {
162
+ return pendingFetch;
163
+ }
164
+
165
+ // Layer 2: Check Redis cache (skip if forceRefresh - startup should always get fresh data)
166
+ if (!forceRefresh) {
167
+ const redisConfig = await getConfigFromRedis();
168
+ if (redisConfig) {
169
+ // Restore to in-memory cache
170
+ cachedConfig = redisConfig;
171
+ cacheExpiry = Date.now() + ((redisConfig.configCacheTtlSeconds || 300) * 1000);
172
+
173
+ // Set NEXTAUTH_SECRET from cached config
174
+ if (redisConfig.nextAuthSecret) {
175
+ process.env.NEXTAUTH_SECRET = redisConfig.nextAuthSecret;
176
+ }
177
+
178
+ // Set IDENTITY_CLIENT_BASE_EXTERNAL_URL from cached config
179
+ // AUTH_TRUST_HOST=true tells NextAuth to derive OAuth callback URLs from headers.
180
+ if (redisConfig.baseClientUrl) {
181
+ process.env.IDENTITY_CLIENT_BASE_EXTERNAL_URL = redisConfig.baseClientUrl;
182
+ }
183
+
184
+ return redisConfig;
185
+ }
186
+ }
187
+
188
+ // Layer 3: Fetch from IDP
189
+ const idpUrl = process.env.IDP_URL;
190
+ const clientIdStr = process.env.CLIENT_ID || process.env.NEXT_PUBLIC_CLIENT_ID;
191
+
192
+ if (!idpUrl) {
193
+ throw new Error('[IDP_CONFIG] FATAL: IDP_URL must be set');
194
+ }
195
+ if (!clientIdStr) {
196
+ throw new Error('[IDP_CONFIG] FATAL: CLIENT_ID or NEXT_PUBLIC_CLIENT_ID must be set');
197
+ }
198
+
199
+ // Start fetch and store promise so concurrent callers wait for same result
200
+ pendingFetch = fetchConfigFromIDP(idpUrl, clientIdStr)
201
+ .then(async config => {
202
+ // Cache with TTL from response (default 5 minutes)
203
+ cachedConfig = config;
204
+ cacheExpiry = Date.now() + ((config.configCacheTtlSeconds || 300) * 1000);
205
+
206
+ // Store in Redis for persistence across module reloads
207
+ await setConfigInRedis(config);
208
+
209
+ // Set NEXTAUTH_SECRET from config
210
+ if (config.nextAuthSecret) {
211
+ process.env.NEXTAUTH_SECRET = config.nextAuthSecret;
212
+ } else {
213
+ throw new Error('[IDP_CONFIG] FATAL: IDP did not return nextAuthSecret');
214
+ }
215
+
216
+ // Set IDENTITY_CLIENT_BASE_EXTERNAL_URL from config
217
+ // AUTH_TRUST_HOST=true tells NextAuth to derive OAuth callback URLs from headers.
218
+ if (config.baseClientUrl) {
219
+ process.env.IDENTITY_CLIENT_BASE_EXTERNAL_URL = config.baseClientUrl;
220
+ console.log("[IDP_CONFIG] Set IDENTITY_CLIENT_BASE_EXTERNAL_URL:", config.baseClientUrl);
221
+ }
222
+
223
+ return config;
224
+ })
225
+ .finally(() => {
226
+ pendingFetch = null; // Clear so next cache miss can fetch again
227
+ });
228
+
229
+ return pendingFetch;
230
+ }
231
+
232
+ /**
233
+ * Clear the config cache (useful for testing or forced refresh)
234
+ */
235
+ export function clearConfigCache(): void {
236
+ cachedConfig = null;
237
+ cacheExpiry = 0;
238
+ }
239
+
240
+ /**
241
+ * Get enabled OAuth providers from config
242
+ */
243
+ export function getEnabledProviders(config: IDPClientConfig): OAuthProviderConfig[] {
244
+ return config.oauthProviders?.filter(p => p.enabled) || [];
245
+ }
246
+
247
+ // ============================================================================
248
+ // Internal Functions
249
+ // ============================================================================
250
+
251
+ async function fetchConfigFromIDP(idpUrl: string, clientIdStr: string): Promise<IDPClientConfig> {
252
+ // =========================================================================
253
+ // Circuit Breaker Check
254
+ // =========================================================================
255
+ if (consecutiveFailures >= MAX_FAILURES) {
256
+ const timeSinceFailure = Date.now() - lastFailureTime;
257
+ if (timeSinceFailure < CIRCUIT_OPEN_MS) {
258
+ // Circuit is open - return stale cache if available
259
+ if (cachedConfig) {
260
+ return cachedConfig;
261
+ }
262
+ throw new Error(`[IDP_CONFIG] Circuit breaker OPEN - no cached config available. Retry in ${Math.round((CIRCUIT_OPEN_MS - timeSinceFailure) / 1000)}s`);
263
+ }
264
+ // Half-open state: allow one request to test
265
+ consecutiveFailures = MAX_FAILURES - 1;
266
+ }
267
+
268
+ // =========================================================================
269
+ // Exponential Backoff Check
270
+ // =========================================================================
271
+ if (consecutiveFailures > 0) {
272
+ const backoffMs = Math.min(1000 * Math.pow(2, consecutiveFailures), MAX_BACKOFF_MS);
273
+ const timeSinceFailure = Date.now() - lastFailureTime;
274
+ if (timeSinceFailure < backoffMs) {
275
+ const remainingMs = backoffMs - timeSinceFailure;
276
+ // Return stale cache during backoff if available
277
+ if (cachedConfig) {
278
+ return cachedConfig;
279
+ }
280
+ throw new Error(`[IDP_CONFIG] In backoff period - retry in ${Math.round(remainingMs)}ms`);
281
+ }
282
+ }
283
+
284
+ try {
285
+ // Step 1: Get signed client assertion from IDP
286
+ const signingUrl = `${idpUrl.replace(/\/$/, '')}/api/ExternalAuth/sign-client-assertion`;
287
+
288
+ const signingPayload = {
289
+ issuer: clientIdStr,
290
+ subject: clientIdStr,
291
+ audience: 'urn:payez:externalauth:clientconfig',
292
+ expires_in: 60
293
+ };
294
+
295
+ const signingResp = await fetch(signingUrl, {
296
+ method: 'POST',
297
+ headers: {
298
+ 'Accept': 'application/json',
299
+ 'Content-Type': 'application/json',
300
+ 'X-Client-Id': clientIdStr,
301
+ 'X-Correlation-Id': randomUUID().replace(/-/g, ''),
302
+ },
303
+ body: JSON.stringify(signingPayload),
304
+ cache: 'no-store'
305
+ } as RequestInit);
306
+
307
+ if (!signingResp.ok) {
308
+ const txt = await signingResp.text().catch(() => 'Unknown error');
309
+ throw new Error(`[IDP_CONFIG] FATAL: Failed to sign client assertion: ${signingResp.status} - ${txt}`);
310
+ }
311
+
312
+ const signingBody: any = await signingResp.json().catch(() => null);
313
+
314
+ if (!signingBody) {
315
+ throw new Error('[IDP_CONFIG] FATAL: IDP returned empty or invalid JSON for sign-client-assertion');
316
+ }
317
+
318
+ // Per PayEz API standard: response is { success, data: { client_assertion }, ... }
319
+ // But IDP might use camelCase (clientAssertion) - check both
320
+ const client_assertion = (
321
+ signingBody?.data?.client_assertion ??
322
+ signingBody?.data?.clientAssertion
323
+ ) as string | undefined;
324
+
325
+ if (!client_assertion) {
326
+ console.error('[IDP_CONFIG] FATAL: Full response body:', JSON.stringify(signingBody, null, 2));
327
+ throw new Error(`[IDP_CONFIG] FATAL: IDP response missing client_assertion. Got keys: ${JSON.stringify(Object.keys(signingBody?.data || signingBody || {}))}`);
328
+ }
329
+
330
+ // Step 2: Fetch client config using the assertion
331
+ const configUrl = `${idpUrl.replace(/\/$/, '')}/api/ExternalAuth/client-config`;
332
+
333
+ const configResp = await fetch(configUrl, {
334
+ method: 'POST',
335
+ headers: {
336
+ 'Accept': 'application/json',
337
+ 'Content-Type': 'application/json',
338
+ 'X-Client-Id': clientIdStr,
339
+ 'X-Correlation-Id': randomUUID().replace(/-/g, ''),
340
+ },
341
+ body: JSON.stringify({ client_assertion }),
342
+ cache: 'no-store'
343
+ } as RequestInit);
344
+
345
+ if (!configResp.ok) {
346
+ const txt = await configResp.text().catch(() => 'Unknown error');
347
+ throw new Error(`[IDP_CONFIG] FATAL: Failed to fetch client config: ${configResp.status} - ${txt}`);
348
+ }
349
+
350
+ const configBody: any = await configResp.json().catch(() => null);
351
+
352
+ if (!configBody) {
353
+ throw new Error('[IDP_CONFIG] FATAL: IDP returned empty or invalid JSON for client-config');
354
+ }
355
+
356
+ // Per PayEz API standard: response is wrapped in { success, data: {...} }
357
+ const configData = configBody?.data;
358
+
359
+ if (!configData || typeof configData !== 'object') {
360
+ console.error('[IDP_CONFIG] FATAL: Full config response body:', JSON.stringify(configBody, null, 2));
361
+ throw new Error('[IDP_CONFIG] FATAL: IDP client-config response missing data envelope');
362
+ }
363
+
364
+ // Validate required fields - handle both number and string client_id
365
+ const rawClientId = configData.clientId ?? configData.client_id;
366
+ if (rawClientId === undefined || rawClientId === null) {
367
+ throw new Error(`[IDP_CONFIG] FATAL: IDP response missing clientId/client_id. Got: ${JSON.stringify(Object.keys(configData))}`);
368
+ }
369
+
370
+ // Map response to our interface (IDP always returns snake_case)
371
+ const config: IDPClientConfig = {
372
+ clientId: typeof rawClientId === 'string' ? parseInt(rawClientId, 10) : rawClientId,
373
+ clientSlug: configData.clientSlug ?? configData.client_slug ?? configData.slug ?? '',
374
+ nextAuthSecret: configData.nextAuthSecret ?? configData.next_auth_secret ?? '',
375
+ configCacheTtlSeconds: configData.configCacheTtlSeconds ?? configData.config_cache_ttl_seconds ?? 300,
376
+ oauthProviders: (configData.oauthProviders ?? configData.oauth_providers ?? []).map((p: any) => ({
377
+ provider: p.provider ?? '',
378
+ enabled: p.enabled ?? false,
379
+ clientId: p.clientId ?? p.client_id ?? '',
380
+ clientSecret: p.clientSecret ?? p.client_secret ?? '',
381
+ scopes: p.scopes,
382
+ additionalParams: p.additionalParams ?? p.additional_params
383
+ })),
384
+ authSettings: {
385
+ require2FA: (() => {
386
+ // Check nested locations first (canonical)
387
+ const nested = configData.authSettings?.require2FA ?? configData.auth_settings?.require_2fa;
388
+ if (nested !== undefined) return nested;
389
+ // TRANSITION FALLBACK: Check top-level (deprecated)
390
+ const topLevel = configData.require2FA ?? configData.require_2fa;
391
+ if (topLevel !== undefined) {
392
+ console.warn('[IDP_CONFIG] DEPRECATION: require2FA found at top-level. Should be nested under auth_settings. Update IDP.');
393
+ return topLevel;
394
+ }
395
+ return true; // Default to true for security
396
+ })(),
397
+ allowed2FAMethods: configData.authSettings?.allowed2FAMethods ?? configData.auth_settings?.allowed_2fa_methods ?? ['email', 'sms'],
398
+ mfaGracePeriodHours: configData.authSettings?.mfaGracePeriodHours ?? configData.auth_settings?.mfa_grace_period_hours ?? 24,
399
+ mfaRememberDeviceDays: configData.authSettings?.mfaRememberDeviceDays ?? configData.auth_settings?.mfa_remember_device_days ?? 30,
400
+ sessionTimeoutMinutes: configData.authSettings?.sessionTimeoutMinutes ?? configData.auth_settings?.session_timeout_minutes ?? 60,
401
+ idleTimeoutMinutes: configData.authSettings?.idleTimeoutMinutes ?? configData.auth_settings?.idle_timeout_minutes ?? 15,
402
+ allowRememberMe: configData.authSettings?.allowRememberMe ?? configData.auth_settings?.allow_remember_me ?? true,
403
+ rememberMeDays: configData.authSettings?.rememberMeDays ?? configData.auth_settings?.remember_me_days ?? 30,
404
+ lockoutThreshold: configData.authSettings?.lockoutThreshold ?? configData.auth_settings?.lockout_threshold ?? 5,
405
+ lockoutDurationMinutes: configData.authSettings?.lockoutDurationMinutes ?? configData.auth_settings?.lockout_duration_minutes ?? 15
406
+ },
407
+ branding: {
408
+ theme: configData.branding?.theme,
409
+ primaryColor: configData.branding?.primaryColor ?? configData.branding?.primary_color,
410
+ secondaryColor: configData.branding?.secondaryColor ?? configData.branding?.secondary_color,
411
+ logoUrl: configData.branding?.logoUrl ?? configData.branding?.logo_url
412
+ },
413
+ baseClientUrl: configData.baseClientUrl ?? configData.base_client_url ?? configData.BaseClientUrl
414
+ };
415
+
416
+ // Debug: log what we got for baseClientUrl
417
+ console.log(`[IDP_CONFIG] Parsed baseClientUrl:`, config.baseClientUrl, `| raw keys:`, Object.keys(configData).filter(k => k.toLowerCase().includes('client')));
418
+
419
+ // Validate we got what we need
420
+ if (!config.clientId) {
421
+ throw new Error('[IDP_CONFIG] FATAL: clientId is 0 or missing after parsing');
422
+ }
423
+ if (!config.nextAuthSecret) {
424
+ throw new Error('[IDP_CONFIG] FATAL: nextAuthSecret is empty after parsing');
425
+ }
426
+
427
+ // Success - reset failure tracking
428
+ consecutiveFailures = 0;
429
+ return config;
430
+
431
+ } catch (error) {
432
+ // Track failure for circuit breaker
433
+ consecutiveFailures++;
434
+ lastFailureTime = Date.now();
435
+ console.error('[IDP_CONFIG] Fetch failed', {
436
+ consecutiveFailures,
437
+ maxFailures: MAX_FAILURES,
438
+ error: error instanceof Error ? error.message : String(error)
439
+ });
440
+ throw error;
441
+ }
442
+ }
@@ -0,0 +1,101 @@
1
+ import { NextRequest } from 'next/server';
2
+ import { getTokenTestAware } from './test-aware-get-token';
3
+ import { getSession } from './session-store';
4
+ import { internalRefresh } from './internal-api';
5
+
6
+ /**
7
+ * Centralized IDP fetch helper
8
+ * - Injects Bearer from Redis session
9
+ * - If access token is expired/near-expiry, triggers one refresh and retries fetch once
10
+ * - Returns parsed JSON and HTTP status
11
+ */
12
+ export interface IdpFetchResult<T = any> {
13
+ ok: boolean;
14
+ status: number;
15
+ json: T | null;
16
+ attemptedRefresh: boolean;
17
+ }
18
+
19
+ function buildHeaders(req: NextRequest, bearer?: string, extra?: Record<string, string>) {
20
+ const headers: Record<string, string> = {
21
+ Accept: 'application/json',
22
+ 'Content-Type': 'application/json',
23
+ ...extra,
24
+ };
25
+ const xfwd = req.headers.get('x-forwarded-for') || req.headers.get('x-real-ip');
26
+ if (xfwd) headers['X-Forwarded-For'] = xfwd.split(',')[0].trim();
27
+ const ua = req.headers.get('user-agent');
28
+ if (ua) headers['User-Agent'] = ua;
29
+ if (bearer) headers['Authorization'] = `Bearer ${bearer}`;
30
+ return headers;
31
+ }
32
+
33
+ async function ensureFreshAccessToken(req: NextRequest): Promise<{ sessionToken?: string; accessToken?: string }> {
34
+ const token = await getTokenTestAware(req);
35
+ // Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
36
+ const sessionToken = (token?.sessionToken || token?.redisSessionId) as string | undefined;
37
+ console.log('[IDP_FETCH] ensureFreshAccessToken:', {
38
+ hasToken: !!token,
39
+ sessionToken: sessionToken?.substring(0, 20) + '...',
40
+ pathname: req.nextUrl.pathname
41
+ });
42
+ if (!sessionToken) {
43
+ console.warn('[IDP_FETCH] No sessionToken found in JWT - Bearer token will NOT be sent!');
44
+ return {};
45
+ }
46
+ let session = await getSession(sessionToken);
47
+ console.log('[IDP_FETCH] Redis session lookup:', {
48
+ hasSession: !!session,
49
+ hasAccessToken: !!session?.idpAccessToken,
50
+ bearerKeyId: session?.bearerKeyId || 'NOT_SET',
51
+ idpClientId: session?.idpClientId || 'NOT_SET',
52
+ });
53
+ if (!session?.idpAccessToken) return { sessionToken };
54
+ const now = Date.now();
55
+ const timeLeft = (session.idpAccessTokenExpires ?? now) - now;
56
+ // Treat tokens as effectively expired if within 5 minutes of expiry
57
+ if (timeLeft > 5 * 60 * 1000) {
58
+ return { sessionToken, accessToken: session.idpAccessToken };
59
+ }
60
+ // attempt refresh once via centralized internal API helper
61
+ try {
62
+ await internalRefresh(req.headers.get('cookie') || '', sessionToken);
63
+ } catch {}
64
+ session = await getSession(sessionToken);
65
+ return { sessionToken, accessToken: session?.idpAccessToken };
66
+ }
67
+
68
+ export async function idpFetchJSON<T = any>(
69
+ req: NextRequest,
70
+ targetUrl: string,
71
+ init: RequestInit = {}
72
+ ): Promise<IdpFetchResult<T>> {
73
+ let attemptedRefresh = false;
74
+ let { accessToken, sessionToken } = await ensureFreshAccessToken(req);
75
+
76
+ const makeCall = async (bearer?: string) => {
77
+ const res = await fetch(targetUrl, {
78
+ ...init,
79
+ headers: buildHeaders(req, bearer, init.headers as any),
80
+ });
81
+ let json: any = null;
82
+ try { json = await res.json(); } catch { json = null; }
83
+ return { res, json } as const;
84
+ };
85
+
86
+ // First attempt
87
+ let { res, json } = await makeCall(accessToken);
88
+ if ((res.status === 401 || res.status === 403) && sessionToken && !attemptedRefresh) {
89
+ attemptedRefresh = true;
90
+ try {
91
+ // Use centralized internal API helper for server-to-server calls
92
+ const rf = await internalRefresh(req.headers.get('cookie') || '', sessionToken);
93
+ if (rf.ok) {
94
+ const fresh = await getSession(sessionToken);
95
+ ({ res, json } = await makeCall(fresh?.idpAccessToken));
96
+ }
97
+ } catch {}
98
+ }
99
+
100
+ return { ok: res.ok, status: res.status, json: json as T | null, attemptedRefresh };
101
+ }