@payez/next-mvp 4.8.1 → 4.8.3

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 (314) hide show
  1. package/POST-INSTALL.md +408 -408
  2. package/README.md +859 -859
  3. package/dist/api-handlers/admin/audit.js +13 -21
  4. package/dist/api-handlers/admin/sessions.js +59 -45
  5. package/dist/api-handlers/admin/stats.js +1 -1
  6. package/dist/api-handlers/admin/users.js +15 -23
  7. package/dist/api-handlers/admin/vibe-data.d.ts +5 -0
  8. package/dist/api-handlers/admin/vibe-data.js +5 -0
  9. package/dist/components/account/MobileNavDrawer.js +18 -18
  10. package/dist/components/account/UserAvatarMenu.js +1 -1
  11. package/dist/components/admin/AlertSettingsTab.js +40 -40
  12. package/dist/components/admin/LoggingSettingsTab.js +28 -28
  13. package/dist/lib/session-store.js +21 -21
  14. package/dist/lib/startup-init.js +19 -19
  15. package/dist/pages/login/page.js +28 -28
  16. package/dist/pages/settings/EnhancedSettingsPage.js +17 -17
  17. package/dist/vibe/client.d.ts +1 -1
  18. package/dist/vibe/client.js +2 -1
  19. package/dist/vibe/filters.d.ts +36 -0
  20. package/dist/vibe/filters.js +47 -0
  21. package/dist/vibe/generic.js +2 -1
  22. package/dist/vibe/sessions.js +28 -3
  23. package/package.json +2 -2
  24. package/scripts/check-publish-eol.mjs +33 -15
  25. package/src/api/auth-handler.ts +550 -550
  26. package/src/api/index.ts +17 -17
  27. package/src/api-handlers/account/change-password.ts +170 -170
  28. package/src/api-handlers/account/masked-info.ts +46 -46
  29. package/src/api-handlers/account/profile.ts +99 -99
  30. package/src/api-handlers/account/recovery/forward.ts +117 -117
  31. package/src/api-handlers/account/recovery/initiate.ts +59 -59
  32. package/src/api-handlers/account/recovery/send-code.ts +21 -21
  33. package/src/api-handlers/account/recovery/verify-code.ts +20 -20
  34. package/src/api-handlers/account/reset-password.ts +87 -87
  35. package/src/api-handlers/account/send-code.ts +70 -70
  36. package/src/api-handlers/account/update-phone.ts +84 -84
  37. package/src/api-handlers/account/validate-password.ts +139 -139
  38. package/src/api-handlers/account/verify-email.ts +134 -134
  39. package/src/api-handlers/account/verify-sms.ts +134 -134
  40. package/src/api-handlers/admin/analytics.ts +452 -452
  41. package/src/api-handlers/admin/audit.ts +223 -232
  42. package/src/api-handlers/admin/index.ts +63 -63
  43. package/src/api-handlers/admin/redis-sessions.ts +259 -259
  44. package/src/api-handlers/admin/sessions.ts +341 -327
  45. package/src/api-handlers/admin/site-logs.ts +388 -388
  46. package/src/api-handlers/admin/stats.ts +260 -260
  47. package/src/api-handlers/admin/users.ts +240 -251
  48. package/src/api-handlers/admin/vibe-data.ts +338 -333
  49. package/src/api-handlers/anon/preferences.ts +123 -123
  50. package/src/api-handlers/auth/credential-login-email-code.ts +92 -92
  51. package/src/api-handlers/auth/credential-login.ts +948 -948
  52. package/src/api-handlers/auth/jwks.ts +31 -31
  53. package/src/api-handlers/auth/login.ts +252 -252
  54. package/src/api-handlers/auth/passkey-signin.ts +116 -116
  55. package/src/api-handlers/auth/refresh.ts +829 -829
  56. package/src/api-handlers/auth/signout.ts +201 -201
  57. package/src/api-handlers/auth/status.ts +23 -23
  58. package/src/api-handlers/auth/update-session.ts +144 -144
  59. package/src/api-handlers/auth/validate.ts +45 -45
  60. package/src/api-handlers/auth/verify-code.ts +116 -116
  61. package/src/api-handlers/mfa/backup-code-verify.ts +170 -170
  62. package/src/api-handlers/mfa/backup-codes.ts +42 -42
  63. package/src/api-handlers/mfa/methods.ts +47 -47
  64. package/src/api-handlers/mfa/totp-confirm.ts +43 -43
  65. package/src/api-handlers/mfa/totp-enroll.ts +43 -43
  66. package/src/api-handlers/mfa/totp-verify.ts +172 -172
  67. package/src/api-handlers/oauth/resume.ts +182 -182
  68. package/src/api-handlers/onboarding/send-email-code.ts +18 -18
  69. package/src/api-handlers/onboarding/set-password.ts +21 -21
  70. package/src/api-handlers/onboarding/verify-code.ts +20 -20
  71. package/src/api-handlers/onboarding/verify-welcome-email.ts +17 -17
  72. package/src/api-handlers/passkeys/list.ts +32 -32
  73. package/src/api-handlers/passkeys/manage.ts +55 -55
  74. package/src/api-handlers/passkeys/register-options.ts +43 -43
  75. package/src/api-handlers/passkeys/register-verify.ts +42 -42
  76. package/src/api-handlers/session/refresh-viability.ts +56 -56
  77. package/src/api-handlers/session/viability.ts +238 -238
  78. package/src/api-handlers/test/force-expire.ts +167 -167
  79. package/src/auth/auth-decision.ts +292 -292
  80. package/src/auth/better-auth.ts +1688 -1688
  81. package/src/auth/idp-oauth.ts +310 -310
  82. package/src/auth/password-reset-bridge.ts +98 -98
  83. package/src/auth/revocation-fields.ts +16 -16
  84. package/src/auth/route-config.ts +236 -236
  85. package/src/auth/safe-callback.ts +199 -199
  86. package/src/auth/session-cookie-clear.ts +30 -30
  87. package/src/auth/session-reset-link.ts +159 -159
  88. package/src/auth/session-response-sanitizer.ts +151 -151
  89. package/src/auth/types/auth-types.ts +555 -555
  90. package/src/auth/types/index.ts +7 -7
  91. package/src/auth/unauthenticated-routes.ts +2 -2
  92. package/src/auth/utils/idp-client.ts +364 -364
  93. package/src/auth/utils/index.ts +6 -6
  94. package/src/auth/utils/token-utils.ts +243 -243
  95. package/src/client/AuthContext.tsx +192 -192
  96. package/src/client/better-auth-client.ts +70 -70
  97. package/src/client/fetch-with-auth.ts +47 -47
  98. package/src/client/fetchWithSession.ts +21 -21
  99. package/src/client/index.ts +13 -13
  100. package/src/client/useAnonSession.ts +131 -131
  101. package/src/components/SessionSync.tsx +138 -138
  102. package/src/components/SignalRHealthCheck.tsx +131 -131
  103. package/src/components/account/MobileNavDrawer.tsx +305 -305
  104. package/src/components/account/UserAvatarMenu.tsx +277 -277
  105. package/src/components/account/index.ts +13 -13
  106. package/src/components/admin/AlertSettingsTab.tsx +728 -728
  107. package/src/components/admin/AnalyticsTab.tsx +703 -703
  108. package/src/components/admin/DataBrowserTab.tsx +508 -508
  109. package/src/components/admin/LoggingSettingsTab.tsx +665 -665
  110. package/src/components/admin/SessionsTab.tsx +421 -421
  111. package/src/components/admin/StatsTab.tsx +379 -379
  112. package/src/components/admin/VibeAdminContext.tsx +87 -87
  113. package/src/components/admin/VibeAdminLayout.tsx +187 -187
  114. package/src/components/admin/index.ts +59 -59
  115. package/src/components/auth/CredentialSignInForm.tsx +240 -240
  116. package/src/components/auth/FederatedAuthSection.tsx +129 -129
  117. package/src/components/auth/ModeAwareLoginPage.tsx +146 -146
  118. package/src/components/auth/ModeAwareSignupPage.tsx +200 -200
  119. package/src/components/auth/PasswordResetBridge.tsx +30 -30
  120. package/src/components/auth/TraditionalAuthSection.tsx +103 -103
  121. package/src/components/recovery/CompleteStep.tsx +36 -36
  122. package/src/components/recovery/InitiateRecoveryStep.tsx +68 -68
  123. package/src/components/recovery/RequestedStep.tsx +30 -30
  124. package/src/components/recovery/SelectMethodStep.tsx +73 -73
  125. package/src/components/recovery/SetPasswordStep.tsx +118 -118
  126. package/src/components/recovery/VerifyCodeStep.tsx +90 -90
  127. package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -160
  128. package/src/components/reserved/ReservedStatusBox.tsx +118 -118
  129. package/src/components/ui/BetaBadge.tsx +58 -58
  130. package/src/components/ui/Footer.tsx +93 -93
  131. package/src/config/env.ts +55 -55
  132. package/src/config/logger.ts +62 -62
  133. package/src/config/logging-config.ts +82 -82
  134. package/src/config/unauthenticated-routes.ts +19 -19
  135. package/src/config/vibe-log-transport.ts +264 -264
  136. package/src/edge/internal-api-url.ts +65 -65
  137. package/src/edge/middleware.ts +42 -42
  138. package/src/hooks/useAuth.ts +117 -117
  139. package/src/hooks/useAuthSettings.ts +109 -109
  140. package/src/hooks/useAvailableProviders.ts +143 -143
  141. package/src/hooks/usePasswordValidation.ts +127 -127
  142. package/src/hooks/useProfile.ts +82 -82
  143. package/src/hooks/usePublicAuthSettings.ts +171 -171
  144. package/src/hooks/useSessionExpiration.ts +101 -101
  145. package/src/hooks/useViabilitySession.ts +337 -337
  146. package/src/index.ts +64 -64
  147. package/src/lib/anon-session.ts +213 -213
  148. package/src/lib/api-handler.ts +643 -643
  149. package/src/lib/app-slug.ts +228 -228
  150. package/src/lib/authorize-resume.ts +172 -172
  151. package/src/lib/bearer-fetch.ts +31 -31
  152. package/src/lib/client-key.ts +88 -88
  153. package/src/lib/code-step-copy.ts +83 -83
  154. package/src/lib/credential-sign-in-client.ts +101 -101
  155. package/src/lib/demo-mode.ts +18 -18
  156. package/src/lib/device-id.ts +67 -67
  157. package/src/lib/ensure-fresh-access-token.ts +509 -509
  158. package/src/lib/geolocation.ts +265 -265
  159. package/src/lib/idp-client-config.ts +1005 -1005
  160. package/src/lib/idp-fetch.ts +169 -169
  161. package/src/lib/idp-url-guard.ts +37 -37
  162. package/src/lib/internal-api.ts +171 -171
  163. package/src/lib/jwt-decode-client.ts +45 -45
  164. package/src/lib/jwt-decode.ts +82 -82
  165. package/src/lib/lock-window.ts +49 -49
  166. package/src/lib/login-error-message.ts +41 -41
  167. package/src/lib/never-in-response.ts +64 -64
  168. package/src/lib/nextauth-secret.ts +168 -168
  169. package/src/lib/onboarding-proxy.ts +57 -57
  170. package/src/lib/password-rules.ts +50 -50
  171. package/src/lib/rate-limit-service.ts +9 -9
  172. package/src/lib/redis.ts +105 -105
  173. package/src/lib/refresh-token-validator.ts +64 -64
  174. package/src/lib/roles.ts +177 -177
  175. package/src/lib/safe-error-response.ts +149 -149
  176. package/src/lib/secret-validation.ts +8 -8
  177. package/src/lib/session-cookie-shape.ts +185 -185
  178. package/src/lib/session-store.ts +1092 -1092
  179. package/src/lib/session.ts +34 -34
  180. package/src/lib/single-flight.ts +64 -64
  181. package/src/lib/site-logger.ts +245 -245
  182. package/src/lib/standardized-client-api.ts +901 -901
  183. package/src/lib/startup-init.ts +276 -276
  184. package/src/lib/test-aware-get-token.ts +41 -41
  185. package/src/lib/token-expiry.ts +40 -40
  186. package/src/lib/token-lifecycle.ts +546 -546
  187. package/src/lib/token-log-id.ts +69 -69
  188. package/src/lib/twofa-rejection.ts +91 -91
  189. package/src/lib/types/api-responses.ts +336 -336
  190. package/src/lib/user-agent-parser.ts +252 -252
  191. package/src/logging/api/admin-analytics.ts +51 -51
  192. package/src/logging/api/audit-log.ts +53 -53
  193. package/src/logging/components/AdminAnalyticsLayout.tsx +49 -49
  194. package/src/logging/components/AuditLogViewer.tsx +125 -125
  195. package/src/logging/components/ErrorMetricsCard.tsx +98 -98
  196. package/src/logging/components/HealthMetricsCard.tsx +70 -70
  197. package/src/logging/hooks/useAdminAnalytics.ts +22 -22
  198. package/src/logging/hooks/useAuditLog.ts +24 -24
  199. package/src/logging/hooks/useErrorMetrics.ts +40 -40
  200. package/src/logging/hooks/useHealthMetrics.ts +44 -44
  201. package/src/logging/index.ts +18 -18
  202. package/src/logging/types/analytics.ts +81 -81
  203. package/src/logging/types/audit.ts +31 -31
  204. package/src/logging/types/index.ts +3 -3
  205. package/src/middleware/create-middleware.ts +1141 -1141
  206. package/src/middleware/rbac-check.ts +279 -279
  207. package/src/middleware/twofa-presets.ts +224 -224
  208. package/src/models/DecodedAccessToken.ts +16 -16
  209. package/src/models/SessionModel.ts +331 -331
  210. package/src/pages/admin-login/page.tsx +111 -111
  211. package/src/pages/admin-page-permissions/PagePermissionsAdminPage.tsx +527 -527
  212. package/src/pages/admin-page-permissions/index.ts +7 -7
  213. package/src/pages/admin-roles/RolesAdminPage.tsx +533 -533
  214. package/src/pages/admin-roles/index.ts +9 -9
  215. package/src/pages/admin-roles/modals.tsx +469 -469
  216. package/src/pages/client-admin/ClientSiteAdminPage.tsx +382 -382
  217. package/src/pages/client-admin/index.ts +33 -33
  218. package/src/pages/coming-soon/page.tsx +83 -83
  219. package/src/pages/login/page.tsx +338 -338
  220. package/src/pages/onboarding/index.ts +11 -11
  221. package/src/pages/onboarding/page.tsx +212 -212
  222. package/src/pages/profile/EnhancedProfilePage.tsx +514 -514
  223. package/src/pages/profile/index.ts +9 -9
  224. package/src/pages/profile/page.tsx +166 -166
  225. package/src/pages/recovery/page.tsx +267 -267
  226. package/src/pages/roles/MyRolesPage.tsx +211 -211
  227. package/src/pages/roles/components.tsx +294 -294
  228. package/src/pages/roles/index.ts +17 -17
  229. package/src/pages/security/EnhancedSecurityPage.tsx +660 -660
  230. package/src/pages/security/index.ts +12 -12
  231. package/src/pages/security/page.tsx +507 -507
  232. package/src/pages/service-unavailable/page.tsx +63 -63
  233. package/src/pages/settings/EnhancedSettingsPage.tsx +642 -642
  234. package/src/pages/settings/index.ts +9 -9
  235. package/src/pages/settings/page.tsx +47 -47
  236. package/src/pages/showcase/ShowcasePage.tsx +532 -532
  237. package/src/pages/showcase/index.ts +13 -13
  238. package/src/pages/test-env/EmergencyLogoutPage.tsx +192 -192
  239. package/src/pages/test-env/JwtInspectPage.tsx +449 -449
  240. package/src/pages/test-env/RefreshTokenPage.tsx +178 -178
  241. package/src/pages/test-env/TestEnvPage.tsx +130 -130
  242. package/src/pages/test-env/guarded.tsx +81 -81
  243. package/src/pages/test-env/index.ts +77 -77
  244. package/src/pages/test-env/redact-credentials.ts +96 -96
  245. package/src/pages/verify-code/page.tsx +746 -746
  246. package/src/routes/account/index.ts +31 -31
  247. package/src/routes/account/masked-info.ts +36 -36
  248. package/src/routes/account/send-code.ts +39 -39
  249. package/src/routes/account/update-phone.ts +13 -13
  250. package/src/routes/account/verify-email.ts +40 -40
  251. package/src/routes/account/verify-sms.ts +40 -40
  252. package/src/routes/auth/credential-login-email-code.ts +6 -6
  253. package/src/routes/auth/credential-login.ts +6 -6
  254. package/src/routes/auth/index.ts +22 -22
  255. package/src/routes/auth/logout.ts +111 -111
  256. package/src/routes/auth/nextauth.ts +45 -45
  257. package/src/routes/auth/passkey-signin.ts +13 -13
  258. package/src/routes/auth/refresh.ts +77 -77
  259. package/src/routes/auth/session-reset.ts +37 -37
  260. package/src/routes/auth/session.ts +261 -261
  261. package/src/routes/auth/settings.ts +181 -181
  262. package/src/routes/auth/viability.ts +519 -519
  263. package/src/routes/index.ts +17 -17
  264. package/src/routes/mfa/backup-code-verify.ts +1 -1
  265. package/src/routes/mfa/backup-codes.ts +10 -10
  266. package/src/routes/mfa/methods.ts +22 -22
  267. package/src/routes/mfa/totp-confirm.ts +10 -10
  268. package/src/routes/mfa/totp-enroll.ts +10 -10
  269. package/src/routes/mfa/totp-verify.ts +14 -14
  270. package/src/routes/onboarding/index.ts +15 -15
  271. package/src/routes/onboarding/send-email-code.ts +2 -2
  272. package/src/routes/onboarding/set-password.ts +2 -2
  273. package/src/routes/onboarding/verify-code.ts +2 -2
  274. package/src/routes/onboarding/verify-welcome-email.ts +2 -2
  275. package/src/routes/passkeys/list.ts +10 -10
  276. package/src/routes/passkeys/manage.ts +23 -23
  277. package/src/routes/passkeys/register-options.ts +10 -10
  278. package/src/routes/passkeys/register-verify.ts +10 -10
  279. package/src/routes/session/index.ts +7 -7
  280. package/src/routes/session/refresh-viability.ts +17 -17
  281. package/src/server/auth-guard.ts +203 -203
  282. package/src/server/auth.ts +486 -486
  283. package/src/server/decode-session.ts +309 -309
  284. package/src/server/slim-middleware.ts +117 -117
  285. package/src/server/verified-session-token.ts +103 -103
  286. package/src/server/with-auth.ts +93 -93
  287. package/src/services/signalrActivityService.ts +258 -258
  288. package/src/stores/authStore.ts +1900 -1900
  289. package/src/templates/instrumentation.ts +60 -60
  290. package/src/theme/ThemeProvider.tsx +39 -39
  291. package/src/theme/default.ts +33 -33
  292. package/src/theme/index.ts +31 -31
  293. package/src/theme/types.ts +69 -69
  294. package/src/theme/useTheme.ts +57 -57
  295. package/src/theme/utils.ts +40 -40
  296. package/src/types/api.ts +12 -12
  297. package/src/types/auth.d.ts +23 -23
  298. package/src/types/auth.ts +48 -48
  299. package/src/types/logging.ts +11 -11
  300. package/src/types/recovery.ts +54 -54
  301. package/src/utils/api.ts +401 -401
  302. package/src/utils/circuitBreaker.ts +40 -40
  303. package/src/utils/error-message.ts +108 -108
  304. package/src/utils/layout/reservedSpace.ts +124 -124
  305. package/src/utils/logout.ts +30 -30
  306. package/src/vibe/client.ts +878 -877
  307. package/src/vibe/enterprise-auth.ts +208 -208
  308. package/src/vibe/errors.ts +209 -209
  309. package/src/vibe/filters.ts +52 -0
  310. package/src/vibe/generic.ts +340 -339
  311. package/src/vibe/hooks/index.ts +367 -367
  312. package/src/vibe/index.ts +133 -133
  313. package/src/vibe/sessions.ts +925 -899
  314. package/src/vibe/types.ts +577 -577
@@ -1,336 +1,336 @@
1
- // ========================================================================================
2
- // BULLETPROOF API RESPONSE TYPES - ENFORCES STANDARDIZED FORMAT
3
- // ========================================================================================
4
- // These types ENFORCE the standardized response format from our Identity API
5
- // If the API doesn't return this exact structure, TypeScript will break the build
6
- // NO MORE data.data.data.data NONSENSE - EVER!
7
- // ========================================================================================
8
-
9
- /**
10
- * BASE STANDARDIZED RESPONSE FORMAT
11
- * This is THE ONLY acceptable response format from our APIs
12
- */
13
- export interface StandardizedApiResponse<TData = unknown> {
14
- /** REQUIRED: Operation success status */
15
- success: true;
16
- /** REQUIRED: The actual data payload */
17
- data: TData;
18
- /** REQUIRED: Human-readable success message */
19
- message: string;
20
- /** REQUIRED: Unique operation code for tracking */
21
- operation_code: string;
22
- /** Optional: Server timestamp */
23
- timestamp?: string;
24
- /** Optional: Request ID for tracing */
25
- request_id?: string;
26
- }
27
-
28
- /**
29
- * STANDARDIZED ERROR RESPONSE FORMAT
30
- * This is THE ONLY acceptable error format from our APIs
31
- */
32
- export interface StandardizedErrorResponse {
33
- /** REQUIRED: Always false for errors */
34
- success: false;
35
- /** REQUIRED: Standard error code */
36
- error_code: string;
37
- /** REQUIRED: Human-readable error message */
38
- message: string;
39
- /** REQUIRED: Operation that failed */
40
- operation: string;
41
- /** Optional: Additional error details - can be any structure from IDP */
42
- details?: unknown;
43
- /** Optional: Validation errors */
44
- validation_errors?: Record<string, string[]>;
45
- /** Optional: Server timestamp */
46
- timestamp?: string;
47
- /** Optional: Request ID for tracing */
48
- request_id?: string;
49
- }
50
-
51
- /**
52
- * STANDARDIZED PAGINATED RESPONSE FORMAT
53
- * For endpoints that return paged data
54
- */
55
- export interface StandardizedPagedResponse<TData = unknown> {
56
- /** REQUIRED: Always true for success */
57
- success: true;
58
- /** REQUIRED: Array of data items */
59
- data: TData[];
60
- /** REQUIRED: Human-readable success message */
61
- message: string;
62
- /** REQUIRED: Unique operation code */
63
- operation_code: string;
64
- /** REQUIRED: Pagination metadata */
65
- pagination: {
66
- /** Current page number (1-based) */
67
- current_page: number;
68
- /** Total number of pages */
69
- total_pages: number;
70
- /** Number of items per page */
71
- page_size: number;
72
- /** Total number of items across all pages */
73
- total_items: number;
74
- /** True if there are more pages after current */
75
- has_next_page: boolean;
76
- /** True if there are pages before current */
77
- has_previous_page: boolean;
78
- };
79
- /** Optional: Server timestamp */
80
- timestamp?: string;
81
- /** Optional: Request ID for tracing */
82
- request_id?: string;
83
- }
84
-
85
- /**
86
- * VALIDATION ERROR RESPONSE FORMAT
87
- * For input validation failures
88
- */
89
- export interface StandardizedValidationResponse {
90
- /** REQUIRED: Always false for validation errors */
91
- success: false;
92
- /** REQUIRED: Always 'VALIDATION_ERROR' */
93
- error_code: 'VALIDATION_ERROR';
94
- /** REQUIRED: Summary message */
95
- message: string;
96
- /** REQUIRED: Operation that failed */
97
- operation: string;
98
- /** REQUIRED: Field-specific validation errors */
99
- payload: {
100
- /** Field name mapped to array of error messages */
101
- validation_errors: Record<string, string[]>;
102
- /** The invalid value that caused the error */
103
- invalid_value?: unknown;
104
- /** The field that caused the primary error */
105
- primary_field?: string;
106
- };
107
- }
108
-
109
- // ========================================================================================
110
- // RESPONSE TYPE UNION - THE ONLY VALID API RESPONSES
111
- // ========================================================================================
112
-
113
- /** ALL POSSIBLE STANDARDIZED RESPONSES */
114
- export type StandardizedResponse<TData = unknown> =
115
- | StandardizedApiResponse<TData>
116
- | StandardizedPagedResponse<TData>
117
- | StandardizedErrorResponse
118
- | StandardizedValidationResponse;
119
-
120
- // ========================================================================================
121
- // TYPE GUARDS FOR RUNTIME VALIDATION
122
- // ========================================================================================
123
-
124
- /**
125
- * Type guard to check if response is a success response
126
- * THROWS if response doesn't match standardized format
127
- */
128
- export function isSuccessResponse<TData = unknown>(
129
- response: unknown
130
- ): response is StandardizedApiResponse<TData> {
131
- if (!response || typeof response !== 'object') {
132
- throw new Error('INVALID_API_RESPONSE: Response is not an object');
133
- }
134
-
135
- const r = response as any;
136
-
137
- if (r.success !== true) {
138
- return false; // This is an error response, not invalid format
139
- }
140
-
141
- // SUCCESS RESPONSE VALIDATION - BE STRICT!
142
- if (!('data' in r)) {
143
- throw new Error('INVALID_API_RESPONSE: Success response missing required "data" field');
144
- }
145
-
146
- if (!('message' in r) || typeof r.message !== 'string') {
147
- throw new Error('INVALID_API_RESPONSE: Success response missing required "message" field');
148
- }
149
-
150
- if (!('operation_code' in r) || typeof r.operation_code !== 'string') {
151
- throw new Error('INVALID_API_RESPONSE: Success response missing required "operation_code" field');
152
- }
153
-
154
- return true;
155
- }
156
-
157
- /**
158
- * Type guard to check if response is a paged success response
159
- * THROWS if response doesn't match standardized format
160
- */
161
- export function isPagedResponse<TData = unknown>(
162
- response: unknown
163
- ): response is StandardizedPagedResponse<TData> {
164
- if (!isSuccessResponse(response)) {
165
- return false;
166
- }
167
-
168
- const r = response as any;
169
-
170
- // Check if it has pagination metadata
171
- if (!('pagination' in r) || typeof r.pagination !== 'object') {
172
- return false;
173
- }
174
-
175
- const pagination = r.pagination;
176
- const requiredPaginationFields = [
177
- 'current_page', 'total_pages', 'page_size', 'total_items',
178
- 'has_next_page', 'has_previous_page'
179
- ];
180
-
181
- for (const field of requiredPaginationFields) {
182
- if (!(field in pagination)) {
183
- throw new Error(`INVALID_API_RESPONSE: Paged response missing required pagination.${field}`);
184
- }
185
- }
186
-
187
- // Ensure data is an array for paged responses
188
- if (!Array.isArray(r.data)) {
189
- throw new Error('INVALID_API_RESPONSE: Paged response data must be an array');
190
- }
191
-
192
- return true;
193
- }
194
-
195
- /**
196
- * Type guard to check if response is an error response
197
- * THROWS if response doesn't match standardized format
198
- */
199
- export function isErrorResponse(
200
- response: unknown
201
- ): response is StandardizedErrorResponse {
202
- if (!response || typeof response !== 'object') {
203
- throw new Error('INVALID_API_RESPONSE: Response is not an object');
204
- }
205
-
206
- const r = response as any;
207
-
208
- if (r.success !== false) {
209
- return false; // This is a success response, not invalid format
210
- }
211
-
212
- // ERROR RESPONSE VALIDATION - BE STRICT!
213
- if (!('error_code' in r) || typeof r.error_code !== 'string') {
214
- throw new Error('INVALID_API_RESPONSE: Error response missing required "error_code" field');
215
- }
216
-
217
- if (!('message' in r) || typeof r.message !== 'string') {
218
- throw new Error('INVALID_API_RESPONSE: Error response missing required "message" field');
219
- }
220
-
221
- if (!('operation' in r) || typeof r.operation !== 'string') {
222
- throw new Error('INVALID_API_RESPONSE: Error response missing required "operation" field');
223
- }
224
-
225
- return true;
226
- }
227
-
228
- /**
229
- * Type guard to check if response is a validation error
230
- * THROWS if response doesn't match standardized format
231
- */
232
- export function isValidationErrorResponse(
233
- response: unknown
234
- ): response is StandardizedValidationResponse {
235
- if (!isErrorResponse(response)) {
236
- return false;
237
- }
238
-
239
- const r = response as any;
240
-
241
- if (r.error_code !== 'VALIDATION_ERROR') {
242
- return false;
243
- }
244
-
245
- // VALIDATION ERROR RESPONSE VALIDATION - BE STRICT!
246
- if (!('payload' in r) || typeof r.payload !== 'object') {
247
- throw new Error('INVALID_API_RESPONSE: Validation error missing required "payload" field');
248
- }
249
-
250
- if (!('validation_errors' in r.payload) || typeof r.payload.validation_errors !== 'object') {
251
- throw new Error('INVALID_API_RESPONSE: Validation error missing required "payload.validation_errors" field');
252
- }
253
-
254
- return true;
255
- }
256
-
257
- // ========================================================================================
258
- // RESPONSE VALIDATOR - ENFORCES COMPLIANCE AT RUNTIME
259
- // ========================================================================================
260
-
261
- /**
262
- * VALIDATES AND NORMALIZES API RESPONSES
263
- * This function BREAKS THE BUILD if responses don't match our standard
264
- * NO EXCEPTIONS - ZERO TOLERANCE FOR BAD RESPONSES
265
- */
266
- export function validateStandardizedResponse<TData = unknown>(
267
- response: unknown,
268
- endpoint?: string
269
- ): StandardizedResponse<TData> {
270
- const context = endpoint ? ` for endpoint: ${endpoint}` : '';
271
-
272
- try {
273
- // First, basic object validation
274
- if (!response || typeof response !== 'object') {
275
- throw new Error(`CRITICAL_API_ERROR: Invalid response object${context}`);
276
- }
277
-
278
- const r = response as any;
279
-
280
- // Check for success field (REQUIRED)
281
- if (!('success' in r) || typeof r.success !== 'boolean') {
282
- throw new Error(`CRITICAL_API_ERROR: Response missing required boolean "success" field${context}`);
283
- }
284
-
285
- // Route to appropriate validator based on success status
286
- if (r.success === true) {
287
- // Check if it's a paged response
288
- if ('pagination' in r) {
289
- if (isPagedResponse<TData>(response)) {
290
- return response as StandardizedPagedResponse<TData>;
291
- }
292
- } else {
293
- if (isSuccessResponse<TData>(response)) {
294
- return response as StandardizedApiResponse<TData>;
295
- }
296
- }
297
- } else if (r.success === false) {
298
- // Check if it's a validation error
299
- if (r.error_code === 'VALIDATION_ERROR') {
300
- if (isValidationErrorResponse(response)) {
301
- return response as StandardizedValidationResponse;
302
- }
303
- } else {
304
- if (isErrorResponse(response)) {
305
- return response as StandardizedErrorResponse;
306
- }
307
- }
308
- }
309
-
310
- // If we reach here, the response format is invalid
311
- throw new Error(`CRITICAL_API_ERROR: Response format validation failed${context}. Response: ${JSON.stringify(response, null, 2)}`);
312
-
313
- } catch (error) {
314
- // Re-throw validation errors with context
315
- const errorMessage = error instanceof Error ? error.message : 'Unknown validation error';
316
- throw new Error(`${errorMessage}${context}`);
317
- }
318
- }
319
-
320
- // ========================================================================================
321
- // CONVENIENCE TYPE EXTRACTORS
322
- // ========================================================================================
323
-
324
- /** Extract the data type from a standardized response */
325
- export type ExtractResponseData<T> = T extends StandardizedApiResponse<infer U>
326
- ? U
327
- : T extends StandardizedPagedResponse<infer U>
328
- ? U[]
329
- : never;
330
-
331
- /** Extract the error code from an error response */
332
- export type ExtractErrorCode<T> = T extends StandardizedErrorResponse
333
- ? T['error_code']
334
- : T extends StandardizedValidationResponse
335
- ? T['error_code']
336
- : never;
1
+ // ========================================================================================
2
+ // BULLETPROOF API RESPONSE TYPES - ENFORCES STANDARDIZED FORMAT
3
+ // ========================================================================================
4
+ // These types ENFORCE the standardized response format from our Identity API
5
+ // If the API doesn't return this exact structure, TypeScript will break the build
6
+ // NO MORE data.data.data.data NONSENSE - EVER!
7
+ // ========================================================================================
8
+
9
+ /**
10
+ * BASE STANDARDIZED RESPONSE FORMAT
11
+ * This is THE ONLY acceptable response format from our APIs
12
+ */
13
+ export interface StandardizedApiResponse<TData = unknown> {
14
+ /** REQUIRED: Operation success status */
15
+ success: true;
16
+ /** REQUIRED: The actual data payload */
17
+ data: TData;
18
+ /** REQUIRED: Human-readable success message */
19
+ message: string;
20
+ /** REQUIRED: Unique operation code for tracking */
21
+ operation_code: string;
22
+ /** Optional: Server timestamp */
23
+ timestamp?: string;
24
+ /** Optional: Request ID for tracing */
25
+ request_id?: string;
26
+ }
27
+
28
+ /**
29
+ * STANDARDIZED ERROR RESPONSE FORMAT
30
+ * This is THE ONLY acceptable error format from our APIs
31
+ */
32
+ export interface StandardizedErrorResponse {
33
+ /** REQUIRED: Always false for errors */
34
+ success: false;
35
+ /** REQUIRED: Standard error code */
36
+ error_code: string;
37
+ /** REQUIRED: Human-readable error message */
38
+ message: string;
39
+ /** REQUIRED: Operation that failed */
40
+ operation: string;
41
+ /** Optional: Additional error details - can be any structure from IDP */
42
+ details?: unknown;
43
+ /** Optional: Validation errors */
44
+ validation_errors?: Record<string, string[]>;
45
+ /** Optional: Server timestamp */
46
+ timestamp?: string;
47
+ /** Optional: Request ID for tracing */
48
+ request_id?: string;
49
+ }
50
+
51
+ /**
52
+ * STANDARDIZED PAGINATED RESPONSE FORMAT
53
+ * For endpoints that return paged data
54
+ */
55
+ export interface StandardizedPagedResponse<TData = unknown> {
56
+ /** REQUIRED: Always true for success */
57
+ success: true;
58
+ /** REQUIRED: Array of data items */
59
+ data: TData[];
60
+ /** REQUIRED: Human-readable success message */
61
+ message: string;
62
+ /** REQUIRED: Unique operation code */
63
+ operation_code: string;
64
+ /** REQUIRED: Pagination metadata */
65
+ pagination: {
66
+ /** Current page number (1-based) */
67
+ current_page: number;
68
+ /** Total number of pages */
69
+ total_pages: number;
70
+ /** Number of items per page */
71
+ page_size: number;
72
+ /** Total number of items across all pages */
73
+ total_items: number;
74
+ /** True if there are more pages after current */
75
+ has_next_page: boolean;
76
+ /** True if there are pages before current */
77
+ has_previous_page: boolean;
78
+ };
79
+ /** Optional: Server timestamp */
80
+ timestamp?: string;
81
+ /** Optional: Request ID for tracing */
82
+ request_id?: string;
83
+ }
84
+
85
+ /**
86
+ * VALIDATION ERROR RESPONSE FORMAT
87
+ * For input validation failures
88
+ */
89
+ export interface StandardizedValidationResponse {
90
+ /** REQUIRED: Always false for validation errors */
91
+ success: false;
92
+ /** REQUIRED: Always 'VALIDATION_ERROR' */
93
+ error_code: 'VALIDATION_ERROR';
94
+ /** REQUIRED: Summary message */
95
+ message: string;
96
+ /** REQUIRED: Operation that failed */
97
+ operation: string;
98
+ /** REQUIRED: Field-specific validation errors */
99
+ payload: {
100
+ /** Field name mapped to array of error messages */
101
+ validation_errors: Record<string, string[]>;
102
+ /** The invalid value that caused the error */
103
+ invalid_value?: unknown;
104
+ /** The field that caused the primary error */
105
+ primary_field?: string;
106
+ };
107
+ }
108
+
109
+ // ========================================================================================
110
+ // RESPONSE TYPE UNION - THE ONLY VALID API RESPONSES
111
+ // ========================================================================================
112
+
113
+ /** ALL POSSIBLE STANDARDIZED RESPONSES */
114
+ export type StandardizedResponse<TData = unknown> =
115
+ | StandardizedApiResponse<TData>
116
+ | StandardizedPagedResponse<TData>
117
+ | StandardizedErrorResponse
118
+ | StandardizedValidationResponse;
119
+
120
+ // ========================================================================================
121
+ // TYPE GUARDS FOR RUNTIME VALIDATION
122
+ // ========================================================================================
123
+
124
+ /**
125
+ * Type guard to check if response is a success response
126
+ * THROWS if response doesn't match standardized format
127
+ */
128
+ export function isSuccessResponse<TData = unknown>(
129
+ response: unknown
130
+ ): response is StandardizedApiResponse<TData> {
131
+ if (!response || typeof response !== 'object') {
132
+ throw new Error('INVALID_API_RESPONSE: Response is not an object');
133
+ }
134
+
135
+ const r = response as any;
136
+
137
+ if (r.success !== true) {
138
+ return false; // This is an error response, not invalid format
139
+ }
140
+
141
+ // SUCCESS RESPONSE VALIDATION - BE STRICT!
142
+ if (!('data' in r)) {
143
+ throw new Error('INVALID_API_RESPONSE: Success response missing required "data" field');
144
+ }
145
+
146
+ if (!('message' in r) || typeof r.message !== 'string') {
147
+ throw new Error('INVALID_API_RESPONSE: Success response missing required "message" field');
148
+ }
149
+
150
+ if (!('operation_code' in r) || typeof r.operation_code !== 'string') {
151
+ throw new Error('INVALID_API_RESPONSE: Success response missing required "operation_code" field');
152
+ }
153
+
154
+ return true;
155
+ }
156
+
157
+ /**
158
+ * Type guard to check if response is a paged success response
159
+ * THROWS if response doesn't match standardized format
160
+ */
161
+ export function isPagedResponse<TData = unknown>(
162
+ response: unknown
163
+ ): response is StandardizedPagedResponse<TData> {
164
+ if (!isSuccessResponse(response)) {
165
+ return false;
166
+ }
167
+
168
+ const r = response as any;
169
+
170
+ // Check if it has pagination metadata
171
+ if (!('pagination' in r) || typeof r.pagination !== 'object') {
172
+ return false;
173
+ }
174
+
175
+ const pagination = r.pagination;
176
+ const requiredPaginationFields = [
177
+ 'current_page', 'total_pages', 'page_size', 'total_items',
178
+ 'has_next_page', 'has_previous_page'
179
+ ];
180
+
181
+ for (const field of requiredPaginationFields) {
182
+ if (!(field in pagination)) {
183
+ throw new Error(`INVALID_API_RESPONSE: Paged response missing required pagination.${field}`);
184
+ }
185
+ }
186
+
187
+ // Ensure data is an array for paged responses
188
+ if (!Array.isArray(r.data)) {
189
+ throw new Error('INVALID_API_RESPONSE: Paged response data must be an array');
190
+ }
191
+
192
+ return true;
193
+ }
194
+
195
+ /**
196
+ * Type guard to check if response is an error response
197
+ * THROWS if response doesn't match standardized format
198
+ */
199
+ export function isErrorResponse(
200
+ response: unknown
201
+ ): response is StandardizedErrorResponse {
202
+ if (!response || typeof response !== 'object') {
203
+ throw new Error('INVALID_API_RESPONSE: Response is not an object');
204
+ }
205
+
206
+ const r = response as any;
207
+
208
+ if (r.success !== false) {
209
+ return false; // This is a success response, not invalid format
210
+ }
211
+
212
+ // ERROR RESPONSE VALIDATION - BE STRICT!
213
+ if (!('error_code' in r) || typeof r.error_code !== 'string') {
214
+ throw new Error('INVALID_API_RESPONSE: Error response missing required "error_code" field');
215
+ }
216
+
217
+ if (!('message' in r) || typeof r.message !== 'string') {
218
+ throw new Error('INVALID_API_RESPONSE: Error response missing required "message" field');
219
+ }
220
+
221
+ if (!('operation' in r) || typeof r.operation !== 'string') {
222
+ throw new Error('INVALID_API_RESPONSE: Error response missing required "operation" field');
223
+ }
224
+
225
+ return true;
226
+ }
227
+
228
+ /**
229
+ * Type guard to check if response is a validation error
230
+ * THROWS if response doesn't match standardized format
231
+ */
232
+ export function isValidationErrorResponse(
233
+ response: unknown
234
+ ): response is StandardizedValidationResponse {
235
+ if (!isErrorResponse(response)) {
236
+ return false;
237
+ }
238
+
239
+ const r = response as any;
240
+
241
+ if (r.error_code !== 'VALIDATION_ERROR') {
242
+ return false;
243
+ }
244
+
245
+ // VALIDATION ERROR RESPONSE VALIDATION - BE STRICT!
246
+ if (!('payload' in r) || typeof r.payload !== 'object') {
247
+ throw new Error('INVALID_API_RESPONSE: Validation error missing required "payload" field');
248
+ }
249
+
250
+ if (!('validation_errors' in r.payload) || typeof r.payload.validation_errors !== 'object') {
251
+ throw new Error('INVALID_API_RESPONSE: Validation error missing required "payload.validation_errors" field');
252
+ }
253
+
254
+ return true;
255
+ }
256
+
257
+ // ========================================================================================
258
+ // RESPONSE VALIDATOR - ENFORCES COMPLIANCE AT RUNTIME
259
+ // ========================================================================================
260
+
261
+ /**
262
+ * VALIDATES AND NORMALIZES API RESPONSES
263
+ * This function BREAKS THE BUILD if responses don't match our standard
264
+ * NO EXCEPTIONS - ZERO TOLERANCE FOR BAD RESPONSES
265
+ */
266
+ export function validateStandardizedResponse<TData = unknown>(
267
+ response: unknown,
268
+ endpoint?: string
269
+ ): StandardizedResponse<TData> {
270
+ const context = endpoint ? ` for endpoint: ${endpoint}` : '';
271
+
272
+ try {
273
+ // First, basic object validation
274
+ if (!response || typeof response !== 'object') {
275
+ throw new Error(`CRITICAL_API_ERROR: Invalid response object${context}`);
276
+ }
277
+
278
+ const r = response as any;
279
+
280
+ // Check for success field (REQUIRED)
281
+ if (!('success' in r) || typeof r.success !== 'boolean') {
282
+ throw new Error(`CRITICAL_API_ERROR: Response missing required boolean "success" field${context}`);
283
+ }
284
+
285
+ // Route to appropriate validator based on success status
286
+ if (r.success === true) {
287
+ // Check if it's a paged response
288
+ if ('pagination' in r) {
289
+ if (isPagedResponse<TData>(response)) {
290
+ return response as StandardizedPagedResponse<TData>;
291
+ }
292
+ } else {
293
+ if (isSuccessResponse<TData>(response)) {
294
+ return response as StandardizedApiResponse<TData>;
295
+ }
296
+ }
297
+ } else if (r.success === false) {
298
+ // Check if it's a validation error
299
+ if (r.error_code === 'VALIDATION_ERROR') {
300
+ if (isValidationErrorResponse(response)) {
301
+ return response as StandardizedValidationResponse;
302
+ }
303
+ } else {
304
+ if (isErrorResponse(response)) {
305
+ return response as StandardizedErrorResponse;
306
+ }
307
+ }
308
+ }
309
+
310
+ // If we reach here, the response format is invalid
311
+ throw new Error(`CRITICAL_API_ERROR: Response format validation failed${context}. Response: ${JSON.stringify(response, null, 2)}`);
312
+
313
+ } catch (error) {
314
+ // Re-throw validation errors with context
315
+ const errorMessage = error instanceof Error ? error.message : 'Unknown validation error';
316
+ throw new Error(`${errorMessage}${context}`);
317
+ }
318
+ }
319
+
320
+ // ========================================================================================
321
+ // CONVENIENCE TYPE EXTRACTORS
322
+ // ========================================================================================
323
+
324
+ /** Extract the data type from a standardized response */
325
+ export type ExtractResponseData<T> = T extends StandardizedApiResponse<infer U>
326
+ ? U
327
+ : T extends StandardizedPagedResponse<infer U>
328
+ ? U[]
329
+ : never;
330
+
331
+ /** Extract the error code from an error response */
332
+ export type ExtractErrorCode<T> = T extends StandardizedErrorResponse
333
+ ? T['error_code']
334
+ : T extends StandardizedValidationResponse
335
+ ? T['error_code']
336
+ : never;