@aws-amplify/ui-react-core 3.3.5 → 3.4.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 (24) hide show
  1. package/dist/esm/Authenticator/hooks/constants.mjs +4 -0
  2. package/dist/esm/Authenticator/hooks/useAuthenticator/useAuthenticator.mjs +2 -3
  3. package/dist/esm/Authenticator/hooks/useAuthenticator/utils.mjs +18 -6
  4. package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/constants.mjs +11 -0
  5. package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.mjs +8 -2
  6. package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/utils.mjs +19 -1
  7. package/dist/index.js +59 -9
  8. package/dist/types/Authenticator/hooks/types.d.ts +10 -1
  9. package/dist/types/Authenticator/hooks/useAuthenticator/types.d.ts +1 -1
  10. package/dist/types/Authenticator/hooks/useAuthenticator/utils.d.ts +2 -2
  11. package/dist/types/Authenticator/hooks/useAuthenticatorRoute/types.d.ts +3 -1
  12. package/dist/types/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.d.ts +2 -0
  13. package/dist/types/Authenticator/hooks/useAuthenticatorRoute/utils.d.ts +2 -0
  14. package/package.json +3 -3
  15. package/src/Authenticator/hooks/constants.ts +4 -0
  16. package/src/Authenticator/hooks/types.ts +17 -0
  17. package/src/Authenticator/hooks/useAuthenticator/__mock__/useAuthenticator.ts +5 -1
  18. package/src/Authenticator/hooks/useAuthenticator/types.ts +2 -0
  19. package/src/Authenticator/hooks/useAuthenticator/useAuthenticator.ts +2 -8
  20. package/src/Authenticator/hooks/useAuthenticator/utils.ts +26 -6
  21. package/src/Authenticator/hooks/useAuthenticatorRoute/constants.ts +16 -0
  22. package/src/Authenticator/hooks/useAuthenticatorRoute/types.ts +10 -0
  23. package/src/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.ts +16 -0
  24. package/src/Authenticator/hooks/useAuthenticatorRoute/utils.ts +26 -0
@@ -5,6 +5,8 @@ const COMPONENT_ROUTE_KEYS = [
5
5
  'confirmVerifyUser',
6
6
  'forceNewPassword',
7
7
  'forgotPassword',
8
+ 'selectMfaType',
9
+ 'setupEmail',
8
10
  'setupTotp',
9
11
  'signIn',
10
12
  'signUp',
@@ -17,6 +19,8 @@ const COMPONENT_ROUTE_NAMES = [
17
19
  'ConfirmVerifyUser',
18
20
  'ForceNewPassword',
19
21
  'ForgotPassword',
22
+ 'SelectMfaType',
23
+ 'SetupEmail',
20
24
  'SetupTotp',
21
25
  'SignIn',
22
26
  'SignUp',
@@ -22,20 +22,19 @@ function useAuthenticator(selector) {
22
22
  // not update on external sign in events (for example when a user is not using the `Authenticator`).
23
23
  const { authStatus } = context;
24
24
  const facade = useSelector(service, xstateSelector, comparator);
25
- const { route, totpSecretCode, unverifiedUserAttributes, user, ...rest } = facade;
25
+ const { route, totpSecretCode, user, ...rest } = facade;
26
26
  // do not memoize output. `service.getSnapshot` reference remains stable preventing
27
27
  // `fields` from updating with current form state on value changes
28
28
  const serviceSnapshot = service.getSnapshot();
29
29
  // legacy `QRFields` values only used for SetupTotp page to retrieve issuer information, will be removed in future
30
30
  const QRFields = route === 'setupTotp' ? getQRFields(serviceSnapshot) : null;
31
31
  // legacy `formFields` values required until form state is removed from state machine
32
- const fields = getMachineFields(route, serviceSnapshot, unverifiedUserAttributes);
32
+ const fields = getMachineFields(route, serviceSnapshot);
33
33
  return {
34
34
  ...rest,
35
35
  authStatus,
36
36
  route,
37
37
  totpSecretCode,
38
- unverifiedUserAttributes,
39
38
  user,
40
39
  /** @deprecated For internal use only */
41
40
  fields,
@@ -1,4 +1,4 @@
1
- import { getActorContext, getSortedFormFields, isString, areEmptyArrays, areEmptyObjects } from '@aws-amplify/ui';
1
+ import { getActorContext, getSortedFormFields, isString, authenticatorTextUtil, areEmptyArrays, areEmptyObjects } from '@aws-amplify/ui';
2
2
  import { isComponentRouteKey } from '../utils.mjs';
3
3
 
4
4
  const defaultComparator = () => false;
@@ -29,7 +29,7 @@ const getQRFields = (state) => ({
29
29
  ...getActorContext(state)?.formFields?.setupTotp?.QR,
30
30
  });
31
31
  const flattenFormFields = (fields) => fields.flatMap(([name, options]) => ({ name, ...options }));
32
- const convertContactMethodsToFields = (unverifiedUserAttributes) => {
32
+ const convertContactMethodsToFields = (unverifiedUserAttributes = {}) => {
33
33
  return (unverifiedUserAttributes &&
34
34
  Object.entries(unverifiedUserAttributes).map(([name, value]) => {
35
35
  const valueIsString = isString(value);
@@ -39,15 +39,27 @@ const convertContactMethodsToFields = (unverifiedUserAttributes) => {
39
39
  return { name, label: value, type: 'radio', value };
40
40
  }));
41
41
  };
42
+ const convertAllowedMfaTypesToFields = (allowedMfaTypes = []) => {
43
+ return allowedMfaTypes.map((mfaType) => ({
44
+ name: 'mfa_type',
45
+ label: authenticatorTextUtil.getMfaTypeLabelByValue(mfaType),
46
+ type: 'radio',
47
+ value: mfaType,
48
+ }));
49
+ };
42
50
  /**
43
51
  * Retrieves default and custom (RWA only, to be updated) form field values from state machine
44
52
  * for subcomponent routes that render fields
45
53
  */
46
- const getMachineFields = (route, state, unverifiedUserAttributes) => {
54
+ const getMachineFields = (route, state) => {
47
55
  if (isComponentRouteKey(route)) {
48
- return route === 'verifyUser'
49
- ? convertContactMethodsToFields(unverifiedUserAttributes)
50
- : flattenFormFields(getSortedFormFields(route, state));
56
+ if (route === 'verifyUser') {
57
+ return convertContactMethodsToFields(getActorContext(state).unverifiedUserAttributes);
58
+ }
59
+ if (route === 'selectMfaType') {
60
+ return convertAllowedMfaTypesToFields(getActorContext(state).allowedMfaTypes);
61
+ }
62
+ return flattenFormFields(getSortedFormFields(route, state));
51
63
  }
52
64
  return [];
53
65
  };
@@ -61,6 +61,15 @@ const SETUP_TOTP_MACHINE_KEYS = [
61
61
  'totpSecretCode',
62
62
  'username',
63
63
  ];
64
+ const SETUP_EMAIL_MACHINE_KEY = [
65
+ ...COMMON_ROUTE_MACHINE_KEYS,
66
+ 'toSignIn',
67
+ ];
68
+ const SELECT_MFA_MACHINE_KEYS = [
69
+ ...COMMON_ROUTE_MACHINE_KEYS,
70
+ 'challengeName',
71
+ 'toSignIn',
72
+ ];
64
73
  const VERIFY_USER_MACHINE_KEYS = [
65
74
  ...COMMON_ROUTE_MACHINE_KEYS,
66
75
  'skipVerification',
@@ -74,6 +83,8 @@ const MACHINE_PROP_KEYS = {
74
83
  signIn: SIGN_IN_MACHINE_KEYS,
75
84
  signUp: SIGN_UP_MACHINE_KEYS,
76
85
  forgotPassword: RESET_PASSWORD_MACHINE_KEYS,
86
+ selectMfaType: SELECT_MFA_MACHINE_KEYS,
87
+ setupEmail: SETUP_EMAIL_MACHINE_KEY,
77
88
  setupTotp: SETUP_TOTP_MACHINE_KEYS,
78
89
  verifyUser: VERIFY_USER_MACHINE_KEYS,
79
90
  };
@@ -1,6 +1,6 @@
1
1
  import { useMemo } from 'react';
2
2
  import useAuthenticator from '../useAuthenticator/useAuthenticator.mjs';
3
- import { getRouteMachineSelector, resolveDefault, resolveVerifyUserRoute, resolveSignUpRoute, resolveSignInRoute, resolveSetupTotpRoute, resolveForgotPasswordRoute, resolveForceNewPasswordRoute, resolveConfirmVerifyUserRoute, resolveConfirmSignUpRoute, resolveConfirmSignInRoute, resolveConfirmResetPasswordRoute, routeSelector } from './utils.mjs';
3
+ import { getRouteMachineSelector, resolveDefault, resolveVerifyUserRoute, resolveSignUpRoute, resolveSignInRoute, resolveSetupTotpRoute, resolveSetupEmailRoute, resolveSelectMfaTypeRoute, resolveForgotPasswordRoute, resolveForceNewPasswordRoute, resolveConfirmVerifyUserRoute, resolveConfirmSignUpRoute, resolveConfirmSignInRoute, resolveConfirmResetPasswordRoute, routeSelector } from './utils.mjs';
4
4
 
5
5
  function useAuthenticatorRoute({ components, }) {
6
6
  const { route } = useAuthenticator(routeSelector);
@@ -11,7 +11,7 @@ function useAuthenticatorRoute({ components, }) {
11
11
  // Only state machine props specified by the current `routeSelector` will have their current value
12
12
  // returned by `useAuthenticator`, non-machine props returned will always be the current value
13
13
  const routeSelectorProps = useAuthenticator(routeMachineSelector);
14
- const { ConfirmResetPassword, ConfirmSignIn, ConfirmSignUp, ConfirmVerifyUser, ForceNewPassword, ForgotPassword, SetupTotp, SignIn, SignUp, VerifyUser, } = components;
14
+ const { ConfirmResetPassword, ConfirmSignIn, ConfirmSignUp, ConfirmVerifyUser, ForceNewPassword, ForgotPassword, SelectMfaType, SetupEmail, SetupTotp, SignIn, SignUp, VerifyUser, } = components;
15
15
  switch (route) {
16
16
  case 'confirmResetPassword': {
17
17
  return resolveConfirmResetPasswordRoute(ConfirmResetPassword, routeSelectorProps);
@@ -31,6 +31,12 @@ function useAuthenticatorRoute({ components, }) {
31
31
  case 'forgotPassword': {
32
32
  return resolveForgotPasswordRoute(ForgotPassword, routeSelectorProps);
33
33
  }
34
+ case 'selectMfaType': {
35
+ return resolveSelectMfaTypeRoute(SelectMfaType, routeSelectorProps);
36
+ }
37
+ case 'setupEmail': {
38
+ return resolveSetupEmailRoute(SetupEmail, routeSelectorProps);
39
+ }
34
40
  case 'setupTotp': {
35
41
  return resolveSetupTotpRoute(SetupTotp, routeSelectorProps);
36
42
  }
@@ -80,6 +80,24 @@ function resolveSetupTotpRoute(Component, props) {
80
80
  },
81
81
  };
82
82
  }
83
+ function resolveSetupEmailRoute(Component, props) {
84
+ return {
85
+ Component,
86
+ props: {
87
+ ...Component,
88
+ ...getConvertedMachineProps('setupEmail', props),
89
+ },
90
+ };
91
+ }
92
+ function resolveSelectMfaTypeRoute(Component, props) {
93
+ return {
94
+ Component,
95
+ props: {
96
+ ...Component,
97
+ ...getConvertedMachineProps('selectMfaType', props),
98
+ },
99
+ };
100
+ }
83
101
  function resolveSignInRoute(Component, props) {
84
102
  // default `hideSignUp` to false
85
103
  const hideSignUp = false;
@@ -114,4 +132,4 @@ function resolveDefault() {
114
132
  };
115
133
  }
116
134
 
117
- export { getRouteMachineSelector, resolveConfirmResetPasswordRoute, resolveConfirmSignInRoute, resolveConfirmSignUpRoute, resolveConfirmVerifyUserRoute, resolveDefault, resolveForceNewPasswordRoute, resolveForgotPasswordRoute, resolveSetupTotpRoute, resolveSignInRoute, resolveSignUpRoute, resolveVerifyUserRoute, routeSelector };
135
+ export { getRouteMachineSelector, resolveConfirmResetPasswordRoute, resolveConfirmSignInRoute, resolveConfirmSignUpRoute, resolveConfirmVerifyUserRoute, resolveDefault, resolveForceNewPasswordRoute, resolveForgotPasswordRoute, resolveSelectMfaTypeRoute, resolveSetupEmailRoute, resolveSetupTotpRoute, resolveSignInRoute, resolveSignUpRoute, resolveVerifyUserRoute, routeSelector };
package/dist/index.js CHANGED
@@ -88,6 +88,8 @@ const COMPONENT_ROUTE_KEYS = [
88
88
  'confirmVerifyUser',
89
89
  'forceNewPassword',
90
90
  'forgotPassword',
91
+ 'selectMfaType',
92
+ 'setupEmail',
91
93
  'setupTotp',
92
94
  'signIn',
93
95
  'signUp',
@@ -100,6 +102,8 @@ const COMPONENT_ROUTE_NAMES = [
100
102
  'ConfirmVerifyUser',
101
103
  'ForceNewPassword',
102
104
  'ForgotPassword',
105
+ 'SelectMfaType',
106
+ 'SetupEmail',
103
107
  'SetupTotp',
104
108
  'SignIn',
105
109
  'SignUp',
@@ -155,7 +159,7 @@ const getQRFields = (state) => ({
155
159
  ...ui.getActorContext(state)?.formFields?.setupTotp?.QR,
156
160
  });
157
161
  const flattenFormFields = (fields) => fields.flatMap(([name, options]) => ({ name, ...options }));
158
- const convertContactMethodsToFields = (unverifiedUserAttributes) => {
162
+ const convertContactMethodsToFields = (unverifiedUserAttributes = {}) => {
159
163
  return (unverifiedUserAttributes &&
160
164
  Object.entries(unverifiedUserAttributes).map(([name, value]) => {
161
165
  const valueIsString = ui.isString(value);
@@ -165,15 +169,27 @@ const convertContactMethodsToFields = (unverifiedUserAttributes) => {
165
169
  return { name, label: value, type: 'radio', value };
166
170
  }));
167
171
  };
172
+ const convertAllowedMfaTypesToFields = (allowedMfaTypes = []) => {
173
+ return allowedMfaTypes.map((mfaType) => ({
174
+ name: 'mfa_type',
175
+ label: ui.authenticatorTextUtil.getMfaTypeLabelByValue(mfaType),
176
+ type: 'radio',
177
+ value: mfaType,
178
+ }));
179
+ };
168
180
  /**
169
181
  * Retrieves default and custom (RWA only, to be updated) form field values from state machine
170
182
  * for subcomponent routes that render fields
171
183
  */
172
- const getMachineFields = (route, state, unverifiedUserAttributes) => {
184
+ const getMachineFields = (route, state) => {
173
185
  if (isComponentRouteKey(route)) {
174
- return route === 'verifyUser'
175
- ? convertContactMethodsToFields(unverifiedUserAttributes)
176
- : flattenFormFields(ui.getSortedFormFields(route, state));
186
+ if (route === 'verifyUser') {
187
+ return convertContactMethodsToFields(ui.getActorContext(state).unverifiedUserAttributes);
188
+ }
189
+ if (route === 'selectMfaType') {
190
+ return convertAllowedMfaTypesToFields(ui.getActorContext(state).allowedMfaTypes);
191
+ }
192
+ return flattenFormFields(ui.getSortedFormFields(route, state));
177
193
  }
178
194
  return [];
179
195
  };
@@ -194,20 +210,19 @@ function useAuthenticator(selector) {
194
210
  // not update on external sign in events (for example when a user is not using the `Authenticator`).
195
211
  const { authStatus } = context;
196
212
  const facade = react.useSelector(service, xstateSelector, comparator);
197
- const { route, totpSecretCode, unverifiedUserAttributes, user, ...rest } = facade;
213
+ const { route, totpSecretCode, user, ...rest } = facade;
198
214
  // do not memoize output. `service.getSnapshot` reference remains stable preventing
199
215
  // `fields` from updating with current form state on value changes
200
216
  const serviceSnapshot = service.getSnapshot();
201
217
  // legacy `QRFields` values only used for SetupTotp page to retrieve issuer information, will be removed in future
202
218
  const QRFields = route === 'setupTotp' ? getQRFields(serviceSnapshot) : null;
203
219
  // legacy `formFields` values required until form state is removed from state machine
204
- const fields = getMachineFields(route, serviceSnapshot, unverifiedUserAttributes);
220
+ const fields = getMachineFields(route, serviceSnapshot);
205
221
  return {
206
222
  ...rest,
207
223
  authStatus,
208
224
  route,
209
225
  totpSecretCode,
210
- unverifiedUserAttributes,
211
226
  user,
212
227
  /** @deprecated For internal use only */
213
228
  fields,
@@ -370,6 +385,15 @@ const SETUP_TOTP_MACHINE_KEYS = [
370
385
  'totpSecretCode',
371
386
  'username',
372
387
  ];
388
+ const SETUP_EMAIL_MACHINE_KEY = [
389
+ ...COMMON_ROUTE_MACHINE_KEYS,
390
+ 'toSignIn',
391
+ ];
392
+ const SELECT_MFA_MACHINE_KEYS = [
393
+ ...COMMON_ROUTE_MACHINE_KEYS,
394
+ 'challengeName',
395
+ 'toSignIn',
396
+ ];
373
397
  const VERIFY_USER_MACHINE_KEYS = [
374
398
  ...COMMON_ROUTE_MACHINE_KEYS,
375
399
  'skipVerification',
@@ -383,6 +407,8 @@ const MACHINE_PROP_KEYS = {
383
407
  signIn: SIGN_IN_MACHINE_KEYS,
384
408
  signUp: SIGN_UP_MACHINE_KEYS,
385
409
  forgotPassword: RESET_PASSWORD_MACHINE_KEYS,
410
+ selectMfaType: SELECT_MFA_MACHINE_KEYS,
411
+ setupEmail: SETUP_EMAIL_MACHINE_KEY,
386
412
  setupTotp: SETUP_TOTP_MACHINE_KEYS,
387
413
  verifyUser: VERIFY_USER_MACHINE_KEYS,
388
414
  };
@@ -461,6 +487,24 @@ function resolveSetupTotpRoute(Component, props) {
461
487
  },
462
488
  };
463
489
  }
490
+ function resolveSetupEmailRoute(Component, props) {
491
+ return {
492
+ Component,
493
+ props: {
494
+ ...Component,
495
+ ...getConvertedMachineProps('setupEmail', props),
496
+ },
497
+ };
498
+ }
499
+ function resolveSelectMfaTypeRoute(Component, props) {
500
+ return {
501
+ Component,
502
+ props: {
503
+ ...Component,
504
+ ...getConvertedMachineProps('selectMfaType', props),
505
+ },
506
+ };
507
+ }
464
508
  function resolveSignInRoute(Component, props) {
465
509
  // default `hideSignUp` to false
466
510
  const hideSignUp = false;
@@ -504,7 +548,7 @@ function useAuthenticatorRoute({ components, }) {
504
548
  // Only state machine props specified by the current `routeSelector` will have their current value
505
549
  // returned by `useAuthenticator`, non-machine props returned will always be the current value
506
550
  const routeSelectorProps = useAuthenticator(routeMachineSelector);
507
- const { ConfirmResetPassword, ConfirmSignIn, ConfirmSignUp, ConfirmVerifyUser, ForceNewPassword, ForgotPassword, SetupTotp, SignIn, SignUp, VerifyUser, } = components;
551
+ const { ConfirmResetPassword, ConfirmSignIn, ConfirmSignUp, ConfirmVerifyUser, ForceNewPassword, ForgotPassword, SelectMfaType, SetupEmail, SetupTotp, SignIn, SignUp, VerifyUser, } = components;
508
552
  switch (route) {
509
553
  case 'confirmResetPassword': {
510
554
  return resolveConfirmResetPasswordRoute(ConfirmResetPassword, routeSelectorProps);
@@ -524,6 +568,12 @@ function useAuthenticatorRoute({ components, }) {
524
568
  case 'forgotPassword': {
525
569
  return resolveForgotPasswordRoute(ForgotPassword, routeSelectorProps);
526
570
  }
571
+ case 'selectMfaType': {
572
+ return resolveSelectMfaTypeRoute(SelectMfaType, routeSelectorProps);
573
+ }
574
+ case 'setupEmail': {
575
+ return resolveSetupEmailRoute(SetupEmail, routeSelectorProps);
576
+ }
527
577
  case 'setupTotp': {
528
578
  return resolveSetupTotpRoute(SetupTotp, routeSelectorProps);
529
579
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { ChallengeName, AuthenticatorServiceFacade, LegacyFormFieldOptions } from '@aws-amplify/ui';
3
3
  import { UseAuthenticator } from './useAuthenticator';
4
- export type AuthenticatorRouteComponentKey = 'confirmResetPassword' | 'confirmSignIn' | 'confirmSignUp' | 'confirmVerifyUser' | 'forceNewPassword' | 'forgotPassword' | 'setupTotp' | 'signIn' | 'signUp' | 'verifyUser';
4
+ export type AuthenticatorRouteComponentKey = 'confirmResetPassword' | 'confirmSignIn' | 'confirmSignUp' | 'confirmVerifyUser' | 'forceNewPassword' | 'forgotPassword' | 'selectMfaType' | 'setupEmail' | 'setupTotp' | 'signIn' | 'signUp' | 'verifyUser';
5
5
  export type AuthenticatorLegacyField = LegacyFormFieldOptions;
6
6
  export type AuthenticatorLegacyFields = AuthenticatorLegacyField[];
7
7
  /**
@@ -73,6 +73,13 @@ export type SetupTotpBaseProps<FieldType = {}> = {
73
73
  totpSecretCode: UseAuthenticator['totpSecretCode'];
74
74
  username: UseAuthenticator['username'];
75
75
  } & CommonRouteProps & ComponentSlots<FieldType> & ValidationProps;
76
+ export type SetupEmailBaseProps<FieldType = {}> = {
77
+ toSignIn: UseAuthenticator['toSignIn'];
78
+ } & CommonRouteProps & ComponentSlots<FieldType> & ValidationProps;
79
+ export type SelectMfaTypeBaseProps<FieldType = {}> = {
80
+ challengeName: UseAuthenticator['challengeName'];
81
+ toSignIn: UseAuthenticator['toSignIn'];
82
+ } & CommonRouteProps & ComponentSlots<FieldType> & ValidationProps;
76
83
  export type SignInBaseProps<FieldType = {}> = {
77
84
  hideSignUp?: boolean;
78
85
  socialProviders?: UseAuthenticator['socialProviders'];
@@ -96,6 +103,8 @@ export interface DefaultProps<FieldType = {}> {
96
103
  ConfirmVerifyUser: ConfirmVerifyUserProps<FieldType>;
97
104
  ForceNewPassword: ForceResetPasswordBaseProps<FieldType>;
98
105
  ForgotPassword: ResetPasswordBaseProps<FieldType>;
106
+ SelectMfaType: SelectMfaTypeBaseProps<FieldType>;
107
+ SetupEmail: SetupEmailBaseProps<FieldType>;
99
108
  SetupTotp: SetupTotpBaseProps<FieldType>;
100
109
  SignIn: SignInBaseProps<FieldType>;
101
110
  SignUp: SignUpBaseProps<FieldType>;
@@ -5,7 +5,7 @@ import { AuthenticatorServiceFacade, LegacyFormFieldOptions } from '@aws-amplify
5
5
  */
6
6
  type AuthenticatorMachineContext = AuthenticatorServiceFacade;
7
7
  type AuthenticatorMachineContextKey = keyof AuthenticatorMachineContext;
8
- export type AuthenticatorRouteComponentKey = 'signIn' | 'signUp' | 'forceNewPassword' | 'confirmResetPassword' | 'confirmSignIn' | 'confirmSignUp' | 'confirmVerifyUser' | 'forgotPassword' | 'setupTotp' | 'verifyUser';
8
+ export type AuthenticatorRouteComponentKey = 'signIn' | 'signUp' | 'forceNewPassword' | 'confirmResetPassword' | 'confirmSignIn' | 'confirmSignUp' | 'confirmVerifyUser' | 'forgotPassword' | 'selectMfaType' | 'setupEmail' | 'setupTotp' | 'verifyUser';
9
9
  export type AuthenticatorLegacyFields = LegacyFormFieldOptions[];
10
10
  /**
11
11
  * Inspired from https://xstate.js.org/docs/packages/xstate-react/#useselector-actor-selector-compare-getsnapshot.
@@ -1,4 +1,4 @@
1
- import { AuthenticatorRoute, AuthMachineState, UnverifiedUserAttributes } from '@aws-amplify/ui';
1
+ import { AuthenticatorRoute, AuthMachineState } from '@aws-amplify/ui';
2
2
  import { AuthenticatorLegacyFields } from '../types';
3
3
  import { Comparator, UseAuthenticatorSelector } from './types';
4
4
  export declare const defaultComparator: () => false;
@@ -16,4 +16,4 @@ export declare const getQRFields: (state: AuthMachineState) => {
16
16
  * Retrieves default and custom (RWA only, to be updated) form field values from state machine
17
17
  * for subcomponent routes that render fields
18
18
  */
19
- export declare const getMachineFields: (route: AuthenticatorRoute, state: AuthMachineState, unverifiedUserAttributes: UnverifiedUserAttributes) => AuthenticatorLegacyFields;
19
+ export declare const getMachineFields: (route: AuthenticatorRoute, state: AuthMachineState) => AuthenticatorLegacyFields;
@@ -1,4 +1,4 @@
1
- import { AuthenticatorMachineContext, AuthenticatorMachineContextKey, AuthenticatorRouteComponentName, CommonRouteProps, ConfirmResetPasswordBaseProps, ConfirmSignInBaseProps, ConfirmSignUpBaseProps, Defaults, DefaultProps, ForceResetPasswordBaseProps, ResetPasswordBaseProps, SetupTotpBaseProps, SignInBaseProps, SignUpBaseProps, VerifyUserProps, ConfirmVerifyUserProps } from '../types';
1
+ import { AuthenticatorMachineContext, AuthenticatorMachineContextKey, AuthenticatorRouteComponentName, CommonRouteProps, ConfirmResetPasswordBaseProps, ConfirmSignInBaseProps, ConfirmSignUpBaseProps, Defaults, DefaultProps, ForceResetPasswordBaseProps, ResetPasswordBaseProps, SelectMfaTypeBaseProps, SetupEmailBaseProps, SetupTotpBaseProps, SignInBaseProps, SignUpBaseProps, VerifyUserProps, ConfirmVerifyUserProps } from '../types';
2
2
  export type UseAuthenticatorRouteParams<FieldType> = {
3
3
  components: Defaults<FieldType>;
4
4
  };
@@ -24,6 +24,8 @@ export type ConfirmVerifyUserMachineKey = ExtractMachineKey<ConfirmVerifyUserPro
24
24
  export type ForceNewPasswordMachineKey = ExtractMachineKey<ForceResetPasswordBaseProps> | CommonRouteMachineKey;
25
25
  export type ResetPasswordMachineKey = ExtractMachineKey<ResetPasswordBaseProps> | CommonRouteMachineKey;
26
26
  export type SetupTotpMachineKey = ExtractMachineKey<SetupTotpBaseProps> | CommonRouteMachineKey;
27
+ export type SetupEmailMachineKey = ExtractMachineKey<SetupEmailBaseProps> | CommonRouteMachineKey;
28
+ export type SelectMfaMachineKey = ExtractMachineKey<SelectMfaTypeBaseProps> | CommonRouteMachineKey;
27
29
  export type SignInMachineKey = ExtractMachineKey<SignInBaseProps> | CommonRouteMachineKey;
28
30
  export type SignUpMachineKey = ExtractMachineKey<SignUpBaseProps> | CommonRouteMachineKey;
29
31
  export type VerifyUserMachineKey = ExtractMachineKey<VerifyUserProps> | CommonRouteMachineKey;
@@ -6,6 +6,8 @@ export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticato
6
6
  export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'ForceNewPassword'>;
7
7
  export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'ForgotPassword'>;
8
8
  export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'SetupTotp'>;
9
+ export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'SetupEmail'>;
10
+ export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'SelectMfaType'>;
9
11
  export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'SignIn'>;
10
12
  export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'SignUp'>;
11
13
  export default function useAuthenticatorRoute<FieldType>(params: UseAuthenticatorRouteParams<FieldType>): UseAuthenticatorRoute<'VerifyUser'>;
@@ -11,6 +11,8 @@ export declare function resolveConfirmVerifyUserRoute<FieldType = {}>(Component:
11
11
  export declare function resolveForceNewPasswordRoute<FieldType = {}>(Component: Defaults<FieldType>['ForceNewPassword'], props: UseAuthenticator): UseAuthenticatorRoute<'ForceNewPassword', FieldType>;
12
12
  export declare function resolveForgotPasswordRoute<FieldType = {}>(Component: Defaults<FieldType>['ForgotPassword'], props: UseAuthenticator): UseAuthenticatorRoute<'ForgotPassword', FieldType>;
13
13
  export declare function resolveSetupTotpRoute<FieldType = {}>(Component: Defaults<FieldType>['SetupTotp'], props: UseAuthenticator): UseAuthenticatorRoute<'SetupTotp', FieldType>;
14
+ export declare function resolveSetupEmailRoute<FieldType = {}>(Component: Defaults<FieldType>['SetupEmail'], props: UseAuthenticator): UseAuthenticatorRoute<'SetupEmail', FieldType>;
15
+ export declare function resolveSelectMfaTypeRoute<FieldType = {}>(Component: Defaults<FieldType>['SelectMfaType'], props: UseAuthenticator): UseAuthenticatorRoute<'SelectMfaType', FieldType>;
14
16
  export declare function resolveSignInRoute<FieldType = {}>(Component: Defaults<FieldType>['SignIn'], props: UseAuthenticator): UseAuthenticatorRoute<'SignIn', FieldType>;
15
17
  export declare function resolveSignUpRoute<FieldType = {}>(Component: Defaults<FieldType>['SignUp'], props: UseAuthenticator): UseAuthenticatorRoute<'SignUp', FieldType>;
16
18
  export declare function resolveVerifyUserRoute<FieldType = {}>(Component: Defaults<FieldType>['VerifyUser'], props: UseAuthenticator): UseAuthenticatorRoute<'VerifyUser', FieldType>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-core",
3
- "version": "3.3.5",
3
+ "version": "3.4.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "react-native": "src/index.ts",
@@ -40,7 +40,7 @@
40
40
  "typecheck": "tsc --noEmit"
41
41
  },
42
42
  "dependencies": {
43
- "@aws-amplify/ui": "6.9.1",
43
+ "@aws-amplify/ui": "6.10.0",
44
44
  "@xstate/react": "^3.2.2",
45
45
  "lodash": "4.17.21",
46
46
  "react-hook-form": "^7.53.2",
@@ -51,4 +51,4 @@
51
51
  "react": "^16.14 || ^17 || ^18 || ^19"
52
52
  },
53
53
  "sideEffects": false
54
- }
54
+ }
@@ -10,6 +10,8 @@ export const COMPONENT_ROUTE_KEYS: AuthenticatorRouteComponentKey[] = [
10
10
  'confirmVerifyUser',
11
11
  'forceNewPassword',
12
12
  'forgotPassword',
13
+ 'selectMfaType',
14
+ 'setupEmail',
13
15
  'setupTotp',
14
16
  'signIn',
15
17
  'signUp',
@@ -23,6 +25,8 @@ export const COMPONENT_ROUTE_NAMES: AuthenticatorRouteComponentName[] = [
23
25
  'ConfirmVerifyUser',
24
26
  'ForceNewPassword',
25
27
  'ForgotPassword',
28
+ 'SelectMfaType',
29
+ 'SetupEmail',
26
30
  'SetupTotp',
27
31
  'SignIn',
28
32
  'SignUp',
@@ -15,6 +15,8 @@ export type AuthenticatorRouteComponentKey =
15
15
  | 'confirmVerifyUser'
16
16
  | 'forceNewPassword'
17
17
  | 'forgotPassword'
18
+ | 'selectMfaType'
19
+ | 'setupEmail'
18
20
  | 'setupTotp'
19
21
  | 'signIn'
20
22
  | 'signUp'
@@ -131,6 +133,19 @@ export type SetupTotpBaseProps<FieldType = {}> = {
131
133
  ComponentSlots<FieldType> &
132
134
  ValidationProps;
133
135
 
136
+ export type SetupEmailBaseProps<FieldType = {}> = {
137
+ toSignIn: UseAuthenticator['toSignIn'];
138
+ } & CommonRouteProps &
139
+ ComponentSlots<FieldType> &
140
+ ValidationProps;
141
+
142
+ export type SelectMfaTypeBaseProps<FieldType = {}> = {
143
+ challengeName: UseAuthenticator['challengeName'];
144
+ toSignIn: UseAuthenticator['toSignIn'];
145
+ } & CommonRouteProps &
146
+ ComponentSlots<FieldType> &
147
+ ValidationProps;
148
+
134
149
  export type SignInBaseProps<FieldType = {}> = {
135
150
  hideSignUp?: boolean;
136
151
  socialProviders?: UseAuthenticator['socialProviders'];
@@ -163,6 +178,8 @@ export interface DefaultProps<FieldType = {}> {
163
178
  ConfirmVerifyUser: ConfirmVerifyUserProps<FieldType>;
164
179
  ForceNewPassword: ForceResetPasswordBaseProps<FieldType>;
165
180
  ForgotPassword: ResetPasswordBaseProps<FieldType>;
181
+ SelectMfaType: SelectMfaTypeBaseProps<FieldType>;
182
+ SetupEmail: SetupEmailBaseProps<FieldType>;
166
183
  SetupTotp: SetupTotpBaseProps<FieldType>;
167
184
  SignIn: SignInBaseProps<FieldType>;
168
185
  SignUp: SignUpBaseProps<FieldType>;
@@ -4,6 +4,10 @@ import {
4
4
  } from '../../types';
5
5
  import { UseAuthenticator } from '../types';
6
6
 
7
+ const allowedMfaTypes = [
8
+ 'EMAIL',
9
+ 'TOTP',
10
+ ] as AuthenticatorMachineContext['allowedMfaTypes'];
7
11
  const authStatus = 'unauthenticated';
8
12
  const challengeName = 'CUSTOM_CHALLENGE';
9
13
  const codeDeliveryDetails =
@@ -32,6 +36,7 @@ const user = { username: 'username', userId: 'userId' };
32
36
  const validationErrors = {};
33
37
 
34
38
  export const mockMachineContext: AuthenticatorMachineContext = {
39
+ allowedMfaTypes,
35
40
  authStatus,
36
41
  challengeName,
37
42
  codeDeliveryDetails,
@@ -53,7 +58,6 @@ export const mockMachineContext: AuthenticatorMachineContext = {
53
58
  toFederatedSignIn,
54
59
  toForgotPassword,
55
60
  totpSecretCode,
56
-
57
61
  unverifiedUserAttributes,
58
62
  username: 'george',
59
63
  validationErrors,
@@ -19,6 +19,8 @@ export type AuthenticatorRouteComponentKey =
19
19
  | 'confirmSignUp'
20
20
  | 'confirmVerifyUser'
21
21
  | 'forgotPassword'
22
+ | 'selectMfaType'
23
+ | 'setupEmail'
22
24
  | 'setupTotp'
23
25
  | 'verifyUser';
24
26
 
@@ -41,8 +41,7 @@ export default function useAuthenticator(
41
41
  const { authStatus } = context;
42
42
  const facade = useSelector(service, xstateSelector, comparator);
43
43
 
44
- const { route, totpSecretCode, unverifiedUserAttributes, user, ...rest } =
45
- facade;
44
+ const { route, totpSecretCode, user, ...rest } = facade;
46
45
 
47
46
  // do not memoize output. `service.getSnapshot` reference remains stable preventing
48
47
  // `fields` from updating with current form state on value changes
@@ -52,18 +51,13 @@ export default function useAuthenticator(
52
51
  const QRFields = route === 'setupTotp' ? getQRFields(serviceSnapshot) : null;
53
52
 
54
53
  // legacy `formFields` values required until form state is removed from state machine
55
- const fields = getMachineFields(
56
- route,
57
- serviceSnapshot,
58
- unverifiedUserAttributes
59
- );
54
+ const fields = getMachineFields(route, serviceSnapshot);
60
55
 
61
56
  return {
62
57
  ...rest,
63
58
  authStatus,
64
59
  route,
65
60
  totpSecretCode,
66
- unverifiedUserAttributes,
67
61
  user,
68
62
  /** @deprecated For internal use only */
69
63
  fields,
@@ -8,6 +8,8 @@ import {
8
8
  UnverifiedUserAttributes,
9
9
  getActorContext,
10
10
  isString,
11
+ AuthMFAType,
12
+ authenticatorTextUtil,
11
13
  } from '@aws-amplify/ui';
12
14
 
13
15
  import { AuthenticatorLegacyField, AuthenticatorLegacyFields } from '../types';
@@ -64,7 +66,7 @@ const flattenFormFields = (
64
66
  fields.flatMap(([name, options]) => ({ name, ...options }));
65
67
 
66
68
  const convertContactMethodsToFields = (
67
- unverifiedUserAttributes: UnverifiedUserAttributes
69
+ unverifiedUserAttributes: UnverifiedUserAttributes = {}
68
70
  ): AuthenticatorLegacyFields => {
69
71
  return (
70
72
  unverifiedUserAttributes &&
@@ -78,19 +80,37 @@ const convertContactMethodsToFields = (
78
80
  );
79
81
  };
80
82
 
83
+ const convertAllowedMfaTypesToFields = (
84
+ allowedMfaTypes: AuthMFAType[] = []
85
+ ): AuthenticatorLegacyFields => {
86
+ return allowedMfaTypes.map((mfaType) => ({
87
+ name: 'mfa_type',
88
+ label: authenticatorTextUtil.getMfaTypeLabelByValue(mfaType),
89
+ type: 'radio',
90
+ value: mfaType,
91
+ }));
92
+ };
93
+
81
94
  /**
82
95
  * Retrieves default and custom (RWA only, to be updated) form field values from state machine
83
96
  * for subcomponent routes that render fields
84
97
  */
85
98
  export const getMachineFields = (
86
99
  route: AuthenticatorRoute,
87
- state: AuthMachineState,
88
- unverifiedUserAttributes: UnverifiedUserAttributes
100
+ state: AuthMachineState
89
101
  ): AuthenticatorLegacyFields => {
90
102
  if (isComponentRouteKey(route)) {
91
- return route === 'verifyUser'
92
- ? convertContactMethodsToFields(unverifiedUserAttributes)
93
- : flattenFormFields(getSortedFormFields(route, state));
103
+ if (route === 'verifyUser') {
104
+ return convertContactMethodsToFields(
105
+ getActorContext(state).unverifiedUserAttributes
106
+ );
107
+ }
108
+ if (route === 'selectMfaType') {
109
+ return convertAllowedMfaTypesToFields(
110
+ getActorContext(state).allowedMfaTypes
111
+ );
112
+ }
113
+ return flattenFormFields(getSortedFormFields(route, state));
94
114
  }
95
115
 
96
116
  return [];
@@ -14,6 +14,8 @@ import {
14
14
  ResetPasswordMachineKey,
15
15
  SignInMachineKey,
16
16
  SignUpMachineKey,
17
+ SelectMfaMachineKey,
18
+ SetupEmailMachineKey,
17
19
  SetupTotpMachineKey,
18
20
  VerifyUserMachineKey,
19
21
  } from './types';
@@ -86,6 +88,18 @@ const SETUP_TOTP_MACHINE_KEYS: SetupTotpMachineKey[] = [
86
88
  'totpSecretCode',
87
89
  'username',
88
90
  ];
91
+
92
+ const SETUP_EMAIL_MACHINE_KEY: SetupEmailMachineKey[] = [
93
+ ...COMMON_ROUTE_MACHINE_KEYS,
94
+ 'toSignIn',
95
+ ];
96
+
97
+ const SELECT_MFA_MACHINE_KEYS: SelectMfaMachineKey[] = [
98
+ ...COMMON_ROUTE_MACHINE_KEYS,
99
+ 'challengeName',
100
+ 'toSignIn',
101
+ ];
102
+
89
103
  const VERIFY_USER_MACHINE_KEYS: VerifyUserMachineKey[] = [
90
104
  ...COMMON_ROUTE_MACHINE_KEYS,
91
105
  'skipVerification',
@@ -103,6 +117,8 @@ export const MACHINE_PROP_KEYS: Record<
103
117
  signIn: SIGN_IN_MACHINE_KEYS,
104
118
  signUp: SIGN_UP_MACHINE_KEYS,
105
119
  forgotPassword: RESET_PASSWORD_MACHINE_KEYS,
120
+ selectMfaType: SELECT_MFA_MACHINE_KEYS,
121
+ setupEmail: SETUP_EMAIL_MACHINE_KEY,
106
122
  setupTotp: SETUP_TOTP_MACHINE_KEYS,
107
123
  verifyUser: VERIFY_USER_MACHINE_KEYS,
108
124
  };
@@ -10,6 +10,8 @@ import {
10
10
  DefaultProps,
11
11
  ForceResetPasswordBaseProps,
12
12
  ResetPasswordBaseProps,
13
+ SelectMfaTypeBaseProps,
14
+ SetupEmailBaseProps,
13
15
  SetupTotpBaseProps,
14
16
  SignInBaseProps,
15
17
  SignUpBaseProps,
@@ -86,6 +88,14 @@ export type SetupTotpMachineKey =
86
88
  | ExtractMachineKey<SetupTotpBaseProps>
87
89
  | CommonRouteMachineKey;
88
90
 
91
+ export type SetupEmailMachineKey =
92
+ | ExtractMachineKey<SetupEmailBaseProps>
93
+ | CommonRouteMachineKey;
94
+
95
+ export type SelectMfaMachineKey =
96
+ | ExtractMachineKey<SelectMfaTypeBaseProps>
97
+ | CommonRouteMachineKey;
98
+
89
99
  export type SignInMachineKey =
90
100
  | ExtractMachineKey<SignInBaseProps>
91
101
  | CommonRouteMachineKey;
@@ -16,6 +16,8 @@ import {
16
16
  resolveDefault,
17
17
  resolveForceNewPasswordRoute,
18
18
  resolveForgotPasswordRoute,
19
+ resolveSelectMfaTypeRoute,
20
+ resolveSetupEmailRoute,
19
21
  resolveSetupTotpRoute,
20
22
  resolveSignInRoute,
21
23
  resolveSignUpRoute,
@@ -43,6 +45,12 @@ export default function useAuthenticatorRoute<FieldType>(
43
45
  export default function useAuthenticatorRoute<FieldType>(
44
46
  params: UseAuthenticatorRouteParams<FieldType>
45
47
  ): UseAuthenticatorRoute<'SetupTotp'>;
48
+ export default function useAuthenticatorRoute<FieldType>(
49
+ params: UseAuthenticatorRouteParams<FieldType>
50
+ ): UseAuthenticatorRoute<'SetupEmail'>;
51
+ export default function useAuthenticatorRoute<FieldType>(
52
+ params: UseAuthenticatorRouteParams<FieldType>
53
+ ): UseAuthenticatorRoute<'SelectMfaType'>;
46
54
  export default function useAuthenticatorRoute<FieldType>(
47
55
  params: UseAuthenticatorRouteParams<FieldType>
48
56
  ): UseAuthenticatorRoute<'SignIn'>;
@@ -76,6 +84,8 @@ export default function useAuthenticatorRoute<FieldType>({
76
84
  ConfirmVerifyUser,
77
85
  ForceNewPassword,
78
86
  ForgotPassword,
87
+ SelectMfaType,
88
+ SetupEmail,
79
89
  SetupTotp,
80
90
  SignIn,
81
91
  SignUp,
@@ -107,6 +117,12 @@ export default function useAuthenticatorRoute<FieldType>({
107
117
  case 'forgotPassword': {
108
118
  return resolveForgotPasswordRoute(ForgotPassword, routeSelectorProps);
109
119
  }
120
+ case 'selectMfaType': {
121
+ return resolveSelectMfaTypeRoute(SelectMfaType, routeSelectorProps);
122
+ }
123
+ case 'setupEmail': {
124
+ return resolveSetupEmailRoute(SetupEmail, routeSelectorProps);
125
+ }
110
126
  case 'setupTotp': {
111
127
  return resolveSetupTotpRoute(SetupTotp, routeSelectorProps);
112
128
  }
@@ -154,6 +154,32 @@ export function resolveSetupTotpRoute<FieldType = {}>(
154
154
  };
155
155
  }
156
156
 
157
+ export function resolveSetupEmailRoute<FieldType = {}>(
158
+ Component: Defaults<FieldType>['SetupEmail'],
159
+ props: UseAuthenticator
160
+ ): UseAuthenticatorRoute<'SetupEmail', FieldType> {
161
+ return {
162
+ Component,
163
+ props: {
164
+ ...Component,
165
+ ...getConvertedMachineProps('setupEmail', props),
166
+ },
167
+ };
168
+ }
169
+
170
+ export function resolveSelectMfaTypeRoute<FieldType = {}>(
171
+ Component: Defaults<FieldType>['SelectMfaType'],
172
+ props: UseAuthenticator
173
+ ): UseAuthenticatorRoute<'SelectMfaType', FieldType> {
174
+ return {
175
+ Component,
176
+ props: {
177
+ ...Component,
178
+ ...getConvertedMachineProps('selectMfaType', props),
179
+ },
180
+ };
181
+ }
182
+
157
183
  export function resolveSignInRoute<FieldType = {}>(
158
184
  Component: Defaults<FieldType>['SignIn'],
159
185
  props: UseAuthenticator