@aws-amplify/ui 6.13.0 → 6.15.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.
Files changed (34) hide show
  1. package/dist/esm/helpers/authenticator/facade.mjs +9 -2
  2. package/dist/esm/helpers/authenticator/formFields/defaults.mjs +34 -8
  3. package/dist/esm/helpers/authenticator/getRoute.mjs +8 -0
  4. package/dist/esm/helpers/authenticator/textUtil.mjs +34 -0
  5. package/dist/esm/i18n/dictionaries/authenticator/defaultTexts.mjs +27 -0
  6. package/dist/esm/i18n/dictionaries/authenticator/es.mjs +1 -1
  7. package/dist/esm/i18n/dictionaries/authenticator/fr.mjs +1 -1
  8. package/dist/esm/machines/authenticator/actions.mjs +63 -4
  9. package/dist/esm/machines/authenticator/actors/signIn.mjs +199 -49
  10. package/dist/esm/machines/authenticator/actors/signUp.mjs +81 -27
  11. package/dist/esm/machines/authenticator/defaultServices.mjs +37 -0
  12. package/dist/esm/machines/authenticator/guards.mjs +49 -1
  13. package/dist/esm/machines/authenticator/index.mjs +29 -15
  14. package/dist/esm/machines/authenticator/utils.mjs +58 -6
  15. package/dist/index.js +625 -111
  16. package/dist/styles/StorageBrowser.css +0 -1
  17. package/dist/styles/StorageBrowser.layer.css +0 -1
  18. package/dist/styles/authenticator.css +17 -0
  19. package/dist/styles/authenticator.layer.css +17 -0
  20. package/dist/styles/modal.css +81 -0
  21. package/dist/styles/modal.layer.css +83 -0
  22. package/dist/styles.css +100 -1
  23. package/dist/styles.layer.css +100 -1
  24. package/dist/types/helpers/authenticator/facade.d.ts +6 -2
  25. package/dist/types/helpers/authenticator/textUtil.d.ts +24 -1
  26. package/dist/types/i18n/dictionaries/authenticator/defaultTexts.d.ts +27 -0
  27. package/dist/types/i18n/dictionaries/index.d.ts +27 -0
  28. package/dist/types/i18n/translations.d.ts +27 -0
  29. package/dist/types/machines/authenticator/defaultServices.d.ts +105 -0
  30. package/dist/types/machines/authenticator/types.d.ts +26 -2
  31. package/dist/types/machines/authenticator/utils.d.ts +14 -2
  32. package/dist/types/theme/components/index.d.ts +3 -1
  33. package/dist/types/theme/components/modal.d.ts +10 -0
  34. package/package.json +5 -4
@@ -1,5 +1,5 @@
1
1
  import { createMachine, sendUpdate } from 'xstate';
2
- import { signInWithRedirect, confirmSignIn, resetPassword, fetchUserAttributes } from 'aws-amplify/auth';
2
+ import { listWebAuthnCredentials, signInWithRedirect, confirmSignIn, resetPassword, fetchUserAttributes } from 'aws-amplify/auth';
3
3
  import { runValidators } from '../../../validators/index.mjs';
4
4
  import ACTIONS from '../actions.mjs';
5
5
  import { defaultServices } from '../defaultServices.mjs';
@@ -35,32 +35,13 @@ const handleSignInResponse = {
35
35
  'setNextSignInStep',
36
36
  'setTotpSecretCode',
37
37
  'setAllowedMfaTypes',
38
+ 'setCodeDeliveryDetails',
38
39
  ],
39
40
  target: '#signInActor.init',
40
41
  },
41
42
  ],
42
43
  onError: { actions: 'setRemoteError', target: 'edit' },
43
44
  };
44
- const handleFetchUserAttributesResponse = {
45
- onDone: [
46
- {
47
- cond: 'shouldVerifyAttribute',
48
- actions: [
49
- 'setShouldVerifyUserAttributeStep',
50
- 'setUnverifiedUserAttributes',
51
- ],
52
- target: '#signInActor.resolved',
53
- },
54
- {
55
- actions: 'setConfirmAttributeCompleteStep',
56
- target: '#signInActor.resolved',
57
- },
58
- ],
59
- onError: {
60
- actions: 'setConfirmAttributeCompleteStep',
61
- target: '#signInActor.resolved',
62
- },
63
- };
64
45
  const getDefaultConfirmSignInState = (exit) => ({
65
46
  initial: 'edit',
66
47
  exit,
@@ -71,6 +52,7 @@ const getDefaultConfirmSignInState = (exit) => ({
71
52
  SUBMIT: { actions: 'handleSubmit', target: 'submit' },
72
53
  SIGN_IN: '#signInActor.signIn',
73
54
  CHANGE: { actions: 'handleInput' },
55
+ RESEND: { target: 'resend' },
74
56
  },
75
57
  },
76
58
  submit: {
@@ -78,6 +60,21 @@ const getDefaultConfirmSignInState = (exit) => ({
78
60
  entry: ['sendUpdate', 'clearError'],
79
61
  invoke: { src: 'confirmSignIn', ...handleSignInResponse },
80
62
  },
63
+ resend: {
64
+ tags: 'pending',
65
+ entry: ['sendUpdate', 'clearError'],
66
+ invoke: {
67
+ src: 'resendSignInCode',
68
+ onDone: {
69
+ actions: ['setCodeDeliveryDetails', 'sendUpdate'],
70
+ target: 'edit',
71
+ },
72
+ onError: {
73
+ actions: 'setRemoteError',
74
+ target: 'edit',
75
+ },
76
+ },
77
+ },
81
78
  },
82
79
  });
83
80
  function signInActor({ services }) {
@@ -112,13 +109,68 @@ function signInActor({ services }) {
112
109
  { target: 'signIn' },
113
110
  ],
114
111
  },
115
- federatedSignIn: getFederatedSignInState('signIn'),
112
+ federatedSignIn: { ...getFederatedSignInState('signIn') },
116
113
  fetchUserAttributes: {
117
114
  invoke: {
118
115
  src: 'fetchUserAttributes',
119
- ...handleFetchUserAttributesResponse,
116
+ onDone: [
117
+ {
118
+ cond: 'hasPasskeyRegistrationPrompts',
119
+ actions: 'setFetchedUserAttributes',
120
+ target: 'checkPasskeys',
121
+ },
122
+ {
123
+ actions: 'setFetchedUserAttributes',
124
+ target: 'evaluatePasskeyPrompt',
125
+ },
126
+ ],
127
+ onError: {
128
+ actions: 'setConfirmAttributeCompleteStep',
129
+ target: '#signInActor.resolved',
130
+ },
120
131
  },
121
132
  },
133
+ checkPasskeys: {
134
+ invoke: {
135
+ src: async () => {
136
+ try {
137
+ const result = await listWebAuthnCredentials();
138
+ return result.credentials && result.credentials.length > 0;
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ },
144
+ onDone: {
145
+ actions: 'setHasExistingPasskeys',
146
+ target: 'evaluatePasskeyPrompt',
147
+ },
148
+ onError: {
149
+ actions: 'clearHasExistingPasskeys',
150
+ target: 'evaluatePasskeyPrompt',
151
+ },
152
+ },
153
+ },
154
+ evaluatePasskeyPrompt: {
155
+ always: [
156
+ {
157
+ cond: 'shouldPromptPasskeyRegistration',
158
+ target: '#signInActor.passkeyPrompt',
159
+ },
160
+ {
161
+ cond: 'shouldVerifyAttribute',
162
+ actions: [
163
+ 'setShouldVerifyUserAttributeStep',
164
+ 'setUnverifiedUserAttributes',
165
+ ],
166
+ target: '#signInActor.resolved',
167
+ },
168
+ {
169
+ actions: 'setConfirmAttributeCompleteStep',
170
+ target: '#signInActor.resolved',
171
+ },
172
+ ],
173
+ },
122
174
  resendSignUpCode: {
123
175
  invoke: {
124
176
  src: 'handleResendSignUpCode',
@@ -153,23 +205,70 @@ function signInActor({ services }) {
153
205
  on: {
154
206
  CHANGE: { actions: 'handleInput' },
155
207
  FEDERATED_SIGN_IN: { target: '#signInActor.federatedSignIn' },
156
- SUBMIT: { actions: 'handleSubmit', target: 'submit' },
208
+ SHOW_AUTH_METHODS: {
209
+ actions: 'setUsernameSignIn',
210
+ target: 'selectMethod',
211
+ },
212
+ SUBMIT: [
213
+ {
214
+ cond: 'shouldSelectAuthMethod',
215
+ actions: 'handleSubmit',
216
+ target: 'selectMethod',
217
+ },
218
+ {
219
+ actions: 'handleSubmit',
220
+ target: 'submit',
221
+ },
222
+ ],
223
+ },
224
+ },
225
+ selectMethod: {
226
+ entry: [
227
+ 'sendUpdate',
228
+ 'setSelectAuthMethodStep',
229
+ 'setUsernameSignIn',
230
+ ],
231
+ on: {
232
+ SELECT_METHOD: {
233
+ actions: 'setSelectedAuthMethod',
234
+ target: 'submit',
235
+ },
236
+ SUBMIT: {
237
+ actions: ['handleSubmit', 'setSelectedAuthMethodFromForm'],
238
+ target: 'submit',
239
+ },
240
+ SIGN_IN: {
241
+ target: 'edit',
242
+ },
157
243
  },
158
244
  },
159
245
  submit: {
160
246
  tags: 'pending',
161
247
  entry: ['clearError', 'sendUpdate', 'setUsernameSignIn'],
162
248
  exit: 'clearFormValues',
163
- invoke: { src: 'handleSignIn', ...handleSignInResponse },
249
+ invoke: {
250
+ src: 'handleSignIn',
251
+ onDone: handleSignInResponse.onDone,
252
+ onError: [
253
+ {
254
+ cond: 'shouldReturnToSelectMethod',
255
+ actions: 'setRemoteError',
256
+ target: 'selectMethod',
257
+ },
258
+ handleSignInResponse.onError,
259
+ ],
260
+ },
164
261
  },
165
262
  },
166
263
  },
167
- confirmSignIn: getDefaultConfirmSignInState([
168
- 'clearChallengeName',
169
- 'clearFormValues',
170
- 'clearError',
171
- 'clearTouched',
172
- ]),
264
+ confirmSignIn: {
265
+ ...getDefaultConfirmSignInState([
266
+ 'clearChallengeName',
267
+ 'clearFormValues',
268
+ 'clearError',
269
+ 'clearTouched',
270
+ ]),
271
+ },
173
272
  forceChangePassword: {
174
273
  entry: 'sendUpdate',
175
274
  type: 'parallel',
@@ -242,21 +341,40 @@ function signInActor({ services }) {
242
341
  },
243
342
  },
244
343
  },
245
- setupTotp: getDefaultConfirmSignInState([
246
- 'clearFormValues',
247
- 'clearError',
248
- 'clearTouched',
249
- ]),
250
- setupEmail: getDefaultConfirmSignInState([
251
- 'clearFormValues',
252
- 'clearError',
253
- 'clearTouched',
254
- ]),
255
- selectMfaType: getDefaultConfirmSignInState([
256
- 'clearFormValues',
257
- 'clearError',
258
- 'clearTouched',
259
- ]),
344
+ setupTotp: {
345
+ ...getDefaultConfirmSignInState([
346
+ 'clearFormValues',
347
+ 'clearError',
348
+ 'clearTouched',
349
+ ]),
350
+ },
351
+ setupEmail: {
352
+ ...getDefaultConfirmSignInState([
353
+ 'clearFormValues',
354
+ 'clearError',
355
+ 'clearTouched',
356
+ ]),
357
+ },
358
+ selectMfaType: {
359
+ ...getDefaultConfirmSignInState([
360
+ 'clearFormValues',
361
+ 'clearError',
362
+ 'clearTouched',
363
+ ]),
364
+ },
365
+ passkeyPrompt: {
366
+ entry: 'sendUpdate',
367
+ on: {
368
+ SUBMIT: {
369
+ actions: 'setConfirmAttributeCompleteStep',
370
+ target: 'resolved',
371
+ },
372
+ SKIP: {
373
+ actions: 'setConfirmAttributeCompleteStep',
374
+ target: 'resolved',
375
+ },
376
+ },
377
+ },
260
378
  resolved: {
261
379
  type: 'final',
262
380
  data: (context) => ({
@@ -282,9 +400,41 @@ function signInActor({ services }) {
282
400
  handleResendSignUpCode({ username }) {
283
401
  return services.handleResendSignUpCode({ username });
284
402
  },
285
- handleSignIn({ formValues, username }) {
286
- const { password } = formValues;
287
- return services.handleSignIn({ username, password });
403
+ resendSignInCode({ username, selectedAuthMethod, availableAuthMethods, preferredChallenge, }) {
404
+ // Resend code by calling signIn again with the same parameters
405
+ const method = selectedAuthMethod ??
406
+ preferredChallenge ??
407
+ availableAuthMethods?.[0] ??
408
+ 'PASSWORD';
409
+ return services.handleSignIn({
410
+ username,
411
+ options: {
412
+ authFlowType: 'USER_AUTH',
413
+ preferredChallenge: method,
414
+ },
415
+ });
416
+ },
417
+ handleSignIn({ formValues, username, selectedAuthMethod, availableAuthMethods, preferredChallenge, }) {
418
+ // Determine which method to use
419
+ const method = selectedAuthMethod ??
420
+ preferredChallenge ??
421
+ availableAuthMethods?.[0] ??
422
+ 'PASSWORD';
423
+ if (method === 'PASSWORD') {
424
+ // Traditional password flow
425
+ const { password } = formValues;
426
+ return services.handleSignIn({ username, password });
427
+ }
428
+ else {
429
+ // Passwordless flow using USER_AUTH
430
+ return services.handleSignIn({
431
+ username,
432
+ options: {
433
+ authFlowType: 'USER_AUTH',
434
+ preferredChallenge: method,
435
+ },
436
+ });
437
+ }
288
438
  },
289
439
  confirmSignIn({ formValues, step }) {
290
440
  const formValuesKey = getConfirmSignInFormValuesKey(step);
@@ -1,5 +1,5 @@
1
1
  import { createMachine, sendUpdate } from 'xstate';
2
- import { signInWithRedirect, fetchUserAttributes, autoSignIn } from 'aws-amplify/auth';
2
+ import { listWebAuthnCredentials, signInWithRedirect, fetchUserAttributes, autoSignIn } from 'aws-amplify/auth';
3
3
  import { getSignUpInput } from '../utils.mjs';
4
4
  import { runValidators } from '../../../validators/index.mjs';
5
5
  import ACTIONS from '../actions.mjs';
@@ -50,26 +50,6 @@ const handleAutoSignInResponse = {
50
50
  target: '#signUpActor.resolved',
51
51
  },
52
52
  };
53
- const handleFetchUserAttributesResponse = {
54
- onDone: [
55
- {
56
- cond: 'shouldVerifyAttribute',
57
- actions: [
58
- 'setShouldVerifyUserAttributeStep',
59
- 'setUnverifiedUserAttributes',
60
- ],
61
- target: '#signUpActor.resolved',
62
- },
63
- {
64
- actions: 'setConfirmAttributeCompleteStep',
65
- target: '#signUpActor.resolved',
66
- },
67
- ],
68
- onError: {
69
- actions: 'setConfirmAttributeCompleteStep',
70
- target: '#signUpActor.resolved',
71
- },
72
- };
73
53
  function signUpActor({ services }) {
74
54
  return createMachine({
75
55
  id: 'signUpActor',
@@ -89,10 +69,65 @@ function signUpActor({ services }) {
89
69
  fetchUserAttributes: {
90
70
  invoke: {
91
71
  src: 'fetchUserAttributes',
92
- ...handleFetchUserAttributesResponse,
72
+ onDone: [
73
+ {
74
+ cond: 'hasPasskeyRegistrationPrompts',
75
+ actions: 'setFetchedUserAttributes',
76
+ target: 'checkPasskeys',
77
+ },
78
+ {
79
+ actions: 'setFetchedUserAttributes',
80
+ target: 'evaluatePasskeyPrompt',
81
+ },
82
+ ],
83
+ onError: {
84
+ actions: 'setConfirmAttributeCompleteStep',
85
+ target: '#signUpActor.resolved',
86
+ },
93
87
  },
94
88
  },
95
- federatedSignIn: getFederatedSignInState('signUp'),
89
+ checkPasskeys: {
90
+ invoke: {
91
+ src: async () => {
92
+ try {
93
+ const result = await listWebAuthnCredentials();
94
+ return result.credentials && result.credentials.length > 0;
95
+ }
96
+ catch {
97
+ return false;
98
+ }
99
+ },
100
+ onDone: {
101
+ actions: 'setHasExistingPasskeys',
102
+ target: 'evaluatePasskeyPrompt',
103
+ },
104
+ onError: {
105
+ actions: 'clearHasExistingPasskeys',
106
+ target: 'evaluatePasskeyPrompt',
107
+ },
108
+ },
109
+ },
110
+ evaluatePasskeyPrompt: {
111
+ always: [
112
+ {
113
+ cond: 'shouldPromptPasskeyRegistrationAfterSignup',
114
+ target: '#signUpActor.passkeyPrompt',
115
+ },
116
+ {
117
+ cond: 'shouldVerifyAttribute',
118
+ actions: [
119
+ 'setShouldVerifyUserAttributeStep',
120
+ 'setUnverifiedUserAttributes',
121
+ ],
122
+ target: '#signUpActor.resolved',
123
+ },
124
+ {
125
+ actions: 'setConfirmAttributeCompleteStep',
126
+ target: '#signUpActor.resolved',
127
+ },
128
+ ],
129
+ },
130
+ federatedSignIn: { ...getFederatedSignInState('signUp') },
96
131
  resetPassword: {
97
132
  invoke: { src: 'resetPassword', ...handleResetPasswordResponse },
98
133
  },
@@ -111,7 +146,10 @@ function signUpActor({ services }) {
111
146
  cond: 'isUserAlreadyConfirmed',
112
147
  target: '#signUpActor.resolved',
113
148
  },
114
- { actions: ['setRemoteError', 'sendUpdate'] },
149
+ {
150
+ actions: ['setRemoteError', 'sendUpdate'],
151
+ target: '#signUpActor.confirmSignUp',
152
+ },
115
153
  ],
116
154
  },
117
155
  },
@@ -149,7 +187,13 @@ function signUpActor({ services }) {
149
187
  idle: {
150
188
  entry: ['sendUpdate'],
151
189
  on: {
152
- SUBMIT: { actions: 'handleSubmit', target: 'validate' },
190
+ SUBMIT: {
191
+ actions: [
192
+ 'setSelectedAuthMethodFromForm',
193
+ 'handleSubmit',
194
+ ],
195
+ target: 'validate',
196
+ },
153
197
  },
154
198
  },
155
199
  validate: {
@@ -234,6 +278,13 @@ function signUpActor({ services }) {
234
278
  },
235
279
  },
236
280
  },
281
+ passkeyPrompt: {
282
+ entry: 'sendUpdate',
283
+ on: {
284
+ SKIP: { target: 'resolved' },
285
+ SUBMIT: { target: 'resolved' },
286
+ },
287
+ },
237
288
  resolved: {
238
289
  type: 'final',
239
290
  data: (context) => ({
@@ -271,9 +322,10 @@ function signUpActor({ services }) {
271
322
  return signInWithRedirect(data);
272
323
  },
273
324
  handleSignUp(context) {
274
- const { formValues, loginMechanisms, username } = context;
325
+ const { formValues, loginMechanisms, username, selectedAuthMethod, preferredChallenge, } = context;
275
326
  const loginMechanism = loginMechanisms[0];
276
- const input = getSignUpInput(username, formValues, loginMechanism);
327
+ const authMethod = selectedAuthMethod ?? preferredChallenge;
328
+ const input = getSignUpInput(username, formValues, loginMechanism, authMethod);
277
329
  return services.handleSignUp(input);
278
330
  },
279
331
  async validateSignUp(context) {
@@ -284,6 +336,8 @@ function signUpActor({ services }) {
284
336
  // Validation for default form fields
285
337
  services.validateConfirmPassword,
286
338
  services.validatePreferredUsername,
339
+ // Validation for required fields based on auth method
340
+ services.validateRequiredFieldsForAuthMethod,
287
341
  // Validation for any custom Sign Up fields
288
342
  services.validateCustomSignUp,
289
343
  ]);
@@ -40,11 +40,24 @@ const defaultServices = {
40
40
  const parsedSocialProviders = loginWith?.oauth?.providers
41
41
  ? loginWith.oauth.providers?.map((provider) => provider.toString().toLowerCase())
42
42
  : undefined;
43
+ // Detect passwordless capabilities from amplify_outputs.json
44
+ // Support both snake_case (legacy) and camelCase (current) formats
45
+ const passwordlessConfig = result.Auth?.Cognito?.passwordless;
46
+ const passwordlessCapabilities = {
47
+ emailOtpEnabled: passwordlessConfig?.emailOtpEnabled ??
48
+ passwordlessConfig?.email_otp_enabled === true,
49
+ smsOtpEnabled: passwordlessConfig?.smsOtpEnabled ??
50
+ passwordlessConfig?.sms_otp_enabled === true,
51
+ webAuthnEnabled: !!(passwordlessConfig?.webAuthn ?? passwordlessConfig?.web_authn),
52
+ preferredChallenge: passwordlessConfig?.preferredChallenge ??
53
+ passwordlessConfig?.preferred_challenge,
54
+ };
43
55
  return {
44
56
  ...cliConfig,
45
57
  loginMechanisms: parsedLoginMechanisms,
46
58
  signUpAttributes: parsedSignupAttributes,
47
59
  socialProviders: parsedSocialProviders,
60
+ passwordlessCapabilities,
48
61
  };
49
62
  },
50
63
  getCurrentUser,
@@ -107,6 +120,30 @@ const defaultServices = {
107
120
  }
108
121
  },
109
122
  async validatePreferredUsername(_, __) { },
123
+ async validateRequiredFieldsForAuthMethod(formData) {
124
+ const authMethod = formData.__authMethod;
125
+ // If no auth method specified, skip validation (will use default required fields)
126
+ if (!authMethod)
127
+ return null;
128
+ // Check required fields based on auth method
129
+ if (authMethod === 'EMAIL_OTP' && !formData.email) {
130
+ return { email: 'Email is required for Email OTP sign up' };
131
+ }
132
+ if (authMethod === 'SMS_OTP' && !formData.phone_number) {
133
+ return { phone_number: 'Phone number is required for SMS OTP sign up' };
134
+ }
135
+ if (authMethod === 'PASSWORD') {
136
+ const errors = {};
137
+ if (!formData.password) {
138
+ errors.password = 'Password is required';
139
+ }
140
+ if (!formData.confirm_password) {
141
+ errors.confirm_password = 'Confirm Password is required';
142
+ }
143
+ return Object.keys(errors).length > 0 ? errors : null;
144
+ }
145
+ return null;
146
+ },
110
147
  };
111
148
 
112
149
  export { defaultServices };
@@ -30,7 +30,11 @@ const shouldResetPassword = ({ step }) => step === 'RESET_PASSWORD';
30
30
  const shouldConfirmResetPassword = ({ step }) => step === 'CONFIRM_RESET_PASSWORD_WITH_CODE';
31
31
  const shouldConfirmSignUp = ({ step }) => step === 'CONFIRM_SIGN_UP';
32
32
  // miscellaneous guards
33
- const shouldVerifyAttribute = (_, { data }) => {
33
+ const shouldVerifyAttribute = (context, event) => {
34
+ // Try to get data from event first (for backward compatibility), then from context
35
+ const data = (event.data || context.fetchedUserAttributes);
36
+ if (!data)
37
+ return false;
34
38
  const { email, phone_number, phone_number_verified, email_verified } = data;
35
39
  // if neither email nor phone_number exist
36
40
  // there is nothing to verify
@@ -55,11 +59,51 @@ const shouldVerifyAttribute = (_, { data }) => {
55
59
  * https://github.com/aws-amplify/amplify-ui/issues/219
56
60
  */
57
61
  const isUserAlreadyConfirmed = (_, { data }) => data.message === 'User is already confirmed.';
62
+ // passwordless guards
63
+ const shouldSelectAuthMethod = ({ availableAuthMethods, preferredChallenge, selectedAuthMethod, }) => {
64
+ // Show selection if:
65
+ // 1. Multiple methods available
66
+ // 2. AND either no preferredChallenge OR selectedAuthMethod is explicitly cleared (null)
67
+ const hasMultipleMethods = availableAuthMethods && availableAuthMethods.length > 1;
68
+ const shouldShowSelection = !preferredChallenge || selectedAuthMethod === null;
69
+ return hasMultipleMethods && shouldShowSelection;
70
+ };
71
+ const shouldPromptPasskeyRegistration = ({ passwordless, hasExistingPasskeys, }) => {
72
+ const { passkeyRegistrationPrompts } = passwordless || {};
73
+ if (!passkeyRegistrationPrompts) {
74
+ return false;
75
+ }
76
+ // Don't prompt if user already has passkeys
77
+ if (hasExistingPasskeys) {
78
+ return false;
79
+ }
80
+ if (typeof passkeyRegistrationPrompts === 'boolean') {
81
+ return passkeyRegistrationPrompts;
82
+ }
83
+ return passkeyRegistrationPrompts.afterSignin === 'ALWAYS';
84
+ };
85
+ const shouldPromptPasskeyRegistrationAfterSignup = ({ passwordless, hasExistingPasskeys, }) => {
86
+ const { passkeyRegistrationPrompts } = passwordless || {};
87
+ if (!passkeyRegistrationPrompts) {
88
+ return false;
89
+ }
90
+ // Don't prompt if user already has passkeys
91
+ if (hasExistingPasskeys) {
92
+ return false;
93
+ }
94
+ if (typeof passkeyRegistrationPrompts === 'boolean') {
95
+ return passkeyRegistrationPrompts;
96
+ }
97
+ return passkeyRegistrationPrompts.afterSignup === 'ALWAYS';
98
+ };
99
+ const hasPasskeyRegistrationPrompts = ({ passwordless }) => passwordless?.passkeyRegistrationPrompts != null;
100
+ const shouldReturnToSelectMethod = ({ selectedAuthMethod, step, }) => selectedAuthMethod != null && step === 'SELECT_AUTH_METHOD';
58
101
  const GUARDS = {
59
102
  hasCompletedAttributeConfirmation,
60
103
  hasCompletedResetPassword,
61
104
  hasCompletedSignIn,
62
105
  hasCompletedSignUp,
106
+ hasPasskeyRegistrationPrompts,
63
107
  isConfirmSignUpStep,
64
108
  isConfirmUserAttributeStep,
65
109
  isResetPasswordStep,
@@ -73,10 +117,14 @@ const GUARDS = {
73
117
  shouldConfirmSignUpFromSignIn,
74
118
  shouldResetPassword,
75
119
  shouldResetPasswordFromSignIn,
120
+ shouldReturnToSelectMethod,
121
+ shouldSelectAuthMethod,
76
122
  shouldSetupTotp,
77
123
  shouldSetupEmail,
78
124
  shouldSelectMfaType,
79
125
  shouldVerifyAttribute,
126
+ shouldPromptPasskeyRegistration,
127
+ shouldPromptPasskeyRegistrationAfterSignup,
80
128
  };
81
129
 
82
130
  export { GUARDS as default };