@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
package/dist/auth.cjs CHANGED
@@ -40,7 +40,6 @@ __export(auth_exports, {
40
40
  authLogger: () => authLogger,
41
41
  clearProfileCache: () => clearProfileCache,
42
42
  decodeBase64: () => decodeBase64,
43
- detectChannelFromIdentifier: () => detectChannelFromIdentifier,
44
43
  encodeBase64: () => encodeBase64,
45
44
  formatAuthError: () => formatAuthError,
46
45
  getCacheMetadata: () => getCacheMetadata,
@@ -182,9 +181,13 @@ __name(useQueryParams, "useQueryParams");
182
181
 
183
182
  // src/auth/hooks/useAuthFormState.ts
184
183
  var import_react3 = require("react");
185
- var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "", initialChannel = "email") => {
184
+ var formatCountdown = /* @__PURE__ */ __name((s) => {
185
+ if (s <= 0) return "";
186
+ const m = Math.floor(s / 60);
187
+ return m > 0 ? `${m}:${String(s % 60).padStart(2, "0")}` : `${s}s`;
188
+ }, "formatCountdown");
189
+ var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "") => {
186
190
  const [identifier, setIdentifier] = (0, import_react3.useState)(initialIdentifier);
187
- const [channel, setChannel] = (0, import_react3.useState)(initialChannel);
188
191
  const [otp, setOtp] = (0, import_react3.useState)("");
189
192
  const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
190
193
  const [acceptedTerms, setAcceptedTerms] = (0, import_react3.useState)(true);
@@ -194,11 +197,29 @@ var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "", initialCh
194
197
  const [shouldPrompt2FA, setShouldPrompt2FA] = (0, import_react3.useState)(false);
195
198
  const [twoFactorCode, setTwoFactorCode] = (0, import_react3.useState)("");
196
199
  const [useBackupCode, setUseBackupCode] = (0, import_react3.useState)(false);
200
+ const [rateLimitSeconds, setRateLimitSeconds] = (0, import_react3.useState)(0);
201
+ const rateLimitTimerRef = (0, import_react3.useRef)(null);
202
+ const startRateLimitCountdown = (0, import_react3.useCallback)((seconds) => {
203
+ if (rateLimitTimerRef.current) clearInterval(rateLimitTimerRef.current);
204
+ setRateLimitSeconds(seconds);
205
+ rateLimitTimerRef.current = setInterval(() => {
206
+ setRateLimitSeconds((prev) => {
207
+ if (prev <= 1) {
208
+ clearInterval(rateLimitTimerRef.current);
209
+ rateLimitTimerRef.current = null;
210
+ return 0;
211
+ }
212
+ return prev - 1;
213
+ });
214
+ }, 1e3);
215
+ }, []);
216
+ (0, import_react3.useEffect)(() => () => {
217
+ if (rateLimitTimerRef.current) clearInterval(rateLimitTimerRef.current);
218
+ }, []);
197
219
  const clearError = (0, import_react3.useCallback)(() => setError(""), []);
198
220
  return {
199
221
  // State
200
222
  identifier,
201
- channel,
202
223
  otp,
203
224
  isLoading,
204
225
  acceptedTerms,
@@ -208,9 +229,11 @@ var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "", initialCh
208
229
  shouldPrompt2FA,
209
230
  twoFactorCode,
210
231
  useBackupCode,
232
+ rateLimitSeconds,
233
+ isRateLimited: rateLimitSeconds > 0,
234
+ rateLimitLabel: formatCountdown(rateLimitSeconds),
211
235
  // Handlers
212
236
  setIdentifier,
213
- setChannel,
214
237
  setOtp,
215
238
  setAcceptedTerms,
216
239
  setError,
@@ -220,54 +243,21 @@ var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "", initialCh
220
243
  setTwoFactorSessionId,
221
244
  setShouldPrompt2FA,
222
245
  setTwoFactorCode,
223
- setUseBackupCode
246
+ setUseBackupCode,
247
+ startRateLimitCountdown
224
248
  };
225
249
  }, "useAuthFormState");
226
250
 
227
251
  // src/auth/hooks/useAuthValidation.ts
228
252
  var import_react4 = require("react");
229
253
  var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
230
- var PHONE_REGEX = /^\+[1-9]\d{6,14}$/;
231
254
  var useAuthValidation = /* @__PURE__ */ __name(() => {
232
- const detectChannelFromIdentifier2 = (0, import_react4.useCallback)((id) => {
233
- if (!id) return null;
234
- if (id.includes("@")) {
235
- return "email";
236
- }
237
- if (id.startsWith("+") && PHONE_REGEX.test(id)) {
238
- return "phone";
239
- }
240
- return null;
255
+ const validateIdentifier2 = (0, import_react4.useCallback)((id) => {
256
+ return EMAIL_REGEX.test(id);
241
257
  }, []);
242
- const validateIdentifier2 = (0, import_react4.useCallback)((id, channelType) => {
243
- if (!id) return false;
244
- const channel = channelType || detectChannelFromIdentifier2(id);
245
- if (channel === "email") {
246
- return EMAIL_REGEX.test(id);
247
- }
248
- if (channel === "phone") {
249
- return PHONE_REGEX.test(id);
250
- }
251
- return false;
252
- }, [detectChannelFromIdentifier2]);
253
- return {
254
- detectChannelFromIdentifier: detectChannelFromIdentifier2,
255
- validateIdentifier: validateIdentifier2
256
- };
258
+ return { validateIdentifier: validateIdentifier2 };
257
259
  }, "useAuthValidation");
258
- var detectChannelFromIdentifier = /* @__PURE__ */ __name((id) => {
259
- if (!id) return null;
260
- if (id.includes("@")) return "email";
261
- if (id.startsWith("+") && PHONE_REGEX.test(id)) return "phone";
262
- return null;
263
- }, "detectChannelFromIdentifier");
264
- var validateIdentifier = /* @__PURE__ */ __name((id, channelType) => {
265
- if (!id) return false;
266
- const channel = channelType || detectChannelFromIdentifier(id);
267
- if (channel === "email") return EMAIL_REGEX.test(id);
268
- if (channel === "phone") return PHONE_REGEX.test(id);
269
- return false;
270
- }, "validateIdentifier");
260
+ var validateIdentifier = /* @__PURE__ */ __name((id) => EMAIL_REGEX.test(id), "validateIdentifier");
271
261
 
272
262
  // src/auth/hooks/useAuthForm.ts
273
263
  var import_react7 = require("react");
@@ -483,7 +473,7 @@ var Accounts = class {
483
473
  this.client = client;
484
474
  }
485
475
  /**
486
- * Request OTP code to email or phone.
476
+ * Request OTP code to email.
487
477
  */
488
478
  async otpRequestCreate(data) {
489
479
  const response = await this.client.request("POST", "/cfg/accounts/otp/request/", { body: data });
@@ -1124,20 +1114,10 @@ var LocalStorageAdapter = class {
1124
1114
  };
1125
1115
 
1126
1116
  // src/_api/generated/cfg_accounts/enums.ts
1127
- var enums_exports = {};
1128
- __export(enums_exports, {
1129
- OAuthConnectionProvider: () => OAuthConnectionProvider,
1130
- OTPRequestRequestChannel: () => OTPRequestRequestChannel
1131
- });
1132
1117
  var OAuthConnectionProvider = /* @__PURE__ */ ((OAuthConnectionProvider2) => {
1133
1118
  OAuthConnectionProvider2["GITHUB"] = "github";
1134
1119
  return OAuthConnectionProvider2;
1135
1120
  })(OAuthConnectionProvider || {});
1136
- var OTPRequestRequestChannel = /* @__PURE__ */ ((OTPRequestRequestChannel2) => {
1137
- OTPRequestRequestChannel2["EMAIL"] = "email";
1138
- OTPRequestRequestChannel2["PHONE"] = "phone";
1139
- return OTPRequestRequestChannel2;
1140
- })(OTPRequestRequestChannel || {});
1141
1121
 
1142
1122
  // src/_api/generated/cfg_accounts/_utils/schemas/AccountDeleteResponse.schema.ts
1143
1123
  var import_zod = require("zod");
@@ -1231,14 +1211,15 @@ var OAuthTokenResponseSchema = import_zod11.z.object({
1231
1211
  // src/_api/generated/cfg_accounts/_utils/schemas/OTPErrorResponse.schema.ts
1232
1212
  var import_zod12 = require("zod");
1233
1213
  var OTPErrorResponseSchema = import_zod12.z.object({
1234
- error: import_zod12.z.string()
1214
+ error: import_zod12.z.string(),
1215
+ error_code: import_zod12.z.string().nullable().optional(),
1216
+ retry_after: import_zod12.z.number().int().nullable().optional()
1235
1217
  });
1236
1218
 
1237
1219
  // src/_api/generated/cfg_accounts/_utils/schemas/OTPRequestRequest.schema.ts
1238
1220
  var import_zod13 = require("zod");
1239
1221
  var OTPRequestRequestSchema = import_zod13.z.object({
1240
1222
  identifier: import_zod13.z.string().min(1),
1241
- channel: import_zod13.z.nativeEnum(OTPRequestRequestChannel).optional(),
1242
1223
  source_url: import_zod13.z.string().optional()
1243
1224
  });
1244
1225
 
@@ -1253,7 +1234,6 @@ var import_zod15 = require("zod");
1253
1234
  var OTPVerifyRequestSchema = import_zod15.z.object({
1254
1235
  identifier: import_zod15.z.string().min(1),
1255
1236
  otp: import_zod15.z.string().min(6).max(6),
1256
- channel: import_zod15.z.nativeEnum(OTPRequestRequestChannel).optional(),
1257
1237
  source_url: import_zod15.z.string().optional()
1258
1238
  });
1259
1239
 
@@ -4373,6 +4353,7 @@ var useTwoFactor = /* @__PURE__ */ __name((options = {}) => {
4373
4353
  const [error, setError] = (0, import_react6.useState)(null);
4374
4354
  const [warning, setWarning] = (0, import_react6.useState)(null);
4375
4355
  const [remainingBackupCodes, setRemainingBackupCodes] = (0, import_react6.useState)(null);
4356
+ const [attemptsRemaining, setAttemptsRemaining] = (0, import_react6.useState)(null);
4376
4357
  const clearError = (0, import_react6.useCallback)(() => {
4377
4358
  setError(null);
4378
4359
  }, []);
@@ -4425,8 +4406,11 @@ var useTwoFactor = /* @__PURE__ */ __name((options = {}) => {
4425
4406
  handleSuccess(response);
4426
4407
  return true;
4427
4408
  } catch (err) {
4428
- const errorMessage = err instanceof Error ? err.message : "Invalid verification code";
4429
4409
  authLogger.error("2FA TOTP verification error:", err);
4410
+ const errorMessage = err instanceof APIError3 ? err.response?.error || err.response?.detail || err.response?.message || err.errorMessage : err instanceof Error ? err.message : "Invalid verification code";
4411
+ if (err instanceof APIError3 && typeof err.response?.attempts_remaining === "number") {
4412
+ setAttemptsRemaining(err.response.attempts_remaining);
4413
+ }
4430
4414
  setError(errorMessage);
4431
4415
  onError?.(errorMessage);
4432
4416
  Analytics.event("auth_otp_verify_fail" /* AUTH_OTP_VERIFY_FAIL */, {
@@ -4466,8 +4450,11 @@ var useTwoFactor = /* @__PURE__ */ __name((options = {}) => {
4466
4450
  handleSuccess(response);
4467
4451
  return true;
4468
4452
  } catch (err) {
4469
- const errorMessage = err instanceof Error ? err.message : "Invalid backup code";
4470
4453
  authLogger.error("2FA backup code verification error:", err);
4454
+ const errorMessage = err instanceof APIError3 ? err.response?.error || err.response?.detail || err.response?.message || err.errorMessage : err instanceof Error ? err.message : "Invalid backup code";
4455
+ if (err instanceof APIError3 && typeof err.response?.attempts_remaining === "number") {
4456
+ setAttemptsRemaining(err.response.attempts_remaining);
4457
+ }
4471
4458
  setError(errorMessage);
4472
4459
  onError?.(errorMessage);
4473
4460
  Analytics.event("auth_otp_verify_fail" /* AUTH_OTP_VERIFY_FAIL */, {
@@ -4484,6 +4471,7 @@ var useTwoFactor = /* @__PURE__ */ __name((options = {}) => {
4484
4471
  error,
4485
4472
  warning,
4486
4473
  remainingBackupCodes,
4474
+ attemptsRemaining,
4487
4475
  verifyTOTP,
4488
4476
  verifyBackupCode,
4489
4477
  clearError
@@ -4509,15 +4497,10 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4509
4497
  requestOTP,
4510
4498
  verifyOTP,
4511
4499
  getSavedEmail,
4512
- saveEmail,
4513
- clearSavedEmail,
4514
- getSavedPhone,
4515
- savePhone,
4516
- clearSavedPhone
4500
+ saveEmail
4517
4501
  } = useAuth();
4518
4502
  const {
4519
4503
  identifier,
4520
- channel,
4521
4504
  otp,
4522
4505
  isLoading,
4523
4506
  acceptedTerms,
@@ -4525,7 +4508,6 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4525
4508
  twoFactorCode,
4526
4509
  useBackupCode,
4527
4510
  setIdentifier,
4528
- setChannel,
4529
4511
  setOtp,
4530
4512
  setStep,
4531
4513
  setError,
@@ -4534,7 +4516,8 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4534
4516
  setTwoFactorSessionId,
4535
4517
  setShouldPrompt2FA,
4536
4518
  setTwoFactorCode,
4537
- setUseBackupCode
4519
+ setUseBackupCode,
4520
+ startRateLimitCountdown
4538
4521
  } = formState;
4539
4522
  const twoFactor = useTwoFactor({
4540
4523
  onSuccess: /* @__PURE__ */ __name(() => {
@@ -4550,45 +4533,26 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4550
4533
  skipRedirect: true
4551
4534
  // We handle navigation via success step
4552
4535
  });
4553
- const { detectChannelFromIdentifier: detectChannelFromIdentifier2, validateIdentifier: validateIdentifier2 } = validation;
4554
- const saveIdentifierToStorage = (0, import_react7.useCallback)((id, ch) => {
4555
- if (ch === "email") {
4556
- saveEmail(id);
4557
- clearSavedPhone();
4558
- } else {
4559
- savePhone(id);
4560
- clearSavedEmail();
4561
- }
4562
- }, [saveEmail, savePhone, clearSavedEmail, clearSavedPhone]);
4536
+ const { validateIdentifier: validateIdentifier2 } = validation;
4537
+ const saveIdentifierToStorage = (0, import_react7.useCallback)((id) => {
4538
+ saveEmail(id);
4539
+ }, [saveEmail]);
4563
4540
  (0, import_react7.useEffect)(() => {
4564
- const savedPhone = getSavedPhone();
4565
4541
  const savedEmail = getSavedEmail();
4566
- if (savedPhone) {
4567
- setIdentifier(savedPhone);
4568
- setChannel("phone");
4569
- } else if (savedEmail) {
4542
+ if (savedEmail) {
4570
4543
  setIdentifier(savedEmail);
4571
- setChannel("email");
4572
4544
  }
4573
- }, [getSavedEmail, getSavedPhone, setIdentifier, setChannel]);
4574
- (0, import_react7.useEffect)(() => {
4575
- if (identifier) {
4576
- const detected = detectChannelFromIdentifier2(identifier);
4577
- if (detected && detected !== channel) {
4578
- setChannel(detected);
4579
- }
4580
- }
4581
- }, [identifier, channel, detectChannelFromIdentifier2, setChannel]);
4545
+ }, []);
4582
4546
  const handleIdentifierSubmit = (0, import_react7.useCallback)(async (e) => {
4583
4547
  e.preventDefault();
4584
4548
  if (!identifier) {
4585
- const msg = channel === "phone" ? "Please enter your phone number" : "Please enter your email address";
4549
+ const msg = "Please enter your email address";
4586
4550
  setError(msg);
4587
4551
  onError?.(msg);
4588
4552
  return;
4589
4553
  }
4590
- if (!validateIdentifier2(identifier, channel)) {
4591
- const msg = channel === "phone" ? "Please enter a valid phone number (e.g., +1234567890)" : "Please enter a valid email address";
4554
+ if (!validateIdentifier2(identifier)) {
4555
+ const msg = "Please enter a valid email address";
4592
4556
  setError(msg);
4593
4557
  onError?.(msg);
4594
4558
  return;
@@ -4602,14 +4566,19 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4602
4566
  setIsLoading(true);
4603
4567
  clearError();
4604
4568
  try {
4605
- const result = await requestOTP(identifier, channel, sourceUrl);
4569
+ const result = await requestOTP(identifier, sourceUrl);
4606
4570
  if (result.success) {
4607
- saveIdentifierToStorage(identifier, channel);
4571
+ saveIdentifierToStorage(identifier);
4608
4572
  setStep("otp");
4609
- onIdentifierSuccess?.(identifier, channel);
4573
+ onIdentifierSuccess?.(identifier);
4610
4574
  } else {
4611
- setError(result.message);
4612
- onError?.(result.message);
4575
+ if (result.retryAfter) {
4576
+ startRateLimitCountdown(result.retryAfter);
4577
+ clearError();
4578
+ } else {
4579
+ setError(result.message);
4580
+ onError?.(result.message);
4581
+ }
4613
4582
  }
4614
4583
  } catch {
4615
4584
  const msg = "An unexpected error occurred";
@@ -4620,7 +4589,6 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4620
4589
  }
4621
4590
  }, [
4622
4591
  identifier,
4623
- channel,
4624
4592
  acceptedTerms,
4625
4593
  requireTermsAcceptance,
4626
4594
  validateIdentifier2,
@@ -4630,11 +4598,12 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4630
4598
  setIsLoading,
4631
4599
  setStep,
4632
4600
  clearError,
4601
+ startRateLimitCountdown,
4633
4602
  onIdentifierSuccess,
4634
4603
  onError,
4635
4604
  sourceUrl
4636
4605
  ]);
4637
- const submitOTP = (0, import_react7.useCallback)(async (submitIdentifier, submitOtp, submitChannel) => {
4606
+ const submitOTP = (0, import_react7.useCallback)(async (submitIdentifier, submitOtp) => {
4638
4607
  if (!submitOtp || submitOtp.length < 6) {
4639
4608
  const msg = "Please enter the 6-digit verification code";
4640
4609
  setError(msg);
@@ -4644,17 +4613,17 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4644
4613
  setIsLoading(true);
4645
4614
  clearError();
4646
4615
  try {
4647
- const result = await verifyOTP(submitIdentifier, submitOtp, submitChannel, sourceUrl, redirectUrl, true);
4616
+ const result = await verifyOTP(submitIdentifier, submitOtp, sourceUrl, redirectUrl, true);
4648
4617
  if (result.requires_2fa && result.session_id) {
4649
4618
  authLogger.info("2FA required after OTP verification");
4650
4619
  setTwoFactorSessionId(result.session_id);
4651
4620
  setShouldPrompt2FA(result.should_prompt_2fa || false);
4652
4621
  setStep("2fa");
4653
- saveIdentifierToStorage(submitIdentifier, submitChannel);
4622
+ saveIdentifierToStorage(submitIdentifier);
4654
4623
  return true;
4655
4624
  }
4656
4625
  if (result.success) {
4657
- saveIdentifierToStorage(submitIdentifier, submitChannel);
4626
+ saveIdentifierToStorage(submitIdentifier);
4658
4627
  if (result.should_prompt_2fa && enable2FASetup) {
4659
4628
  authLogger.info("OTP verification successful, prompting 2FA setup");
4660
4629
  setShouldPrompt2FA(true);
@@ -4686,19 +4655,24 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4686
4655
  }, [verifyOTP, saveIdentifierToStorage, setError, setIsLoading, clearError, onOTPSuccess, onError, sourceUrl, redirectUrl, setTwoFactorSessionId, setShouldPrompt2FA, setStep, enable2FASetup]);
4687
4656
  const handleOTPSubmit = (0, import_react7.useCallback)(async (e) => {
4688
4657
  e.preventDefault();
4689
- await submitOTP(identifier, otp, channel);
4690
- }, [identifier, otp, channel, submitOTP]);
4658
+ await submitOTP(identifier, otp);
4659
+ }, [identifier, otp, submitOTP]);
4691
4660
  const handleResendOTP = (0, import_react7.useCallback)(async () => {
4692
4661
  setIsLoading(true);
4693
4662
  clearError();
4694
4663
  try {
4695
- const result = await requestOTP(identifier, channel, sourceUrl);
4664
+ const result = await requestOTP(identifier, sourceUrl);
4696
4665
  if (result.success) {
4697
- saveIdentifierToStorage(identifier, channel);
4666
+ saveIdentifierToStorage(identifier);
4698
4667
  setOtp("");
4699
4668
  } else {
4700
- setError(result.message);
4701
- onError?.(result.message);
4669
+ if (result.retryAfter) {
4670
+ startRateLimitCountdown(result.retryAfter);
4671
+ clearError();
4672
+ } else {
4673
+ setError(result.message);
4674
+ onError?.(result.message);
4675
+ }
4702
4676
  }
4703
4677
  } catch {
4704
4678
  const msg = "Failed to resend verification code";
@@ -4707,7 +4681,7 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4707
4681
  } finally {
4708
4682
  setIsLoading(false);
4709
4683
  }
4710
- }, [identifier, channel, requestOTP, saveIdentifierToStorage, setOtp, setError, setIsLoading, clearError, onError, sourceUrl]);
4684
+ }, [identifier, requestOTP, saveIdentifierToStorage, setOtp, setError, setIsLoading, clearError, startRateLimitCountdown, onError, sourceUrl]);
4711
4685
  const handleBackToIdentifier = (0, import_react7.useCallback)(() => {
4712
4686
  setStep("identifier");
4713
4687
  clearError();
@@ -4746,29 +4720,19 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4746
4720
  if (isAutoSubmitFromUrlRef.current || isLoading) return;
4747
4721
  isAutoSubmitFromUrlRef.current = true;
4748
4722
  authLogger.info("OTP detected from URL, auto-submitting");
4749
- const savedPhone = getSavedPhone();
4750
4723
  const savedEmail = getSavedEmail();
4751
- let autoIdentifier = "";
4752
- let autoChannel = "email";
4753
- if (savedPhone) {
4754
- autoIdentifier = savedPhone;
4755
- autoChannel = "phone";
4756
- } else if (savedEmail) {
4757
- autoIdentifier = savedEmail;
4758
- autoChannel = "email";
4759
- }
4724
+ const autoIdentifier = savedEmail || "";
4760
4725
  if (!autoIdentifier) {
4761
4726
  authLogger.warn("No saved identifier found for auto-submit");
4762
4727
  isAutoSubmitFromUrlRef.current = false;
4763
4728
  return;
4764
4729
  }
4765
4730
  setIdentifier(autoIdentifier);
4766
- setChannel(autoChannel);
4767
4731
  setOtp(detectedOtp);
4768
4732
  setStep("otp");
4769
4733
  setTimeout(async () => {
4770
4734
  try {
4771
- await submitOTP(autoIdentifier, detectedOtp, autoChannel);
4735
+ await submitOTP(autoIdentifier, detectedOtp);
4772
4736
  } finally {
4773
4737
  isAutoSubmitFromUrlRef.current = false;
4774
4738
  }
@@ -4795,7 +4759,8 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
4795
4759
  isAutoSubmittingFromUrl: isAutoSubmitFromUrlRef,
4796
4760
  // 2FA state from hook (for loading indicator)
4797
4761
  is2FALoading: twoFactor.isLoading,
4798
- twoFactorWarning: twoFactor.warning
4762
+ twoFactorWarning: twoFactor.warning,
4763
+ twoFactorAttemptsRemaining: twoFactor.attemptsRemaining
4799
4764
  };
4800
4765
  }, "useAuthForm");
4801
4766
 
@@ -5826,7 +5791,11 @@ function AccountsProvider({ children }) {
5826
5791
  }
5827
5792
  if (result.access && result.refresh) {
5828
5793
  api.setToken(result.access, result.refresh);
5829
- await refreshProfile({ callerId: "verifyOTP", force: true });
5794
+ try {
5795
+ await refreshProfile({ callerId: "verifyOTP", force: true });
5796
+ } catch (profileError2) {
5797
+ authLogger.warn("Profile refresh failed after OTP verify (tokens are saved):", profileError2);
5798
+ }
5830
5799
  }
5831
5800
  return result;
5832
5801
  }, "verifyOTP");
@@ -5877,7 +5846,6 @@ var defaultRoutes = {
5877
5846
  };
5878
5847
  var AuthContext = (0, import_react17.createContext)(void 0);
5879
5848
  var EMAIL_STORAGE_KEY = "auth_email";
5880
- var PHONE_STORAGE_KEY = "auth_phone";
5881
5849
  var hasValidTokens = /* @__PURE__ */ __name(() => {
5882
5850
  if (typeof window === "undefined") return false;
5883
5851
  return api.isAuthenticated();
@@ -5900,7 +5868,6 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5900
5868
  const pathname = (0, import_navigation4.usePathname)();
5901
5869
  const queryParams = useQueryParams();
5902
5870
  const [storedEmail, setStoredEmail, clearStoredEmail] = useLocalStorage(EMAIL_STORAGE_KEY, null);
5903
- const [storedPhone, setStoredPhone, clearStoredPhone] = useLocalStorage(PHONE_STORAGE_KEY, null);
5904
5871
  useTokenRefresh({
5905
5872
  enabled: true,
5906
5873
  onRefresh: /* @__PURE__ */ __name((newToken) => {
@@ -6090,25 +6057,33 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
6090
6057
  }
6091
6058
  }, [loadCurrentProfile, clearAuthState, pushToDefaultCallbackUrl, pushToDefaultAuthCallbackUrl, handleGlobalAuthError]);
6092
6059
  const requestOTP = (0, import_react17.useCallback)(
6093
- async (identifier, channel, sourceUrl) => {
6060
+ async (identifier, sourceUrl) => {
6094
6061
  api.clearTokens();
6095
6062
  try {
6096
- const channelValue = channel === "phone" ? enums_exports.OTPRequestRequestChannel.PHONE : enums_exports.OTPRequestRequestChannel.EMAIL;
6097
6063
  const result = await accounts.requestOTP({
6098
6064
  identifier,
6099
- channel: channelValue
6065
+ source_url: sourceUrl
6100
6066
  });
6101
- const channelName = channel === "phone" ? "phone number" : "email address";
6102
6067
  Analytics.event("auth_otp_request" /* AUTH_OTP_REQUEST */, {
6103
6068
  category: "auth" /* AUTH */,
6104
- label: channel || "email"
6069
+ label: "email"
6105
6070
  });
6106
6071
  return {
6107
6072
  success: true,
6108
- message: result.message || `OTP code sent to your ${channelName}`
6073
+ message: result.message || `OTP code sent to your email address`
6109
6074
  };
6110
6075
  } catch (error) {
6111
6076
  authLogger.error("Request OTP error:", error);
6077
+ if (error instanceof APIError) {
6078
+ const retryAfter = error.response?.retry_after ?? error.response?.retryAfter;
6079
+ const message = error.response?.error || error.response?.detail || error.response?.message || error.errorMessage;
6080
+ return {
6081
+ success: false,
6082
+ statusCode: error.statusCode,
6083
+ message,
6084
+ retryAfter: typeof retryAfter === "number" ? retryAfter : void 0
6085
+ };
6086
+ }
6112
6087
  return {
6113
6088
  success: false,
6114
6089
  message: "Failed to send OTP"
@@ -6118,13 +6093,12 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
6118
6093
  [accounts]
6119
6094
  );
6120
6095
  const verifyOTP = (0, import_react17.useCallback)(
6121
- async (identifier, otpCode, channel, sourceUrl, redirectUrl, skipRedirect) => {
6096
+ async (identifier, otpCode, sourceUrl, redirectUrl, skipRedirect) => {
6122
6097
  try {
6123
- const channelValue = channel === "phone" ? enums_exports.OTPRequestRequestChannel.PHONE : enums_exports.OTPRequestRequestChannel.EMAIL;
6124
6098
  const result = await accounts.verifyOTP({
6125
6099
  identifier,
6126
6100
  otp: otpCode,
6127
- channel: channelValue
6101
+ source_url: sourceUrl
6128
6102
  });
6129
6103
  if (result.requires_2fa && result.session_id) {
6130
6104
  authLogger.info("2FA required, session:", result.session_id);
@@ -6143,17 +6117,13 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
6143
6117
  message: "Invalid OTP verification response"
6144
6118
  };
6145
6119
  }
6146
- if (channel === "phone") {
6147
- setStoredPhone(identifier);
6148
- clearStoredEmail();
6149
- } else if (identifier.includes("@")) {
6120
+ if (identifier.includes("@")) {
6150
6121
  setStoredEmail(identifier);
6151
- clearStoredPhone();
6152
6122
  }
6153
6123
  await new Promise((resolve) => setTimeout(resolve, 200));
6154
6124
  Analytics.event("auth_login_success" /* AUTH_LOGIN_SUCCESS */, {
6155
6125
  category: "auth" /* AUTH */,
6156
- label: channel || "email"
6126
+ label: "email"
6157
6127
  });
6158
6128
  if (result.user?.id) {
6159
6129
  Analytics.setUser(String(result.user.id));
@@ -6174,15 +6144,19 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
6174
6144
  authLogger.error("Verify OTP error:", error);
6175
6145
  Analytics.event("auth_otp_verify_fail" /* AUTH_OTP_VERIFY_FAIL */, {
6176
6146
  category: "auth" /* AUTH */,
6177
- label: channel || "email"
6147
+ label: "email"
6178
6148
  });
6149
+ if (error instanceof APIError) {
6150
+ const message = error.response?.error || error.response?.detail || error.response?.message || error.errorMessage;
6151
+ return { success: false, message };
6152
+ }
6179
6153
  return {
6180
6154
  success: false,
6181
6155
  message: "Failed to verify OTP"
6182
6156
  };
6183
6157
  }
6184
6158
  },
6185
- [setStoredEmail, setStoredPhone, clearStoredEmail, clearStoredPhone, config?.routes?.defaultCallback, accounts, router]
6159
+ [setStoredEmail, config?.routes?.defaultCallback, accounts, router]
6186
6160
  );
6187
6161
  const refreshToken = (0, import_react17.useCallback)(async () => {
6188
6162
  try {
@@ -6258,9 +6232,6 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
6258
6232
  getSavedEmail: /* @__PURE__ */ __name(() => storedEmail, "getSavedEmail"),
6259
6233
  saveEmail: setStoredEmail,
6260
6234
  clearSavedEmail: clearStoredEmail,
6261
- getSavedPhone: /* @__PURE__ */ __name(() => storedPhone, "getSavedPhone"),
6262
- savePhone: setStoredPhone,
6263
- clearSavedPhone: clearStoredPhone,
6264
6235
  requestOTP,
6265
6236
  verifyOTP,
6266
6237
  refreshToken,
@@ -6283,9 +6254,6 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
6283
6254
  storedEmail,
6284
6255
  setStoredEmail,
6285
6256
  clearStoredEmail,
6286
- storedPhone,
6287
- setStoredPhone,
6288
- clearStoredPhone,
6289
6257
  requestOTP,
6290
6258
  verifyOTP,
6291
6259
  refreshToken,
@@ -6319,12 +6287,6 @@ var defaultAuthState = {
6319
6287
  }, "saveEmail"),
6320
6288
  clearSavedEmail: /* @__PURE__ */ __name(() => {
6321
6289
  }, "clearSavedEmail"),
6322
- getSavedPhone: /* @__PURE__ */ __name(() => null, "getSavedPhone"),
6323
- savePhone: /* @__PURE__ */ __name(() => {
6324
- authLogger.warn("useAuth: savePhone called outside AuthProvider");
6325
- }, "savePhone"),
6326
- clearSavedPhone: /* @__PURE__ */ __name(() => {
6327
- }, "clearSavedPhone"),
6328
6290
  requestOTP: /* @__PURE__ */ __name(async () => {
6329
6291
  authLogger.warn("useAuth: requestOTP called outside AuthProvider");
6330
6292
  return { success: false, message: "AuthProvider not available" };