@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,125 @@
1
+ /**
2
+ * Verify Email 2FA Code Handler
3
+ *
4
+ * Verifies the 2FA email verification code and completes the 2FA flow.
5
+ * Updates the session with new tokens upon successful verification.
6
+ *
7
+ * @package @payez/next-mvp
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { idpFetchJSON } from '../../lib/idp-fetch';
12
+ import { ENV_CONFIG } from '../../config/env';
13
+ import { getTokenTestAware } from '../../lib/test-aware-get-token';
14
+ import { transitionTo2FASession } from '../../lib/session-store';
15
+ import { jwtDecode } from '../../lib/jwt-decode';
16
+
17
+ export async function POST(req: NextRequest) {
18
+ try {
19
+ // Parse request body
20
+ const body = await req.json();
21
+ const verificationCode = body.verificationCode || body.verification_code;
22
+
23
+ if (!verificationCode) {
24
+ return NextResponse.json(
25
+ {
26
+ success: false,
27
+ error: 'Verification code is required',
28
+ code: 'INVALID_REQUEST',
29
+ },
30
+ { status: 400 }
31
+ );
32
+ }
33
+
34
+ // Call IDP using idpFetchJSON which auto-injects Bearer token from Redis session
35
+ const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/ExternalAuth/twofa/email/verify`, {
36
+ method: 'POST',
37
+ headers: { 'Content-Type': 'application/json' },
38
+ body: JSON.stringify({ verification_code: verificationCode }),
39
+ });
40
+
41
+ if (!result.ok) {
42
+ return NextResponse.json(
43
+ {
44
+ success: false,
45
+ error: result.json?.message || 'Verification failed',
46
+ code: result.json?.code || 'IDP_ERROR',
47
+ meta: { attemptedRefresh: result.attemptedRefresh },
48
+ },
49
+ { status: result.status }
50
+ );
51
+ }
52
+
53
+ // Unwrap IDP envelope
54
+ const unwrappedData = result.json?.data || result.json;
55
+
56
+ // If we have new tokens, update the session to complete 2FA
57
+ if (unwrappedData.access_token && unwrappedData.refresh_token) {
58
+ // Get session token from NextAuth
59
+ // Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
60
+ const token = await getTokenTestAware(req);
61
+ const sessionToken = (token?.sessionToken || token?.redisSessionId) as string | undefined;
62
+
63
+ if (sessionToken) {
64
+ console.log('[VERIFY_EMAIL] Updating session with new tokens');
65
+
66
+ // Decode access token to get actual expiration
67
+ let accessTokenExpires = Date.now() + (15 * 60 * 1000); // Default: 15 minutes
68
+ try {
69
+ const decoded = jwtDecode<{ exp?: number }>(unwrappedData.access_token);
70
+ if (decoded?.exp) {
71
+ accessTokenExpires = decoded.exp * 1000; // Convert to milliseconds
72
+ }
73
+ } catch (err) {
74
+ console.warn('[VERIFY_EMAIL] Could not decode access token, using default expiration');
75
+ }
76
+
77
+ // Decode refresh token to get actual expiration (optional)
78
+ let refreshTokenExpires = Date.now() + (3 * 24 * 60 * 60 * 1000); // Default: 3 days
79
+ try {
80
+ const decoded = jwtDecode<{ exp?: number }>(unwrappedData.refresh_token);
81
+ if (decoded?.exp) {
82
+ refreshTokenExpires = decoded.exp * 1000;
83
+ }
84
+ } catch {
85
+ // Refresh token may not have exp claim, use default
86
+ }
87
+
88
+ // Update session with new tokens and mark 2FA complete
89
+ await transitionTo2FASession(
90
+ sessionToken,
91
+ {
92
+ accessToken: unwrappedData.access_token,
93
+ refreshToken: unwrappedData.refresh_token,
94
+ accessTokenExpires,
95
+ refreshTokenExpires
96
+ },
97
+ 'email' // Store 2FA method for refresh token flow
98
+ );
99
+
100
+ console.log('[VERIFY_EMAIL] Session updated successfully', {
101
+ accessTokenExpires: new Date(accessTokenExpires).toISOString(),
102
+ refreshTokenExpires: new Date(refreshTokenExpires).toISOString()
103
+ });
104
+ }
105
+ }
106
+
107
+ // Return simplified success response (don't expose tokens to client)
108
+ return NextResponse.json({
109
+ success: true,
110
+ verificationSuccessful: true,
111
+ twoFactorSessionVerified: true,
112
+ message: unwrappedData.message || 'Email code verified successfully'
113
+ }, { status: 200 });
114
+ } catch (error) {
115
+ console.error('[VERIFY_EMAIL] Error:', error);
116
+ return NextResponse.json(
117
+ {
118
+ success: false,
119
+ error: 'Failed to verify code',
120
+ code: 'INTERNAL_ERROR',
121
+ },
122
+ { status: 500 }
123
+ );
124
+ }
125
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Verify SMS 2FA Code Handler
3
+ *
4
+ * Verifies the 2FA SMS verification code and completes the 2FA flow.
5
+ * Updates the session with new tokens upon successful verification.
6
+ *
7
+ * @package @payez/next-mvp
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import { idpFetchJSON } from '../../lib/idp-fetch';
12
+ import { ENV_CONFIG } from '../../config/env';
13
+ import { getTokenTestAware } from '../../lib/test-aware-get-token';
14
+ import { transitionTo2FASession } from '../../lib/session-store';
15
+ import { jwtDecode } from '../../lib/jwt-decode';
16
+
17
+ export async function POST(req: NextRequest) {
18
+ try {
19
+ // Parse request body
20
+ const body = await req.json();
21
+ const verificationCode = body.verificationCode || body.verification_code;
22
+
23
+ if (!verificationCode) {
24
+ return NextResponse.json(
25
+ {
26
+ success: false,
27
+ error: 'Verification code is required',
28
+ code: 'INVALID_REQUEST',
29
+ },
30
+ { status: 400 }
31
+ );
32
+ }
33
+
34
+ // Call IDP using idpFetchJSON which auto-injects Bearer token from Redis session
35
+ const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/ExternalAuth/twofa/sms/verify`, {
36
+ method: 'POST',
37
+ headers: { 'Content-Type': 'application/json' },
38
+ body: JSON.stringify({ verification_code: verificationCode }),
39
+ });
40
+
41
+ if (!result.ok) {
42
+ return NextResponse.json(
43
+ {
44
+ success: false,
45
+ error: result.json?.message || 'Verification failed',
46
+ code: result.json?.code || 'IDP_ERROR',
47
+ meta: { attemptedRefresh: result.attemptedRefresh },
48
+ },
49
+ { status: result.status }
50
+ );
51
+ }
52
+
53
+ // Unwrap IDP envelope
54
+ const unwrappedData = result.json?.data || result.json;
55
+
56
+ // If we have new tokens, update the session to complete 2FA
57
+ if (unwrappedData.access_token && unwrappedData.refresh_token) {
58
+ // Get session token from NextAuth
59
+ // Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
60
+ const token = await getTokenTestAware(req);
61
+ const sessionToken = (token?.sessionToken || token?.redisSessionId) as string | undefined;
62
+
63
+ if (sessionToken) {
64
+ console.log('[VERIFY_SMS] Updating session with new tokens');
65
+
66
+ // Decode access token to get actual expiration
67
+ let accessTokenExpires = Date.now() + (15 * 60 * 1000); // Default: 15 minutes
68
+ try {
69
+ const decoded = jwtDecode<{ exp?: number }>(unwrappedData.access_token);
70
+ if (decoded?.exp) {
71
+ accessTokenExpires = decoded.exp * 1000; // Convert to milliseconds
72
+ }
73
+ } catch (err) {
74
+ console.warn('[VERIFY_SMS] Could not decode access token, using default expiration');
75
+ }
76
+
77
+ // Decode refresh token to get actual expiration (optional)
78
+ let refreshTokenExpires = Date.now() + (3 * 24 * 60 * 60 * 1000); // Default: 3 days
79
+ try {
80
+ const decoded = jwtDecode<{ exp?: number }>(unwrappedData.refresh_token);
81
+ if (decoded?.exp) {
82
+ refreshTokenExpires = decoded.exp * 1000;
83
+ }
84
+ } catch {
85
+ // Refresh token may not have exp claim, use default
86
+ }
87
+
88
+ // Update session with new tokens and mark 2FA complete
89
+ await transitionTo2FASession(
90
+ sessionToken,
91
+ {
92
+ accessToken: unwrappedData.access_token,
93
+ refreshToken: unwrappedData.refresh_token,
94
+ accessTokenExpires,
95
+ refreshTokenExpires
96
+ },
97
+ 'sms' // Store 2FA method for refresh token flow
98
+ );
99
+
100
+ console.log('[VERIFY_SMS] Session updated successfully', {
101
+ accessTokenExpires: new Date(accessTokenExpires).toISOString(),
102
+ refreshTokenExpires: new Date(refreshTokenExpires).toISOString()
103
+ });
104
+ }
105
+ }
106
+
107
+ // Return simplified success response (don't expose tokens to client)
108
+ return NextResponse.json({
109
+ success: true,
110
+ verificationSuccessful: true,
111
+ twoFactorSessionVerified: true,
112
+ message: unwrappedData.message || 'SMS code verified successfully'
113
+ }, { status: 200 });
114
+ } catch (error) {
115
+ console.error('[VERIFY_SMS] Error:', error);
116
+ return NextResponse.json(
117
+ {
118
+ success: false,
119
+ error: 'Failed to verify code',
120
+ code: 'INTERNAL_ERROR',
121
+ },
122
+ { status: 500 }
123
+ );
124
+ }
125
+ }
@@ -0,0 +1,445 @@
1
+ /**
2
+ * Admin Analytics API Handler
3
+ *
4
+ * Provides admin-level analytics data using service account credentials.
5
+ * Supports: geo stats, login stats, revenue stats, feature usage.
6
+ *
7
+ * @version 1.0
8
+ * @requires Admin role (vibe_app_admin or payez_admin)
9
+ */
10
+
11
+ import { NextRequest, NextResponse } from 'next/server';
12
+ import { getServerSession } from 'next-auth';
13
+ import { getStartupIDPConfig } from '../../lib/startup-init';
14
+ import { ADMIN_ROLES, hasAnyRole } from '../../lib/roles';
15
+
16
+ interface VibeRequestOptions {
17
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
18
+ body?: unknown;
19
+ }
20
+
21
+ async function checkAdminRole(getAuthOptions: () => Promise<any>): Promise<{ isAdmin: boolean; error?: NextResponse }> {
22
+ const authOptions = await getAuthOptions();
23
+ const session = await getServerSession(authOptions) as any;
24
+
25
+ if (!session?.user) {
26
+ return {
27
+ isAdmin: false,
28
+ error: NextResponse.json({ success: false, error: 'Please sign in' }, { status: 401 }),
29
+ };
30
+ }
31
+
32
+ const userRoles = (session.user?.roles as string[]) || [];
33
+ const hasAdminRole = ADMIN_ROLES.some(role => userRoles.includes(role));
34
+
35
+ if (!hasAdminRole) {
36
+ return {
37
+ isAdmin: false,
38
+ error: NextResponse.json({ success: false, error: 'Admin access required' }, { status: 403 }),
39
+ };
40
+ }
41
+
42
+ return { isAdmin: true };
43
+ }
44
+
45
+ async function vibeServiceRequest<T = unknown>(
46
+ endpoint: string,
47
+ options: VibeRequestOptions
48
+ ): Promise<{ ok: boolean; status: number; data: T | null; error?: string }> {
49
+ const idpUrl = process.env.NEXT_PUBLIC_IDP_URL || process.env.IDP_URL;
50
+ const clientId = process.env.VIBE_CLIENT_ID;
51
+ const signingKey = process.env.VIBE_HMAC_KEY;
52
+
53
+ if (!idpUrl || !clientId || !signingKey) {
54
+ return { ok: false, status: 500, data: null, error: 'Vibe not configured' };
55
+ }
56
+
57
+ const timestamp = Math.floor(Date.now() / 1000);
58
+ const stringToSign = `${timestamp}|${options.method}|${endpoint}`;
59
+
60
+ const crypto = await import('crypto');
61
+ const signature = crypto
62
+ .createHmac('sha256', Buffer.from(signingKey, 'base64'))
63
+ .update(stringToSign)
64
+ .digest('base64');
65
+
66
+ const proxyUrl = `${idpUrl}/api/vibe/proxy`;
67
+
68
+ // Get the numeric client ID from startup config for multi-client admin support
69
+ const idpConfig = getStartupIDPConfig();
70
+ const numericClientId = idpConfig?.clientId;
71
+
72
+ try {
73
+ const res = await fetch(proxyUrl, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ 'X-Vibe-Client-Id': clientId,
78
+ 'X-Vibe-Timestamp': String(timestamp),
79
+ 'X-Vibe-Signature': signature,
80
+ ...(numericClientId && { 'X-Client-Id': String(numericClientId) }),
81
+ },
82
+ body: JSON.stringify({
83
+ endpoint,
84
+ method: options.method,
85
+ data: options.body ?? null,
86
+ }),
87
+ cache: 'no-store',
88
+ });
89
+
90
+ if (res.status === 204) return { ok: true, status: 204, data: null };
91
+ if (!res.ok) {
92
+ const errorText = await res.text();
93
+ return { ok: false, status: res.status, data: null, error: errorText };
94
+ }
95
+
96
+ const body = await res.json();
97
+ return { ok: true, status: res.status, data: body };
98
+ } catch (error) {
99
+ return { ok: false, status: 0, data: null, error: String(error) };
100
+ }
101
+ }
102
+
103
+ function getCountryFlag(countryCode: string): string {
104
+ if (!countryCode || countryCode.length !== 2) return '';
105
+ const codePoints = countryCode
106
+ .toUpperCase()
107
+ .split('')
108
+ .map(char => 127397 + char.charCodeAt(0));
109
+ return String.fromCodePoint(...codePoints);
110
+ }
111
+
112
+ export interface AdminAnalyticsHandlerConfig {
113
+ getAuthOptions: () => Promise<any>;
114
+ }
115
+
116
+ /**
117
+ * POST /api/admin/analytics
118
+ * Body: { type: 'geo' | 'logins' | 'revenue' | 'features', period?: string }
119
+ */
120
+ export function createAnalyticsHandler(config: AdminAnalyticsHandlerConfig) {
121
+ return {
122
+ async POST(request: NextRequest) {
123
+ const adminCheck = await checkAdminRole(config.getAuthOptions);
124
+ if (adminCheck.error) return adminCheck.error;
125
+
126
+ const body = await request.json();
127
+ const { type, period = '7d' } = body;
128
+
129
+ const now = new Date();
130
+ let startDate: Date;
131
+ switch (period) {
132
+ case '24h':
133
+ startDate = new Date(now.getTime() - 24 * 60 * 60 * 1000);
134
+ break;
135
+ case '7d':
136
+ startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
137
+ break;
138
+ case '30d':
139
+ startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
140
+ break;
141
+ case '90d':
142
+ startDate = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
143
+ break;
144
+ default:
145
+ startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
146
+ }
147
+
148
+ if (type === 'geo') {
149
+ return await getGeoAnalytics(startDate);
150
+ }
151
+
152
+ if (type === 'logins') {
153
+ return await getLoginAnalytics(startDate);
154
+ }
155
+
156
+ if (type === 'revenue') {
157
+ return await getRevenueAnalytics(startDate);
158
+ }
159
+
160
+ if (type === 'features') {
161
+ return await getFeatureUsageAnalytics(startDate);
162
+ }
163
+
164
+ if (type === 'summary') {
165
+ return await getSummaryAnalytics(startDate);
166
+ }
167
+
168
+ return NextResponse.json({ error: 'Invalid analytics type' }, { status: 400 });
169
+ },
170
+ };
171
+ }
172
+
173
+ async function getGeoAnalytics(startDate: Date) {
174
+ const result = await vibeServiceRequest<any>(
175
+ '/v1/collections/vibe_app/tables/login_sessions/query',
176
+ { method: 'POST', body: { page: 1, pageSize: 5000 } }
177
+ );
178
+
179
+ if (!result.ok) {
180
+ return NextResponse.json({ error: result.error }, { status: result.status || 500 });
181
+ }
182
+
183
+ const sessions = result.data?.data || result.data?.documents || [];
184
+ const recentSessions = sessions.filter((s: any) => new Date(s.created_at) >= startDate);
185
+
186
+ const byCountry: Record<string, { count: number; flag: string; cities: Set<string> }> = {};
187
+ const byCity: Record<string, number> = {};
188
+
189
+ recentSessions.forEach((s: any) => {
190
+ const country = s.country_code || s.country || 'Unknown';
191
+ const city = s.city || 'Unknown';
192
+
193
+ if (!byCountry[country]) {
194
+ byCountry[country] = { count: 0, flag: getCountryFlag(country), cities: new Set() };
195
+ }
196
+ byCountry[country].count++;
197
+ byCountry[country].cities.add(city);
198
+
199
+ const cityKey = `${city}, ${country}`;
200
+ byCity[cityKey] = (byCity[cityKey] || 0) + 1;
201
+ });
202
+
203
+ const countries = Object.entries(byCountry)
204
+ .map(([code, data]) => ({
205
+ code,
206
+ flag: data.flag,
207
+ count: data.count,
208
+ cities: data.cities.size,
209
+ }))
210
+ .sort((a, b) => b.count - a.count);
211
+
212
+ const cities = Object.entries(byCity)
213
+ .map(([name, count]) => ({ name, count }))
214
+ .sort((a, b) => b.count - a.count)
215
+ .slice(0, 20);
216
+
217
+ return NextResponse.json({
218
+ geo: {
219
+ totalSessions: recentSessions.length,
220
+ uniqueCountries: countries.length,
221
+ countries,
222
+ topCities: cities,
223
+ },
224
+ });
225
+ }
226
+
227
+ async function getLoginAnalytics(startDate: Date) {
228
+ const result = await vibeServiceRequest<any>(
229
+ '/v1/collections/vibe_app/tables/login_sessions/query',
230
+ { method: 'POST', body: { page: 1, pageSize: 5000 } }
231
+ );
232
+
233
+ if (!result.ok) {
234
+ return NextResponse.json({ error: result.error }, { status: result.status || 500 });
235
+ }
236
+
237
+ const sessions = result.data?.data || result.data?.documents || [];
238
+ const recentSessions = sessions.filter((s: any) => new Date(s.created_at) >= startDate);
239
+
240
+ // Group by day
241
+ const byDay: Record<string, number> = {};
242
+ const byHour: Record<number, number> = {};
243
+ const byDevice: Record<string, number> = {};
244
+ const byBrowser: Record<string, number> = {};
245
+
246
+ recentSessions.forEach((s: any) => {
247
+ const date = new Date(s.created_at);
248
+ const dayKey = date.toISOString().split('T')[0];
249
+ byDay[dayKey] = (byDay[dayKey] || 0) + 1;
250
+
251
+ const hour = date.getHours();
252
+ byHour[hour] = (byHour[hour] || 0) + 1;
253
+
254
+ const device = s.device_type || s.device || 'Unknown';
255
+ byDevice[device] = (byDevice[device] || 0) + 1;
256
+
257
+ const browser = s.browser || 'Unknown';
258
+ byBrowser[browser] = (byBrowser[browser] || 0) + 1;
259
+ });
260
+
261
+ const dailyLogins = Object.entries(byDay)
262
+ .map(([date, count]) => ({ date, count }))
263
+ .sort((a, b) => a.date.localeCompare(b.date));
264
+
265
+ const hourlyDistribution = Object.entries(byHour)
266
+ .map(([hour, count]) => ({ hour: parseInt(hour), count }))
267
+ .sort((a, b) => a.hour - b.hour);
268
+
269
+ return NextResponse.json({
270
+ logins: {
271
+ total: recentSessions.length,
272
+ uniqueUsers: new Set(recentSessions.map((s: any) => s.idp_user_id || s.user_id)).size,
273
+ dailyLogins,
274
+ hourlyDistribution,
275
+ byDevice: Object.entries(byDevice).map(([device, count]) => ({ device, count })),
276
+ byBrowser: Object.entries(byBrowser).map(([browser, count]) => ({ browser, count })),
277
+ },
278
+ });
279
+ }
280
+
281
+ async function getRevenueAnalytics(startDate: Date) {
282
+ // Try to get transactions table
283
+ const result = await vibeServiceRequest<any>(
284
+ '/v1/collections/vibe_app/tables/transactions/query',
285
+ { method: 'POST', body: { page: 1, pageSize: 5000 } }
286
+ );
287
+
288
+ if (!result.ok) {
289
+ // Table might not exist, return empty stats
290
+ return NextResponse.json({
291
+ revenue: {
292
+ total: 0,
293
+ count: 0,
294
+ byDay: [],
295
+ byTier: {},
296
+ message: 'No transactions table or data available',
297
+ },
298
+ });
299
+ }
300
+
301
+ const transactions = result.data?.data || result.data?.documents || [];
302
+ const recentTxns = transactions.filter((t: any) => new Date(t.created_at) >= startDate);
303
+
304
+ const byDay: Record<string, { count: number; amount: number }> = {};
305
+ const byTier: Record<string, { count: number; amount: number }> = {};
306
+ let totalAmount = 0;
307
+
308
+ recentTxns.forEach((t: any) => {
309
+ const date = new Date(t.created_at).toISOString().split('T')[0];
310
+ const amount = parseFloat(t.amount) || 0;
311
+ const tier = t.tier || t.product || 'unknown';
312
+
313
+ if (!byDay[date]) byDay[date] = { count: 0, amount: 0 };
314
+ byDay[date].count++;
315
+ byDay[date].amount += amount;
316
+
317
+ if (!byTier[tier]) byTier[tier] = { count: 0, amount: 0 };
318
+ byTier[tier].count++;
319
+ byTier[tier].amount += amount;
320
+
321
+ totalAmount += amount;
322
+ });
323
+
324
+ const dailyRevenue = Object.entries(byDay)
325
+ .map(([date, data]) => ({ date, ...data }))
326
+ .sort((a, b) => a.date.localeCompare(b.date));
327
+
328
+ return NextResponse.json({
329
+ revenue: {
330
+ total: totalAmount,
331
+ count: recentTxns.length,
332
+ byDay: dailyRevenue,
333
+ byTier,
334
+ },
335
+ });
336
+ }
337
+
338
+ async function getFeatureUsageAnalytics(startDate: Date) {
339
+ // Try to get feature_usage or analytics table
340
+ const result = await vibeServiceRequest<any>(
341
+ '/v1/collections/vibe_app/tables/feature_usage/query',
342
+ { method: 'POST', body: { page: 1, pageSize: 5000 } }
343
+ );
344
+
345
+ if (!result.ok) {
346
+ // Try analytics table as fallback
347
+ const analyticsResult = await vibeServiceRequest<any>(
348
+ '/v1/collections/vibe_app/tables/analytics/query',
349
+ { method: 'POST', body: { page: 1, pageSize: 5000 } }
350
+ );
351
+
352
+ if (!analyticsResult.ok) {
353
+ return NextResponse.json({
354
+ features: {
355
+ total: 0,
356
+ byFeature: {},
357
+ message: 'No feature usage data available',
358
+ },
359
+ });
360
+ }
361
+
362
+ const events = analyticsResult.data?.data || analyticsResult.data?.documents || [];
363
+ return processFeatureUsage(events, startDate);
364
+ }
365
+
366
+ const events = result.data?.data || result.data?.documents || [];
367
+ return processFeatureUsage(events, startDate);
368
+ }
369
+
370
+ function processFeatureUsage(events: any[], startDate: Date) {
371
+ const recentEvents = events.filter((e: any) => new Date(e.created_at) >= startDate);
372
+
373
+ const byFeature: Record<string, { count: number; uniqueUsers: Set<string> }> = {};
374
+ const byDay: Record<string, number> = {};
375
+
376
+ recentEvents.forEach((e: any) => {
377
+ const feature = e.feature || e.action || e.event_type || 'unknown';
378
+ const userId = e.user_id || e.idp_user_id || 'anonymous';
379
+ const date = new Date(e.created_at).toISOString().split('T')[0];
380
+
381
+ if (!byFeature[feature]) {
382
+ byFeature[feature] = { count: 0, uniqueUsers: new Set() };
383
+ }
384
+ byFeature[feature].count++;
385
+ byFeature[feature].uniqueUsers.add(userId);
386
+
387
+ byDay[date] = (byDay[date] || 0) + 1;
388
+ });
389
+
390
+ const features = Object.entries(byFeature)
391
+ .map(([name, data]) => ({
392
+ name,
393
+ count: data.count,
394
+ uniqueUsers: data.uniqueUsers.size,
395
+ }))
396
+ .sort((a, b) => b.count - a.count);
397
+
398
+ const dailyUsage = Object.entries(byDay)
399
+ .map(([date, count]) => ({ date, count }))
400
+ .sort((a, b) => a.date.localeCompare(b.date));
401
+
402
+ return NextResponse.json({
403
+ features: {
404
+ total: recentEvents.length,
405
+ byFeature: features,
406
+ dailyUsage,
407
+ },
408
+ });
409
+ }
410
+
411
+ async function getSummaryAnalytics(startDate: Date) {
412
+ // Get users
413
+ const usersResult = await vibeServiceRequest<any>(
414
+ '/v1/collections/vibe_app/tables/users/query',
415
+ { method: 'POST', body: { page: 1, pageSize: 10000 } }
416
+ );
417
+
418
+ // Get sessions
419
+ const sessionsResult = await vibeServiceRequest<any>(
420
+ '/v1/collections/vibe_app/tables/login_sessions/query',
421
+ { method: 'POST', body: { page: 1, pageSize: 5000 } }
422
+ );
423
+
424
+ const users = usersResult.ok ? (usersResult.data?.data || usersResult.data?.documents || []) : [];
425
+ const sessions = sessionsResult.ok ? (sessionsResult.data?.data || sessionsResult.data?.documents || []) : [];
426
+
427
+ const recentUsers = users.filter((u: any) => new Date(u.created_at) >= startDate);
428
+ const recentSessions = sessions.filter((s: any) => new Date(s.created_at) >= startDate);
429
+
430
+ const tierCounts: Record<string, number> = {};
431
+ users.forEach((u: any) => {
432
+ const tier = u.tier || 'free';
433
+ tierCounts[tier] = (tierCounts[tier] || 0) + 1;
434
+ });
435
+
436
+ return NextResponse.json({
437
+ summary: {
438
+ totalUsers: users.length,
439
+ newUsers: recentUsers.length,
440
+ activeSessions: sessions.filter((s: any) => s.status === 'active').length,
441
+ recentLogins: recentSessions.length,
442
+ usersByTier: tierCounts,
443
+ },
444
+ });
445
+ }