@payez/next-mvp 4.8.1 → 4.8.2

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 (302) hide show
  1. package/POST-INSTALL.md +408 -408
  2. package/README.md +859 -859
  3. package/dist/components/account/MobileNavDrawer.js +18 -18
  4. package/dist/components/account/UserAvatarMenu.js +1 -1
  5. package/dist/components/admin/AlertSettingsTab.js +40 -40
  6. package/dist/components/admin/LoggingSettingsTab.js +28 -28
  7. package/dist/lib/session-store.js +21 -21
  8. package/dist/lib/startup-init.js +19 -19
  9. package/dist/pages/login/page.js +28 -28
  10. package/dist/pages/settings/EnhancedSettingsPage.js +17 -17
  11. package/dist/vibe/sessions.js +28 -3
  12. package/package.json +2 -2
  13. package/scripts/check-publish-eol.mjs +33 -15
  14. package/src/api/auth-handler.ts +550 -550
  15. package/src/api/index.ts +17 -17
  16. package/src/api-handlers/account/change-password.ts +170 -170
  17. package/src/api-handlers/account/masked-info.ts +46 -46
  18. package/src/api-handlers/account/profile.ts +99 -99
  19. package/src/api-handlers/account/recovery/forward.ts +117 -117
  20. package/src/api-handlers/account/recovery/initiate.ts +59 -59
  21. package/src/api-handlers/account/recovery/send-code.ts +21 -21
  22. package/src/api-handlers/account/recovery/verify-code.ts +20 -20
  23. package/src/api-handlers/account/reset-password.ts +87 -87
  24. package/src/api-handlers/account/send-code.ts +70 -70
  25. package/src/api-handlers/account/update-phone.ts +84 -84
  26. package/src/api-handlers/account/validate-password.ts +139 -139
  27. package/src/api-handlers/account/verify-email.ts +134 -134
  28. package/src/api-handlers/account/verify-sms.ts +134 -134
  29. package/src/api-handlers/admin/analytics.ts +452 -452
  30. package/src/api-handlers/admin/audit.ts +232 -232
  31. package/src/api-handlers/admin/index.ts +63 -63
  32. package/src/api-handlers/admin/redis-sessions.ts +259 -259
  33. package/src/api-handlers/admin/sessions.ts +327 -327
  34. package/src/api-handlers/admin/site-logs.ts +388 -388
  35. package/src/api-handlers/admin/stats.ts +260 -260
  36. package/src/api-handlers/admin/users.ts +251 -251
  37. package/src/api-handlers/admin/vibe-data.ts +333 -333
  38. package/src/api-handlers/anon/preferences.ts +123 -123
  39. package/src/api-handlers/auth/credential-login-email-code.ts +92 -92
  40. package/src/api-handlers/auth/credential-login.ts +948 -948
  41. package/src/api-handlers/auth/jwks.ts +31 -31
  42. package/src/api-handlers/auth/login.ts +252 -252
  43. package/src/api-handlers/auth/passkey-signin.ts +116 -116
  44. package/src/api-handlers/auth/refresh.ts +829 -829
  45. package/src/api-handlers/auth/signout.ts +201 -201
  46. package/src/api-handlers/auth/status.ts +23 -23
  47. package/src/api-handlers/auth/update-session.ts +144 -144
  48. package/src/api-handlers/auth/validate.ts +45 -45
  49. package/src/api-handlers/auth/verify-code.ts +116 -116
  50. package/src/api-handlers/mfa/backup-code-verify.ts +170 -170
  51. package/src/api-handlers/mfa/backup-codes.ts +42 -42
  52. package/src/api-handlers/mfa/methods.ts +47 -47
  53. package/src/api-handlers/mfa/totp-confirm.ts +43 -43
  54. package/src/api-handlers/mfa/totp-enroll.ts +43 -43
  55. package/src/api-handlers/mfa/totp-verify.ts +172 -172
  56. package/src/api-handlers/oauth/resume.ts +182 -182
  57. package/src/api-handlers/onboarding/send-email-code.ts +18 -18
  58. package/src/api-handlers/onboarding/set-password.ts +21 -21
  59. package/src/api-handlers/onboarding/verify-code.ts +20 -20
  60. package/src/api-handlers/onboarding/verify-welcome-email.ts +17 -17
  61. package/src/api-handlers/passkeys/list.ts +32 -32
  62. package/src/api-handlers/passkeys/manage.ts +55 -55
  63. package/src/api-handlers/passkeys/register-options.ts +43 -43
  64. package/src/api-handlers/passkeys/register-verify.ts +42 -42
  65. package/src/api-handlers/session/refresh-viability.ts +56 -56
  66. package/src/api-handlers/session/viability.ts +238 -238
  67. package/src/api-handlers/test/force-expire.ts +167 -167
  68. package/src/auth/auth-decision.ts +292 -292
  69. package/src/auth/better-auth.ts +1688 -1688
  70. package/src/auth/idp-oauth.ts +310 -310
  71. package/src/auth/password-reset-bridge.ts +98 -98
  72. package/src/auth/revocation-fields.ts +16 -16
  73. package/src/auth/route-config.ts +236 -236
  74. package/src/auth/safe-callback.ts +199 -199
  75. package/src/auth/session-cookie-clear.ts +30 -30
  76. package/src/auth/session-reset-link.ts +159 -159
  77. package/src/auth/session-response-sanitizer.ts +151 -151
  78. package/src/auth/types/auth-types.ts +555 -555
  79. package/src/auth/types/index.ts +7 -7
  80. package/src/auth/unauthenticated-routes.ts +2 -2
  81. package/src/auth/utils/idp-client.ts +364 -364
  82. package/src/auth/utils/index.ts +6 -6
  83. package/src/auth/utils/token-utils.ts +243 -243
  84. package/src/client/AuthContext.tsx +192 -192
  85. package/src/client/better-auth-client.ts +70 -70
  86. package/src/client/fetch-with-auth.ts +47 -47
  87. package/src/client/fetchWithSession.ts +21 -21
  88. package/src/client/index.ts +13 -13
  89. package/src/client/useAnonSession.ts +131 -131
  90. package/src/components/SessionSync.tsx +138 -138
  91. package/src/components/SignalRHealthCheck.tsx +131 -131
  92. package/src/components/account/MobileNavDrawer.tsx +305 -305
  93. package/src/components/account/UserAvatarMenu.tsx +277 -277
  94. package/src/components/account/index.ts +13 -13
  95. package/src/components/admin/AlertSettingsTab.tsx +728 -728
  96. package/src/components/admin/AnalyticsTab.tsx +703 -703
  97. package/src/components/admin/DataBrowserTab.tsx +508 -508
  98. package/src/components/admin/LoggingSettingsTab.tsx +665 -665
  99. package/src/components/admin/SessionsTab.tsx +421 -421
  100. package/src/components/admin/StatsTab.tsx +379 -379
  101. package/src/components/admin/VibeAdminContext.tsx +87 -87
  102. package/src/components/admin/VibeAdminLayout.tsx +187 -187
  103. package/src/components/admin/index.ts +59 -59
  104. package/src/components/auth/CredentialSignInForm.tsx +240 -240
  105. package/src/components/auth/FederatedAuthSection.tsx +129 -129
  106. package/src/components/auth/ModeAwareLoginPage.tsx +146 -146
  107. package/src/components/auth/ModeAwareSignupPage.tsx +200 -200
  108. package/src/components/auth/PasswordResetBridge.tsx +30 -30
  109. package/src/components/auth/TraditionalAuthSection.tsx +103 -103
  110. package/src/components/recovery/CompleteStep.tsx +36 -36
  111. package/src/components/recovery/InitiateRecoveryStep.tsx +68 -68
  112. package/src/components/recovery/RequestedStep.tsx +30 -30
  113. package/src/components/recovery/SelectMethodStep.tsx +73 -73
  114. package/src/components/recovery/SetPasswordStep.tsx +118 -118
  115. package/src/components/recovery/VerifyCodeStep.tsx +90 -90
  116. package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -160
  117. package/src/components/reserved/ReservedStatusBox.tsx +118 -118
  118. package/src/components/ui/BetaBadge.tsx +58 -58
  119. package/src/components/ui/Footer.tsx +93 -93
  120. package/src/config/env.ts +55 -55
  121. package/src/config/logger.ts +62 -62
  122. package/src/config/logging-config.ts +82 -82
  123. package/src/config/unauthenticated-routes.ts +19 -19
  124. package/src/config/vibe-log-transport.ts +264 -264
  125. package/src/edge/internal-api-url.ts +65 -65
  126. package/src/edge/middleware.ts +42 -42
  127. package/src/hooks/useAuth.ts +117 -117
  128. package/src/hooks/useAuthSettings.ts +109 -109
  129. package/src/hooks/useAvailableProviders.ts +143 -143
  130. package/src/hooks/usePasswordValidation.ts +127 -127
  131. package/src/hooks/useProfile.ts +82 -82
  132. package/src/hooks/usePublicAuthSettings.ts +171 -171
  133. package/src/hooks/useSessionExpiration.ts +101 -101
  134. package/src/hooks/useViabilitySession.ts +337 -337
  135. package/src/index.ts +64 -64
  136. package/src/lib/anon-session.ts +213 -213
  137. package/src/lib/api-handler.ts +643 -643
  138. package/src/lib/app-slug.ts +228 -228
  139. package/src/lib/authorize-resume.ts +172 -172
  140. package/src/lib/bearer-fetch.ts +31 -31
  141. package/src/lib/client-key.ts +88 -88
  142. package/src/lib/code-step-copy.ts +83 -83
  143. package/src/lib/credential-sign-in-client.ts +101 -101
  144. package/src/lib/demo-mode.ts +18 -18
  145. package/src/lib/device-id.ts +67 -67
  146. package/src/lib/ensure-fresh-access-token.ts +509 -509
  147. package/src/lib/geolocation.ts +265 -265
  148. package/src/lib/idp-client-config.ts +1005 -1005
  149. package/src/lib/idp-fetch.ts +169 -169
  150. package/src/lib/idp-url-guard.ts +37 -37
  151. package/src/lib/internal-api.ts +171 -171
  152. package/src/lib/jwt-decode-client.ts +45 -45
  153. package/src/lib/jwt-decode.ts +82 -82
  154. package/src/lib/lock-window.ts +49 -49
  155. package/src/lib/login-error-message.ts +41 -41
  156. package/src/lib/never-in-response.ts +64 -64
  157. package/src/lib/nextauth-secret.ts +168 -168
  158. package/src/lib/onboarding-proxy.ts +57 -57
  159. package/src/lib/password-rules.ts +50 -50
  160. package/src/lib/rate-limit-service.ts +9 -9
  161. package/src/lib/redis.ts +105 -105
  162. package/src/lib/refresh-token-validator.ts +64 -64
  163. package/src/lib/roles.ts +177 -177
  164. package/src/lib/safe-error-response.ts +149 -149
  165. package/src/lib/secret-validation.ts +8 -8
  166. package/src/lib/session-cookie-shape.ts +185 -185
  167. package/src/lib/session-store.ts +1092 -1092
  168. package/src/lib/session.ts +34 -34
  169. package/src/lib/single-flight.ts +64 -64
  170. package/src/lib/site-logger.ts +245 -245
  171. package/src/lib/standardized-client-api.ts +901 -901
  172. package/src/lib/startup-init.ts +276 -276
  173. package/src/lib/test-aware-get-token.ts +41 -41
  174. package/src/lib/token-expiry.ts +40 -40
  175. package/src/lib/token-lifecycle.ts +546 -546
  176. package/src/lib/token-log-id.ts +69 -69
  177. package/src/lib/twofa-rejection.ts +91 -91
  178. package/src/lib/types/api-responses.ts +336 -336
  179. package/src/lib/user-agent-parser.ts +252 -252
  180. package/src/logging/api/admin-analytics.ts +51 -51
  181. package/src/logging/api/audit-log.ts +53 -53
  182. package/src/logging/components/AdminAnalyticsLayout.tsx +49 -49
  183. package/src/logging/components/AuditLogViewer.tsx +125 -125
  184. package/src/logging/components/ErrorMetricsCard.tsx +98 -98
  185. package/src/logging/components/HealthMetricsCard.tsx +70 -70
  186. package/src/logging/hooks/useAdminAnalytics.ts +22 -22
  187. package/src/logging/hooks/useAuditLog.ts +24 -24
  188. package/src/logging/hooks/useErrorMetrics.ts +40 -40
  189. package/src/logging/hooks/useHealthMetrics.ts +44 -44
  190. package/src/logging/index.ts +18 -18
  191. package/src/logging/types/analytics.ts +81 -81
  192. package/src/logging/types/audit.ts +31 -31
  193. package/src/logging/types/index.ts +3 -3
  194. package/src/middleware/create-middleware.ts +1141 -1141
  195. package/src/middleware/rbac-check.ts +279 -279
  196. package/src/middleware/twofa-presets.ts +224 -224
  197. package/src/models/DecodedAccessToken.ts +16 -16
  198. package/src/models/SessionModel.ts +331 -331
  199. package/src/pages/admin-login/page.tsx +111 -111
  200. package/src/pages/admin-page-permissions/PagePermissionsAdminPage.tsx +527 -527
  201. package/src/pages/admin-page-permissions/index.ts +7 -7
  202. package/src/pages/admin-roles/RolesAdminPage.tsx +533 -533
  203. package/src/pages/admin-roles/index.ts +9 -9
  204. package/src/pages/admin-roles/modals.tsx +469 -469
  205. package/src/pages/client-admin/ClientSiteAdminPage.tsx +382 -382
  206. package/src/pages/client-admin/index.ts +33 -33
  207. package/src/pages/coming-soon/page.tsx +83 -83
  208. package/src/pages/login/page.tsx +338 -338
  209. package/src/pages/onboarding/index.ts +11 -11
  210. package/src/pages/onboarding/page.tsx +212 -212
  211. package/src/pages/profile/EnhancedProfilePage.tsx +514 -514
  212. package/src/pages/profile/index.ts +9 -9
  213. package/src/pages/profile/page.tsx +166 -166
  214. package/src/pages/recovery/page.tsx +267 -267
  215. package/src/pages/roles/MyRolesPage.tsx +211 -211
  216. package/src/pages/roles/components.tsx +294 -294
  217. package/src/pages/roles/index.ts +17 -17
  218. package/src/pages/security/EnhancedSecurityPage.tsx +660 -660
  219. package/src/pages/security/index.ts +12 -12
  220. package/src/pages/security/page.tsx +507 -507
  221. package/src/pages/service-unavailable/page.tsx +63 -63
  222. package/src/pages/settings/EnhancedSettingsPage.tsx +642 -642
  223. package/src/pages/settings/index.ts +9 -9
  224. package/src/pages/settings/page.tsx +47 -47
  225. package/src/pages/showcase/ShowcasePage.tsx +532 -532
  226. package/src/pages/showcase/index.ts +13 -13
  227. package/src/pages/test-env/EmergencyLogoutPage.tsx +192 -192
  228. package/src/pages/test-env/JwtInspectPage.tsx +449 -449
  229. package/src/pages/test-env/RefreshTokenPage.tsx +178 -178
  230. package/src/pages/test-env/TestEnvPage.tsx +130 -130
  231. package/src/pages/test-env/guarded.tsx +81 -81
  232. package/src/pages/test-env/index.ts +77 -77
  233. package/src/pages/test-env/redact-credentials.ts +96 -96
  234. package/src/pages/verify-code/page.tsx +746 -746
  235. package/src/routes/account/index.ts +31 -31
  236. package/src/routes/account/masked-info.ts +36 -36
  237. package/src/routes/account/send-code.ts +39 -39
  238. package/src/routes/account/update-phone.ts +13 -13
  239. package/src/routes/account/verify-email.ts +40 -40
  240. package/src/routes/account/verify-sms.ts +40 -40
  241. package/src/routes/auth/credential-login-email-code.ts +6 -6
  242. package/src/routes/auth/credential-login.ts +6 -6
  243. package/src/routes/auth/index.ts +22 -22
  244. package/src/routes/auth/logout.ts +111 -111
  245. package/src/routes/auth/nextauth.ts +45 -45
  246. package/src/routes/auth/passkey-signin.ts +13 -13
  247. package/src/routes/auth/refresh.ts +77 -77
  248. package/src/routes/auth/session-reset.ts +37 -37
  249. package/src/routes/auth/session.ts +261 -261
  250. package/src/routes/auth/settings.ts +181 -181
  251. package/src/routes/auth/viability.ts +519 -519
  252. package/src/routes/index.ts +17 -17
  253. package/src/routes/mfa/backup-code-verify.ts +1 -1
  254. package/src/routes/mfa/backup-codes.ts +10 -10
  255. package/src/routes/mfa/methods.ts +22 -22
  256. package/src/routes/mfa/totp-confirm.ts +10 -10
  257. package/src/routes/mfa/totp-enroll.ts +10 -10
  258. package/src/routes/mfa/totp-verify.ts +14 -14
  259. package/src/routes/onboarding/index.ts +15 -15
  260. package/src/routes/onboarding/send-email-code.ts +2 -2
  261. package/src/routes/onboarding/set-password.ts +2 -2
  262. package/src/routes/onboarding/verify-code.ts +2 -2
  263. package/src/routes/onboarding/verify-welcome-email.ts +2 -2
  264. package/src/routes/passkeys/list.ts +10 -10
  265. package/src/routes/passkeys/manage.ts +23 -23
  266. package/src/routes/passkeys/register-options.ts +10 -10
  267. package/src/routes/passkeys/register-verify.ts +10 -10
  268. package/src/routes/session/index.ts +7 -7
  269. package/src/routes/session/refresh-viability.ts +17 -17
  270. package/src/server/auth-guard.ts +203 -203
  271. package/src/server/auth.ts +486 -486
  272. package/src/server/decode-session.ts +309 -309
  273. package/src/server/slim-middleware.ts +117 -117
  274. package/src/server/verified-session-token.ts +103 -103
  275. package/src/server/with-auth.ts +93 -93
  276. package/src/services/signalrActivityService.ts +258 -258
  277. package/src/stores/authStore.ts +1900 -1900
  278. package/src/templates/instrumentation.ts +60 -60
  279. package/src/theme/ThemeProvider.tsx +39 -39
  280. package/src/theme/default.ts +33 -33
  281. package/src/theme/index.ts +31 -31
  282. package/src/theme/types.ts +69 -69
  283. package/src/theme/useTheme.ts +57 -57
  284. package/src/theme/utils.ts +40 -40
  285. package/src/types/api.ts +12 -12
  286. package/src/types/auth.d.ts +23 -23
  287. package/src/types/auth.ts +48 -48
  288. package/src/types/logging.ts +11 -11
  289. package/src/types/recovery.ts +54 -54
  290. package/src/utils/api.ts +401 -401
  291. package/src/utils/circuitBreaker.ts +40 -40
  292. package/src/utils/error-message.ts +108 -108
  293. package/src/utils/layout/reservedSpace.ts +124 -124
  294. package/src/utils/logout.ts +30 -30
  295. package/src/vibe/client.ts +877 -877
  296. package/src/vibe/enterprise-auth.ts +208 -208
  297. package/src/vibe/errors.ts +209 -209
  298. package/src/vibe/generic.ts +339 -339
  299. package/src/vibe/hooks/index.ts +367 -367
  300. package/src/vibe/index.ts +133 -133
  301. package/src/vibe/sessions.ts +925 -899
  302. 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;