@dloizides/auth-web 1.22.1 → 1.24.0

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/dist/index.mjs CHANGED
@@ -305,7 +305,8 @@ var DEFAULT_RESET_PASSWORD_LABELS = {
305
305
  errorWeakPassword: "Use at least 8 characters with an uppercase letter, a lowercase letter and a digit.",
306
306
  errorMismatch: "The passwords do not match.",
307
307
  errorTokenInvalid: "This reset link is invalid or has expired. Request a new one.",
308
- errorNetwork: "Something went wrong. Please try again."
308
+ errorNetwork: "Something went wrong. Please try again.",
309
+ errorRateLimited: "Too many attempts. Wait a minute and try again."
309
310
  };
310
311
 
311
312
  // src/components/labels/accountSettingsLabels.ts
@@ -342,6 +343,8 @@ var DEFAULT_REGISTER_LABELS = {
342
343
  submitHint: "Creates your account",
343
344
  submitting: "Creating account...",
344
345
  fullName: field("Your name", "Enter your full name"),
346
+ checkEmailTitle: "Check your email",
347
+ checkEmailBody: "If this address can be used, a link to finish signing up is on its way.",
345
348
  fields: {
346
349
  firstName: field("First name", "Enter your first name"),
347
350
  lastName: field("Last name", "Enter your last name"),
@@ -354,6 +357,19 @@ var DEFAULT_REGISTER_LABELS = {
354
357
  };
355
358
 
356
359
  // src/components/labels/verifyEmailLabels.ts
360
+ var DEFAULT_VERIFY_NEW_PASSWORD_LABELS = {
361
+ ...DEFAULT_RESET_PASSWORD_LABELS,
362
+ title: "Set a new password",
363
+ description: "To finish signing in, choose a new password for your account.",
364
+ submit: "Save and sign in",
365
+ submitting: "Saving..."
366
+ };
367
+ var DEFAULT_VERIFY_SIGN_IN_LABELS = {
368
+ title: "Your email is verified",
369
+ body: "We could not sign you in automatically. Please sign in with your password.",
370
+ action: "Sign in",
371
+ actionHint: "Go to the sign in page"
372
+ };
357
373
  var DEFAULT_VERIFY_EMAIL_LABELS = {
358
374
  loadingTitle: "Verifying your email...",
359
375
  loadingHint: "Please wait while we verify your address.",
@@ -375,7 +391,49 @@ var DEFAULT_VERIFY_EMAIL_LABELS = {
375
391
  resendMissingEmail: "Enter your email address.",
376
392
  resendSubmit: "Send link",
377
393
  resendSubmitHint: "Sends a new verification email",
378
- resendConfirmation: "If that address has an account, a new verification link is on its way."
394
+ resendConfirmation: "If that address has an account, a new verification link is on its way.",
395
+ errorRateLimited: "Too many attempts. Wait a minute and try again.",
396
+ newPassword: DEFAULT_VERIFY_NEW_PASSWORD_LABELS,
397
+ signIn: DEFAULT_VERIFY_SIGN_IN_LABELS
398
+ };
399
+
400
+ // src/components/labels/accountDeletionLabels.ts
401
+ var DEFAULT_ACCOUNT_DELETION_LABELS = {
402
+ title: "Delete your account",
403
+ subtitle: "We email you a link to confirm. Nothing is deleted until you open it.",
404
+ reason: {
405
+ label: "Reason (optional)",
406
+ placeholder: "Why are you leaving?",
407
+ hint: "Optional reason for deleting your account",
408
+ inputLabel: "Reason for deleting your account"
409
+ },
410
+ submit: "Request account deletion",
411
+ submitHint: "Emails you a link to confirm the deletion",
412
+ submitting: "Sending the request",
413
+ stepUpTitle: "Confirm your password",
414
+ stepUpSubtitle: "You signed in a while ago. Enter your password to continue.",
415
+ password: {
416
+ label: "Password",
417
+ placeholder: "Your password",
418
+ hint: "Your current password",
419
+ inputLabel: "Password"
420
+ },
421
+ stepUpSubmit: "Confirm and continue",
422
+ stepUpSubmitHint: "Checks your password, then sends the deletion request",
423
+ checkEmailTitle: "Check your email",
424
+ checkEmailBody: "Open the link we sent you to confirm. Your account stays active until then.",
425
+ emailNotSentTitle: "We could not send the email",
426
+ emailNotSentBody: "Your request is recorded, but the confirmation email did not go out. Contact support to finish it.",
427
+ scheduledDate: "Scheduled deletion date: {date}",
428
+ alreadyRequestedTitle: "Deletion already requested",
429
+ alreadyRequestedBody: "Look for the confirmation link in your email. You do not need to ask again.",
430
+ errorPasswordRequired: "Enter your password.",
431
+ errorWrongPassword: "That password is not correct.",
432
+ errorSignInRequired: "Your session ended. Sign in and try again.",
433
+ errorRateLimited: "Too many attempts. Wait a moment and try again.",
434
+ errorRateLimitedSeconds: "Too many attempts. Try again in {seconds} seconds.",
435
+ errorRetryLater: "We could not reach the account service. Try again later.",
436
+ errorFailed: "Something went wrong. Try again."
379
437
  };
380
438
 
381
439
  // src/components/testIds.ts
@@ -474,6 +532,8 @@ var AuthTestIds = {
474
532
  verifyEmailSuccess: "auth-verify-email-success",
475
533
  verifyEmailContinue: "auth-verify-email-continue",
476
534
  verifyEmailError: "auth-verify-email-error",
535
+ verifyEmailSignIn: "auth-verify-email-sign-in",
536
+ verifyEmailSignInContinue: "auth-verify-email-sign-in-continue",
477
537
  verifyEmailResendCta: "auth-verify-email-resend-cta",
478
538
  verifyEmailResendForm: "auth-verify-email-resend-form",
479
539
  verifyEmailResendEmail: "auth-verify-email-resend-email",
@@ -658,7 +718,7 @@ function useLoginSubmit({
658
718
  missingFieldsLabel,
659
719
  invalidCredentialsLabel
660
720
  }) {
661
- const [errorText, setErrorText] = useState(null);
721
+ const [errorText2, setErrorText] = useState(null);
662
722
  const inFlight = useRef(false);
663
723
  const runLogin = useCallback(async () => {
664
724
  if (inFlight.current) {
@@ -684,7 +744,7 @@ function useLoginSubmit({
684
744
  const handleSubmit = useCallback(() => {
685
745
  void runLogin();
686
746
  }, [runLogin]);
687
- return { errorText, handleSubmit };
747
+ return { errorText: errorText2, handleSubmit };
688
748
  }
689
749
  function isKeyRepeat(event) {
690
750
  const native = event?.nativeEvent;
@@ -844,7 +904,7 @@ function LoginForm({
844
904
  prefillNonce,
845
905
  prefillIntent
846
906
  });
847
- const { errorText, handleSubmit } = useLoginSubmit({
907
+ const { errorText: errorText2, handleSubmit } = useLoginSubmit({
848
908
  username,
849
909
  password,
850
910
  login,
@@ -900,12 +960,12 @@ function LoginForm({
900
960
  }
901
961
  )
902
962
  ] }),
903
- errorText !== null ? /* @__PURE__ */ jsx(
963
+ errorText2 !== null ? /* @__PURE__ */ jsx(
904
964
  Text,
905
965
  {
906
966
  style: styles3.errorText,
907
967
  testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
908
- children: errorText
968
+ children: errorText2
909
969
  }
910
970
  ) : null,
911
971
  onForgotPassword !== void 0 ? /* @__PURE__ */ jsx(
@@ -997,7 +1057,7 @@ function ForgotPasswordForm({
997
1057
  );
998
1058
  const [email, setEmail] = useState("");
999
1059
  const [submitted, setSubmitted] = useState(false);
1000
- const [errorText, setErrorText] = useState(null);
1060
+ const [errorText2, setErrorText] = useState(null);
1001
1061
  const mutationOptions = useMemo(
1002
1062
  () => ({
1003
1063
  client,
@@ -1059,12 +1119,12 @@ function ForgotPasswordForm({
1059
1119
  }
1060
1120
  )
1061
1121
  ] }),
1062
- errorText !== null ? /* @__PURE__ */ jsx(
1122
+ errorText2 !== null ? /* @__PURE__ */ jsx(
1063
1123
  Text,
1064
1124
  {
1065
1125
  style: styles3.errorText,
1066
1126
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
1067
- children: errorText
1127
+ children: errorText2
1068
1128
  }
1069
1129
  ) : null,
1070
1130
  /* @__PURE__ */ jsx(
@@ -1274,8 +1334,107 @@ var ResetPasswordError = /* @__PURE__ */ ((ResetPasswordError2) => {
1274
1334
  ResetPasswordError2["Mismatch"] = "mismatch";
1275
1335
  ResetPasswordError2["TokenInvalid"] = "tokenInvalid";
1276
1336
  ResetPasswordError2["Network"] = "network";
1337
+ ResetPasswordError2["RateLimited"] = "rateLimited";
1277
1338
  return ResetPasswordError2;
1278
1339
  })(ResetPasswordError || {});
1340
+ function errorMessage(errorKey, labels) {
1341
+ switch (errorKey) {
1342
+ case "empty" /* Empty */:
1343
+ return labels.errorEmpty;
1344
+ case "weakPassword" /* WeakPassword */:
1345
+ return labels.errorWeakPassword;
1346
+ case "mismatch" /* Mismatch */:
1347
+ return labels.errorMismatch;
1348
+ case "tokenInvalid" /* TokenInvalid */:
1349
+ return labels.errorTokenInvalid;
1350
+ case "network" /* Network */:
1351
+ return labels.errorNetwork;
1352
+ case "rateLimited" /* RateLimited */:
1353
+ return labels.errorRateLimited ?? labels.errorNetwork;
1354
+ default:
1355
+ return null;
1356
+ }
1357
+ }
1358
+ function ResetPasswordFields({
1359
+ form,
1360
+ labels,
1361
+ styles: styles3,
1362
+ theme,
1363
+ testIdPrefix,
1364
+ newPasswordRef,
1365
+ onSubmitEditing
1366
+ }) {
1367
+ const message = errorMessage(form.errorKey, labels);
1368
+ const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1369
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1370
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
1371
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
1372
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1373
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.newPasswordLabel }),
1374
+ /* @__PURE__ */ jsx(
1375
+ TextInput,
1376
+ {
1377
+ ref: newPasswordRef,
1378
+ secureTextEntry: true,
1379
+ accessibilityHint: labels.newPasswordPlaceholder,
1380
+ accessibilityLabel: labels.newPasswordLabel,
1381
+ autoCapitalize: "none",
1382
+ autoCorrect: false,
1383
+ editable: !form.isSubmitting,
1384
+ placeholder: labels.newPasswordPlaceholder,
1385
+ placeholderTextColor: theme.colors.textSecondary,
1386
+ style: styles3.input,
1387
+ testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
1388
+ value: form.newPassword,
1389
+ onChangeText: form.setNewPassword,
1390
+ onSubmitEditing
1391
+ }
1392
+ )
1393
+ ] }),
1394
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1395
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
1396
+ /* @__PURE__ */ jsx(
1397
+ TextInput,
1398
+ {
1399
+ secureTextEntry: true,
1400
+ accessibilityHint: labels.confirmPasswordPlaceholder,
1401
+ accessibilityLabel: labels.confirmPasswordLabel,
1402
+ autoCapitalize: "none",
1403
+ autoCorrect: false,
1404
+ editable: !form.isSubmitting,
1405
+ placeholder: labels.confirmPasswordPlaceholder,
1406
+ placeholderTextColor: theme.colors.textSecondary,
1407
+ style: styles3.input,
1408
+ testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
1409
+ value: form.confirmPassword,
1410
+ onChangeText: form.setConfirmPassword,
1411
+ onSubmitEditing
1412
+ }
1413
+ )
1414
+ ] }),
1415
+ message !== null ? /* @__PURE__ */ jsx(
1416
+ Text,
1417
+ {
1418
+ style: styles3.errorText,
1419
+ testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
1420
+ children: message
1421
+ }
1422
+ ) : null,
1423
+ /* @__PURE__ */ jsx(
1424
+ TouchableOpacity,
1425
+ {
1426
+ accessibilityHint: labels.submit,
1427
+ accessibilityLabel: form.isSubmitting ? labels.submitting : labels.submit,
1428
+ accessibilityRole: "button",
1429
+ disabled: form.isSubmitting,
1430
+ style: submitButtonStyle,
1431
+ testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
1432
+ onPress: form.submit,
1433
+ children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
1434
+ }
1435
+ )
1436
+ ] });
1437
+ }
1279
1438
 
1280
1439
  // src/password/PasswordPolicyError.ts
1281
1440
  var PasswordPolicyError = /* @__PURE__ */ ((PasswordPolicyError2) => {
@@ -1414,22 +1573,6 @@ function useResetPasswordForm({
1414
1573
  submit
1415
1574
  };
1416
1575
  }
1417
- function errorMessage(errorKey, labels) {
1418
- switch (errorKey) {
1419
- case "empty" /* Empty */:
1420
- return labels.errorEmpty;
1421
- case "weakPassword" /* WeakPassword */:
1422
- return labels.errorWeakPassword;
1423
- case "mismatch" /* Mismatch */:
1424
- return labels.errorMismatch;
1425
- case "tokenInvalid" /* TokenInvalid */:
1426
- return labels.errorTokenInvalid;
1427
- case "network" /* Network */:
1428
- return labels.errorNetwork;
1429
- default:
1430
- return null;
1431
- }
1432
- }
1433
1576
  function ResetPasswordForm({
1434
1577
  client,
1435
1578
  token,
@@ -1445,78 +1588,21 @@ function ResetPasswordForm({
1445
1588
  [labelsProp]
1446
1589
  );
1447
1590
  const form = useResetPasswordForm({ client, token, onSuccess });
1448
- const message = errorMessage(form.errorKey, labels);
1449
- const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1450
- return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
1591
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsx(
1451
1592
  View,
1452
1593
  {
1453
1594
  style: styles3.card,
1454
1595
  testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
1455
- children: [
1456
- /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
1457
- /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
1458
- /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1459
- /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.newPasswordLabel }),
1460
- /* @__PURE__ */ jsx(
1461
- TextInput,
1462
- {
1463
- secureTextEntry: true,
1464
- accessibilityHint: labels.newPasswordPlaceholder,
1465
- accessibilityLabel: labels.newPasswordLabel,
1466
- autoCapitalize: "none",
1467
- autoCorrect: false,
1468
- editable: !form.isSubmitting,
1469
- placeholder: labels.newPasswordPlaceholder,
1470
- placeholderTextColor: theme.colors.textSecondary,
1471
- style: styles3.input,
1472
- testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
1473
- value: form.newPassword,
1474
- onChangeText: form.setNewPassword
1475
- }
1476
- )
1477
- ] }),
1478
- /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1479
- /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
1480
- /* @__PURE__ */ jsx(
1481
- TextInput,
1482
- {
1483
- secureTextEntry: true,
1484
- accessibilityHint: labels.confirmPasswordPlaceholder,
1485
- accessibilityLabel: labels.confirmPasswordLabel,
1486
- autoCapitalize: "none",
1487
- autoCorrect: false,
1488
- editable: !form.isSubmitting,
1489
- placeholder: labels.confirmPasswordPlaceholder,
1490
- placeholderTextColor: theme.colors.textSecondary,
1491
- style: styles3.input,
1492
- testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
1493
- value: form.confirmPassword,
1494
- onChangeText: form.setConfirmPassword
1495
- }
1496
- )
1497
- ] }),
1498
- message !== null ? /* @__PURE__ */ jsx(
1499
- Text,
1500
- {
1501
- style: styles3.errorText,
1502
- testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
1503
- children: message
1504
- }
1505
- ) : null,
1506
- /* @__PURE__ */ jsx(
1507
- TouchableOpacity,
1508
- {
1509
- accessibilityHint: labels.submit,
1510
- accessibilityLabel: form.isSubmitting ? labels.submitting : labels.submit,
1511
- accessibilityRole: "button",
1512
- disabled: form.isSubmitting,
1513
- style: submitButtonStyle,
1514
- testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
1515
- onPress: form.submit,
1516
- children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
1517
- }
1518
- )
1519
- ]
1596
+ children: /* @__PURE__ */ jsx(
1597
+ ResetPasswordFields,
1598
+ {
1599
+ form,
1600
+ labels,
1601
+ styles: styles3,
1602
+ testIdPrefix,
1603
+ theme
1604
+ }
1605
+ )
1520
1606
  }
1521
1607
  ) });
1522
1608
  }
@@ -1526,7 +1612,7 @@ function OtpRequestStep({
1526
1612
  labels,
1527
1613
  testIdPrefix,
1528
1614
  isSubmitting,
1529
- errorText,
1615
+ errorText: errorText2,
1530
1616
  onSubmit
1531
1617
  }) {
1532
1618
  const [email, setEmail] = useState("");
@@ -1554,7 +1640,7 @@ function OtpRequestStep({
1554
1640
  }
1555
1641
  )
1556
1642
  ] }),
1557
- errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1643
+ errorText2 !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText2 }) : null,
1558
1644
  /* @__PURE__ */ jsx(
1559
1645
  TouchableOpacity,
1560
1646
  {
@@ -1577,7 +1663,7 @@ function OtpVerifyStep({
1577
1663
  testIdPrefix,
1578
1664
  identifier,
1579
1665
  isSubmitting,
1580
- errorText,
1666
+ errorText: errorText2,
1581
1667
  onSubmit,
1582
1668
  onResend,
1583
1669
  onChangeEmail
@@ -1608,7 +1694,7 @@ function OtpVerifyStep({
1608
1694
  }
1609
1695
  )
1610
1696
  ] }),
1611
- errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1697
+ errorText2 !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText2 }) : null,
1612
1698
  /* @__PURE__ */ jsx(
1613
1699
  TouchableOpacity,
1614
1700
  {
@@ -1831,11 +1917,11 @@ function OtpForm({
1831
1917
  setLocalError(null);
1832
1918
  otp.reset();
1833
1919
  }, [otp]);
1834
- const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);
1920
+ const errorText2 = localError ?? transportErrorFor(otp.step, otp.error, labels);
1835
1921
  const content = otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsx(
1836
1922
  OtpRequestStep,
1837
1923
  {
1838
- errorText,
1924
+ errorText: errorText2,
1839
1925
  isSubmitting: otp.isSubmitting,
1840
1926
  labels,
1841
1927
  styles: styles3,
@@ -1846,7 +1932,7 @@ function OtpForm({
1846
1932
  ) : /* @__PURE__ */ jsx(
1847
1933
  OtpVerifyStep,
1848
1934
  {
1849
- errorText,
1935
+ errorText: errorText2,
1850
1936
  identifier: otp.identifier,
1851
1937
  isSubmitting: otp.isSubmitting,
1852
1938
  labels,
@@ -1958,7 +2044,7 @@ function PinForm({
1958
2044
  const [localError, setLocalError] = useState(null);
1959
2045
  const [pinValue, setPinValue] = useState("");
1960
2046
  const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
1961
- const errorText = localError ?? transportErrorFor2(pin.error, labels);
2047
+ const errorText2 = localError ?? transportErrorFor2(pin.error, labels);
1962
2048
  const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1963
2049
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1964
2050
  /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
@@ -1984,12 +2070,12 @@ function PinForm({
1984
2070
  }
1985
2071
  )
1986
2072
  ] }),
1987
- errorText !== null ? /* @__PURE__ */ jsx(
2073
+ errorText2 !== null ? /* @__PURE__ */ jsx(
1988
2074
  Text,
1989
2075
  {
1990
2076
  style: styles3.errorText,
1991
2077
  testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
1992
- children: errorText
2078
+ children: errorText2
1993
2079
  }
1994
2080
  ) : null,
1995
2081
  /* @__PURE__ */ jsx(
@@ -2215,7 +2301,7 @@ function useDevicePinUnlock({
2215
2301
  const [pin, setPinState] = useState("");
2216
2302
  const [submitting, setSubmitting] = useState(false);
2217
2303
  const [errorKey, setErrorKey] = useState(null);
2218
- const [retryAfterSeconds, setRetryAfterSeconds] = useState(null);
2304
+ const [retryAfterSeconds2, setRetryAfterSeconds] = useState(null);
2219
2305
  const setPin = useCallback((next) => {
2220
2306
  setPinState(next);
2221
2307
  setErrorKey(null);
@@ -2255,7 +2341,7 @@ function useDevicePinUnlock({
2255
2341
  setSubmitting(false);
2256
2342
  });
2257
2343
  }, [client, pin, digits, onSignedIn]);
2258
- return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
2344
+ return { pin, submitting, errorKey, retryAfterSeconds: retryAfterSeconds2, setPin, submit };
2259
2345
  }
2260
2346
  function resolveErrorText(errorKey, digits, retryAfter, labels) {
2261
2347
  if (errorKey === null) {
@@ -2291,14 +2377,14 @@ function DevicePinUnlockScreen({
2291
2377
  () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
2292
2378
  [labelsProp]
2293
2379
  );
2294
- const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
2380
+ const { pin, submitting, errorKey, retryAfterSeconds: retryAfterSeconds2, setPin, submit } = useDevicePinUnlock({
2295
2381
  client,
2296
2382
  digits,
2297
2383
  onSignedIn
2298
2384
  });
2299
2385
  const hasName = rememberedUsername !== "";
2300
2386
  const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
2301
- const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
2387
+ const error = resolveErrorText(errorKey, digits, retryAfterSeconds2, labels);
2302
2388
  const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
2303
2389
  return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
2304
2390
  View,
@@ -4145,7 +4231,8 @@ var RegisterTestIds = {
4145
4231
  confirmPasswordInput: "register-confirm-password-input",
4146
4232
  tenantNameInput: "register-tenant-name-input",
4147
4233
  submitButton: "register-submit-button",
4148
- websiteInput: "register-website"
4234
+ websiteInput: "register-website",
4235
+ checkEmail: "register-check-email"
4149
4236
  };
4150
4237
  var FIELDS = [
4151
4238
  { key: "firstName", testId: RegisterTestIds.firstNameInput, autoComplete: "name" },
@@ -4257,14 +4344,22 @@ var RegisterErrorCode = /* @__PURE__ */ ((RegisterErrorCode2) => {
4257
4344
  })(RegisterErrorCode || {});
4258
4345
 
4259
4346
  // src/hooks/routeRegisterOutcome.ts
4260
- function routeRegisterOutcome(outcome, handlers) {
4261
- if (outcome.ok) {
4262
- handlers.onSuccess(outcome.result);
4347
+ function routeRegisterOutcome(outcome2, handlers) {
4348
+ if (outcome2.ok) {
4349
+ handlers.onSuccess(outcome2.result);
4263
4350
  return;
4264
4351
  }
4265
- if (outcome.error !== "inFlight" /* InFlight */) {
4266
- handlers.onError?.(outcome.error);
4352
+ if (outcome2.error !== "inFlight" /* InFlight */) {
4353
+ handlers.onError?.(outcome2.error);
4354
+ }
4355
+ }
4356
+
4357
+ // src/hooks/registerAccepted.ts
4358
+ function isRegisterAccepted(result) {
4359
+ if (typeof result !== "object" || result === null) {
4360
+ return false;
4267
4361
  }
4362
+ return result.accepted === true;
4268
4363
  }
4269
4364
 
4270
4365
  // src/hooks/registerErrors.ts
@@ -4419,6 +4514,42 @@ function expandCompactRegisterValues(values) {
4419
4514
  };
4420
4515
  }
4421
4516
 
4517
+ // src/hooks/newIdempotencyKey.ts
4518
+ var HEX_RADIX = 16;
4519
+ var HEX_BYTE_LENGTH = 2;
4520
+ var KEY_BYTES = 16;
4521
+ var fallbackSequence = 0;
4522
+ function newIdempotencyKey() {
4523
+ const cryptoApi = globalThis.crypto;
4524
+ if (typeof cryptoApi?.randomUUID === "function") {
4525
+ return cryptoApi.randomUUID();
4526
+ }
4527
+ if (typeof cryptoApi?.getRandomValues === "function") {
4528
+ const bytes = cryptoApi.getRandomValues(new Uint8Array(KEY_BYTES));
4529
+ return Array.from(bytes, (byte) => byte.toString(HEX_RADIX).padStart(HEX_BYTE_LENGTH, "0")).join("");
4530
+ }
4531
+ fallbackSequence += 1;
4532
+ return `${Date.now().toString(HEX_RADIX)}-${String(fallbackSequence)}`;
4533
+ }
4534
+
4535
+ // src/hooks/useRegisterSubmitMeta.ts
4536
+ function useRegisterSubmitMeta() {
4537
+ const openedAt = useRef(Date.now());
4538
+ const key = useRef(null);
4539
+ return useMemo(
4540
+ () => ({
4541
+ next: () => {
4542
+ key.current ?? (key.current = newIdempotencyKey());
4543
+ return { idempotencyKey: key.current, formElapsedMs: Date.now() - openedAt.current };
4544
+ },
4545
+ resetKey: () => {
4546
+ key.current = null;
4547
+ }
4548
+ }),
4549
+ []
4550
+ );
4551
+ }
4552
+
4422
4553
  // src/hooks/useRegisterForm.ts
4423
4554
  var EMPTY_VALUES = {
4424
4555
  firstName: "",
@@ -4430,6 +4561,9 @@ var EMPTY_VALUES = {
4430
4561
  tenantName: "",
4431
4562
  website: ""
4432
4563
  };
4564
+ function withoutPasswords(values) {
4565
+ return { ...values, password: "", confirmPassword: "" };
4566
+ }
4433
4567
  function toSubmitValues(values) {
4434
4568
  return {
4435
4569
  firstName: values.firstName,
@@ -4445,15 +4579,18 @@ function useRegisterForm({
4445
4579
  onSubmit,
4446
4580
  passwordPolicy = isRegisterPasswordStrong,
4447
4581
  onSubmitAttempt,
4448
- compact = false
4582
+ compact = false,
4583
+ sharedRegistration = false
4449
4584
  }) {
4450
4585
  const [state, setState] = useState(EMPTY_VALUES);
4451
4586
  const [isSubmitting, setIsSubmitting] = useState(false);
4452
4587
  const [error, setError] = useState(null);
4453
4588
  const inFlight = useRef(false);
4589
+ const submitMeta = useRegisterSubmitMeta();
4454
4590
  const setField = useCallback((field2, value) => {
4591
+ submitMeta.resetKey();
4455
4592
  setState((prev) => ({ ...prev, [field2]: value }));
4456
- }, []);
4593
+ }, [submitMeta]);
4457
4594
  const submit = useCallback(async () => {
4458
4595
  if (inFlight.current) {
4459
4596
  return { ok: false, error: "inFlight" /* InFlight */ };
@@ -4470,7 +4607,11 @@ function useRegisterForm({
4470
4607
  setError(null);
4471
4608
  setIsSubmitting(true);
4472
4609
  try {
4473
- const result = await onSubmit(toSubmitValues(trimmed));
4610
+ const values = toSubmitValues(trimmed);
4611
+ const result = await (sharedRegistration ? onSubmit(values, submitMeta.next()) : onSubmit(values));
4612
+ if (sharedRegistration && isRegisterAccepted(result)) {
4613
+ setState(withoutPasswords);
4614
+ }
4474
4615
  return { ok: true, result };
4475
4616
  } catch (caught) {
4476
4617
  const code = mapRegisterErrorCode(caught);
@@ -4480,10 +4621,10 @@ function useRegisterForm({
4480
4621
  inFlight.current = false;
4481
4622
  setIsSubmitting(false);
4482
4623
  }
4483
- }, [compact, onSubmit, onSubmitAttempt, passwordPolicy, state]);
4624
+ }, [compact, onSubmit, onSubmitAttempt, passwordPolicy, sharedRegistration, state, submitMeta]);
4484
4625
  return { state, setField, submit, isSubmitting, error };
4485
4626
  }
4486
- function RegisterForm({
4627
+ function RegisterFormCore({
4487
4628
  onSubmit,
4488
4629
  onSuccess,
4489
4630
  onError,
@@ -4493,7 +4634,8 @@ function RegisterForm({
4493
4634
  theme: themeProp,
4494
4635
  footer,
4495
4636
  testIdPrefix,
4496
- compact = false
4637
+ compact = false,
4638
+ sharedRegistration
4497
4639
  }) {
4498
4640
  const theme = useAuthTheme(themeProp);
4499
4641
  const styles3 = useAuthStyles(theme);
@@ -4505,7 +4647,8 @@ function RegisterForm({
4505
4647
  onSubmit,
4506
4648
  onSubmitAttempt,
4507
4649
  passwordPolicy,
4508
- compact
4650
+ compact,
4651
+ sharedRegistration
4509
4652
  });
4510
4653
  const handlePress = useCallback(async () => {
4511
4654
  routeRegisterOutcome(await submit(), { onSuccess, onError });
@@ -4543,6 +4686,9 @@ function RegisterForm({
4543
4686
  footer
4544
4687
  ] }) });
4545
4688
  }
4689
+ function RegisterForm(props) {
4690
+ return /* @__PURE__ */ jsx(RegisterFormCore, { ...props, sharedRegistration: false });
4691
+ }
4546
4692
  async function lazyFetchHttpClient(request) {
4547
4693
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
4548
4694
  if (fetchImpl === void 0) {
@@ -4771,19 +4917,155 @@ var VerifyEmailErrorCode = /* @__PURE__ */ ((VerifyEmailErrorCode2) => {
4771
4917
  VerifyEmailErrorCode2["TokenUsed"] = "TOKEN_USED";
4772
4918
  VerifyEmailErrorCode2["KeycloakUpdateFailed"] = "KEYCLOAK_UPDATE_FAILED";
4773
4919
  VerifyEmailErrorCode2["MissingToken"] = "MISSING_TOKEN";
4920
+ VerifyEmailErrorCode2["NewPasswordRequired"] = "NEW_PASSWORD_REQUIRED";
4921
+ VerifyEmailErrorCode2["WeakPassword"] = "WEAK_PASSWORD";
4922
+ VerifyEmailErrorCode2["RateLimited"] = "RATE_LIMITED";
4923
+ VerifyEmailErrorCode2["SignInFailed"] = "SIGN_IN_FAILED";
4774
4924
  VerifyEmailErrorCode2["Generic"] = "GENERIC";
4775
4925
  return VerifyEmailErrorCode2;
4776
4926
  })(VerifyEmailErrorCode || {});
4777
4927
 
4928
+ // src/verify/useVerifyNewPasswordForm.ts
4929
+ var GENERIC_FAILURE = { success: false, errorCode: "GENERIC" /* Generic */ };
4930
+ var DEAD_LINK_CODES = [
4931
+ "TOKEN_INVALID" /* TokenInvalid */,
4932
+ "TOKEN_EXPIRED" /* TokenExpired */,
4933
+ "TOKEN_USED" /* TokenUsed */,
4934
+ "SIGN_IN_FAILED" /* SignInFailed */
4935
+ ];
4936
+ function retryableError(code) {
4937
+ if (DEAD_LINK_CODES.includes(code)) {
4938
+ return null;
4939
+ }
4940
+ if (code === "WEAK_PASSWORD" /* WeakPassword */) {
4941
+ return "weakPassword" /* WeakPassword */;
4942
+ }
4943
+ return code === "RATE_LIMITED" /* RateLimited */ ? "rateLimited" /* RateLimited */ : "network" /* Network */;
4944
+ }
4945
+ function useVerifyNewPasswordForm({
4946
+ client,
4947
+ token,
4948
+ onSettled
4949
+ }) {
4950
+ const { state, setters } = useFormState();
4951
+ const [isSubmitting, setIsSubmitting] = useState(false);
4952
+ const inFlight = useRef(false);
4953
+ const send = useMemo(
4954
+ () => async (newPassword) => {
4955
+ if (inFlight.current) {
4956
+ return;
4957
+ }
4958
+ inFlight.current = true;
4959
+ setIsSubmitting(true);
4960
+ const result = await (client.setNewPassword?.(token, newPassword) ?? Promise.resolve(GENERIC_FAILURE)).catch(
4961
+ () => GENERIC_FAILURE
4962
+ );
4963
+ inFlight.current = false;
4964
+ setIsSubmitting(false);
4965
+ const formError = result.success ? null : retryableError(result.errorCode);
4966
+ if (formError === null) {
4967
+ onSettled(result);
4968
+ return;
4969
+ }
4970
+ setters.setErrorKey(formError);
4971
+ },
4972
+ [client, onSettled, setters, token]
4973
+ );
4974
+ return {
4975
+ ...state,
4976
+ setNewPassword: setters.setNewPassword,
4977
+ setConfirmPassword: setters.setConfirmPassword,
4978
+ isSubmitting,
4979
+ submit: () => runSubmit({
4980
+ newPassword: state.newPassword,
4981
+ confirmPassword: state.confirmPassword,
4982
+ token,
4983
+ setErrorKey: setters.setErrorKey,
4984
+ setHasInvalidToken: setters.setHasInvalidToken,
4985
+ mutate: (request) => {
4986
+ void send(request.newPassword);
4987
+ }
4988
+ })
4989
+ };
4990
+ }
4991
+ function VerifyNewPasswordStep({
4992
+ client,
4993
+ token,
4994
+ labels: labelsProp,
4995
+ styles: styles3,
4996
+ theme,
4997
+ testIdPrefix,
4998
+ onSettled
4999
+ }) {
5000
+ const labels = useMemo(
5001
+ () => ({ ...DEFAULT_VERIFY_NEW_PASSWORD_LABELS, ...labelsProp }),
5002
+ [labelsProp]
5003
+ );
5004
+ const form = useVerifyNewPasswordForm({ client, token, onSettled });
5005
+ const handleSubmitEditing = useSubmitOnEnter(form.submit);
5006
+ const newPasswordRef = useRef(null);
5007
+ useFocusOnMount(newPasswordRef);
5008
+ return /* @__PURE__ */ jsx(View, { testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix), children: /* @__PURE__ */ jsx(
5009
+ ResetPasswordFields,
5010
+ {
5011
+ form,
5012
+ labels,
5013
+ newPasswordRef,
5014
+ styles: styles3,
5015
+ testIdPrefix,
5016
+ theme,
5017
+ onSubmitEditing: handleSubmitEditing
5018
+ }
5019
+ ) });
5020
+ }
5021
+ function VerifySignInPrompt({
5022
+ labels: labelsProp,
5023
+ styles: styles3,
5024
+ testID,
5025
+ actionTestID,
5026
+ onContinue
5027
+ }) {
5028
+ const labels = useMemo(() => ({ ...DEFAULT_VERIFY_SIGN_IN_LABELS, ...labelsProp }), [labelsProp]);
5029
+ const actionRef = useRef(null);
5030
+ useFocusOnMount(actionRef);
5031
+ return /* @__PURE__ */ jsxs(View, { testID, children: [
5032
+ /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: styles3.title, children: labels.title }),
5033
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.body }),
5034
+ /* @__PURE__ */ jsx(
5035
+ TouchableOpacity,
5036
+ {
5037
+ ref: actionRef,
5038
+ accessibilityHint: labels.actionHint,
5039
+ accessibilityLabel: labels.action,
5040
+ accessibilityRole: "button",
5041
+ style: styles3.primaryButton,
5042
+ testID: actionTestID,
5043
+ onPress: onContinue,
5044
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.action })
5045
+ }
5046
+ )
5047
+ ] });
5048
+ }
5049
+
4778
5050
  // src/verify/VerifyEmailPhase.ts
4779
5051
  var VerifyEmailPhase = /* @__PURE__ */ ((VerifyEmailPhase2) => {
4780
5052
  VerifyEmailPhase2["Loading"] = "loading";
4781
5053
  VerifyEmailPhase2["Success"] = "success";
4782
5054
  VerifyEmailPhase2["Failure"] = "failure";
5055
+ VerifyEmailPhase2["NewPasswordRequired"] = "newPasswordRequired";
4783
5056
  return VerifyEmailPhase2;
4784
5057
  })(VerifyEmailPhase || {});
4785
5058
 
4786
- // src/verify/useVerifyEmail.ts
5059
+ // src/verify/resolveVerifyView.ts
5060
+ function resolveVerifyView(verify, passwordOutcome) {
5061
+ if (passwordOutcome === null) {
5062
+ return verify;
5063
+ }
5064
+ if (passwordOutcome.success) {
5065
+ return { phase: "success" /* Success */, errorCode: "GENERIC" /* Generic */ };
5066
+ }
5067
+ return { phase: "failure" /* Failure */, errorCode: passwordOutcome.errorCode };
5068
+ }
4787
5069
  var LOADING = {
4788
5070
  phase: "loading" /* Loading */,
4789
5071
  errorCode: "GENERIC" /* Generic */
@@ -4792,6 +5074,10 @@ var SUCCESS = {
4792
5074
  phase: "success" /* Success */,
4793
5075
  errorCode: "GENERIC" /* Generic */
4794
5076
  };
5077
+ var NEW_PASSWORD_REQUIRED = {
5078
+ phase: "newPasswordRequired" /* NewPasswordRequired */,
5079
+ errorCode: "GENERIC" /* Generic */
5080
+ };
4795
5081
  var REJECTED = { success: false, errorCode: "GENERIC" /* Generic */ };
4796
5082
  function failure(errorCode) {
4797
5083
  return { phase: "failure" /* Failure */, errorCode };
@@ -4817,6 +5103,10 @@ function useVerifyEmail({ client, token, onVerified, onFailed }) {
4817
5103
  latest.current.onVerified?.();
4818
5104
  return;
4819
5105
  }
5106
+ if (result.errorCode === "NEW_PASSWORD_REQUIRED" /* NewPasswordRequired */) {
5107
+ setState(NEW_PASSWORD_REQUIRED);
5108
+ return;
5109
+ }
4820
5110
  setState(failure(result.errorCode));
4821
5111
  latest.current.onFailed?.(result.errorCode);
4822
5112
  };
@@ -4842,6 +5132,12 @@ function verifyEmailErrorText(code, labels) {
4842
5132
  if (code === "MISSING_TOKEN" /* MissingToken */) {
4843
5133
  return labels.missingToken;
4844
5134
  }
5135
+ if (code === "SIGN_IN_FAILED" /* SignInFailed */) {
5136
+ return labels.signIn?.body ?? DEFAULT_VERIFY_SIGN_IN_LABELS.body;
5137
+ }
5138
+ if (code === "RATE_LIMITED" /* RateLimited */) {
5139
+ return labels.errorRateLimited ?? labels.errorGeneric;
5140
+ }
4845
5141
  return labels.errorGeneric;
4846
5142
  }
4847
5143
  function ResendCta({ label, hint, style, textStyle, testID, onPress }) {
@@ -4878,7 +5174,20 @@ function VerifyEmailScreen({
4878
5174
  () => ({ ...DEFAULT_VERIFY_EMAIL_LABELS, ...labelsProp }),
4879
5175
  [labelsProp]
4880
5176
  );
4881
- const { phase, errorCode } = useVerifyEmail({ client, token, onVerified, onFailed });
5177
+ const verify = useVerifyEmail({ client, token, onVerified, onFailed });
5178
+ const [passwordOutcome, setPasswordOutcome] = useState(null);
5179
+ const { phase, errorCode } = resolveVerifyView(verify, passwordOutcome);
5180
+ const settlePassword = useCallback(
5181
+ (result) => {
5182
+ setPasswordOutcome(result);
5183
+ if (result.success) {
5184
+ onVerified?.();
5185
+ return;
5186
+ }
5187
+ onFailed?.(result.errorCode);
5188
+ },
5189
+ [onFailed, onVerified]
5190
+ );
4882
5191
  const [resendOpen, setResendOpen] = useState(false);
4883
5192
  const openResend = useCallback(() => setResendOpen(true), []);
4884
5193
  const id = (base) => withTestIdPrefix(base, testIdPrefix);
@@ -4888,6 +5197,18 @@ function VerifyEmailScreen({
4888
5197
  /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: styles3.title, children: labels.loadingTitle }),
4889
5198
  /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.loadingHint })
4890
5199
  ] }) : null,
5200
+ phase === "newPasswordRequired" /* NewPasswordRequired */ ? /* @__PURE__ */ jsx(
5201
+ VerifyNewPasswordStep,
5202
+ {
5203
+ client,
5204
+ labels: labels.newPassword,
5205
+ styles: styles3,
5206
+ testIdPrefix,
5207
+ theme,
5208
+ token,
5209
+ onSettled: settlePassword
5210
+ }
5211
+ ) : null,
4891
5212
  phase === "success" /* Success */ ? /* @__PURE__ */ jsxs(View, { testID: id(AuthTestIds.verifyEmailSuccess), children: [
4892
5213
  /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: styles3.title, children: labels.successTitle }),
4893
5214
  /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.successBody }),
@@ -4904,7 +5225,17 @@ function VerifyEmailScreen({
4904
5225
  }
4905
5226
  )
4906
5227
  ] }) : null,
4907
- phase === "failure" /* Failure */ ? /* @__PURE__ */ jsxs(View, { testID: id(AuthTestIds.verifyEmailError), children: [
5228
+ phase === "failure" /* Failure */ && errorCode === "SIGN_IN_FAILED" /* SignInFailed */ ? /* @__PURE__ */ jsx(
5229
+ VerifySignInPrompt,
5230
+ {
5231
+ actionTestID: id(AuthTestIds.verifyEmailSignInContinue),
5232
+ labels: labels.signIn,
5233
+ styles: styles3,
5234
+ testID: id(AuthTestIds.verifyEmailSignIn),
5235
+ onContinue
5236
+ }
5237
+ ) : null,
5238
+ phase === "failure" /* Failure */ && errorCode !== "SIGN_IN_FAILED" /* SignInFailed */ ? /* @__PURE__ */ jsxs(View, { testID: id(AuthTestIds.verifyEmailError), children: [
4908
5239
  /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: styles3.title, children: labels.errorTitle }),
4909
5240
  /* @__PURE__ */ jsx(Text, { style: styles3.errorBody, children: verifyEmailErrorText(errorCode, labels) }),
4910
5241
  resendOpen ? /* @__PURE__ */ jsx(
@@ -4942,7 +5273,7 @@ var SERVER_ERROR_CODES2 = [
4942
5273
  "TOKEN_USED" /* TokenUsed */,
4943
5274
  "KEYCLOAK_UPDATE_FAILED" /* KeycloakUpdateFailed */
4944
5275
  ];
4945
- var GENERIC_FAILURE = { success: false, errorCode: "GENERIC" /* Generic */ };
5276
+ var GENERIC_FAILURE2 = { success: false, errorCode: "GENERIC" /* Generic */ };
4946
5277
  var INVALID_TOKEN = { success: false, errorCode: "TOKEN_INVALID" /* TokenInvalid */ };
4947
5278
  var HTTP_BAD_REQUEST3 = 400;
4948
5279
  var TOKEN_FIELD = "token";
@@ -4967,7 +5298,7 @@ function isTokenValidationRejection(status, body) {
4967
5298
  }
4968
5299
  function decodeVerifyResponse(status, body) {
4969
5300
  if (!isRecord3(body)) {
4970
- return GENERIC_FAILURE;
5301
+ return GENERIC_FAILURE2;
4971
5302
  }
4972
5303
  if (body.success === true) {
4973
5304
  return { success: true };
@@ -4975,7 +5306,7 @@ function decodeVerifyResponse(status, body) {
4975
5306
  if (isServerErrorCode(body.errorCode)) {
4976
5307
  return { success: false, errorCode: body.errorCode };
4977
5308
  }
4978
- return isTokenValidationRejection(status, body) ? INVALID_TOKEN : GENERIC_FAILURE;
5309
+ return isTokenValidationRejection(status, body) ? INVALID_TOKEN : GENERIC_FAILURE2;
4979
5310
  }
4980
5311
  function createBffVerifyEmailClient(options = {}) {
4981
5312
  const http = options.http ?? lazyFetchHttpClient3;
@@ -4993,7 +5324,7 @@ function createBffVerifyEmailClient(options = {}) {
4993
5324
  const response = await post(VERIFY_EMAIL_ENDPOINT, { token });
4994
5325
  return decodeVerifyResponse(response.status, response.data);
4995
5326
  } catch {
4996
- return GENERIC_FAILURE;
5327
+ return GENERIC_FAILURE2;
4997
5328
  }
4998
5329
  },
4999
5330
  resendVerification: async (email, verifyUrlTemplate) => {
@@ -5033,6 +5364,548 @@ function readVerifyToken(raw) {
5033
5364
  return typeof first === "string" ? first : "";
5034
5365
  }
5035
5366
 
5036
- export { AccountSettingsScreen, AuthScreen, AuthTestIds, AuthThemeProvider, BffAuthStatus, CHANGE_PASSWORD_ENDPOINT, ChangePasswordCard, ChangePasswordErrorKey, DEFAULT_ACCOUNT_SETTINGS_LABELS, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_REGISTER_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEFAULT_VERIFY_EMAIL_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DemoCredentialsHint, DemoCredentialsHintVariant, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, PreferredMethodHint, PreferredMethodSettingsCard, PrefillIntent, RESEND_VERIFICATION_ENDPOINT, RegisterErrorCode, RegisterForm, RegisterTestIds, ResetPasswordError, ResetPasswordForm, VERIFY_EMAIL_ENDPOINT, VERIFY_TOKEN_PLACEHOLDER, VerifyEmailErrorCode, VerifyEmailPhase, VerifyEmailScreen, buildVerifyUrlTemplate, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createBffChangePasswordClient, createBffVerifyEmailClient, createPreferencesClient, defaultAuthTheme, deriveUsernameFromEmail, isAllowedPinDigits, isPasswordValid, isRegisterPasswordStrong, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, readVerifyToken, resolveAccessibleRoutes, resolveAccountList, resolveDemoAccounts, resolveDemoCredentials, resolvePostLoginRoute, splitFullName, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useChangePassword, useDemoCredentials, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useRegisterForm, useResendVerification, useResetPasswordForm, useVerifyEmail, validatePasswordPolicy, verifyEmailErrorText, withTestIdPrefix };
5367
+ // src/verify/sharedRegistrationClient.ts
5368
+ var REGISTER_ENDPOINT = "/bff/register";
5369
+ var VERIFY_AND_LOGIN_ENDPOINT = "/bff/verify-and-login";
5370
+ var HTTP_ACCEPTED = 202;
5371
+ var HTTP_UNAUTHORIZED2 = 401;
5372
+ var HTTP_TOO_MANY_REQUESTS2 = 429;
5373
+ var NO_MESSAGE = "";
5374
+ var GENERIC_FAILURE3 = { success: false, errorCode: "GENERIC" /* Generic */ };
5375
+ function decodeVerifyAndLogin(response) {
5376
+ if (response.ok) {
5377
+ return { success: true };
5378
+ }
5379
+ if (response.status === HTTP_TOO_MANY_REQUESTS2) {
5380
+ return { success: false, errorCode: "RATE_LIMITED" /* RateLimited */ };
5381
+ }
5382
+ if (response.status === HTTP_UNAUTHORIZED2) {
5383
+ return { success: false, errorCode: "SIGN_IN_FAILED" /* SignInFailed */ };
5384
+ }
5385
+ const body = isRecord3(response.data) ? response.data : {};
5386
+ if (body.errorCode === "NEW_PASSWORD_REQUIRED" /* NewPasswordRequired */ || body.errorCode === "WEAK_PASSWORD" /* WeakPassword */) {
5387
+ return { success: false, errorCode: body.errorCode };
5388
+ }
5389
+ return decodeVerifyResponse(response.status, response.data);
5390
+ }
5391
+ function registerFailure(response) {
5392
+ const body = isRecord3(response.data) ? response.data : {};
5393
+ const errorCode = body.errorCode ?? body.code;
5394
+ const message = `Registration failed with status ${String(response.status)}`;
5395
+ return Object.assign(new Error(message), { status: response.status, errorCode });
5396
+ }
5397
+ function createSharedRegistrationClient(options = {}) {
5398
+ const http = options.http ?? lazyFetchHttpClient3;
5399
+ const baseUrl = options.baseUrl ?? "";
5400
+ const post = (path, body, headers = {}) => http({
5401
+ url: `${baseUrl}${path}`,
5402
+ method: "POST",
5403
+ headers: { "Content-Type": "application/json", "X-BFF-Csrf": "1", ...headers },
5404
+ body: JSON.stringify(body),
5405
+ credentials: "include"
5406
+ });
5407
+ const verifyAndLogin = async (body) => {
5408
+ try {
5409
+ return decodeVerifyAndLogin(await post(VERIFY_AND_LOGIN_ENDPOINT, body));
5410
+ } catch {
5411
+ return GENERIC_FAILURE3;
5412
+ }
5413
+ };
5414
+ const verifyEmailClient = createBffVerifyEmailClient(options);
5415
+ return {
5416
+ register: async (request, meta) => {
5417
+ const body = meta === void 0 ? request : { ...request, formElapsedMs: meta.formElapsedMs };
5418
+ const headers = meta === void 0 ? {} : { "Idempotency-Key": meta.idempotencyKey };
5419
+ const response = await post(REGISTER_ENDPOINT, body, headers).catch(() => {
5420
+ throw new Error(NO_MESSAGE);
5421
+ });
5422
+ if (!response.ok) {
5423
+ throw registerFailure(response);
5424
+ }
5425
+ return { accepted: response.status === HTTP_ACCEPTED, body: response.data };
5426
+ },
5427
+ verifyEmail: (token) => verifyAndLogin({ token }),
5428
+ setNewPassword: (token, newPassword) => verifyAndLogin({ token, newPassword }),
5429
+ resendVerification: (email, verifyUrlTemplate) => verifyEmailClient.resendVerification(email, verifyUrlTemplate)
5430
+ };
5431
+ }
5432
+ function RegisterCheckEmail({
5433
+ labels,
5434
+ styles: styles3,
5435
+ footer,
5436
+ testIdPrefix
5437
+ }) {
5438
+ const headingRef = useRef(null);
5439
+ useFocusOnMount(headingRef);
5440
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
5441
+ View,
5442
+ {
5443
+ accessibilityLiveRegion: "polite",
5444
+ style: styles3.card,
5445
+ testID: withTestIdPrefix(RegisterTestIds.checkEmail, testIdPrefix),
5446
+ children: [
5447
+ /* @__PURE__ */ jsx(View, { ref: headingRef, accessible: true, focusable: true, children: /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: styles3.title, children: labels.checkEmailTitle }) }),
5448
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.checkEmailBody }),
5449
+ footer
5450
+ ]
5451
+ }
5452
+ ) });
5453
+ }
5454
+ function SharedRegisterForm({
5455
+ onSuccess,
5456
+ onAccepted,
5457
+ ...formProps
5458
+ }) {
5459
+ const { footer, labels: labelsProp, testIdPrefix, theme: themeProp } = formProps;
5460
+ const styles3 = useAuthStyles(useAuthTheme(themeProp));
5461
+ const labels = useMemo(
5462
+ () => ({ ...DEFAULT_REGISTER_LABELS, ...labelsProp }),
5463
+ [labelsProp]
5464
+ );
5465
+ const [accepted, setAccepted] = useState(false);
5466
+ const handleResult = useCallback(
5467
+ (result) => {
5468
+ if (!isRegisterAccepted(result)) {
5469
+ onSuccess(result);
5470
+ return;
5471
+ }
5472
+ setAccepted(true);
5473
+ onAccepted?.(result);
5474
+ },
5475
+ [onAccepted, onSuccess]
5476
+ );
5477
+ if (accepted) {
5478
+ return /* @__PURE__ */ jsx(RegisterCheckEmail, { footer, labels, styles: styles3, testIdPrefix });
5479
+ }
5480
+ return /* @__PURE__ */ jsx(RegisterFormCore, { ...formProps, sharedRegistration: true, onSuccess: handleResult });
5481
+ }
5482
+
5483
+ // src/account/AccountDeletionStatus.ts
5484
+ var AccountDeletionStatus = /* @__PURE__ */ ((AccountDeletionStatus2) => {
5485
+ AccountDeletionStatus2["Accepted"] = "accepted";
5486
+ AccountDeletionStatus2["StepUpRequired"] = "stepUpRequired";
5487
+ AccountDeletionStatus2["AlreadyRequested"] = "alreadyRequested";
5488
+ AccountDeletionStatus2["SignInRequired"] = "signInRequired";
5489
+ AccountDeletionStatus2["RateLimited"] = "rateLimited";
5490
+ AccountDeletionStatus2["RetryLater"] = "retryLater";
5491
+ AccountDeletionStatus2["Failed"] = "failed";
5492
+ return AccountDeletionStatus2;
5493
+ })(AccountDeletionStatus || {});
5494
+
5495
+ // src/account/StepUpStatus.ts
5496
+ var StepUpStatus = /* @__PURE__ */ ((StepUpStatus2) => {
5497
+ StepUpStatus2["Confirmed"] = "confirmed";
5498
+ StepUpStatus2["WrongPassword"] = "wrongPassword";
5499
+ StepUpStatus2["RateLimited"] = "rateLimited";
5500
+ StepUpStatus2["Failed"] = "failed";
5501
+ return StepUpStatus2;
5502
+ })(StepUpStatus || {});
5503
+
5504
+ // src/account/accountDeletionClient.ts
5505
+ var ACCOUNT_DELETE_REQUEST_ENDPOINT = "/bff/account/delete-request";
5506
+ var STEP_UP_PASSWORD_ENDPOINT = "/bff/step-up/password";
5507
+ var RECENT_AUTHENTICATION_REQUIRED = "RECENT_AUTHENTICATION_REQUIRED";
5508
+ var HTTP_ACCEPTED2 = 202;
5509
+ var HTTP_UNAUTHORIZED3 = 401;
5510
+ var HTTP_FORBIDDEN = 403;
5511
+ var HTTP_CONFLICT = 409;
5512
+ var HTTP_TOO_MANY_REQUESTS3 = 429;
5513
+ var HTTP_BAD_GATEWAY = 502;
5514
+ var DELTA_SECONDS = /^\d+$/;
5515
+ function retryAfterSeconds(response) {
5516
+ const raw = response.header?.("Retry-After")?.trim();
5517
+ return raw !== void 0 && DELTA_SECONDS.test(raw) ? Number(raw) : null;
5518
+ }
5519
+ function decodeReceipt(data) {
5520
+ const body = isRecord3(data) ? data : {};
5521
+ return {
5522
+ requestId: typeof body.requestId === "string" ? body.requestId : "",
5523
+ scheduledDeletionDate: typeof body.scheduledDeletionDate === "string" ? body.scheduledDeletionDate : "",
5524
+ confirmationEmailSent: body.confirmationEmailSent === true
5525
+ };
5526
+ }
5527
+ function isStaleLogin(data) {
5528
+ return isRecord3(data) && data.code === RECENT_AUTHENTICATION_REQUIRED;
5529
+ }
5530
+ function decodeDeletion(response) {
5531
+ switch (response.status) {
5532
+ case HTTP_ACCEPTED2:
5533
+ return { status: "accepted" /* Accepted */, receipt: decodeReceipt(response.data) };
5534
+ case HTTP_FORBIDDEN:
5535
+ return { status: isStaleLogin(response.data) ? "stepUpRequired" /* StepUpRequired */ : "failed" /* Failed */ };
5536
+ case HTTP_CONFLICT:
5537
+ return { status: "alreadyRequested" /* AlreadyRequested */ };
5538
+ case HTTP_UNAUTHORIZED3:
5539
+ return { status: "signInRequired" /* SignInRequired */ };
5540
+ case HTTP_TOO_MANY_REQUESTS3:
5541
+ return { status: "rateLimited" /* RateLimited */, retryAfterSeconds: retryAfterSeconds(response) };
5542
+ case HTTP_BAD_GATEWAY:
5543
+ return { status: "retryLater" /* RetryLater */ };
5544
+ default:
5545
+ return { status: "failed" /* Failed */ };
5546
+ }
5547
+ }
5548
+ function decodeStepUp(response) {
5549
+ if (response.ok) {
5550
+ return { status: "confirmed" /* Confirmed */ };
5551
+ }
5552
+ if (response.status === HTTP_UNAUTHORIZED3) {
5553
+ return { status: "wrongPassword" /* WrongPassword */ };
5554
+ }
5555
+ if (response.status === HTTP_TOO_MANY_REQUESTS3) {
5556
+ return { status: "rateLimited" /* RateLimited */, retryAfterSeconds: retryAfterSeconds(response) };
5557
+ }
5558
+ return { status: "failed" /* Failed */ };
5559
+ }
5560
+ function createBffAccountDeletionClient(options = {}) {
5561
+ const http = options.http ?? lazyFetchHttpClient3;
5562
+ const baseUrl = options.baseUrl ?? "";
5563
+ const post = (path, body) => http({
5564
+ url: `${baseUrl}${path}`,
5565
+ method: "POST",
5566
+ headers: { "Content-Type": "application/json", "X-BFF-Csrf": "1" },
5567
+ body: JSON.stringify(body),
5568
+ credentials: "include"
5569
+ });
5570
+ return {
5571
+ requestDeletion: async (reason) => {
5572
+ try {
5573
+ return decodeDeletion(await post(ACCOUNT_DELETE_REQUEST_ENDPOINT, reason === void 0 ? {} : { reason }));
5574
+ } catch {
5575
+ return { status: "failed" /* Failed */ };
5576
+ }
5577
+ },
5578
+ stepUpPassword: async (password) => {
5579
+ try {
5580
+ return decodeStepUp(await post(STEP_UP_PASSWORD_ENDPOINT, { password }));
5581
+ } catch {
5582
+ return { status: "failed" /* Failed */ };
5583
+ }
5584
+ }
5585
+ };
5586
+ }
5587
+
5588
+ // src/account/AccountDeletionErrorKey.ts
5589
+ var AccountDeletionErrorKey = /* @__PURE__ */ ((AccountDeletionErrorKey2) => {
5590
+ AccountDeletionErrorKey2["PasswordRequired"] = "passwordRequired";
5591
+ AccountDeletionErrorKey2["WrongPassword"] = "wrongPassword";
5592
+ AccountDeletionErrorKey2["SignInRequired"] = "signInRequired";
5593
+ AccountDeletionErrorKey2["RateLimited"] = "rateLimited";
5594
+ AccountDeletionErrorKey2["RetryLater"] = "retryLater";
5595
+ AccountDeletionErrorKey2["Failed"] = "failed";
5596
+ return AccountDeletionErrorKey2;
5597
+ })(AccountDeletionErrorKey || {});
5598
+
5599
+ // src/account/AccountDeletionPhase.ts
5600
+ var AccountDeletionPhase = /* @__PURE__ */ ((AccountDeletionPhase2) => {
5601
+ AccountDeletionPhase2["Confirm"] = "confirm";
5602
+ AccountDeletionPhase2["StepUp"] = "stepUp";
5603
+ AccountDeletionPhase2["Accepted"] = "accepted";
5604
+ AccountDeletionPhase2["AlreadyRequested"] = "alreadyRequested";
5605
+ return AccountDeletionPhase2;
5606
+ })(AccountDeletionPhase || {});
5607
+
5608
+ // src/account/accountDeletionFlow.ts
5609
+ function outcome(phase, errorKey = null, retryAfterSeconds2 = null) {
5610
+ return { phase, errorKey, receipt: null, retryAfterSeconds: retryAfterSeconds2 };
5611
+ }
5612
+ function fromDeletion(result, steppedUp) {
5613
+ switch (result.status) {
5614
+ case "accepted" /* Accepted */:
5615
+ return { ...outcome("accepted" /* Accepted */), receipt: result.receipt };
5616
+ case "stepUpRequired" /* StepUpRequired */:
5617
+ return outcome("stepUp" /* StepUp */, steppedUp ? "failed" /* Failed */ : null);
5618
+ case "alreadyRequested" /* AlreadyRequested */:
5619
+ return outcome("alreadyRequested" /* AlreadyRequested */);
5620
+ case "signInRequired" /* SignInRequired */:
5621
+ return outcome("confirm" /* Confirm */, "signInRequired" /* SignInRequired */);
5622
+ case "rateLimited" /* RateLimited */:
5623
+ return outcome("confirm" /* Confirm */, "rateLimited" /* RateLimited */, result.retryAfterSeconds);
5624
+ case "retryLater" /* RetryLater */:
5625
+ return outcome("confirm" /* Confirm */, "retryLater" /* RetryLater */);
5626
+ default:
5627
+ return outcome("confirm" /* Confirm */, "failed" /* Failed */);
5628
+ }
5629
+ }
5630
+ function fromStepUpFailure(result) {
5631
+ if (result.status === "wrongPassword" /* WrongPassword */) {
5632
+ return outcome("stepUp" /* StepUp */, "wrongPassword" /* WrongPassword */);
5633
+ }
5634
+ if (result.status === "rateLimited" /* RateLimited */) {
5635
+ return outcome("stepUp" /* StepUp */, "rateLimited" /* RateLimited */, result.retryAfterSeconds);
5636
+ }
5637
+ return outcome("stepUp" /* StepUp */, "failed" /* Failed */);
5638
+ }
5639
+ async function runDeletionAttempt(client, { phase, reason, password }) {
5640
+ const trimmed = reason.trim();
5641
+ const sentReason = trimmed === "" ? void 0 : trimmed;
5642
+ if (phase !== "stepUp" /* StepUp */) {
5643
+ return fromDeletion(await client.requestDeletion(sentReason), false);
5644
+ }
5645
+ const stepUp = await client.stepUpPassword(password);
5646
+ if (stepUp.status !== "confirmed" /* Confirmed */) {
5647
+ return fromStepUpFailure(stepUp);
5648
+ }
5649
+ return fromDeletion(await client.requestDeletion(sentReason), true);
5650
+ }
5651
+ var MS_PER_SECOND = 1e3;
5652
+ function useRetryAfterBlock(onExpired) {
5653
+ const [retryAfterSeconds2, setRetryAfterSeconds] = useState(null);
5654
+ const timer = useRef(null);
5655
+ const stopTimer = useCallback(() => {
5656
+ if (timer.current !== null) {
5657
+ clearTimeout(timer.current);
5658
+ }
5659
+ timer.current = null;
5660
+ }, []);
5661
+ useEffect(() => stopTimer, [stopTimer]);
5662
+ const block = useCallback(
5663
+ (seconds) => {
5664
+ stopTimer();
5665
+ setRetryAfterSeconds(seconds);
5666
+ timer.current = setTimeout(() => {
5667
+ timer.current = null;
5668
+ setRetryAfterSeconds(null);
5669
+ onExpired();
5670
+ }, seconds * MS_PER_SECOND);
5671
+ },
5672
+ [onExpired, stopTimer]
5673
+ );
5674
+ return { retryAfterSeconds: retryAfterSeconds2, block };
5675
+ }
5676
+
5677
+ // src/account/useAccountDeletion.ts
5678
+ function useAccountDeletion(args) {
5679
+ const { client, onAccepted, onSignInRequired } = args;
5680
+ const [reason, setReason] = useState("");
5681
+ const [password, setPasswordValue] = useState("");
5682
+ const [phase, setPhase] = useState("confirm" /* Confirm */);
5683
+ const [submitting, setSubmitting] = useState(false);
5684
+ const [errorKey, setErrorKey] = useState(null);
5685
+ const [receipt, setReceipt] = useState(null);
5686
+ const inFlight = useRef(false);
5687
+ const clearRateLimit = useCallback(() => {
5688
+ setErrorKey((current) => current === "rateLimited" /* RateLimited */ ? null : current);
5689
+ }, []);
5690
+ const { retryAfterSeconds: retryAfterSeconds2, block } = useRetryAfterBlock(clearRateLimit);
5691
+ const blocked = retryAfterSeconds2 !== null;
5692
+ const setPassword = useCallback((value) => {
5693
+ setPasswordValue(value);
5694
+ setErrorKey((current) => current === "rateLimited" /* RateLimited */ ? current : null);
5695
+ }, []);
5696
+ const applyOutcome = useCallback((outcome2) => {
5697
+ setPhase(outcome2.phase);
5698
+ setErrorKey(outcome2.errorKey);
5699
+ setPasswordValue("");
5700
+ if (outcome2.retryAfterSeconds !== null) {
5701
+ block(outcome2.retryAfterSeconds);
5702
+ }
5703
+ if (outcome2.errorKey === "signInRequired" /* SignInRequired */) {
5704
+ onSignInRequired?.();
5705
+ }
5706
+ if (outcome2.receipt === null) {
5707
+ return;
5708
+ }
5709
+ setReceipt(outcome2.receipt);
5710
+ onAccepted?.(outcome2.receipt);
5711
+ }, [block, onAccepted, onSignInRequired]);
5712
+ const submit = useCallback(() => {
5713
+ if (inFlight.current || blocked) {
5714
+ return;
5715
+ }
5716
+ if (phase === "stepUp" /* StepUp */ && password === "") {
5717
+ setErrorKey("passwordRequired" /* PasswordRequired */);
5718
+ return;
5719
+ }
5720
+ inFlight.current = true;
5721
+ setSubmitting(true);
5722
+ setErrorKey(null);
5723
+ runDeletionAttempt(client, { phase, reason, password }).then(applyOutcome).catch(() => {
5724
+ setPasswordValue("");
5725
+ setErrorKey("failed" /* Failed */);
5726
+ }).finally(() => {
5727
+ inFlight.current = false;
5728
+ setSubmitting(false);
5729
+ });
5730
+ }, [applyOutcome, blocked, client, password, phase, reason]);
5731
+ return { phase, reason, password, setReason, setPassword, submitting, blocked, retryAfterSeconds: retryAfterSeconds2, errorKey, receipt, submit };
5732
+ }
5733
+ var REASON_MAX_LENGTH = 1e3;
5734
+ function AccountDeletionField({
5735
+ copy,
5736
+ placeholderColor,
5737
+ secure,
5738
+ disabled,
5739
+ value,
5740
+ styles: styles3,
5741
+ testID,
5742
+ onChangeText,
5743
+ onSubmitEditing
5744
+ }) {
5745
+ const inputRef = useRef(null);
5746
+ useFocusOnMount(inputRef);
5747
+ return /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
5748
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: copy.label }),
5749
+ /* @__PURE__ */ jsx(
5750
+ TextInput,
5751
+ {
5752
+ ref: inputRef,
5753
+ accessibilityHint: copy.hint,
5754
+ accessibilityLabel: copy.inputLabel,
5755
+ autoComplete: secure ? "current-password" : "off",
5756
+ editable: !disabled,
5757
+ maxLength: secure ? void 0 : REASON_MAX_LENGTH,
5758
+ placeholder: copy.placeholder,
5759
+ placeholderTextColor: placeholderColor,
5760
+ returnKeyType: "go",
5761
+ secureTextEntry: secure,
5762
+ style: styles3.input,
5763
+ testID,
5764
+ value,
5765
+ onChangeText,
5766
+ onSubmitEditing
5767
+ }
5768
+ )
5769
+ ] });
5770
+ }
5771
+ function AccountDeletionNotice({
5772
+ title,
5773
+ body,
5774
+ detail,
5775
+ styles: styles3,
5776
+ testID,
5777
+ footer
5778
+ }) {
5779
+ const headingRef = useRef(null);
5780
+ useFocusOnMount(headingRef);
5781
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { accessibilityLiveRegion: "polite", style: styles3.card, testID, children: [
5782
+ /* @__PURE__ */ jsx(View, { ref: headingRef, accessible: true, focusable: true, children: /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", style: styles3.title, children: title }) }),
5783
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: body }),
5784
+ detail === null ? null : /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: detail }),
5785
+ footer
5786
+ ] }) });
5787
+ }
5788
+
5789
+ // src/components/accountDeletionTestIds.ts
5790
+ var AccountDeletionTestIds = {
5791
+ form: "account-deletion-form",
5792
+ reasonInput: "account-deletion-reason-input",
5793
+ stepUpInput: "account-deletion-password-input",
5794
+ submitButton: "account-deletion-submit-button",
5795
+ error: "account-deletion-error",
5796
+ checkEmail: "account-deletion-check-email",
5797
+ emailNotSent: "account-deletion-email-not-sent",
5798
+ alreadyRequested: "account-deletion-already-requested"
5799
+ };
5800
+ function errorText(errorKey, seconds, labels) {
5801
+ switch (errorKey) {
5802
+ case null:
5803
+ return null;
5804
+ case "passwordRequired" /* PasswordRequired */:
5805
+ return labels.errorPasswordRequired;
5806
+ case "wrongPassword" /* WrongPassword */:
5807
+ return labels.errorWrongPassword;
5808
+ case "signInRequired" /* SignInRequired */:
5809
+ return labels.errorSignInRequired;
5810
+ case "rateLimited" /* RateLimited */:
5811
+ return seconds === null ? labels.errorRateLimited : interpolate(labels.errorRateLimitedSeconds, { seconds });
5812
+ case "retryLater" /* RetryLater */:
5813
+ return labels.errorRetryLater;
5814
+ default:
5815
+ return labels.errorFailed;
5816
+ }
5817
+ }
5818
+ function scheduledDetail(receipt, labels) {
5819
+ const date = new Date(receipt?.scheduledDeletionDate ?? "");
5820
+ return Number.isNaN(date.getTime()) ? null : interpolate(labels.scheduledDate, { date: date.toLocaleDateString() });
5821
+ }
5822
+ function noticeCopy(phase, receipt, labels) {
5823
+ if (phase === "alreadyRequested" /* AlreadyRequested */) {
5824
+ return {
5825
+ title: labels.alreadyRequestedTitle,
5826
+ body: labels.alreadyRequestedBody,
5827
+ detail: null,
5828
+ testId: AccountDeletionTestIds.alreadyRequested
5829
+ };
5830
+ }
5831
+ if (phase !== "accepted" /* Accepted */) {
5832
+ return null;
5833
+ }
5834
+ const detail = scheduledDetail(receipt, labels);
5835
+ if (receipt?.confirmationEmailSent === true) {
5836
+ return { title: labels.checkEmailTitle, body: labels.checkEmailBody, detail, testId: AccountDeletionTestIds.checkEmail };
5837
+ }
5838
+ return { title: labels.emailNotSentTitle, body: labels.emailNotSentBody, detail, testId: AccountDeletionTestIds.emailNotSent };
5839
+ }
5840
+ function AccountDeletionForm({
5841
+ client,
5842
+ labels: labelsProp,
5843
+ theme: themeProp,
5844
+ testIdPrefix,
5845
+ footer,
5846
+ onAccepted,
5847
+ onSignInRequired
5848
+ }) {
5849
+ const theme = useAuthTheme(themeProp);
5850
+ const styles3 = useAuthStyles(theme);
5851
+ const labels = useMemo(() => ({ ...DEFAULT_ACCOUNT_DELETION_LABELS, ...labelsProp }), [labelsProp]);
5852
+ const form = useAccountDeletion({ client, onAccepted, onSignInRequired });
5853
+ const handleSubmitEditing = useSubmitOnEnter(form.submit);
5854
+ const testId = (id) => withTestIdPrefix(id, testIdPrefix);
5855
+ const notice = noticeCopy(form.phase, form.receipt, labels);
5856
+ if (notice !== null) {
5857
+ return /* @__PURE__ */ jsx(
5858
+ AccountDeletionNotice,
5859
+ {
5860
+ body: notice.body,
5861
+ detail: notice.detail,
5862
+ footer,
5863
+ styles: styles3,
5864
+ testID: testId(notice.testId),
5865
+ title: notice.title
5866
+ }
5867
+ );
5868
+ }
5869
+ const steppingUp = form.phase === "stepUp" /* StepUp */;
5870
+ const message = errorText(form.errorKey, form.retryAfterSeconds, labels);
5871
+ const submitLabel = steppingUp ? labels.stepUpSubmit : labels.submit;
5872
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: testId(AccountDeletionTestIds.form), children: [
5873
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: steppingUp ? labels.stepUpTitle : labels.title }),
5874
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: steppingUp ? labels.stepUpSubtitle : labels.subtitle }),
5875
+ /* @__PURE__ */ jsx(
5876
+ AccountDeletionField,
5877
+ {
5878
+ copy: steppingUp ? labels.password : labels.reason,
5879
+ disabled: form.submitting,
5880
+ placeholderColor: theme.colors.textSecondary,
5881
+ secure: steppingUp,
5882
+ styles: styles3,
5883
+ testID: testId(steppingUp ? AccountDeletionTestIds.stepUpInput : AccountDeletionTestIds.reasonInput),
5884
+ value: steppingUp ? form.password : form.reason,
5885
+ onChangeText: steppingUp ? form.setPassword : form.setReason,
5886
+ onSubmitEditing: handleSubmitEditing
5887
+ },
5888
+ form.phase
5889
+ ),
5890
+ message === null ? null : /* @__PURE__ */ jsx(Text, { accessibilityLiveRegion: "polite", style: styles3.errorText, testID: testId(AccountDeletionTestIds.error), children: message }),
5891
+ /* @__PURE__ */ jsx(View, { style: styles3.fieldGroup, children: /* @__PURE__ */ jsx(
5892
+ Button,
5893
+ {
5894
+ fullWidth: true,
5895
+ accessibilityHint: steppingUp ? labels.stepUpSubmitHint : labels.submitHint,
5896
+ accessibilityLabel: form.submitting ? labels.submitting : submitLabel,
5897
+ disabled: form.blocked,
5898
+ label: submitLabel,
5899
+ loading: form.submitting,
5900
+ testID: testId(AccountDeletionTestIds.submitButton),
5901
+ variant: "danger",
5902
+ onPress: form.submit
5903
+ }
5904
+ ) }),
5905
+ footer
5906
+ ] }) });
5907
+ }
5908
+
5909
+ export { ACCOUNT_DELETE_REQUEST_ENDPOINT, AccountDeletionErrorKey, AccountDeletionForm, AccountDeletionPhase, AccountDeletionStatus, AccountDeletionTestIds, AccountSettingsScreen, AuthScreen, AuthTestIds, AuthThemeProvider, BffAuthStatus, CHANGE_PASSWORD_ENDPOINT, ChangePasswordCard, ChangePasswordErrorKey, DEFAULT_ACCOUNT_DELETION_LABELS, DEFAULT_ACCOUNT_SETTINGS_LABELS, DEFAULT_AUTH_CARD_MAX_WIDTH, DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_PREFERRED_METHOD_HINT_LABELS, DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, DEFAULT_REGISTER_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEFAULT_VERIFY_EMAIL_LABELS, DEFAULT_VERIFY_NEW_PASSWORD_LABELS, DEFAULT_VERIFY_SIGN_IN_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DemoCredentialsHint, DemoCredentialsHintVariant, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyCeremonyMode, PasskeyCeremonyStatus, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, PreferredMethodHint, PreferredMethodSettingsCard, PrefillIntent, REGISTER_ENDPOINT, RESEND_VERIFICATION_ENDPOINT, RegisterErrorCode, RegisterForm, RegisterTestIds, ResetPasswordError, ResetPasswordForm, STEP_UP_PASSWORD_ENDPOINT, SharedRegisterForm, StepUpStatus, VERIFY_AND_LOGIN_ENDPOINT, VERIFY_EMAIL_ENDPOINT, VERIFY_TOKEN_PLACEHOLDER, VerifyEmailErrorCode, VerifyEmailPhase, VerifyEmailScreen, buildVerifyUrlTemplate, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAccountDeletionClient, createBffAuthClient, createBffChangePasswordClient, createBffVerifyEmailClient, createPreferencesClient, createSharedRegistrationClient, defaultAuthTheme, deriveUsernameFromEmail, isAllowedPinDigits, isPasswordValid, isRegisterAccepted, isRegisterPasswordStrong, isValidForgotPasswordEmail, performBffLogout, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, readVerifyToken, resolveAccessibleRoutes, resolveAccountList, resolveDemoAccounts, resolveDemoCredentials, resolvePostLoginRoute, splitFullName, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAccountDeletion, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useChangePassword, useDemoCredentials, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePasskeyCeremony, usePinLogin, usePreferredMethodSetting, useRegisterForm, useResendVerification, useResetPasswordForm, useVerifyEmail, validatePasswordPolicy, verifyEmailErrorText, withTestIdPrefix };
5037
5910
  //# sourceMappingURL=index.mjs.map
5038
5911
  //# sourceMappingURL=index.mjs.map