@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.
- package/README.md +8 -9
- package/dist/auth-server.cjs +4 -9
- package/dist/auth-server.cjs.map +1 -1
- package/dist/auth-server.mjs +4 -9
- package/dist/auth-server.mjs.map +1 -1
- package/dist/auth.cjs +120 -158
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +120 -177
- package/dist/auth.d.ts +120 -177
- package/dist/auth.mjs +149 -191
- package/dist/auth.mjs.map +1 -1
- package/dist/clients.cjs +5 -11
- package/dist/clients.cjs.map +1 -1
- package/dist/clients.d.cts +218 -219
- package/dist/clients.d.ts +218 -219
- package/dist/clients.mjs +5 -11
- package/dist/clients.mjs.map +1 -1
- package/dist/hooks.cjs +4 -9
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +70 -91
- package/dist/hooks.d.ts +70 -91
- package/dist/hooks.mjs +4 -9
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.cjs +5 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +116 -106
- package/dist/index.d.ts +116 -106
- package/dist/index.mjs +5 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/_api/generated/cfg_accounts/_utils/schemas/OTPErrorResponse.schema.ts +24 -2
- package/src/_api/generated/cfg_accounts/_utils/schemas/OTPRequestRequest.schema.ts +0 -2
- package/src/_api/generated/cfg_accounts/_utils/schemas/OTPVerifyRequest.schema.ts +0 -2
- package/src/_api/generated/cfg_accounts/accounts/client.ts +1 -1
- package/src/_api/generated/cfg_accounts/accounts/models.ts +25 -26
- package/src/_api/generated/cfg_accounts/accounts__auth/models.ts +5 -5
- package/src/_api/generated/cfg_accounts/accounts__oauth/models.ts +42 -42
- package/src/_api/generated/cfg_accounts/accounts__user_profile/models.ts +23 -23
- package/src/_api/generated/cfg_accounts/enums.ts +0 -10
- package/src/_api/generated/cfg_accounts/schema.json +31 -25
- package/src/_api/generated/cfg_centrifugo/centrifugo__centrifugo_admin_api/models.ts +57 -57
- package/src/_api/generated/cfg_centrifugo/centrifugo__centrifugo_monitoring/models.ts +24 -24
- package/src/_api/generated/cfg_centrifugo/centrifugo__centrifugo_testing/models.ts +14 -14
- package/src/_api/generated/cfg_totp/totp__backup_codes/models.ts +14 -14
- package/src/_api/generated/cfg_totp/totp__totp_setup/models.ts +10 -10
- package/src/_api/generated/cfg_totp/totp__totp_verification/models.ts +8 -8
- package/src/auth/context/AccountsContext.tsx +6 -2
- package/src/auth/context/AuthContext.tsx +32 -39
- package/src/auth/context/types.ts +5 -9
- package/src/auth/hooks/index.ts +1 -1
- package/src/auth/hooks/useAuthForm.ts +42 -75
- package/src/auth/hooks/useAuthFormState.ts +35 -6
- package/src/auth/hooks/useAuthValidation.ts +5 -65
- package/src/auth/hooks/useTwoFactor.ts +17 -2
- package/src/auth/types/form.ts +25 -70
- 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
|
-
*
|
|
24
|
+
* Channel history response.
|
|
45
25
|
*
|
|
46
26
|
* Response model (includes read-only fields).
|
|
47
27
|
*/
|
|
48
|
-
export interface
|
|
28
|
+
export interface CentrifugoHistoryResponse {
|
|
49
29
|
error?: CentrifugoError | null;
|
|
50
|
-
result?:
|
|
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
|
-
*
|
|
79
|
+
* List of active channels response.
|
|
90
80
|
*
|
|
91
81
|
* Response model (includes read-only fields).
|
|
92
82
|
*/
|
|
93
|
-
export interface
|
|
83
|
+
export interface CentrifugoChannelsResponse {
|
|
94
84
|
error?: CentrifugoError | null;
|
|
95
|
-
result?:
|
|
85
|
+
result?: CentrifugoChannelsResult | null;
|
|
96
86
|
}
|
|
97
87
|
|
|
98
88
|
/**
|
|
99
|
-
*
|
|
89
|
+
* Channel presence stats response.
|
|
100
90
|
*
|
|
101
91
|
* Response model (includes read-only fields).
|
|
102
92
|
*/
|
|
103
|
-
export interface
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
*
|
|
121
|
+
* History result wrapper.
|
|
136
122
|
*
|
|
137
123
|
* Response model (includes read-only fields).
|
|
138
124
|
*/
|
|
139
|
-
export interface
|
|
140
|
-
/** List of
|
|
141
|
-
|
|
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
|
-
*
|
|
135
|
+
* Info result wrapper.
|
|
146
136
|
*
|
|
147
137
|
* Response model (includes read-only fields).
|
|
148
138
|
*/
|
|
149
|
-
export interface
|
|
150
|
-
/**
|
|
151
|
-
|
|
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
|
-
*
|
|
157
|
+
* Channels result wrapper.
|
|
168
158
|
*
|
|
169
159
|
* Response model (includes read-only fields).
|
|
170
160
|
*/
|
|
171
|
-
export interface
|
|
172
|
-
/**
|
|
173
|
-
|
|
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
|
-
*
|
|
167
|
+
* Presence stats result.
|
|
180
168
|
*
|
|
181
169
|
* Response model (includes read-only fields).
|
|
182
170
|
*/
|
|
183
|
-
export interface
|
|
184
|
-
/**
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
*
|
|
40
|
+
* Overview statistics for Centrifugo publishes.
|
|
41
41
|
*
|
|
42
42
|
* Response model (includes read-only fields).
|
|
43
43
|
*/
|
|
44
|
-
export interface
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
|
|
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
|
-
*
|
|
80
|
+
* List of channel statistics.
|
|
69
81
|
*
|
|
70
82
|
* Response model (includes read-only fields).
|
|
71
83
|
*/
|
|
72
|
-
export interface
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
|
|
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
|
|
35
|
+
* Serializer for starting 2FA setup.
|
|
36
36
|
*
|
|
37
37
|
* Request model (no read-only fields).
|
|
38
38
|
*/
|
|
39
|
-
export interface
|
|
40
|
-
/** Device
|
|
41
|
-
|
|
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
|
|
45
|
+
* Serializer for confirming 2FA setup with first code.
|
|
48
46
|
*
|
|
49
47
|
* Request model (no read-only fields).
|
|
50
48
|
*/
|
|
51
|
-
export interface
|
|
52
|
-
/** Device
|
|
53
|
-
|
|
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
|
|
4
|
+
* Serializer for backup code verification during login.
|
|
5
5
|
*
|
|
6
6
|
* Request model (no read-only fields).
|
|
7
7
|
*/
|
|
8
|
-
export interface
|
|
8
|
+
export interface VerifyBackupRequest {
|
|
9
9
|
/** 2FA session ID from login response */
|
|
10
10
|
session_id: string;
|
|
11
|
-
/**
|
|
12
|
-
|
|
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
|
|
34
|
+
* Serializer for TOTP code verification during login.
|
|
35
35
|
*
|
|
36
36
|
* Request model (no read-only fields).
|
|
37
37
|
*/
|
|
38
|
-
export interface
|
|
38
|
+
export interface VerifyRequest {
|
|
39
39
|
/** 2FA session ID from login response */
|
|
40
40
|
session_id: string;
|
|
41
|
-
/**
|
|
42
|
-
|
|
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
|
|
190
|
-
|
|
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
|
|
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
|
|
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 -
|
|
352
|
+
// OTP methods - email only - now uses AccountsContext
|
|
354
353
|
const requestOTP = useCallback(
|
|
355
|
-
async (identifier: 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
|
-
|
|
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:
|
|
367
|
+
label: 'email',
|
|
374
368
|
});
|
|
375
369
|
|
|
376
370
|
return {
|
|
377
371
|
success: true,
|
|
378
|
-
message: result.message || `OTP code sent to your
|
|
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,
|
|
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
|
-
|
|
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
|
|
433
|
-
if (
|
|
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:
|
|
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:
|
|
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,
|
|
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
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
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
|
+
}
|
package/src/auth/hooks/index.ts
CHANGED
|
@@ -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,
|
|
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';
|