@djangocfg/api 2.1.226 → 2.1.228

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 (56) hide show
  1. package/README.md +8 -9
  2. package/dist/auth-server.cjs +4 -9
  3. package/dist/auth-server.cjs.map +1 -1
  4. package/dist/auth-server.mjs +4 -9
  5. package/dist/auth-server.mjs.map +1 -1
  6. package/dist/auth.cjs +120 -158
  7. package/dist/auth.cjs.map +1 -1
  8. package/dist/auth.d.cts +120 -177
  9. package/dist/auth.d.ts +120 -177
  10. package/dist/auth.mjs +149 -191
  11. package/dist/auth.mjs.map +1 -1
  12. package/dist/clients.cjs +5 -11
  13. package/dist/clients.cjs.map +1 -1
  14. package/dist/clients.d.cts +218 -219
  15. package/dist/clients.d.ts +218 -219
  16. package/dist/clients.mjs +5 -11
  17. package/dist/clients.mjs.map +1 -1
  18. package/dist/hooks.cjs +4 -9
  19. package/dist/hooks.cjs.map +1 -1
  20. package/dist/hooks.d.cts +70 -91
  21. package/dist/hooks.d.ts +70 -91
  22. package/dist/hooks.mjs +4 -9
  23. package/dist/hooks.mjs.map +1 -1
  24. package/dist/index.cjs +5 -11
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +116 -106
  27. package/dist/index.d.ts +116 -106
  28. package/dist/index.mjs +5 -11
  29. package/dist/index.mjs.map +1 -1
  30. package/package.json +2 -2
  31. package/src/_api/generated/cfg_accounts/_utils/schemas/OTPErrorResponse.schema.ts +24 -2
  32. package/src/_api/generated/cfg_accounts/_utils/schemas/OTPRequestRequest.schema.ts +0 -2
  33. package/src/_api/generated/cfg_accounts/_utils/schemas/OTPVerifyRequest.schema.ts +0 -2
  34. package/src/_api/generated/cfg_accounts/accounts/client.ts +1 -1
  35. package/src/_api/generated/cfg_accounts/accounts/models.ts +25 -26
  36. package/src/_api/generated/cfg_accounts/accounts__auth/models.ts +5 -5
  37. package/src/_api/generated/cfg_accounts/accounts__oauth/models.ts +42 -42
  38. package/src/_api/generated/cfg_accounts/accounts__user_profile/models.ts +23 -23
  39. package/src/_api/generated/cfg_accounts/enums.ts +0 -10
  40. package/src/_api/generated/cfg_accounts/schema.json +31 -25
  41. package/src/_api/generated/cfg_centrifugo/centrifugo__centrifugo_admin_api/models.ts +57 -57
  42. package/src/_api/generated/cfg_centrifugo/centrifugo__centrifugo_monitoring/models.ts +24 -24
  43. package/src/_api/generated/cfg_centrifugo/centrifugo__centrifugo_testing/models.ts +14 -14
  44. package/src/_api/generated/cfg_totp/totp__backup_codes/models.ts +14 -14
  45. package/src/_api/generated/cfg_totp/totp__totp_setup/models.ts +10 -10
  46. package/src/_api/generated/cfg_totp/totp__totp_verification/models.ts +8 -8
  47. package/src/auth/context/AccountsContext.tsx +6 -2
  48. package/src/auth/context/AuthContext.tsx +32 -39
  49. package/src/auth/context/types.ts +5 -9
  50. package/src/auth/hooks/index.ts +1 -1
  51. package/src/auth/hooks/useAuthForm.ts +42 -75
  52. package/src/auth/hooks/useAuthFormState.ts +35 -6
  53. package/src/auth/hooks/useAuthValidation.ts +5 -65
  54. package/src/auth/hooks/useTwoFactor.ts +17 -2
  55. package/src/auth/types/form.ts +25 -70
  56. package/src/auth/types/index.ts +2 -6
@@ -1,15 +1,5 @@
1
1
  // @ts-nocheck
2
2
  // Auto-generated by DjangoCFG - see CLAUDE.md
3
- /**
4
- * Channel history response.
5
- *
6
- * Response model (includes read-only fields).
7
- */
8
- export interface CentrifugoHistoryResponse {
9
- error?: CentrifugoError | null;
10
- result?: CentrifugoHistoryResult | null;
11
- }
12
-
13
3
  /**
14
4
  * Channel presence response.
15
5
  *
@@ -20,16 +10,6 @@ export interface CentrifugoPresenceResponse {
20
10
  result?: CentrifugoPresenceResult | null;
21
11
  }
22
12
 
23
- /**
24
- * Server info response.
25
- *
26
- * Response model (includes read-only fields).
27
- */
28
- export interface CentrifugoInfoResponse {
29
- error?: CentrifugoError | null;
30
- result?: CentrifugoInfoResult | null;
31
- }
32
-
33
13
  /**
34
14
  * Request to get channel presence.
35
15
  *
@@ -41,13 +21,23 @@ export interface CentrifugoPresenceRequestRequest {
41
21
  }
42
22
 
43
23
  /**
44
- * List of active channels response.
24
+ * Channel history response.
45
25
  *
46
26
  * Response model (includes read-only fields).
47
27
  */
48
- export interface CentrifugoChannelsResponse {
28
+ export interface CentrifugoHistoryResponse {
49
29
  error?: CentrifugoError | null;
50
- result?: CentrifugoChannelsResult | null;
30
+ result?: CentrifugoHistoryResult | null;
31
+ }
32
+
33
+ /**
34
+ * Server info response.
35
+ *
36
+ * Response model (includes read-only fields).
37
+ */
38
+ export interface CentrifugoInfoResponse {
39
+ error?: CentrifugoError | null;
40
+ result?: CentrifugoInfoResult | null;
51
41
  }
52
42
 
53
43
  /**
@@ -86,27 +76,23 @@ export interface CentrifugoChannelsRequestRequest {
86
76
  }
87
77
 
88
78
  /**
89
- * Channel presence stats response.
79
+ * List of active channels response.
90
80
  *
91
81
  * Response model (includes read-only fields).
92
82
  */
93
- export interface CentrifugoPresenceStatsResponse {
83
+ export interface CentrifugoChannelsResponse {
94
84
  error?: CentrifugoError | null;
95
- result?: CentrifugoPresenceStatsResult | null;
85
+ result?: CentrifugoChannelsResult | null;
96
86
  }
97
87
 
98
88
  /**
99
- * History result wrapper.
89
+ * Channel presence stats response.
100
90
  *
101
91
  * Response model (includes read-only fields).
102
92
  */
103
- export interface CentrifugoHistoryResult {
104
- /** List of publications */
105
- publications: Array<CentrifugoPublication>;
106
- /** Current stream epoch */
107
- epoch: string;
108
- /** Latest stream offset */
109
- offset: number;
93
+ export interface CentrifugoPresenceStatsResponse {
94
+ error?: CentrifugoError | null;
95
+ result?: CentrifugoPresenceStatsResult | null;
110
96
  }
111
97
 
112
98
  /**
@@ -132,23 +118,27 @@ export interface CentrifugoPresenceResult {
132
118
  }
133
119
 
134
120
  /**
135
- * Info result wrapper.
121
+ * History result wrapper.
136
122
  *
137
123
  * Response model (includes read-only fields).
138
124
  */
139
- export interface CentrifugoInfoResult {
140
- /** List of Centrifugo nodes */
141
- nodes: Array<CentrifugoNodeInfo>;
125
+ export interface CentrifugoHistoryResult {
126
+ /** List of publications */
127
+ publications: Array<CentrifugoPublication>;
128
+ /** Current stream epoch */
129
+ epoch: string;
130
+ /** Latest stream offset */
131
+ offset: number;
142
132
  }
143
133
 
144
134
  /**
145
- * Channels result wrapper.
135
+ * Info result wrapper.
146
136
  *
147
137
  * Response model (includes read-only fields).
148
138
  */
149
- export interface CentrifugoChannelsResult {
150
- /** Map of channel names to channel info */
151
- channels: Record<string, CentrifugoChannelInfo>;
139
+ export interface CentrifugoInfoResult {
140
+ /** List of Centrifugo nodes */
141
+ nodes: Array<CentrifugoNodeInfo>;
152
142
  }
153
143
 
154
144
  /**
@@ -164,30 +154,25 @@ export interface CentrifugoStreamPosition {
164
154
  }
165
155
 
166
156
  /**
167
- * Presence stats result.
157
+ * Channels result wrapper.
168
158
  *
169
159
  * Response model (includes read-only fields).
170
160
  */
171
- export interface CentrifugoPresenceStatsResult {
172
- /** Number of connected clients */
173
- num_clients: number;
174
- /** Number of unique users */
175
- num_users: number;
161
+ export interface CentrifugoChannelsResult {
162
+ /** Map of channel names to channel info */
163
+ channels: Record<string, CentrifugoChannelInfo>;
176
164
  }
177
165
 
178
166
  /**
179
- * Single publication (message) in channel history.
167
+ * Presence stats result.
180
168
  *
181
169
  * Response model (includes read-only fields).
182
170
  */
183
- export interface CentrifugoPublication {
184
- /** Message payload */
185
- data: Record<string, any>;
186
- info?: CentrifugoClientInfo | null;
187
- /** Message offset in channel stream */
188
- offset: number;
189
- /** Optional message tags */
190
- tags?: Record<string, any> | null;
171
+ export interface CentrifugoPresenceStatsResult {
172
+ /** Number of connected clients */
173
+ num_clients: number;
174
+ /** Number of unique users */
175
+ num_users: number;
191
176
  }
192
177
 
193
178
  /**
@@ -206,6 +191,21 @@ export interface CentrifugoClientInfo {
206
191
  chan_info?: Record<string, any> | null;
207
192
  }
208
193
 
194
+ /**
195
+ * Single publication (message) in channel history.
196
+ *
197
+ * Response model (includes read-only fields).
198
+ */
199
+ export interface CentrifugoPublication {
200
+ /** Message payload */
201
+ data: Record<string, any>;
202
+ info?: CentrifugoClientInfo | null;
203
+ /** Message offset in channel stream */
204
+ offset: number;
205
+ /** Optional message tags */
206
+ tags?: Record<string, any> | null;
207
+ }
208
+
209
209
  /**
210
210
  * Information about a single Centrifugo node.
211
211
  *
@@ -37,15 +37,27 @@ export interface PaginatedPublishList {
37
37
  }
38
38
 
39
39
  /**
40
- * List of channel statistics.
40
+ * Overview statistics for Centrifugo publishes.
41
41
  *
42
42
  * Response model (includes read-only fields).
43
43
  */
44
- export interface ChannelList {
45
- /** Channel statistics */
46
- channels: Array<ChannelStats>;
47
- /** Total number of channels */
48
- total_channels: number;
44
+ export interface CentrifugoOverviewStats {
45
+ /** Total publishes in period */
46
+ total: number;
47
+ /** Successful publishes */
48
+ successful: number;
49
+ /** Failed publishes */
50
+ failed: number;
51
+ /** Timeout publishes */
52
+ timeout: number;
53
+ /** Success rate percentage */
54
+ success_rate: number;
55
+ /** Average duration in milliseconds */
56
+ avg_duration_ms: number;
57
+ /** Average ACKs received */
58
+ avg_acks_received: number;
59
+ /** Statistics period in hours */
60
+ period_hours: number;
49
61
  }
50
62
 
51
63
  /**
@@ -65,27 +77,15 @@ export interface CentrifugoHealthCheck {
65
77
  }
66
78
 
67
79
  /**
68
- * Overview statistics for Centrifugo publishes.
80
+ * List of channel statistics.
69
81
  *
70
82
  * Response model (includes read-only fields).
71
83
  */
72
- export interface CentrifugoOverviewStats {
73
- /** Total publishes in period */
74
- total: number;
75
- /** Successful publishes */
76
- successful: number;
77
- /** Failed publishes */
78
- failed: number;
79
- /** Timeout publishes */
80
- timeout: number;
81
- /** Success rate percentage */
82
- success_rate: number;
83
- /** Average duration in milliseconds */
84
- avg_duration_ms: number;
85
- /** Average ACKs received */
86
- avg_acks_received: number;
87
- /** Statistics period in hours */
88
- period_hours: number;
84
+ export interface ChannelList {
85
+ /** Channel statistics */
86
+ channels: Array<ChannelStats>;
87
+ /** Total number of channels */
88
+ total_channels: number;
89
89
  }
90
90
 
91
91
  /**
@@ -1,19 +1,5 @@
1
1
  // @ts-nocheck
2
2
  // Auto-generated by DjangoCFG - see CLAUDE.md
3
- /**
4
- * Response model for manual ACK.
5
- *
6
- * Response model (includes read-only fields).
7
- */
8
- export interface ManualAckResponse {
9
- /** Whether ACK was sent successfully */
10
- success: boolean;
11
- /** Message ID that was acknowledged */
12
- message_id: string;
13
- /** Error message if failed */
14
- error?: string | null;
15
- }
16
-
17
3
  /**
18
4
  * Request model for test message publishing.
19
5
  *
@@ -50,6 +36,20 @@ export interface PublishTestResponse {
50
36
  error?: string | null;
51
37
  }
52
38
 
39
+ /**
40
+ * Response model for manual ACK.
41
+ *
42
+ * Response model (includes read-only fields).
43
+ */
44
+ export interface ManualAckResponse {
45
+ /** Whether ACK was sent successfully */
46
+ success: boolean;
47
+ /** Message ID that was acknowledged */
48
+ message_id: string;
49
+ /** Error message if failed */
50
+ error?: string | null;
51
+ }
52
+
53
53
  /**
54
54
  * Request model for manual ACK sending.
55
55
  *
@@ -1,19 +1,5 @@
1
1
  // @ts-nocheck
2
2
  // Auto-generated by DjangoCFG - see CLAUDE.md
3
- /**
4
- * Serializer for backup codes status.
5
- *
6
- * Response model (includes read-only fields).
7
- */
8
- export interface BackupCodesStatus {
9
- /** Number of unused backup codes */
10
- remaining_count: number;
11
- /** Total number of codes generated */
12
- total_generated: number;
13
- /** Warning if running low on codes */
14
- warning?: string | null;
15
- }
16
-
17
3
  /**
18
4
  * Serializer for regenerating backup codes.
19
5
  *
@@ -36,3 +22,17 @@ export interface BackupCodesRegenerateResponse {
36
22
  warning: string;
37
23
  }
38
24
 
25
+ /**
26
+ * Serializer for backup codes status.
27
+ *
28
+ * Response model (includes read-only fields).
29
+ */
30
+ export interface BackupCodesStatus {
31
+ /** Number of unused backup codes */
32
+ remaining_count: number;
33
+ /** Total number of codes generated */
34
+ total_generated: number;
35
+ /** Warning if running low on codes */
36
+ warning?: string | null;
37
+ }
38
+
@@ -32,24 +32,24 @@ export interface SetupResponse {
32
32
  }
33
33
 
34
34
  /**
35
- * Serializer for confirming 2FA setup with first code.
35
+ * Serializer for starting 2FA setup.
36
36
  *
37
37
  * Request model (no read-only fields).
38
38
  */
39
- export interface ConfirmSetupRequest {
40
- /** Device ID from setup response */
41
- device_id: string;
42
- /** 6-digit TOTP code from authenticator app */
43
- code: string;
39
+ export interface SetupRequest {
40
+ /** Device name for identification (e.g., 'My iPhone') */
41
+ device_name?: string;
44
42
  }
45
43
 
46
44
  /**
47
- * Serializer for starting 2FA setup.
45
+ * Serializer for confirming 2FA setup with first code.
48
46
  *
49
47
  * Request model (no read-only fields).
50
48
  */
51
- export interface SetupRequest {
52
- /** Device name for identification (e.g., 'My iPhone') */
53
- device_name?: string;
49
+ export interface ConfirmSetupRequest {
50
+ /** Device ID from setup response */
51
+ device_id: string;
52
+ /** 6-digit TOTP code from authenticator app */
53
+ code: string;
54
54
  }
55
55
 
@@ -1,15 +1,15 @@
1
1
  // @ts-nocheck
2
2
  // Auto-generated by DjangoCFG - see CLAUDE.md
3
3
  /**
4
- * Serializer for TOTP code verification during login.
4
+ * Serializer for backup code verification during login.
5
5
  *
6
6
  * Request model (no read-only fields).
7
7
  */
8
- export interface VerifyRequest {
8
+ export interface VerifyBackupRequest {
9
9
  /** 2FA session ID from login response */
10
10
  session_id: string;
11
- /** 6-digit TOTP code from authenticator app */
12
- code: string;
11
+ /** 8-character backup recovery code */
12
+ backup_code: string;
13
13
  }
14
14
 
15
15
  /**
@@ -31,15 +31,15 @@ export interface VerifyResponse {
31
31
  }
32
32
 
33
33
  /**
34
- * Serializer for backup code verification during login.
34
+ * Serializer for TOTP code verification during login.
35
35
  *
36
36
  * Request model (no read-only fields).
37
37
  */
38
- export interface VerifyBackupRequest {
38
+ export interface VerifyRequest {
39
39
  /** 2FA session ID from login response */
40
40
  session_id: string;
41
- /** 8-character backup recovery code */
42
- backup_code: string;
41
+ /** 6-digit TOTP code from authenticator app */
42
+ code: string;
43
43
  }
44
44
 
45
45
  /**
@@ -186,8 +186,12 @@ export function AccountsProvider({ children }: AccountsProviderProps) {
186
186
  // Normal flow - save tokens after successful verification
187
187
  if (result.access && result.refresh) {
188
188
  apiAccounts.setToken(result.access, result.refresh);
189
- // Refresh profile to load user data with new token
190
- await refreshProfile({ callerId: 'verifyOTP', force: true });
189
+ // Refresh profile don't let profile fetch error kill the whole verification
190
+ try {
191
+ await refreshProfile({ callerId: 'verifyOTP', force: true });
192
+ } catch (profileError) {
193
+ authLogger.warn('Profile refresh failed after OTP verify (tokens are saved):', profileError);
194
+ }
191
195
  }
192
196
 
193
197
  return result as OTPVerifyResponse;
@@ -9,7 +9,8 @@ import { SWRConfig } from 'swr';
9
9
 
10
10
  import { useCfgRouter, useLocalStorage, useQueryParams } from '../hooks';
11
11
 
12
- import { api as apiAccounts, Enums } from '../../';
12
+ import { api as apiAccounts } from '../../';
13
+ import { APIError } from '../../_api/generated/cfg_accounts/errors';
13
14
  import { clearProfileCache, getCachedProfile } from '../hooks/useProfileCache';
14
15
  import { useAuthRedirectManager } from '../hooks/useAuthRedirect';
15
16
  import { useTokenRefresh } from '../hooks/useTokenRefresh';
@@ -30,7 +31,6 @@ const AuthContext = createContext<AuthContextType | undefined>(undefined);
30
31
 
31
32
  // Constants
32
33
  const EMAIL_STORAGE_KEY = 'auth_email';
33
- const PHONE_STORAGE_KEY = 'auth_phone';
34
34
 
35
35
  const hasValidTokens = (): boolean => {
36
36
  if (typeof window === 'undefined') return false;
@@ -63,9 +63,8 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
63
63
  const pathname = usePathname();
64
64
  const queryParams = useQueryParams();
65
65
 
66
- // Use localStorage hooks for email and phone
66
+ // Use localStorage hook for email
67
67
  const [storedEmail, setStoredEmail, clearStoredEmail] = useLocalStorage<string | null>(EMAIL_STORAGE_KEY, null);
68
- const [storedPhone, setStoredPhone, clearStoredPhone] = useLocalStorage<string | null>(PHONE_STORAGE_KEY, null);
69
68
 
70
69
  // Automatic token refresh - refreshes token before expiry, on focus, and on network reconnect
71
70
  useTokenRefresh({
@@ -350,35 +349,43 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
350
349
  }
351
350
  }, [loadCurrentProfile, clearAuthState, pushToDefaultCallbackUrl, pushToDefaultAuthCallbackUrl, handleGlobalAuthError]);
352
351
 
353
- // OTP methods - supports both email and phone - now uses AccountsContext
352
+ // OTP methods - email only - now uses AccountsContext
354
353
  const requestOTP = useCallback(
355
- async (identifier: string, channel?: 'email' | 'phone', sourceUrl?: string): Promise<{ success: boolean; message: string }> => {
354
+ async (identifier: string, sourceUrl?: string): Promise<{ success: boolean; message: string; statusCode?: number; retryAfter?: number }> => {
356
355
  // Clear tokens before requesting OTP
357
356
  apiAccounts.clearTokens();
358
357
 
359
358
  try {
360
- const channelValue = channel === 'phone'
361
- ? Enums.OTPRequestRequestChannel.PHONE
362
- : Enums.OTPRequestRequestChannel.EMAIL;
363
359
  const result = await accounts.requestOTP({
364
360
  identifier,
365
- channel: channelValue,
361
+ source_url: sourceUrl,
366
362
  });
367
363
 
368
- const channelName = channel === 'phone' ? 'phone number' : 'email address';
369
-
370
364
  // Track OTP request
371
365
  Analytics.event(AnalyticsEvent.AUTH_OTP_REQUEST, {
372
366
  category: AnalyticsCategory.AUTH,
373
- label: channel || 'email',
367
+ label: 'email',
374
368
  });
375
369
 
376
370
  return {
377
371
  success: true,
378
- message: result.message || `OTP code sent to your ${channelName}`,
372
+ message: result.message || `OTP code sent to your email address`,
379
373
  };
380
374
  } catch (error) {
381
375
  authLogger.error('Request OTP error:', error);
376
+
377
+ if (error instanceof APIError) {
378
+ const retryAfter = error.response?.retry_after ?? error.response?.retryAfter;
379
+ // Django returns { error, error_code, retry_after } — errorMessage reads 'detail'/'message' only
380
+ const message = error.response?.error || error.response?.detail || error.response?.message || error.errorMessage;
381
+ return {
382
+ success: false,
383
+ statusCode: error.statusCode,
384
+ message,
385
+ retryAfter: typeof retryAfter === 'number' ? retryAfter : undefined,
386
+ };
387
+ }
388
+
382
389
  return {
383
390
  success: false,
384
391
  message: 'Failed to send OTP',
@@ -389,7 +396,7 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
389
396
  );
390
397
 
391
398
  const verifyOTP = useCallback(
392
- async (identifier: string, otpCode: string, channel?: 'email' | 'phone', sourceUrl?: string, redirectUrl?: string, skipRedirect?: boolean): Promise<{
399
+ async (identifier: string, otpCode: string, sourceUrl?: string, redirectUrl?: string, skipRedirect?: boolean): Promise<{
393
400
  success: boolean;
394
401
  message: string;
395
402
  user?: UserProfile;
@@ -398,14 +405,11 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
398
405
  should_prompt_2fa?: boolean;
399
406
  }> => {
400
407
  try {
401
- const channelValue = channel === 'phone'
402
- ? Enums.OTPRequestRequestChannel.PHONE
403
- : Enums.OTPRequestRequestChannel.EMAIL;
404
408
  // AccountsContext automatically saves tokens and refreshes profile
405
409
  const result = await accounts.verifyOTP({
406
410
  identifier,
407
411
  otp: otpCode,
408
- channel: channelValue,
412
+ source_url: sourceUrl,
409
413
  });
410
414
 
411
415
  // Check if 2FA is required - return early with session info
@@ -429,13 +433,9 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
429
433
  };
430
434
  }
431
435
 
432
- // Save identifier based on channel and clear opposite channel
433
- if (channel === 'phone') {
434
- setStoredPhone(identifier);
435
- clearStoredEmail();
436
- } else if (identifier.includes('@')) {
436
+ // Save email identifier
437
+ if (identifier.includes('@')) {
437
438
  setStoredEmail(identifier);
438
- clearStoredPhone();
439
439
  }
440
440
 
441
441
  // Small delay to ensure profile state is updated
@@ -444,7 +444,7 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
444
444
  // Track successful login
445
445
  Analytics.event(AnalyticsEvent.AUTH_LOGIN_SUCCESS, {
446
446
  category: AnalyticsCategory.AUTH,
447
- label: channel || 'email',
447
+ label: 'email',
448
448
  });
449
449
 
450
450
  // Set user ID for future tracking
@@ -474,16 +474,20 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
474
474
  // Track failed verification
475
475
  Analytics.event(AnalyticsEvent.AUTH_OTP_VERIFY_FAIL, {
476
476
  category: AnalyticsCategory.AUTH,
477
- label: channel || 'email',
477
+ label: 'email',
478
478
  });
479
479
 
480
+ if (error instanceof APIError) {
481
+ const message = error.response?.error || error.response?.detail || error.response?.message || error.errorMessage;
482
+ return { success: false, message };
483
+ }
480
484
  return {
481
485
  success: false,
482
486
  message: 'Failed to verify OTP',
483
487
  };
484
488
  }
485
489
  },
486
- [setStoredEmail, setStoredPhone, clearStoredEmail, clearStoredPhone, config?.routes?.defaultCallback, accounts, router],
490
+ [setStoredEmail, config?.routes?.defaultCallback, accounts, router],
487
491
  );
488
492
 
489
493
  const refreshToken = useCallback(async (): Promise<{ success: boolean; message: string }> => {
@@ -584,9 +588,6 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
584
588
  getSavedEmail: () => storedEmail,
585
589
  saveEmail: setStoredEmail,
586
590
  clearSavedEmail: clearStoredEmail,
587
- getSavedPhone: () => storedPhone,
588
- savePhone: setStoredPhone,
589
- clearSavedPhone: clearStoredPhone,
590
591
  requestOTP,
591
592
  verifyOTP,
592
593
  refreshToken,
@@ -609,9 +610,6 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
609
610
  storedEmail,
610
611
  setStoredEmail,
611
612
  clearStoredEmail,
612
- storedPhone,
613
- setStoredPhone,
614
- clearStoredPhone,
615
613
  requestOTP,
616
614
  verifyOTP,
617
615
  refreshToken,
@@ -662,11 +660,6 @@ const defaultAuthState: AuthContextType = {
662
660
  authLogger.warn('useAuth: saveEmail called outside AuthProvider');
663
661
  },
664
662
  clearSavedEmail: () => {},
665
- getSavedPhone: () => null,
666
- savePhone: () => {
667
- authLogger.warn('useAuth: savePhone called outside AuthProvider');
668
- },
669
- clearSavedPhone: () => {},
670
663
  requestOTP: async () => {
671
664
  authLogger.warn('useAuth: requestOTP called outside AuthProvider');
672
665
  return { success: false, message: 'AuthProvider not available' };
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  import type { User } from '../../';
4
+ import type { OTPRequestResult } from '../types';
4
5
 
5
6
  // User profile type
6
7
  export type UserProfile = User;
@@ -34,14 +35,9 @@ export interface AuthContextType {
34
35
  saveEmail: (email: string) => void;
35
36
  clearSavedEmail: () => void;
36
37
 
37
- // Phone Methods
38
- getSavedPhone: () => string | null;
39
- savePhone: (phone: string) => void;
40
- clearSavedPhone: () => void;
41
-
42
- // OTP Methods - Multi-channel support
43
- requestOTP: (identifier: string, channel?: 'email' | 'phone', sourceUrl?: string) => Promise<{ success: boolean; message: string }>;
44
- verifyOTP: (identifier: string, otpCode: string, channel?: 'email' | 'phone', sourceUrl?: string, redirectUrl?: string, skipRedirect?: boolean) => Promise<{
38
+ // OTP Methods - email only
39
+ requestOTP: (identifier: string, sourceUrl?: string) => Promise<OTPRequestResult>;
40
+ verifyOTP: (identifier: string, otpCode: string, sourceUrl?: string, redirectUrl?: string, skipRedirect?: boolean) => Promise<{
45
41
  success: boolean;
46
42
  message: string;
47
43
  user?: UserProfile;
@@ -67,4 +63,4 @@ export interface AuthContextType {
67
63
  export interface AuthProviderProps {
68
64
  children: React.ReactNode;
69
65
  config?: AuthConfig;
70
- }
66
+ }
@@ -6,7 +6,7 @@ export { useQueryParams } from './useQueryParams';
6
6
 
7
7
  // Core form hooks (decomposed)
8
8
  export { useAuthFormState, type UseAuthFormStateReturn } from './useAuthFormState';
9
- export { useAuthValidation, detectChannelFromIdentifier, validateIdentifier } from './useAuthValidation';
9
+ export { useAuthValidation, validateIdentifier } from './useAuthValidation';
10
10
 
11
11
  // Complete form hook (composes the above)
12
12
  export { useAuthForm, type AuthFormReturn, type UseAuthFormOptions } from './useAuthForm';