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