@dloizides/auth-web 1.3.0 → 1.5.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
@@ -1,5 +1,5 @@
1
1
  import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
2
- import { View, Text, TextInput, TouchableOpacity, ActivityIndicator, StyleSheet } from 'react-native';
2
+ import { StyleSheet, View, Text, TextInput, TouchableOpacity, ActivityIndicator, Pressable } from 'react-native';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useMutation } from '@tanstack/react-query';
5
5
  import { BffAuthClient, createFetchHttpClient } from '@dloizides/auth-client';
@@ -68,6 +68,92 @@ var DEFAULT_PIN_LABELS = {
68
68
  missingPin: "Enter your event PIN.",
69
69
  invalidPin: "That PIN is incorrect, has expired, or is locked out."
70
70
  };
71
+ var DEFAULT_DEVICE_PIN_UNLOCK_LABELS = {
72
+ title: "Welcome back, {name}",
73
+ titleNoName: "Welcome back",
74
+ description: "Enter your {count}-digit PIN to sign in on this device.",
75
+ pinLabel: "PIN",
76
+ pinPlaceholder: "Enter your PIN",
77
+ submit: "Unlock",
78
+ submitting: "Signing in...",
79
+ usePasswordInstead: "Sign in with password instead",
80
+ usePasswordHint: "Switch to signing in with your username and password",
81
+ errorIncomplete: "Enter all {count} digits of your PIN.",
82
+ errorInvalid: "That PIN is incorrect. Try again.",
83
+ errorLockedOut: "Too many attempts. Try again later.",
84
+ errorLockedOutRetry: "Too many attempts. Try again in {count} seconds.",
85
+ errorRateLimited: "Too many requests. Try again later.",
86
+ errorRateLimitedRetry: "Too many requests. Try again in {count} seconds.",
87
+ errorGeneric: "Something went wrong. Try again, or sign in with your password.",
88
+ digitFilledHint: "PIN digit entered",
89
+ digitEmptyHint: "PIN digit not yet entered"
90
+ };
91
+ var DEFAULT_DEVICE_PIN_ENROLL_LABELS = {
92
+ offerTitle: "Set a PIN for faster sign-in?",
93
+ offerDescription: "Next time, sign in on this device with a short PIN instead of your full password.",
94
+ offerAccept: "Set up a PIN",
95
+ offerAcceptHint: "Open the form to choose a quick sign-in PIN",
96
+ offerSkip: "Not now",
97
+ offerSkipHint: "Dismiss the PIN setup offer",
98
+ formTitle: "Choose your PIN",
99
+ formDescription: "Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.",
100
+ lengthLabel: "PIN length",
101
+ lengthOptionHint: "Use a {count}-digit PIN",
102
+ pinLabel: "New PIN",
103
+ pinPlaceholder: "Enter a new PIN",
104
+ confirmLabel: "Confirm PIN",
105
+ confirmPlaceholder: "Re-enter your PIN",
106
+ submit: "Save PIN",
107
+ submitting: "Saving...",
108
+ cancel: "Cancel",
109
+ cancelHint: "Close the PIN setup form without saving",
110
+ errorMismatch: "The PINs must match and be exactly {count} digits.",
111
+ errorUnauthorized: "Your session has expired. Sign in again to set a PIN.",
112
+ errorForbidden: "A PIN is already set for this session.",
113
+ errorInvalidPin: "That PIN is not allowed. Choose a different one.",
114
+ errorFailed: "Could not set your PIN. Try again later."
115
+ };
116
+ var DEFAULT_DEVICE_PIN_SETTINGS_LABELS = {
117
+ title: "Quick PIN sign-in",
118
+ description: "Sign in on this device with a short PIN instead of your full password.",
119
+ statusEnabled: "Quick PIN sign-in is enabled on this device.",
120
+ statusDisabled: "Quick PIN sign-in is off.",
121
+ enable: "Enable quick PIN sign-in",
122
+ enableHint: "Set a PIN so you can sign in faster on this device",
123
+ disable: "Disable",
124
+ disableHint: "Remove the PIN sign-in from this device",
125
+ disabling: "Disabling...",
126
+ disableFailed: "Could not disable PIN sign-in. Try again later."
127
+ };
128
+ var DEFAULT_PASSKEY_LOGIN_LABELS = {
129
+ signInButton: "Sign in with a passkey",
130
+ signInHint: "Use your fingerprint, face, or security key to sign in",
131
+ errorCancelled: "Passkey sign-in was cancelled. You can try again or sign in another way.",
132
+ errorFailed: "Passkey sign-in didn't work. Try again, or sign in another way."
133
+ };
134
+ var DEFAULT_PASSKEY_SETTINGS_LABELS = {
135
+ title: "Passkeys",
136
+ description: "Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.",
137
+ reauthHint: "You'll be asked to confirm your password before adding a passkey.",
138
+ addButton: "Add a passkey",
139
+ addHint: "Start setting up a passkey for this account",
140
+ registeredSuccess: "Your passkey was added. You can now use it to sign in."
141
+ };
142
+ var DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = {
143
+ title: "Preferred sign-in method",
144
+ description: "Pick how you usually sign in. We will show this method first on your devices.",
145
+ noPreference: "No preference",
146
+ methodPassword: "Password",
147
+ methodPin: "Quick PIN",
148
+ methodPasskey: "Passkey",
149
+ saving: "Saving...",
150
+ saveFailed: "Could not save your preference. Try again later."
151
+ };
152
+ var DEFAULT_PREFERRED_METHOD_HINT_LABELS = {
153
+ password: "You usually sign in with your password.",
154
+ pin: "You usually sign in with your quick PIN on this account.",
155
+ passkey: "You usually sign in with a passkey."
156
+ };
71
157
  var DEFAULT_RESET_PASSWORD_LABELS = {
72
158
  title: "Reset password",
73
159
  description: "Choose a new password for your account.",
@@ -116,7 +202,46 @@ var AuthTestIds = {
116
202
  pinForm: "auth-pin-form",
117
203
  pinInput: "auth-pin-input",
118
204
  pinSubmitButton: "auth-pin-submit",
119
- pinError: "auth-pin-error"
205
+ pinError: "auth-pin-error",
206
+ // Device-PIN unlock gate
207
+ devicePinUnlock: "auth-device-pin-unlock",
208
+ devicePinUnlockInput: "auth-device-pin-unlock-input",
209
+ devicePinUnlockSubmit: "auth-device-pin-unlock-submit",
210
+ devicePinUnlockUsePassword: "auth-device-pin-unlock-use-password",
211
+ devicePinUnlockError: "auth-device-pin-unlock-error",
212
+ // Device-PIN enrol form + length picker
213
+ devicePinEnrollForm: "auth-device-pin-enroll-form",
214
+ devicePinEnrollLength: "auth-device-pin-enroll-length",
215
+ devicePinEnrollPin: "auth-device-pin-enroll-pin",
216
+ devicePinEnrollConfirm: "auth-device-pin-enroll-confirm",
217
+ devicePinEnrollSubmit: "auth-device-pin-enroll-submit",
218
+ devicePinEnrollCancel: "auth-device-pin-enroll-cancel",
219
+ devicePinEnrollError: "auth-device-pin-enroll-error",
220
+ // Device-PIN offer (post-login)
221
+ devicePinOffer: "auth-device-pin-offer",
222
+ devicePinOfferAccept: "auth-device-pin-offer-accept",
223
+ devicePinOfferSkip: "auth-device-pin-offer-skip",
224
+ // Device-PIN settings card
225
+ devicePinSettings: "auth-device-pin-settings",
226
+ devicePinSettingsStatus: "auth-device-pin-settings-status",
227
+ devicePinSettingsEnable: "auth-device-pin-settings-enable",
228
+ devicePinSettingsDisable: "auth-device-pin-settings-disable",
229
+ devicePinSettingsError: "auth-device-pin-settings-error",
230
+ // Passkey login button
231
+ passkeyLogin: "auth-passkey-login",
232
+ passkeyLoginButton: "auth-passkey-login-button",
233
+ passkeyLoginError: "auth-passkey-login-error",
234
+ // Passkey settings card
235
+ passkeySettings: "auth-passkey-settings",
236
+ passkeySettingsAdd: "auth-passkey-settings-add",
237
+ passkeySettingsSuccess: "auth-passkey-settings-success",
238
+ // Preferred-method settings card (cross-device default-method picker).
239
+ // Each option row appends `-${method}` to `preferredMethodSettingsOption`.
240
+ preferredMethodSettings: "auth-preferred-method-settings",
241
+ preferredMethodSettingsOption: "auth-preferred-method-settings-option",
242
+ preferredMethodSettingsError: "auth-preferred-method-settings-error",
243
+ // Preferred-method login-screen hint
244
+ preferredMethodHint: "auth-preferred-method-hint"
120
245
  };
121
246
  function withTestIdPrefix(baseId, prefix) {
122
247
  return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
@@ -210,6 +335,32 @@ function useAuthStyles(theme) {
210
335
  helperText: {
211
336
  fontSize: typography.caption,
212
337
  color: colors.textSecondary
338
+ },
339
+ escapeLink: {
340
+ alignSelf: "center",
341
+ marginTop: spacing.md,
342
+ paddingVertical: spacing.xs / 2
343
+ },
344
+ secondaryButton: {
345
+ borderRadius: radii.input,
346
+ borderWidth: 1,
347
+ borderColor: colors.primary,
348
+ paddingVertical: BUTTON_VERTICAL_PADDING,
349
+ alignItems: "center",
350
+ justifyContent: "center",
351
+ marginTop: spacing.sm,
352
+ backgroundColor: colors.surface
353
+ },
354
+ secondaryButtonText: {
355
+ fontSize: typography.body,
356
+ fontWeight: "600",
357
+ color: colors.primary
358
+ },
359
+ statusText: {
360
+ fontSize: typography.label,
361
+ fontWeight: "600",
362
+ marginTop: spacing.sm,
363
+ color: colors.text
213
364
  }
214
365
  });
215
366
  }, [theme]);
@@ -371,7 +522,7 @@ function LoginForm({
371
522
  testIdPrefix
372
523
  }) {
373
524
  const theme = useAuthTheme(themeProp);
374
- const styles = useAuthStyles(theme);
525
+ const styles3 = useAuthStyles(theme);
375
526
  const labels = useMemo(
376
527
  () => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),
377
528
  [labelsProp]
@@ -398,12 +549,12 @@ function LoginForm({
398
549
  const handleSubmit = useCallback(() => {
399
550
  void runLogin();
400
551
  }, [runLogin]);
401
- const submitButtonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
402
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
403
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
404
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.subtitle }),
405
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
406
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.usernameLabel }),
552
+ const submitButtonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
553
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
554
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
555
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.subtitle }),
556
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
557
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.usernameLabel }),
407
558
  /* @__PURE__ */ jsx(
408
559
  TextInput,
409
560
  {
@@ -414,15 +565,15 @@ function LoginForm({
414
565
  editable: !isSubmitting,
415
566
  placeholder: labels.usernamePlaceholder,
416
567
  placeholderTextColor: theme.colors.textSecondary,
417
- style: styles.input,
568
+ style: styles3.input,
418
569
  testID: withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix),
419
570
  value: username,
420
571
  onChangeText: setUsername
421
572
  }
422
573
  )
423
574
  ] }),
424
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
425
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.passwordLabel }),
575
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
576
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.passwordLabel }),
426
577
  /* @__PURE__ */ jsx(
427
578
  TextInput,
428
579
  {
@@ -434,7 +585,7 @@ function LoginForm({
434
585
  editable: !isSubmitting,
435
586
  placeholder: labels.passwordPlaceholder,
436
587
  placeholderTextColor: theme.colors.textSecondary,
437
- style: styles.input,
588
+ style: styles3.input,
438
589
  testID: withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix),
439
590
  value: password,
440
591
  onChangeText: setPassword
@@ -444,7 +595,7 @@ function LoginForm({
444
595
  errorText !== null ? /* @__PURE__ */ jsx(
445
596
  Text,
446
597
  {
447
- style: styles.errorText,
598
+ style: styles3.errorText,
448
599
  testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
449
600
  children: errorText
450
601
  }
@@ -456,10 +607,10 @@ function LoginForm({
456
607
  accessibilityLabel: labels.forgotPassword,
457
608
  accessibilityRole: "link",
458
609
  disabled: isSubmitting,
459
- style: styles.fieldGroup,
610
+ style: styles3.fieldGroup,
460
611
  testID: withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix),
461
612
  onPress: onForgotPassword,
462
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: labels.forgotPassword })
613
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.forgotPassword })
463
614
  }
464
615
  ) : null,
465
616
  /* @__PURE__ */ jsx(
@@ -472,7 +623,7 @@ function LoginForm({
472
623
  style: submitButtonStyle,
473
624
  testID: withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix),
474
625
  onPress: handleSubmit,
475
- children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
626
+ children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
476
627
  }
477
628
  ),
478
629
  onSignUp !== void 0 ? /* @__PURE__ */ jsx(
@@ -482,10 +633,10 @@ function LoginForm({
482
633
  accessibilityLabel: labels.signUp,
483
634
  accessibilityRole: "link",
484
635
  disabled: isSubmitting,
485
- style: styles.fieldGroup,
636
+ style: styles3.fieldGroup,
486
637
  testID: withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix),
487
638
  onPress: onSignUp,
488
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: labels.signUp })
639
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.signUp })
489
640
  }
490
641
  ) : null
491
642
  ] }) });
@@ -523,7 +674,7 @@ function ForgotPasswordForm({
523
674
  testIdPrefix
524
675
  }) {
525
676
  const theme = useAuthTheme(themeProp);
526
- const styles = useAuthStyles(theme);
677
+ const styles3 = useAuthStyles(theme);
527
678
  const labels = useMemo(
528
679
  () => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),
529
680
  [labelsProp]
@@ -555,25 +706,25 @@ function ForgotPasswordForm({
555
706
  }
556
707
  mutation.mutate({ email: trimmedEmail, resetUrlTemplate });
557
708
  }, [email, mutation, resetUrlTemplate, labels.invalidEmail]);
558
- const submitButtonStyle = isPending ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
559
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(
709
+ const submitButtonStyle = isPending ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
710
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
560
711
  View,
561
712
  {
562
- style: styles.card,
713
+ style: styles3.card,
563
714
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix),
564
715
  children: [
565
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
716
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
566
717
  submitted ? /* @__PURE__ */ jsx(
567
718
  Text,
568
719
  {
569
- style: styles.successText,
720
+ style: styles3.successText,
570
721
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix),
571
722
  children: labels.successMessage
572
723
  }
573
724
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
574
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
575
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
576
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.emailLabel }),
725
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
726
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
727
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
577
728
  /* @__PURE__ */ jsx(
578
729
  TextInput,
579
730
  {
@@ -585,7 +736,7 @@ function ForgotPasswordForm({
585
736
  keyboardType: "email-address",
586
737
  placeholder: labels.emailPlaceholder,
587
738
  placeholderTextColor: theme.colors.textSecondary,
588
- style: styles.input,
739
+ style: styles3.input,
589
740
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
590
741
  value: email,
591
742
  onChangeText: setEmail
@@ -595,7 +746,7 @@ function ForgotPasswordForm({
595
746
  errorText !== null ? /* @__PURE__ */ jsx(
596
747
  Text,
597
748
  {
598
- style: styles.errorText,
749
+ style: styles3.errorText,
599
750
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
600
751
  children: errorText
601
752
  }
@@ -610,7 +761,7 @@ function ForgotPasswordForm({
610
761
  style: submitButtonStyle,
611
762
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
612
763
  onPress: handleSubmit,
613
- children: isPending ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
764
+ children: isPending ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
614
765
  }
615
766
  )
616
767
  ] })
@@ -702,7 +853,7 @@ function ForgotPasswordFields({
702
853
  testIdPrefix
703
854
  }) {
704
855
  const theme = useAuthTheme(themeProp);
705
- const styles = useAuthStyles(theme);
856
+ const styles3 = useAuthStyles(theme);
706
857
  const modalStyles = useModalStyles(theme);
707
858
  const labels = useMemo(
708
859
  () => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),
@@ -715,7 +866,7 @@ function ForgotPasswordFields({
715
866
  reset();
716
867
  }
717
868
  }, [visible, reset]);
718
- const submitButtonStyle = form.canSubmit ? styles.primaryButton : [styles.primaryButton, styles.primaryButtonDisabled];
869
+ const submitButtonStyle = form.canSubmit ? styles3.primaryButton : [styles3.primaryButton, styles3.primaryButtonDisabled];
719
870
  const handleCancel = () => {
720
871
  form.reset();
721
872
  onCancel?.();
@@ -726,25 +877,25 @@ function ForgotPasswordFields({
726
877
  };
727
878
  if (form.submitted) {
728
879
  return /* @__PURE__ */ jsxs(View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
729
- /* @__PURE__ */ jsx(Text, { style: styles.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
880
+ /* @__PURE__ */ jsx(Text, { style: styles3.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
730
881
  onClose !== void 0 ? /* @__PURE__ */ jsx(View, { style: modalStyles.actions, children: /* @__PURE__ */ jsx(
731
882
  TouchableOpacity,
732
883
  {
733
884
  accessibilityHint: labels.close,
734
885
  accessibilityLabel: labels.close,
735
886
  accessibilityRole: "button",
736
- style: styles.primaryButton,
887
+ style: styles3.primaryButton,
737
888
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix),
738
889
  onPress: handleClose,
739
- children: /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.close })
890
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.close })
740
891
  }
741
892
  ) }) : null
742
893
  ] });
743
894
  }
744
895
  return /* @__PURE__ */ jsxs(View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
745
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
746
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
747
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.emailLabel }),
896
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
897
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
898
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
748
899
  /* @__PURE__ */ jsx(
749
900
  TextInput,
750
901
  {
@@ -756,14 +907,14 @@ function ForgotPasswordFields({
756
907
  keyboardType: "email-address",
757
908
  placeholder: labels.emailPlaceholder,
758
909
  placeholderTextColor: theme.colors.textSecondary,
759
- style: styles.input,
910
+ style: styles3.input,
760
911
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
761
912
  value: form.email,
762
913
  onChangeText: form.setEmail
763
914
  }
764
915
  )
765
916
  ] }),
766
- form.hasNetworkError ? /* @__PURE__ */ jsx(Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
917
+ form.hasNetworkError ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
767
918
  /* @__PURE__ */ jsxs(View, { style: modalStyles.actions, children: [
768
919
  onCancel !== void 0 ? /* @__PURE__ */ jsx(
769
920
  TouchableOpacity,
@@ -788,7 +939,7 @@ function ForgotPasswordFields({
788
939
  style: submitButtonStyle,
789
940
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
790
941
  onPress: form.submit,
791
- children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
942
+ children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
792
943
  }
793
944
  )
794
945
  ] })
@@ -967,24 +1118,24 @@ function ResetPasswordForm({
967
1118
  testIdPrefix
968
1119
  }) {
969
1120
  const theme = useAuthTheme(themeProp);
970
- const styles = useAuthStyles(theme);
1121
+ const styles3 = useAuthStyles(theme);
971
1122
  const labels = useMemo(
972
1123
  () => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),
973
1124
  [labelsProp]
974
1125
  );
975
1126
  const form = useResetPasswordForm({ client, token, onSuccess });
976
1127
  const message = errorMessage(form.errorKey, labels);
977
- const submitButtonStyle = form.isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
978
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(
1128
+ const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1129
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
979
1130
  View,
980
1131
  {
981
- style: styles.card,
1132
+ style: styles3.card,
982
1133
  testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
983
1134
  children: [
984
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
985
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
986
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
987
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.newPasswordLabel }),
1135
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
1136
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
1137
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1138
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.newPasswordLabel }),
988
1139
  /* @__PURE__ */ jsx(
989
1140
  TextInput,
990
1141
  {
@@ -996,15 +1147,15 @@ function ResetPasswordForm({
996
1147
  editable: !form.isSubmitting,
997
1148
  placeholder: labels.newPasswordPlaceholder,
998
1149
  placeholderTextColor: theme.colors.textSecondary,
999
- style: styles.input,
1150
+ style: styles3.input,
1000
1151
  testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
1001
1152
  value: form.newPassword,
1002
1153
  onChangeText: form.setNewPassword
1003
1154
  }
1004
1155
  )
1005
1156
  ] }),
1006
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
1007
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.confirmPasswordLabel }),
1157
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1158
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
1008
1159
  /* @__PURE__ */ jsx(
1009
1160
  TextInput,
1010
1161
  {
@@ -1016,7 +1167,7 @@ function ResetPasswordForm({
1016
1167
  editable: !form.isSubmitting,
1017
1168
  placeholder: labels.confirmPasswordPlaceholder,
1018
1169
  placeholderTextColor: theme.colors.textSecondary,
1019
- style: styles.input,
1170
+ style: styles3.input,
1020
1171
  testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
1021
1172
  value: form.confirmPassword,
1022
1173
  onChangeText: form.setConfirmPassword
@@ -1026,7 +1177,7 @@ function ResetPasswordForm({
1026
1177
  message !== null ? /* @__PURE__ */ jsx(
1027
1178
  Text,
1028
1179
  {
1029
- style: styles.errorText,
1180
+ style: styles3.errorText,
1030
1181
  testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
1031
1182
  children: message
1032
1183
  }
@@ -1041,7 +1192,7 @@ function ResetPasswordForm({
1041
1192
  style: submitButtonStyle,
1042
1193
  testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
1043
1194
  onPress: form.submit,
1044
- children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
1195
+ children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
1045
1196
  }
1046
1197
  )
1047
1198
  ]
@@ -1049,7 +1200,7 @@ function ResetPasswordForm({
1049
1200
  ) });
1050
1201
  }
1051
1202
  function OtpRequestStep({
1052
- styles,
1203
+ styles: styles3,
1053
1204
  theme,
1054
1205
  labels,
1055
1206
  testIdPrefix,
@@ -1058,12 +1209,12 @@ function OtpRequestStep({
1058
1209
  onSubmit
1059
1210
  }) {
1060
1211
  const [email, setEmail] = useState("");
1061
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1212
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1062
1213
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1063
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.requestTitle }),
1064
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.requestDescription }),
1065
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
1066
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.emailLabel }),
1214
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.requestTitle }),
1215
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.requestDescription }),
1216
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1217
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
1067
1218
  /* @__PURE__ */ jsx(
1068
1219
  TextInput,
1069
1220
  {
@@ -1075,14 +1226,14 @@ function OtpRequestStep({
1075
1226
  keyboardType: "email-address",
1076
1227
  placeholder: labels.emailPlaceholder,
1077
1228
  placeholderTextColor: theme.colors.textSecondary,
1078
- style: styles.input,
1229
+ style: styles3.input,
1079
1230
  testID: withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix),
1080
1231
  value: email,
1081
1232
  onChangeText: setEmail
1082
1233
  }
1083
1234
  )
1084
1235
  ] }),
1085
- errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1236
+ errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1086
1237
  /* @__PURE__ */ jsx(
1087
1238
  TouchableOpacity,
1088
1239
  {
@@ -1093,13 +1244,13 @@ function OtpRequestStep({
1093
1244
  style: buttonStyle,
1094
1245
  testID: withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix),
1095
1246
  onPress: () => onSubmit(email.trim()),
1096
- children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.requestSubmit })
1247
+ children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.requestSubmit })
1097
1248
  }
1098
1249
  )
1099
1250
  ] });
1100
1251
  }
1101
1252
  function OtpVerifyStep({
1102
- styles,
1253
+ styles: styles3,
1103
1254
  theme,
1104
1255
  labels,
1105
1256
  testIdPrefix,
@@ -1111,13 +1262,13 @@ function OtpVerifyStep({
1111
1262
  onChangeEmail
1112
1263
  }) {
1113
1264
  const [code, setCode] = useState("");
1114
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1265
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1115
1266
  const description = labels.verifyDescription.replace("{identifier}", identifier);
1116
1267
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1117
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.verifyTitle }),
1118
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: description }),
1119
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
1120
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.codeLabel }),
1268
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.verifyTitle }),
1269
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: description }),
1270
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1271
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.codeLabel }),
1121
1272
  /* @__PURE__ */ jsx(
1122
1273
  TextInput,
1123
1274
  {
@@ -1129,14 +1280,14 @@ function OtpVerifyStep({
1129
1280
  keyboardType: "number-pad",
1130
1281
  placeholder: labels.codePlaceholder,
1131
1282
  placeholderTextColor: theme.colors.textSecondary,
1132
- style: styles.input,
1283
+ style: styles3.input,
1133
1284
  testID: withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix),
1134
1285
  value: code,
1135
1286
  onChangeText: setCode
1136
1287
  }
1137
1288
  )
1138
1289
  ] }),
1139
- errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1290
+ errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1140
1291
  /* @__PURE__ */ jsx(
1141
1292
  TouchableOpacity,
1142
1293
  {
@@ -1147,7 +1298,7 @@ function OtpVerifyStep({
1147
1298
  style: buttonStyle,
1148
1299
  testID: withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix),
1149
1300
  onPress: () => onSubmit(code.trim()),
1150
- children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.verifySubmit })
1301
+ children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.verifySubmit })
1151
1302
  }
1152
1303
  ),
1153
1304
  /* @__PURE__ */ jsx(
@@ -1157,10 +1308,10 @@ function OtpVerifyStep({
1157
1308
  accessibilityLabel: isSubmitting ? labels.resending : labels.resend,
1158
1309
  accessibilityRole: "link",
1159
1310
  disabled: isSubmitting,
1160
- style: styles.fieldGroup,
1311
+ style: styles3.fieldGroup,
1161
1312
  testID: withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix),
1162
1313
  onPress: onResend,
1163
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: isSubmitting ? labels.resending : labels.resend })
1314
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: isSubmitting ? labels.resending : labels.resend })
1164
1315
  }
1165
1316
  ),
1166
1317
  /* @__PURE__ */ jsx(
@@ -1172,7 +1323,7 @@ function OtpVerifyStep({
1172
1323
  disabled: isSubmitting,
1173
1324
  testID: withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix),
1174
1325
  onPress: onChangeEmail,
1175
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: labels.changeEmail })
1326
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.changeEmail })
1176
1327
  }
1177
1328
  )
1178
1329
  ] });
@@ -1341,7 +1492,7 @@ function OtpForm({
1341
1492
  testIdPrefix
1342
1493
  }) {
1343
1494
  const theme = useAuthTheme(themeProp);
1344
- const styles = useAuthStyles(theme);
1495
+ const styles3 = useAuthStyles(theme);
1345
1496
  const labels = useMemo(
1346
1497
  () => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),
1347
1498
  [labelsProp]
@@ -1359,13 +1510,13 @@ function OtpForm({
1359
1510
  otp.reset();
1360
1511
  }, [otp]);
1361
1512
  const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);
1362
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsx(View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsx(
1513
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsx(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsx(
1363
1514
  OtpRequestStep,
1364
1515
  {
1365
1516
  errorText,
1366
1517
  isSubmitting: otp.isSubmitting,
1367
1518
  labels,
1368
- styles,
1519
+ styles: styles3,
1369
1520
  testIdPrefix,
1370
1521
  theme,
1371
1522
  onSubmit: handleRequest
@@ -1377,7 +1528,7 @@ function OtpForm({
1377
1528
  identifier: otp.identifier,
1378
1529
  isSubmitting: otp.isSubmitting,
1379
1530
  labels,
1380
- styles,
1531
+ styles: styles3,
1381
1532
  testIdPrefix,
1382
1533
  theme,
1383
1534
  onChangeEmail: handleChangeEmail,
@@ -1466,7 +1617,7 @@ function PinForm({
1466
1617
  testIdPrefix
1467
1618
  }) {
1468
1619
  const theme = useAuthTheme(themeProp);
1469
- const styles = useAuthStyles(theme);
1620
+ const styles3 = useAuthStyles(theme);
1470
1621
  const labels = useMemo(
1471
1622
  () => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),
1472
1623
  [labelsProp]
@@ -1476,12 +1627,12 @@ function PinForm({
1476
1627
  const [pinValue, setPinValue] = useState("");
1477
1628
  const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
1478
1629
  const errorText = localError ?? transportErrorFor2(pin.error, labels);
1479
- const buttonStyle = pin.isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1480
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1481
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
1482
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
1483
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
1484
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.pinLabel }),
1630
+ const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1631
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1632
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
1633
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
1634
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1635
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.pinLabel }),
1485
1636
  /* @__PURE__ */ jsx(
1486
1637
  TextInput,
1487
1638
  {
@@ -1494,7 +1645,7 @@ function PinForm({
1494
1645
  placeholder: labels.pinPlaceholder,
1495
1646
  placeholderTextColor: theme.colors.textSecondary,
1496
1647
  secureTextEntry: true,
1497
- style: styles.input,
1648
+ style: styles3.input,
1498
1649
  testID: withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix),
1499
1650
  value: pinValue,
1500
1651
  onChangeText: setPinValue
@@ -1504,7 +1655,7 @@ function PinForm({
1504
1655
  errorText !== null ? /* @__PURE__ */ jsx(
1505
1656
  Text,
1506
1657
  {
1507
- style: styles.errorText,
1658
+ style: styles3.errorText,
1508
1659
  testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
1509
1660
  children: errorText
1510
1661
  }
@@ -1519,11 +1670,1200 @@ function PinForm({
1519
1670
  style: buttonStyle,
1520
1671
  testID: withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix),
1521
1672
  onPress: () => handleSubmit(pinValue.trim()),
1522
- children: pin.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
1673
+ children: pin.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
1523
1674
  }
1524
1675
  )
1525
1676
  ] }) });
1526
1677
  }
1678
+ var DOT_SIZE = 18;
1679
+ var DOT_BORDER_WIDTH = 2;
1680
+ var DOT_RADIUS = 9;
1681
+ var ROW_GAP = 12;
1682
+ var ROW_MIN_HEIGHT = 44;
1683
+ var ROW_VERTICAL_MARGIN = 16;
1684
+ var HIDDEN_SIZE = 1;
1685
+ function sanitise(raw, length) {
1686
+ return raw.replace(/\D/g, "").slice(0, length);
1687
+ }
1688
+ function useDotStyles(theme) {
1689
+ return useMemo(
1690
+ () => ({
1691
+ filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1692
+ empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border }
1693
+ }),
1694
+ [theme]
1695
+ );
1696
+ }
1697
+ function DevicePinInput({
1698
+ value,
1699
+ length,
1700
+ disabled,
1701
+ testID,
1702
+ testIdPrefix,
1703
+ accessibilityLabel,
1704
+ accessibilityHint,
1705
+ filledHint,
1706
+ emptyHint,
1707
+ theme: themeProp,
1708
+ onChange
1709
+ }) {
1710
+ const theme = useAuthTheme(themeProp);
1711
+ const inputRef = useRef(null);
1712
+ const dotStyles = useDotStyles(theme);
1713
+ const cells = Array.from({ length }, (_unused, index) => index);
1714
+ const baseId = withTestIdPrefix(testID, testIdPrefix);
1715
+ return /* @__PURE__ */ jsxs(
1716
+ Pressable,
1717
+ {
1718
+ accessibilityHint,
1719
+ accessibilityLabel,
1720
+ accessibilityRole: "button",
1721
+ disabled,
1722
+ style: styles.row,
1723
+ testID: `${baseId}-row`,
1724
+ onPress: () => inputRef.current?.focus(),
1725
+ children: [
1726
+ cells.map((index) => {
1727
+ const filled = index < value.length;
1728
+ return /* @__PURE__ */ jsx(
1729
+ View,
1730
+ {
1731
+ accessibilityLabel: filled ? filledHint : emptyHint,
1732
+ style: [styles.dot, filled ? dotStyles.filled : dotStyles.empty],
1733
+ testID: `${baseId}-dot-${String(index)}`
1734
+ },
1735
+ index
1736
+ );
1737
+ }),
1738
+ /* @__PURE__ */ jsx(
1739
+ TextInput,
1740
+ {
1741
+ ref: inputRef,
1742
+ accessibilityHint,
1743
+ accessibilityLabel,
1744
+ autoFocus: true,
1745
+ caretHidden: true,
1746
+ editable: !disabled,
1747
+ keyboardType: "number-pad",
1748
+ maxLength: length,
1749
+ secureTextEntry: true,
1750
+ style: styles.hiddenInput,
1751
+ testID: baseId,
1752
+ value,
1753
+ onChangeText: (raw) => onChange(sanitise(raw, length))
1754
+ }
1755
+ )
1756
+ ]
1757
+ }
1758
+ );
1759
+ }
1760
+ var styles = StyleSheet.create({
1761
+ dot: {
1762
+ borderRadius: DOT_RADIUS,
1763
+ borderWidth: DOT_BORDER_WIDTH,
1764
+ height: DOT_SIZE,
1765
+ width: DOT_SIZE
1766
+ },
1767
+ hiddenInput: {
1768
+ height: HIDDEN_SIZE,
1769
+ opacity: 0,
1770
+ position: "absolute",
1771
+ width: HIDDEN_SIZE
1772
+ },
1773
+ row: {
1774
+ alignItems: "center",
1775
+ flexDirection: "row",
1776
+ gap: ROW_GAP,
1777
+ justifyContent: "center",
1778
+ marginVertical: ROW_VERTICAL_MARGIN,
1779
+ minHeight: ROW_MIN_HEIGHT
1780
+ }
1781
+ });
1782
+
1783
+ // src/components/interpolate.ts
1784
+ function interpolate(template, values) {
1785
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
1786
+ const value = values[key];
1787
+ return value === void 0 ? match : String(value);
1788
+ });
1789
+ }
1790
+
1791
+ // src/devicePin/devicePinConstants.ts
1792
+ var DEVICE_PIN_ALLOWED_DIGITS = [4, 6, 8];
1793
+ var DEVICE_PIN_DEFAULT_DIGITS = 4;
1794
+ function isAllowedPinDigits(value) {
1795
+ return DEVICE_PIN_ALLOWED_DIGITS.includes(value);
1796
+ }
1797
+ var PILL_VERTICAL_PADDING = 10;
1798
+ var PILL_FONT_SIZE = 15;
1799
+ function usePickerStyles(theme) {
1800
+ return useMemo(
1801
+ () => ({
1802
+ pill: { borderColor: theme.colors.border },
1803
+ active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1804
+ text: { color: theme.colors.text },
1805
+ textActive: { color: theme.colors.onPrimary }
1806
+ }),
1807
+ [theme]
1808
+ );
1809
+ }
1810
+ function DevicePinLengthPicker({
1811
+ selected,
1812
+ disabled,
1813
+ optionHint,
1814
+ testIdPrefix,
1815
+ theme: themeProp,
1816
+ onSelect
1817
+ }) {
1818
+ const theme = useAuthTheme(themeProp);
1819
+ const dynamic = usePickerStyles(theme);
1820
+ const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);
1821
+ return /* @__PURE__ */ jsx(View, { style: styles2.row, children: DEVICE_PIN_ALLOWED_DIGITS.map((option) => {
1822
+ const active = option === selected;
1823
+ return /* @__PURE__ */ jsx(
1824
+ Pressable,
1825
+ {
1826
+ accessibilityHint: interpolate(optionHint, { count: option }),
1827
+ accessibilityLabel: String(option),
1828
+ accessibilityRole: "button",
1829
+ accessibilityState: { selected: active },
1830
+ disabled,
1831
+ style: [styles2.pill, dynamic.pill, active ? dynamic.active : null],
1832
+ testID: `${baseId}-${String(option)}`,
1833
+ onPress: () => onSelect(option),
1834
+ children: /* @__PURE__ */ jsx(Text, { style: [styles2.text, dynamic.text, active ? dynamic.textActive : null], children: String(option) })
1835
+ },
1836
+ option
1837
+ );
1838
+ }) });
1839
+ }
1840
+ var styles2 = StyleSheet.create({
1841
+ pill: {
1842
+ alignItems: "center",
1843
+ borderRadius: 8,
1844
+ borderWidth: 1,
1845
+ flex: 1,
1846
+ paddingVertical: PILL_VERTICAL_PADDING
1847
+ },
1848
+ row: {
1849
+ flexDirection: "row",
1850
+ gap: 8,
1851
+ marginBottom: 8
1852
+ },
1853
+ text: {
1854
+ fontSize: PILL_FONT_SIZE,
1855
+ fontWeight: "700"
1856
+ }
1857
+ });
1858
+
1859
+ // src/devicePin/DevicePinErrorKey.ts
1860
+ var DevicePinErrorKey = /* @__PURE__ */ ((DevicePinErrorKey2) => {
1861
+ DevicePinErrorKey2["Incomplete"] = "incomplete";
1862
+ DevicePinErrorKey2["Invalid"] = "invalid";
1863
+ DevicePinErrorKey2["LockedOut"] = "locked_out";
1864
+ DevicePinErrorKey2["RateLimited"] = "rate_limited";
1865
+ DevicePinErrorKey2["Generic"] = "generic";
1866
+ return DevicePinErrorKey2;
1867
+ })(DevicePinErrorKey || {});
1868
+ function useDevicePinUnlock({
1869
+ client,
1870
+ digits,
1871
+ onSignedIn
1872
+ }) {
1873
+ const [pin, setPinState] = useState("");
1874
+ const [submitting, setSubmitting] = useState(false);
1875
+ const [errorKey, setErrorKey] = useState(null);
1876
+ const [retryAfterSeconds, setRetryAfterSeconds] = useState(null);
1877
+ const setPin = useCallback((next) => {
1878
+ setPinState(next);
1879
+ setErrorKey(null);
1880
+ setRetryAfterSeconds(null);
1881
+ }, []);
1882
+ const submit = useCallback(() => {
1883
+ setErrorKey(null);
1884
+ setRetryAfterSeconds(null);
1885
+ if (pin.length < digits) {
1886
+ setErrorKey("incomplete" /* Incomplete */);
1887
+ return;
1888
+ }
1889
+ setSubmitting(true);
1890
+ client.unlockWithDevicePin({ pin }).then((result) => {
1891
+ if (result.status === "success") {
1892
+ onSignedIn(result.user);
1893
+ return;
1894
+ }
1895
+ if (result.status === "invalid") {
1896
+ setErrorKey("invalid" /* Invalid */);
1897
+ return;
1898
+ }
1899
+ if (result.status === "locked") {
1900
+ setRetryAfterSeconds(result.retryAfterSeconds);
1901
+ setErrorKey("locked_out" /* LockedOut */);
1902
+ return;
1903
+ }
1904
+ if (result.status === "rateLimited") {
1905
+ setRetryAfterSeconds(result.retryAfterSeconds);
1906
+ setErrorKey("rate_limited" /* RateLimited */);
1907
+ return;
1908
+ }
1909
+ setErrorKey("generic" /* Generic */);
1910
+ }).catch(() => {
1911
+ setErrorKey("generic" /* Generic */);
1912
+ }).finally(() => {
1913
+ setSubmitting(false);
1914
+ });
1915
+ }, [client, pin, digits, onSignedIn]);
1916
+ return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
1917
+ }
1918
+ function resolveErrorText(errorKey, digits, retryAfter, labels) {
1919
+ if (errorKey === null) {
1920
+ return null;
1921
+ }
1922
+ if (errorKey === "incomplete" /* Incomplete */) {
1923
+ return interpolate(labels.errorIncomplete, { count: digits });
1924
+ }
1925
+ if (errorKey === "invalid" /* Invalid */) {
1926
+ return labels.errorInvalid;
1927
+ }
1928
+ if (errorKey === "locked_out" /* LockedOut */) {
1929
+ return retryAfter !== null ? interpolate(labels.errorLockedOutRetry, { count: retryAfter }) : labels.errorLockedOut;
1930
+ }
1931
+ if (errorKey === "rate_limited" /* RateLimited */) {
1932
+ return retryAfter !== null ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter }) : labels.errorRateLimited;
1933
+ }
1934
+ return labels.errorGeneric;
1935
+ }
1936
+ function DevicePinUnlockScreen({
1937
+ client,
1938
+ digits,
1939
+ rememberedUsername,
1940
+ theme: themeProp,
1941
+ labels: labelsProp,
1942
+ testIdPrefix,
1943
+ onSignedIn,
1944
+ onUsePassword
1945
+ }) {
1946
+ const theme = useAuthTheme(themeProp);
1947
+ const styles3 = useAuthStyles(theme);
1948
+ const labels = useMemo(
1949
+ () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
1950
+ [labelsProp]
1951
+ );
1952
+ const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
1953
+ client,
1954
+ digits,
1955
+ onSignedIn
1956
+ });
1957
+ const hasName = rememberedUsername !== "";
1958
+ const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
1959
+ const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
1960
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1961
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
1962
+ View,
1963
+ {
1964
+ style: styles3.card,
1965
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix),
1966
+ children: [
1967
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: title }),
1968
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: interpolate(labels.description, { count: digits }) }),
1969
+ /* @__PURE__ */ jsx(
1970
+ DevicePinInput,
1971
+ {
1972
+ accessibilityHint: labels.pinPlaceholder,
1973
+ accessibilityLabel: labels.pinLabel,
1974
+ disabled: submitting,
1975
+ emptyHint: labels.digitEmptyHint,
1976
+ filledHint: labels.digitFilledHint,
1977
+ length: digits,
1978
+ testID: AuthTestIds.devicePinUnlockInput,
1979
+ testIdPrefix,
1980
+ theme,
1981
+ value: pin,
1982
+ onChange: setPin
1983
+ }
1984
+ ),
1985
+ error !== null ? /* @__PURE__ */ jsx(
1986
+ Text,
1987
+ {
1988
+ style: styles3.errorText,
1989
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix),
1990
+ children: error
1991
+ }
1992
+ ) : null,
1993
+ /* @__PURE__ */ jsx(
1994
+ TouchableOpacity,
1995
+ {
1996
+ accessibilityHint: labels.submit,
1997
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
1998
+ accessibilityRole: "button",
1999
+ disabled: submitting,
2000
+ style: buttonStyle,
2001
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix),
2002
+ onPress: submit,
2003
+ children: submitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
2004
+ }
2005
+ ),
2006
+ /* @__PURE__ */ jsx(
2007
+ TouchableOpacity,
2008
+ {
2009
+ accessibilityHint: labels.usePasswordHint,
2010
+ accessibilityLabel: labels.usePasswordInstead,
2011
+ accessibilityRole: "button",
2012
+ disabled: submitting,
2013
+ style: styles3.escapeLink,
2014
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix),
2015
+ onPress: onUsePassword,
2016
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.usePasswordInstead })
2017
+ }
2018
+ )
2019
+ ]
2020
+ }
2021
+ ) });
2022
+ }
2023
+
2024
+ // src/devicePin/DevicePinEnrollErrorKey.ts
2025
+ var DevicePinEnrollErrorKey = /* @__PURE__ */ ((DevicePinEnrollErrorKey2) => {
2026
+ DevicePinEnrollErrorKey2["Mismatch"] = "mismatch";
2027
+ DevicePinEnrollErrorKey2["Unauthorized"] = "unauthorized";
2028
+ DevicePinEnrollErrorKey2["Forbidden"] = "forbidden";
2029
+ DevicePinEnrollErrorKey2["InvalidPin"] = "invalid_pin";
2030
+ DevicePinEnrollErrorKey2["Failed"] = "failed";
2031
+ return DevicePinEnrollErrorKey2;
2032
+ })(DevicePinEnrollErrorKey || {});
2033
+ function errorKeyFor(result) {
2034
+ if (result.status === "unauthorized") {
2035
+ return "unauthorized" /* Unauthorized */;
2036
+ }
2037
+ if (result.status === "forbidden") {
2038
+ return "forbidden" /* Forbidden */;
2039
+ }
2040
+ if (result.status === "invalidPin") {
2041
+ return "invalid_pin" /* InvalidPin */;
2042
+ }
2043
+ return "failed" /* Failed */;
2044
+ }
2045
+ function useDevicePinEnroll({
2046
+ client,
2047
+ digits,
2048
+ onEnrolled
2049
+ }) {
2050
+ const [pin, setPinState] = useState("");
2051
+ const [confirmPin, setConfirmState] = useState("");
2052
+ const [submitting, setSubmitting] = useState(false);
2053
+ const [errorKey, setErrorKey] = useState(null);
2054
+ const setPin = useCallback((next) => {
2055
+ setPinState(next);
2056
+ setErrorKey(null);
2057
+ }, []);
2058
+ const setConfirmPin = useCallback((next) => {
2059
+ setConfirmState(next);
2060
+ setErrorKey(null);
2061
+ }, []);
2062
+ const submit = useCallback(() => {
2063
+ setErrorKey(null);
2064
+ const wrongLength = pin.length !== digits;
2065
+ const mismatched = pin !== confirmPin;
2066
+ if (wrongLength || mismatched) {
2067
+ setErrorKey("mismatch" /* Mismatch */);
2068
+ return;
2069
+ }
2070
+ setSubmitting(true);
2071
+ client.enrollDevicePin({ pin, digits }).then((result) => {
2072
+ if (result.status === "success") {
2073
+ onEnrolled();
2074
+ return;
2075
+ }
2076
+ setErrorKey(errorKeyFor(result));
2077
+ }).catch(() => {
2078
+ setErrorKey("failed" /* Failed */);
2079
+ }).finally(() => {
2080
+ setSubmitting(false);
2081
+ });
2082
+ }, [client, pin, confirmPin, digits, onEnrolled]);
2083
+ return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };
2084
+ }
2085
+ function resolveErrorText2(errorKey, digits, labels) {
2086
+ if (errorKey === null) {
2087
+ return null;
2088
+ }
2089
+ if (errorKey === "mismatch" /* Mismatch */) {
2090
+ return interpolate(labels.errorMismatch, { count: digits });
2091
+ }
2092
+ if (errorKey === "unauthorized" /* Unauthorized */) {
2093
+ return labels.errorUnauthorized;
2094
+ }
2095
+ if (errorKey === "forbidden" /* Forbidden */) {
2096
+ return labels.errorForbidden;
2097
+ }
2098
+ if (errorKey === "invalid_pin" /* InvalidPin */) {
2099
+ return labels.errorInvalidPin;
2100
+ }
2101
+ return labels.errorFailed;
2102
+ }
2103
+ function DevicePinEnrollForm({
2104
+ client,
2105
+ initialDigits = DEVICE_PIN_DEFAULT_DIGITS,
2106
+ theme: themeProp,
2107
+ labels: labelsProp,
2108
+ testIdPrefix,
2109
+ onEnrolled,
2110
+ onCancel
2111
+ }) {
2112
+ const theme = useAuthTheme(themeProp);
2113
+ const styles3 = useAuthStyles(theme);
2114
+ const labels = useMemo(
2115
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2116
+ [labelsProp]
2117
+ );
2118
+ const [digits, setDigits] = useState(initialDigits);
2119
+ const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } = useDevicePinEnroll({ client, digits, onEnrolled });
2120
+ const error = resolveErrorText2(errorKey, digits, labels);
2121
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
2122
+ return /* @__PURE__ */ jsxs(
2123
+ View,
2124
+ {
2125
+ style: styles3.card,
2126
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix),
2127
+ children: [
2128
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.formTitle }),
2129
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: interpolate(labels.formDescription, { count: digits }) }),
2130
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.lengthLabel }),
2131
+ /* @__PURE__ */ jsx(
2132
+ DevicePinLengthPicker,
2133
+ {
2134
+ disabled: submitting,
2135
+ optionHint: labels.lengthOptionHint,
2136
+ selected: digits,
2137
+ testIdPrefix,
2138
+ theme,
2139
+ onSelect: (option) => {
2140
+ setDigits(option);
2141
+ setPin("");
2142
+ setConfirmPin("");
2143
+ }
2144
+ }
2145
+ ),
2146
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.pinLabel }),
2147
+ /* @__PURE__ */ jsx(
2148
+ DevicePinInput,
2149
+ {
2150
+ accessibilityHint: labels.pinPlaceholder,
2151
+ accessibilityLabel: labels.pinLabel,
2152
+ disabled: submitting,
2153
+ emptyHint: labels.pinPlaceholder,
2154
+ filledHint: labels.pinLabel,
2155
+ length: digits,
2156
+ testID: AuthTestIds.devicePinEnrollPin,
2157
+ testIdPrefix,
2158
+ theme,
2159
+ value: pin,
2160
+ onChange: setPin
2161
+ }
2162
+ ),
2163
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmLabel }),
2164
+ /* @__PURE__ */ jsx(
2165
+ DevicePinInput,
2166
+ {
2167
+ accessibilityHint: labels.confirmPlaceholder,
2168
+ accessibilityLabel: labels.confirmLabel,
2169
+ disabled: submitting,
2170
+ emptyHint: labels.confirmPlaceholder,
2171
+ filledHint: labels.confirmLabel,
2172
+ length: digits,
2173
+ testID: AuthTestIds.devicePinEnrollConfirm,
2174
+ testIdPrefix,
2175
+ theme,
2176
+ value: confirmPin,
2177
+ onChange: setConfirmPin
2178
+ }
2179
+ ),
2180
+ error !== null ? /* @__PURE__ */ jsx(
2181
+ Text,
2182
+ {
2183
+ style: styles3.errorText,
2184
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix),
2185
+ children: error
2186
+ }
2187
+ ) : null,
2188
+ /* @__PURE__ */ jsx(
2189
+ TouchableOpacity,
2190
+ {
2191
+ accessibilityHint: labels.submit,
2192
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
2193
+ accessibilityRole: "button",
2194
+ disabled: submitting,
2195
+ style: buttonStyle,
2196
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix),
2197
+ onPress: submit,
2198
+ children: submitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
2199
+ }
2200
+ ),
2201
+ /* @__PURE__ */ jsx(
2202
+ TouchableOpacity,
2203
+ {
2204
+ accessibilityHint: labels.cancelHint,
2205
+ accessibilityLabel: labels.cancel,
2206
+ accessibilityRole: "button",
2207
+ disabled: submitting,
2208
+ style: styles3.escapeLink,
2209
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix),
2210
+ onPress: onCancel,
2211
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.cancel })
2212
+ }
2213
+ )
2214
+ ]
2215
+ }
2216
+ );
2217
+ }
2218
+ function DevicePinOffer({
2219
+ client,
2220
+ initialDigits,
2221
+ theme: themeProp,
2222
+ labels: labelsProp,
2223
+ testIdPrefix,
2224
+ onDismiss
2225
+ }) {
2226
+ const theme = useAuthTheme(themeProp);
2227
+ const styles3 = useAuthStyles(theme);
2228
+ const labels = useMemo(
2229
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2230
+ [labelsProp]
2231
+ );
2232
+ const [expanded, setExpanded] = useState(false);
2233
+ const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);
2234
+ if (expanded) {
2235
+ return /* @__PURE__ */ jsx(View, { style: styles3.card, testID: cardTestId, children: /* @__PURE__ */ jsx(
2236
+ DevicePinEnrollForm,
2237
+ {
2238
+ client,
2239
+ initialDigits,
2240
+ labels: labelsProp,
2241
+ testIdPrefix,
2242
+ theme,
2243
+ onCancel: onDismiss,
2244
+ onEnrolled: onDismiss
2245
+ }
2246
+ ) });
2247
+ }
2248
+ return /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: cardTestId, children: [
2249
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.offerTitle }),
2250
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.offerDescription }),
2251
+ /* @__PURE__ */ jsx(
2252
+ TouchableOpacity,
2253
+ {
2254
+ accessibilityHint: labels.offerAcceptHint,
2255
+ accessibilityLabel: labels.offerAccept,
2256
+ accessibilityRole: "button",
2257
+ style: styles3.primaryButton,
2258
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix),
2259
+ onPress: () => setExpanded(true),
2260
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.offerAccept })
2261
+ }
2262
+ ),
2263
+ /* @__PURE__ */ jsx(
2264
+ TouchableOpacity,
2265
+ {
2266
+ accessibilityHint: labels.offerSkipHint,
2267
+ accessibilityLabel: labels.offerSkip,
2268
+ accessibilityRole: "button",
2269
+ style: styles3.secondaryButton,
2270
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix),
2271
+ onPress: onDismiss,
2272
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.offerSkip })
2273
+ }
2274
+ )
2275
+ ] });
2276
+ }
2277
+ function useDevicePinDisable({
2278
+ client,
2279
+ initialHasPin,
2280
+ onChanged
2281
+ }) {
2282
+ const [hasPin, setHasPin] = useState(initialHasPin);
2283
+ const [disabling, setDisabling] = useState(false);
2284
+ const [failed, setFailed] = useState(false);
2285
+ const disable = useCallback(() => {
2286
+ setFailed(false);
2287
+ setDisabling(true);
2288
+ client.disableDevicePin().then((ok) => {
2289
+ if (ok) {
2290
+ setHasPin(false);
2291
+ onChanged?.(false);
2292
+ return;
2293
+ }
2294
+ setFailed(true);
2295
+ }).catch(() => {
2296
+ setFailed(true);
2297
+ }).finally(() => {
2298
+ setDisabling(false);
2299
+ });
2300
+ }, [client, onChanged]);
2301
+ const markEnabled = useCallback(() => {
2302
+ setHasPin(true);
2303
+ onChanged?.(true);
2304
+ }, [onChanged]);
2305
+ return { hasPin, disabling, failed, disable, markEnabled };
2306
+ }
2307
+ function DevicePinSettingsCard({
2308
+ client,
2309
+ initialHasPin,
2310
+ theme: themeProp,
2311
+ labels: labelsProp,
2312
+ enrollLabels,
2313
+ testIdPrefix,
2314
+ onChanged
2315
+ }) {
2316
+ const theme = useAuthTheme(themeProp);
2317
+ const styles3 = useAuthStyles(theme);
2318
+ const labels = useMemo(
2319
+ () => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),
2320
+ [labelsProp]
2321
+ );
2322
+ const resolvedEnrollLabels = useMemo(
2323
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),
2324
+ [enrollLabels]
2325
+ );
2326
+ const [enrolling, setEnrolling] = useState(false);
2327
+ const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({
2328
+ client,
2329
+ initialHasPin,
2330
+ onChanged
2331
+ });
2332
+ const handleEnrolled = () => {
2333
+ setEnrolling(false);
2334
+ markEnabled();
2335
+ };
2336
+ const disableButtonStyle = disabling ? [styles3.secondaryButton, styles3.primaryButtonDisabled] : styles3.secondaryButton;
2337
+ return /* @__PURE__ */ jsxs(
2338
+ View,
2339
+ {
2340
+ style: styles3.card,
2341
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix),
2342
+ children: [
2343
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
2344
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
2345
+ /* @__PURE__ */ jsx(
2346
+ Text,
2347
+ {
2348
+ style: styles3.statusText,
2349
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix),
2350
+ children: hasPin ? labels.statusEnabled : labels.statusDisabled
2351
+ }
2352
+ ),
2353
+ failed ? /* @__PURE__ */ jsx(
2354
+ Text,
2355
+ {
2356
+ style: styles3.errorText,
2357
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix),
2358
+ children: labels.disableFailed
2359
+ }
2360
+ ) : null,
2361
+ renderAction()
2362
+ ]
2363
+ }
2364
+ );
2365
+ function renderAction() {
2366
+ if (enrolling) {
2367
+ return /* @__PURE__ */ jsx(
2368
+ DevicePinEnrollForm,
2369
+ {
2370
+ client,
2371
+ labels: resolvedEnrollLabels,
2372
+ testIdPrefix,
2373
+ theme,
2374
+ onCancel: () => setEnrolling(false),
2375
+ onEnrolled: handleEnrolled
2376
+ }
2377
+ );
2378
+ }
2379
+ if (hasPin) {
2380
+ return /* @__PURE__ */ jsx(
2381
+ TouchableOpacity,
2382
+ {
2383
+ accessibilityHint: labels.disableHint,
2384
+ accessibilityLabel: disabling ? labels.disabling : labels.disable,
2385
+ accessibilityRole: "button",
2386
+ disabled: disabling,
2387
+ style: disableButtonStyle,
2388
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix),
2389
+ onPress: disable,
2390
+ children: disabling ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.primary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.disable })
2391
+ }
2392
+ );
2393
+ }
2394
+ return /* @__PURE__ */ jsx(
2395
+ TouchableOpacity,
2396
+ {
2397
+ accessibilityHint: labels.enableHint,
2398
+ accessibilityLabel: labels.enable,
2399
+ accessibilityRole: "button",
2400
+ style: styles3.primaryButton,
2401
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix),
2402
+ onPress: () => setEnrolling(true),
2403
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.enable })
2404
+ }
2405
+ );
2406
+ }
2407
+ }
2408
+
2409
+ // src/passkey/passkeyNavigation.ts
2410
+ var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
2411
+ var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
2412
+ var RETURN_URL_PARAM = "returnUrl";
2413
+ var PASSKEY_ERROR_PARAM = "passkeyError";
2414
+ var PASSKEY_PARAM = "passkey";
2415
+ var PASSKEY_REGISTERED_VALUE = "registered";
2416
+ var PASSKEY_ERROR_CANCELLED = "cancelled";
2417
+ var PASSKEY_ERROR_FAILED = "failed";
2418
+ function buildNavigationUrl(endpoint, returnUrl) {
2419
+ return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
2420
+ }
2421
+ function readSearchParams() {
2422
+ if (typeof window === "undefined") {
2423
+ return null;
2424
+ }
2425
+ return new URLSearchParams(window.location.search);
2426
+ }
2427
+ function startPasskeyLogin(returnUrl) {
2428
+ if (typeof window === "undefined") {
2429
+ return;
2430
+ }
2431
+ window.location.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
2432
+ }
2433
+ function startPasskeyRegistration(returnUrl) {
2434
+ if (typeof window === "undefined") {
2435
+ return;
2436
+ }
2437
+ window.location.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
2438
+ }
2439
+ function readPasskeyError() {
2440
+ const params = readSearchParams();
2441
+ if (params === null) {
2442
+ return null;
2443
+ }
2444
+ const value = params.get(PASSKEY_ERROR_PARAM);
2445
+ if (value === PASSKEY_ERROR_CANCELLED) {
2446
+ return PASSKEY_ERROR_CANCELLED;
2447
+ }
2448
+ if (value === PASSKEY_ERROR_FAILED) {
2449
+ return PASSKEY_ERROR_FAILED;
2450
+ }
2451
+ return null;
2452
+ }
2453
+ function readPasskeyRegistered() {
2454
+ const params = readSearchParams();
2455
+ if (params === null) {
2456
+ return false;
2457
+ }
2458
+ return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;
2459
+ }
2460
+ var DEFAULT_RETURN_URL = "/";
2461
+ function PasskeyLoginButton({
2462
+ returnUrl = DEFAULT_RETURN_URL,
2463
+ theme: themeProp,
2464
+ labels: labelsProp,
2465
+ testIdPrefix
2466
+ }) {
2467
+ const theme = useAuthTheme(themeProp);
2468
+ const styles3 = useAuthStyles(theme);
2469
+ const labels = useMemo(
2470
+ () => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),
2471
+ [labelsProp]
2472
+ );
2473
+ const error = readPasskeyError();
2474
+ return /* @__PURE__ */ jsxs(View, { testID: withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix), children: [
2475
+ error !== null ? /* @__PURE__ */ jsx(
2476
+ Text,
2477
+ {
2478
+ style: styles3.errorText,
2479
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix),
2480
+ children: error === "cancelled" ? labels.errorCancelled : labels.errorFailed
2481
+ }
2482
+ ) : null,
2483
+ /* @__PURE__ */ jsx(
2484
+ TouchableOpacity,
2485
+ {
2486
+ accessibilityHint: labels.signInHint,
2487
+ accessibilityLabel: labels.signInButton,
2488
+ accessibilityRole: "button",
2489
+ style: styles3.secondaryButton,
2490
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix),
2491
+ onPress: () => startPasskeyLogin(returnUrl),
2492
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.signInButton })
2493
+ }
2494
+ )
2495
+ ] });
2496
+ }
2497
+ var DEFAULT_RETURN_PATH = "/";
2498
+ function readCurrentPath() {
2499
+ if (typeof window === "undefined") {
2500
+ return DEFAULT_RETURN_PATH;
2501
+ }
2502
+ return window.location.pathname;
2503
+ }
2504
+ function PasskeySettingsCard({
2505
+ returnUrl,
2506
+ theme: themeProp,
2507
+ labels: labelsProp,
2508
+ testIdPrefix
2509
+ }) {
2510
+ const theme = useAuthTheme(themeProp);
2511
+ const styles3 = useAuthStyles(theme);
2512
+ const labels = useMemo(
2513
+ () => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),
2514
+ [labelsProp]
2515
+ );
2516
+ const justRegistered = readPasskeyRegistered();
2517
+ const target = returnUrl ?? readCurrentPath();
2518
+ return /* @__PURE__ */ jsxs(
2519
+ View,
2520
+ {
2521
+ style: styles3.card,
2522
+ testID: withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix),
2523
+ children: [
2524
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
2525
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
2526
+ /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: labels.reauthHint }),
2527
+ justRegistered ? /* @__PURE__ */ jsx(
2528
+ Text,
2529
+ {
2530
+ style: styles3.successText,
2531
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix),
2532
+ children: labels.registeredSuccess
2533
+ }
2534
+ ) : null,
2535
+ /* @__PURE__ */ jsx(
2536
+ TouchableOpacity,
2537
+ {
2538
+ accessibilityHint: labels.addHint,
2539
+ accessibilityLabel: labels.addButton,
2540
+ accessibilityRole: "button",
2541
+ style: styles3.primaryButton,
2542
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix),
2543
+ onPress: () => startPasskeyRegistration(target),
2544
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.addButton })
2545
+ }
2546
+ )
2547
+ ]
2548
+ }
2549
+ );
2550
+ }
2551
+
2552
+ // src/preferences/preferredMethodCache.ts
2553
+ var CACHE_KEY = "dloizides.auth.preferredLoginMethod";
2554
+ function safeStorage() {
2555
+ try {
2556
+ if (typeof localStorage === "undefined") {
2557
+ return null;
2558
+ }
2559
+ return localStorage;
2560
+ } catch {
2561
+ return null;
2562
+ }
2563
+ }
2564
+ function readCachedPreferredMethod() {
2565
+ const store = safeStorage();
2566
+ if (store === null) {
2567
+ return null;
2568
+ }
2569
+ try {
2570
+ const value = store.getItem(CACHE_KEY);
2571
+ return value === null || value === "" ? null : value;
2572
+ } catch {
2573
+ return null;
2574
+ }
2575
+ }
2576
+ function cachePreferredMethod(method) {
2577
+ const store = safeStorage();
2578
+ if (store === null) {
2579
+ return;
2580
+ }
2581
+ try {
2582
+ if (method === null || method === "") {
2583
+ store.removeItem(CACHE_KEY);
2584
+ return;
2585
+ }
2586
+ store.setItem(CACHE_KEY, method);
2587
+ } catch {
2588
+ }
2589
+ }
2590
+ function clearCachedPreferredMethod() {
2591
+ cachePreferredMethod(null);
2592
+ }
2593
+
2594
+ // src/preferences/usePreferredMethodSetting.ts
2595
+ function usePreferredMethodSetting({
2596
+ client,
2597
+ onChanged
2598
+ }) {
2599
+ const [loading, setLoading] = useState(true);
2600
+ const [saving, setSaving] = useState(false);
2601
+ const [failed, setFailed] = useState(false);
2602
+ const [selected, setSelected] = useState(null);
2603
+ useEffect(() => {
2604
+ let active = true;
2605
+ client.getPreferredLoginMethod().then((method) => {
2606
+ if (active) {
2607
+ setSelected(method);
2608
+ }
2609
+ }).catch(() => {
2610
+ }).finally(() => {
2611
+ if (active) {
2612
+ setLoading(false);
2613
+ }
2614
+ });
2615
+ return () => {
2616
+ active = false;
2617
+ };
2618
+ }, [client]);
2619
+ const select = useCallback(
2620
+ (method) => {
2621
+ const previous = selected;
2622
+ if (method === previous) {
2623
+ return;
2624
+ }
2625
+ setFailed(false);
2626
+ setSaving(true);
2627
+ setSelected(method);
2628
+ client.setPreferredLoginMethod(method).then((ok) => {
2629
+ if (ok) {
2630
+ cachePreferredMethod(method);
2631
+ onChanged?.(method);
2632
+ return;
2633
+ }
2634
+ setSelected(previous);
2635
+ setFailed(true);
2636
+ }).catch(() => {
2637
+ setSelected(previous);
2638
+ setFailed(true);
2639
+ }).finally(() => {
2640
+ setSaving(false);
2641
+ });
2642
+ },
2643
+ [client, selected, onChanged]
2644
+ );
2645
+ return { loading, saving, failed, selected, select };
2646
+ }
2647
+ var NO_PREFERENCE = "__none__";
2648
+ function methodDisplayName(method, labels) {
2649
+ if (method === "password") {
2650
+ return labels.methodPassword;
2651
+ }
2652
+ if (method === "pin") {
2653
+ return labels.methodPin;
2654
+ }
2655
+ if (method === "passkey") {
2656
+ return labels.methodPasskey;
2657
+ }
2658
+ return method;
2659
+ }
2660
+ function PreferredMethodSettingsCard({
2661
+ client,
2662
+ availableMethods,
2663
+ theme: themeProp,
2664
+ labels: labelsProp,
2665
+ testIdPrefix,
2666
+ onChanged
2667
+ }) {
2668
+ const theme = useAuthTheme(themeProp);
2669
+ const styles3 = useAuthStyles(theme);
2670
+ const labels = useMemo(
2671
+ () => ({ ...DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, ...labelsProp }),
2672
+ [labelsProp]
2673
+ );
2674
+ const { loading, saving, failed, selected, select } = usePreferredMethodSetting({
2675
+ client,
2676
+ onChanged
2677
+ });
2678
+ const options = useMemo(
2679
+ () => [
2680
+ { value: null, key: NO_PREFERENCE, label: labels.noPreference },
2681
+ ...availableMethods.map((method) => ({
2682
+ value: method,
2683
+ key: method,
2684
+ label: methodDisplayName(method, labels)
2685
+ }))
2686
+ ],
2687
+ [availableMethods, labels]
2688
+ );
2689
+ return /* @__PURE__ */ jsxs(
2690
+ View,
2691
+ {
2692
+ style: styles3.card,
2693
+ testID: withTestIdPrefix(AuthTestIds.preferredMethodSettings, testIdPrefix),
2694
+ children: [
2695
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
2696
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
2697
+ loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.primary, size: "small" }) : options.map((option) => {
2698
+ const isSelected = option.value === selected;
2699
+ const optionTestId = `${withTestIdPrefix(
2700
+ AuthTestIds.preferredMethodSettingsOption,
2701
+ testIdPrefix
2702
+ )}-${option.key}`;
2703
+ return /* @__PURE__ */ jsx(
2704
+ TouchableOpacity,
2705
+ {
2706
+ accessibilityHint: labels.description,
2707
+ accessibilityLabel: option.label,
2708
+ accessibilityRole: "radio",
2709
+ accessibilityState: { selected: isSelected },
2710
+ disabled: saving,
2711
+ style: isSelected ? styles3.secondaryButton : styles3.escapeLink,
2712
+ testID: optionTestId,
2713
+ onPress: () => select(option.value),
2714
+ children: /* @__PURE__ */ jsx(Text, { style: isSelected ? styles3.secondaryButtonText : styles3.linkText, children: isSelected ? `\u2713 ${option.label}` : option.label })
2715
+ },
2716
+ option.key
2717
+ );
2718
+ }),
2719
+ saving ? /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: labels.saving }) : null,
2720
+ failed ? /* @__PURE__ */ jsx(
2721
+ Text,
2722
+ {
2723
+ style: styles3.errorText,
2724
+ testID: withTestIdPrefix(AuthTestIds.preferredMethodSettingsError, testIdPrefix),
2725
+ children: labels.saveFailed
2726
+ }
2727
+ ) : null
2728
+ ]
2729
+ }
2730
+ );
2731
+ }
2732
+ function hintFor(method, labels) {
2733
+ if (method === "password") {
2734
+ return labels.password;
2735
+ }
2736
+ if (method === "pin") {
2737
+ return labels.pin;
2738
+ }
2739
+ if (method === "passkey") {
2740
+ return labels.passkey;
2741
+ }
2742
+ return null;
2743
+ }
2744
+ function PreferredMethodHint({
2745
+ method,
2746
+ theme: themeProp,
2747
+ labels: labelsProp,
2748
+ testIdPrefix
2749
+ }) {
2750
+ const theme = useAuthTheme(themeProp);
2751
+ const styles3 = useAuthStyles(theme);
2752
+ const labels = useMemo(
2753
+ () => ({ ...DEFAULT_PREFERRED_METHOD_HINT_LABELS, ...labelsProp }),
2754
+ [labelsProp]
2755
+ );
2756
+ const text = hintFor(method, labels);
2757
+ if (text === null) {
2758
+ return null;
2759
+ }
2760
+ return /* @__PURE__ */ jsx(View, { testID: withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix), children: /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: text }) });
2761
+ }
2762
+ var EMPTY_CONFIG = {
2763
+ methods: [],
2764
+ registrationEnabled: false,
2765
+ deviceState: {
2766
+ rememberedUsername: null,
2767
+ hasPin: false,
2768
+ pinDigits: null,
2769
+ preferredMethod: null
2770
+ }
2771
+ };
2772
+ function useBffLoginConfig(client) {
2773
+ const [config, setConfig] = useState(EMPTY_CONFIG);
2774
+ const [loading, setLoading] = useState(true);
2775
+ useEffect(() => {
2776
+ let active = true;
2777
+ client.getLoginConfig().then((next) => {
2778
+ if (active) {
2779
+ setConfig(next);
2780
+ }
2781
+ }).catch(() => {
2782
+ if (active) {
2783
+ setConfig(EMPTY_CONFIG);
2784
+ }
2785
+ }).finally(() => {
2786
+ if (active) {
2787
+ setLoading(false);
2788
+ }
2789
+ });
2790
+ return () => {
2791
+ active = false;
2792
+ };
2793
+ }, [client]);
2794
+ return { config, loading };
2795
+ }
2796
+
2797
+ // src/preferences/preferencesClient.ts
2798
+ var CSRF_HEADER = "X-BFF-Csrf";
2799
+ var CSRF_HEADER_VALUE = "1";
2800
+ var JSON_CONTENT_TYPE = "application/json";
2801
+ var DEFAULT_TENANTS_SEGMENT = "tenants";
2802
+ var PREFERENCES_PATH = "api/v1/me/preferences";
2803
+ var LOGIN_METHOD_PREFERENCE_PATH = "api/v1/me/login-method-preference";
2804
+ function isRecord(value) {
2805
+ return typeof value === "object" && value !== null;
2806
+ }
2807
+ function readOptionalString(record, key) {
2808
+ const value = record[key];
2809
+ if (typeof value !== "string" || value === "") {
2810
+ return null;
2811
+ }
2812
+ return value;
2813
+ }
2814
+ function createPreferencesClient(options) {
2815
+ const http = options.http;
2816
+ const baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
2817
+ const segment = options.tenantsSegment ?? DEFAULT_TENANTS_SEGMENT;
2818
+ const proxyBase = `${baseUrl}/bff/api/${segment}`;
2819
+ return {
2820
+ async getPreferredLoginMethod() {
2821
+ try {
2822
+ const response = await http({
2823
+ url: `${proxyBase}/${PREFERENCES_PATH}`,
2824
+ method: "GET",
2825
+ headers: { Accept: JSON_CONTENT_TYPE },
2826
+ credentials: "include"
2827
+ });
2828
+ if (!response.ok || !isRecord(response.data)) {
2829
+ return null;
2830
+ }
2831
+ return readOptionalString(response.data, "preferredLoginMethod");
2832
+ } catch {
2833
+ return null;
2834
+ }
2835
+ },
2836
+ async setPreferredLoginMethod(method) {
2837
+ try {
2838
+ const response = await http({
2839
+ url: `${proxyBase}/${LOGIN_METHOD_PREFERENCE_PATH}`,
2840
+ method: "PUT",
2841
+ headers: {
2842
+ "Content-Type": JSON_CONTENT_TYPE,
2843
+ Accept: JSON_CONTENT_TYPE,
2844
+ [CSRF_HEADER]: CSRF_HEADER_VALUE
2845
+ },
2846
+ body: JSON.stringify({ method }),
2847
+ credentials: "include"
2848
+ });
2849
+ return response.ok;
2850
+ } catch {
2851
+ return false;
2852
+ }
2853
+ }
2854
+ };
2855
+ }
2856
+
2857
+ // src/preferences/syncPreferredMethodCache.ts
2858
+ async function syncPreferredMethodFromServer(client) {
2859
+ try {
2860
+ const method = await client.getPreferredLoginMethod();
2861
+ cachePreferredMethod(method);
2862
+ return method;
2863
+ } catch {
2864
+ return null;
2865
+ }
2866
+ }
1527
2867
  async function lazyFetchHttpClient(request) {
1528
2868
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
1529
2869
  if (fetchImpl === void 0) {
@@ -1539,11 +2879,11 @@ function createBffAuthClient(options = {}) {
1539
2879
  }
1540
2880
 
1541
2881
  // src/router/resolvePostLoginRoute.ts
1542
- function isRecord(value) {
2882
+ function isRecord2(value) {
1543
2883
  return typeof value === "object" && value !== null;
1544
2884
  }
1545
2885
  function readRealmAccessRoles(realmAccess) {
1546
- if (!isRecord(realmAccess)) {
2886
+ if (!isRecord2(realmAccess)) {
1547
2887
  return [];
1548
2888
  }
1549
2889
  const roles = realmAccess.roles;
@@ -1567,6 +2907,6 @@ function resolvePostLoginRoute(user, table) {
1567
2907
  return table.fallback ?? null;
1568
2908
  }
1569
2909
 
1570
- export { AuthTestIds, AuthThemeProvider, BffAuthStatus, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PIN_LABELS, DEFAULT_RESET_PASSWORD_LABELS, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasswordPolicyError, PinForm, ResetPasswordError, ResetPasswordForm, collectUserRoles, createBffAuthClient, defaultAuthTheme, isPasswordValid, isValidForgotPasswordEmail, resolvePostLoginRoute, useAuthTheme, useBffAuth, useBffForgotPassword, useBffResetPassword, useForgotPasswordSubmit, useOtpLogin, usePinLogin, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
2910
+ export { AuthTestIds, AuthThemeProvider, BffAuthStatus, 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_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, PreferredMethodHint, PreferredMethodSettingsCard, ResetPasswordError, ResetPasswordForm, cachePreferredMethod, clearCachedPreferredMethod, collectUserRoles, createBffAuthClient, createPreferencesClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readCachedPreferredMethod, readPasskeyError, readPasskeyRegistered, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, syncPreferredMethodFromServer, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePinLogin, usePreferredMethodSetting, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
1571
2911
  //# sourceMappingURL=index.mjs.map
1572
2912
  //# sourceMappingURL=index.mjs.map