@aws-amplify/ui 6.13.0 → 6.14.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/esm/helpers/authenticator/facade.mjs +9 -2
- package/dist/esm/helpers/authenticator/formFields/defaults.mjs +34 -8
- package/dist/esm/helpers/authenticator/getRoute.mjs +8 -0
- package/dist/esm/helpers/authenticator/textUtil.mjs +34 -0
- package/dist/esm/i18n/dictionaries/authenticator/defaultTexts.mjs +27 -0
- package/dist/esm/i18n/dictionaries/authenticator/es.mjs +1 -1
- package/dist/esm/i18n/dictionaries/authenticator/fr.mjs +1 -1
- package/dist/esm/machines/authenticator/actions.mjs +63 -4
- package/dist/esm/machines/authenticator/actors/signIn.mjs +199 -49
- package/dist/esm/machines/authenticator/actors/signUp.mjs +81 -27
- package/dist/esm/machines/authenticator/defaultServices.mjs +37 -0
- package/dist/esm/machines/authenticator/guards.mjs +49 -1
- package/dist/esm/machines/authenticator/index.mjs +29 -15
- package/dist/esm/machines/authenticator/utils.mjs +58 -6
- package/dist/index.js +625 -111
- package/dist/styles/authenticator.css +17 -0
- package/dist/styles/authenticator.layer.css +17 -0
- package/dist/styles.css +17 -0
- package/dist/styles.layer.css +17 -0
- package/dist/types/helpers/authenticator/facade.d.ts +6 -2
- package/dist/types/helpers/authenticator/textUtil.d.ts +24 -1
- package/dist/types/i18n/dictionaries/authenticator/defaultTexts.d.ts +27 -0
- package/dist/types/i18n/dictionaries/index.d.ts +27 -0
- package/dist/types/i18n/translations.d.ts +27 -0
- package/dist/types/machines/authenticator/defaultServices.d.ts +105 -0
- package/dist/types/machines/authenticator/types.d.ts +26 -2
- package/dist/types/machines/authenticator/utils.d.ts +14 -2
- package/package.json +5 -4
|
@@ -27,8 +27,10 @@ const getSendEventAliases = (send) => {
|
|
|
27
27
|
return {
|
|
28
28
|
initializeMachine: sendToMachine('INIT'),
|
|
29
29
|
resendCode: sendToMachine('RESEND'),
|
|
30
|
+
selectAuthMethod: sendToMachine('SELECT_METHOD'),
|
|
30
31
|
signOut: sendToMachine('SIGN_OUT'),
|
|
31
32
|
submitForm: sendToMachine('SUBMIT'),
|
|
33
|
+
toShowAuthMethods: sendToMachine('SHOW_AUTH_METHODS'),
|
|
32
34
|
updateForm: sendToMachine('CHANGE'),
|
|
33
35
|
updateBlur: sendToMachine('BLUR'),
|
|
34
36
|
// Actions that don't immediately invoke a service but instead transition to a screen
|
|
@@ -53,8 +55,9 @@ const getNextSendEventAliases = (send) => {
|
|
|
53
55
|
};
|
|
54
56
|
const getServiceContextFacade = (state) => {
|
|
55
57
|
const actorContext = (getActorContext(state) ?? {});
|
|
56
|
-
const { allowedMfaTypes, challengeName, codeDeliveryDetails, remoteError: error, validationError: validationErrors, totpSecretCode = null, unverifiedUserAttributes, username, } = actorContext;
|
|
57
|
-
const { socialProviders = [] } = state.context?.config ?? {};
|
|
58
|
+
const { allowedMfaTypes, availableAuthMethods, challengeName, codeDeliveryDetails, preferredChallenge, remoteError: error, selectedAuthMethod, validationError: validationErrors, totpSecretCode = null, unverifiedUserAttributes, username, } = actorContext;
|
|
59
|
+
const { socialProviders = [], loginMechanisms } = state.context?.config ?? {};
|
|
60
|
+
const loginMechanism = loginMechanisms?.[0];
|
|
58
61
|
// check for user in actorContext prior to state context. actorContext is more "up to date",
|
|
59
62
|
// but is not available on all states
|
|
60
63
|
const user = actorContext?.user ?? state.context?.user;
|
|
@@ -78,12 +81,16 @@ const getServiceContextFacade = (state) => {
|
|
|
78
81
|
const facade = {
|
|
79
82
|
allowedMfaTypes,
|
|
80
83
|
authStatus,
|
|
84
|
+
availableAuthMethods,
|
|
81
85
|
challengeName,
|
|
82
86
|
codeDeliveryDetails,
|
|
83
87
|
error,
|
|
84
88
|
hasValidationErrors,
|
|
85
89
|
isPending,
|
|
90
|
+
loginMechanism,
|
|
91
|
+
preferredChallenge,
|
|
86
92
|
route,
|
|
93
|
+
selectedAuthMethod,
|
|
87
94
|
socialProviders,
|
|
88
95
|
totpSecretCode,
|
|
89
96
|
unverifiedUserAttributes,
|
|
@@ -32,16 +32,32 @@ const getConfirmationCodeFormFields = (_) => ({
|
|
|
32
32
|
placeholder: 'Code',
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
|
-
const getSignInFormFields = (state) =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
const getSignInFormFields = (state) => {
|
|
36
|
+
const actorContext = state.context.actorRef?.getSnapshot()?.context;
|
|
37
|
+
const availableAuthMethods = actorContext?.availableAuthMethods;
|
|
38
|
+
const preferredChallenge = actorContext?.preferredChallenge;
|
|
39
|
+
const shouldShowPassword = !availableAuthMethods?.length ||
|
|
40
|
+
(availableAuthMethods.length === 1 &&
|
|
41
|
+
availableAuthMethods[0] === 'PASSWORD') ||
|
|
42
|
+
(availableAuthMethods.length > 1 &&
|
|
43
|
+
(!preferredChallenge || preferredChallenge === 'PASSWORD'));
|
|
44
|
+
const fields = {
|
|
45
|
+
username: { ...getAliasDefaultFormField(state) },
|
|
46
|
+
};
|
|
47
|
+
if (shouldShowPassword) {
|
|
48
|
+
fields.password = {
|
|
49
|
+
...getDefaultFormField('password'),
|
|
50
|
+
autocomplete: 'current-password',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return fields;
|
|
54
|
+
};
|
|
42
55
|
const getSignUpFormFields = (state) => {
|
|
43
56
|
const { loginMechanisms, signUpAttributes } = state.context.config;
|
|
44
57
|
const primaryAlias = getPrimaryAlias(state);
|
|
58
|
+
const actorContext = state.context.actorRef?.getSnapshot()?.context;
|
|
59
|
+
const availableAuthMethods = actorContext?.availableAuthMethods;
|
|
60
|
+
const hasMultipleMethods = availableAuthMethods && availableAuthMethods.length > 1;
|
|
45
61
|
/**
|
|
46
62
|
* @migration signUp Fields created here
|
|
47
63
|
*/
|
|
@@ -57,7 +73,17 @@ const getSignUpFormFields = (state) => {
|
|
|
57
73
|
const fieldAttrs = fieldName === primaryAlias
|
|
58
74
|
? getAliasDefaultFormField(state)
|
|
59
75
|
: getDefaultFormField(fieldName);
|
|
60
|
-
|
|
76
|
+
// Make email, phone_number, password, and confirm_password optional when multiple auth methods available
|
|
77
|
+
// Validation will check based on selected method
|
|
78
|
+
const isOptional = hasMultipleMethods &&
|
|
79
|
+
(fieldName === 'email' ||
|
|
80
|
+
fieldName === 'phone_number' ||
|
|
81
|
+
fieldName === 'password' ||
|
|
82
|
+
fieldName === 'confirm_password');
|
|
83
|
+
formField[fieldName] = {
|
|
84
|
+
...fieldAttrs,
|
|
85
|
+
...(isOptional && { isRequired: false }),
|
|
86
|
+
};
|
|
61
87
|
}
|
|
62
88
|
else {
|
|
63
89
|
// There's a `custom:*` attribute or one we don't already have an implementation for
|
|
@@ -27,6 +27,14 @@ const getRoute = (state, actorState) => {
|
|
|
27
27
|
case actorState?.matches('setupTotp.edit'):
|
|
28
28
|
case actorState?.matches('setupTotp.submit'):
|
|
29
29
|
return 'setupTotp';
|
|
30
|
+
case actorState?.matches('signIn.submit'):
|
|
31
|
+
return actorState?.context.selectedAuthMethod != null
|
|
32
|
+
? 'signInSelectAuthFactor'
|
|
33
|
+
: 'signIn';
|
|
34
|
+
case actorState?.matches('signIn.selectMethod'):
|
|
35
|
+
return 'signInSelectAuthFactor';
|
|
36
|
+
case actorState?.matches('passkeyPrompt'):
|
|
37
|
+
return 'passkeyPrompt';
|
|
30
38
|
case actorState?.matches('signIn'):
|
|
31
39
|
return 'signIn';
|
|
32
40
|
case actorState?.matches('signUp'):
|
|
@@ -65,6 +65,17 @@ const getSelectMfaTypeByChallengeName = (challengeName) => {
|
|
|
65
65
|
}
|
|
66
66
|
return translate(DefaultTexts.MFA_SELECTION);
|
|
67
67
|
};
|
|
68
|
+
const getUsernameLabelByLoginMechanism = (loginMechanism) => {
|
|
69
|
+
switch (loginMechanism) {
|
|
70
|
+
case 'email':
|
|
71
|
+
return translate(DefaultTexts.EMAIL_ADDRESS);
|
|
72
|
+
case 'phone_number':
|
|
73
|
+
return translate(DefaultTexts.PHONE_NUMBER);
|
|
74
|
+
case 'username':
|
|
75
|
+
default:
|
|
76
|
+
return translate(DefaultTexts.USERNAME);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
68
79
|
const getMfaTypeLabelByValue = (mfaType) => {
|
|
69
80
|
switch (mfaType) {
|
|
70
81
|
case 'EMAIL':
|
|
@@ -84,6 +95,7 @@ const authenticatorTextUtil = {
|
|
|
84
95
|
getChangingText: () => translate(DefaultTexts.CHANGING_PASSWORD),
|
|
85
96
|
getConfirmText: () => translate(DefaultTexts.CONFIRM),
|
|
86
97
|
getConfirmingText: () => translate(DefaultTexts.CONFIRMING),
|
|
98
|
+
getContinueText: () => translate(DefaultTexts.CONTINUE),
|
|
87
99
|
getCopyText: () => translate(DefaultTexts.UPPERCASE_COPY),
|
|
88
100
|
getHidePasswordText: () => translate(DefaultTexts.HIDE_PASSWORD),
|
|
89
101
|
getLoadingText: () => translate(DefaultTexts.LOADING),
|
|
@@ -106,6 +118,9 @@ const authenticatorTextUtil = {
|
|
|
106
118
|
/** SignUp */
|
|
107
119
|
getCreatingAccountText: () => translate(DefaultTexts.CREATING_ACCOUNT),
|
|
108
120
|
getCreateAccountText: () => translate(DefaultTexts.CREATE_ACCOUNT),
|
|
121
|
+
getCreateAccountWithEmailText: () => translate(DefaultTexts.CREATE_ACCOUNT_WITH_EMAIL_OTP),
|
|
122
|
+
getCreateAccountWithPasswordText: () => translate(DefaultTexts.CREATE_ACCOUNT_WITH_PASSWORD),
|
|
123
|
+
getCreateAccountWithSmsText: () => translate(DefaultTexts.CREATE_ACCOUNT_WITH_SMS_OTP),
|
|
109
124
|
/** ConfirmSignUp */
|
|
110
125
|
getDeliveryMessageText,
|
|
111
126
|
getDeliveryMethodText,
|
|
@@ -132,6 +147,25 @@ const authenticatorTextUtil = {
|
|
|
132
147
|
getVerifyText: () => translate(DefaultTexts.VERIFY),
|
|
133
148
|
getVerifyContactText: () => translate(DefaultTexts.VERIFY_CONTACT),
|
|
134
149
|
getAccountRecoveryInfoText: () => translate(DefaultTexts.VERIFY_HEADING),
|
|
150
|
+
/** Passwordless */
|
|
151
|
+
getPasskeyPromptHeadingText: () => translate(DefaultTexts.PASSKEY_PROMPT_HEADING),
|
|
152
|
+
getPasskeyPromptDescriptionText: () => translate(DefaultTexts.PASSKEY_PROMPT_DESCRIPTION),
|
|
153
|
+
getCreatePasskeyText: () => translate(DefaultTexts.CREATE_PASSKEY),
|
|
154
|
+
getRegisteringText: () => translate(DefaultTexts.REGISTERING),
|
|
155
|
+
getContinueWithoutPasskeyText: () => translate(DefaultTexts.CONTINUE_WITHOUT_PASSKEY),
|
|
156
|
+
getPasskeyCreatedSuccessText: () => translate(DefaultTexts.PASSKEY_CREATED_SUCCESS),
|
|
157
|
+
getPasskeyRegisteredText: () => translate(DefaultTexts.PASSKEY_REGISTERED),
|
|
158
|
+
getPasskeyRegistrationFailedText: () => translate(DefaultTexts.PASSKEY_REGISTRATION_FAILED),
|
|
159
|
+
getPasskeyLabelText: () => translate(DefaultTexts.PASSKEY_LABEL),
|
|
160
|
+
getExistingPasskeysText: () => translate(DefaultTexts.EXISTING_PASSKEYS),
|
|
161
|
+
getSetupAnotherPasskeyText: () => translate(DefaultTexts.SETUP_ANOTHER_PASSKEY),
|
|
162
|
+
getSignInWithPasswordText: () => translate(DefaultTexts.SIGN_IN_WITH_PASSWORD),
|
|
163
|
+
getSignInWithEmailText: () => translate(DefaultTexts.SIGN_IN_WITH_EMAIL),
|
|
164
|
+
getSignInWithSmsText: () => translate(DefaultTexts.SIGN_IN_WITH_SMS),
|
|
165
|
+
getSignInWithPasskeyText: () => translate(DefaultTexts.SIGN_IN_WITH_PASSKEY),
|
|
166
|
+
getOtherSignInOptionsText: () => translate(DefaultTexts.OTHER_SIGN_IN_OPTIONS),
|
|
167
|
+
getEnterUsernameFirstText: () => translate(DefaultTexts.ENTER_USERNAME_FIRST),
|
|
168
|
+
getUsernameLabelByLoginMechanism,
|
|
135
169
|
/** Validations */
|
|
136
170
|
// TODO: add defaultText
|
|
137
171
|
getInvalidEmailText: () => translate('Please enter a valid email'),
|
|
@@ -22,7 +22,13 @@ const defaultTexts = {
|
|
|
22
22
|
CONFIRM: 'Confirm',
|
|
23
23
|
CONFIRMATION_CODE: 'Confirmation Code',
|
|
24
24
|
CONFIRMING: 'Confirming',
|
|
25
|
+
CONTINUE: 'Continue',
|
|
26
|
+
CONTINUE_WITHOUT_PASSKEY: 'Continue without a Passkey',
|
|
25
27
|
CREATE_ACCOUNT: 'Create Account',
|
|
28
|
+
CREATE_ACCOUNT_WITH_EMAIL_OTP: 'Create account with Email OTP',
|
|
29
|
+
CREATE_ACCOUNT_WITH_PASSWORD: 'Create account with Password',
|
|
30
|
+
CREATE_ACCOUNT_WITH_SMS_OTP: 'Create account with SMS OTP',
|
|
31
|
+
CREATE_PASSKEY: 'Create a Passkey',
|
|
26
32
|
CREATING_ACCOUNT: 'Creating Account',
|
|
27
33
|
EMAIL_ADDRESS: 'Email',
|
|
28
34
|
EMAIL_OTP: 'Email Message',
|
|
@@ -39,6 +45,8 @@ const defaultTexts = {
|
|
|
39
45
|
ENTER_PHONE_NUMBER: 'Enter your Phone Number',
|
|
40
46
|
ENTER_PREFERRED_USERNAME: 'Enter your Preferred Username',
|
|
41
47
|
ENTER_USERNAME: 'Enter your username',
|
|
48
|
+
ENTER_USERNAME_FIRST: 'Please enter your username first',
|
|
49
|
+
EXISTING_PASSKEYS: 'Existing Passkeys',
|
|
42
50
|
FAMILY_NAME: 'Family Name',
|
|
43
51
|
GIVEN_NAME: 'Given Name',
|
|
44
52
|
FORGOT_PASSWORD: 'Forgot Password?',
|
|
@@ -53,16 +61,30 @@ const defaultTexts = {
|
|
|
53
61
|
NICKNAME: 'Nickname',
|
|
54
62
|
NEW_PASSWORD: 'New password',
|
|
55
63
|
OR: 'or',
|
|
64
|
+
OTHER_SIGN_IN_OPTIONS: 'Other sign-in options',
|
|
65
|
+
PASSKEY_AUTHENTICATION_CANCELED: 'Passkey authentication was canceled. Please try again or use a different sign-in method.',
|
|
66
|
+
PASSKEY_CREATED_SUCCESS: 'Passkey created successfully!',
|
|
67
|
+
PASSKEY_LABEL: 'Passkey',
|
|
68
|
+
PASSKEY_PROMPT_DESCRIPTION: 'Passkeys are WebAuthn credentials that validate your identity using biometric data like touch or facial recognition or device authentication like passwords or PINs, serving as a secure password replacement.',
|
|
69
|
+
PASSKEY_PROMPT_HEADING: 'Sign in faster with Passkey',
|
|
70
|
+
PASSKEY_REGISTERED: 'Your passkey has been successfully registered.',
|
|
71
|
+
PASSKEY_REGISTRATION_FAILED: 'Failed to create passkey. Please try again.',
|
|
56
72
|
PASSWORD: 'Password',
|
|
73
|
+
PASSWORDLESS_NOT_ENABLED: 'Passwordless authentication is not enabled for this account. Please contact your administrator or use password sign-in.',
|
|
57
74
|
PHONE_NUMBER: 'Phone Number',
|
|
58
75
|
PREFERRED_USERNAME: 'Preferred Username',
|
|
59
76
|
PROFILE: 'Profile',
|
|
77
|
+
REGISTERING: 'Registering',
|
|
60
78
|
RESEND_CODE: 'Resend Code',
|
|
61
79
|
RESET_PASSWORD_HEADING: 'Reset your password',
|
|
62
80
|
RESET_PASSWORD: 'Reset Password',
|
|
63
81
|
SEND_CODE: 'Send code',
|
|
82
|
+
CODE_DELIVERY_FAILED: 'Unable to send verification code. Please try again.',
|
|
83
|
+
VERIFICATION_CODE_EXPIRED: 'Your verification code has expired. Please request a new code.',
|
|
84
|
+
VERIFICATION_CODE_INVALID: 'The verification code you entered is incorrect. Please try again.',
|
|
64
85
|
SENDING: 'Sending',
|
|
65
86
|
SELECT_MFA_TYPE: 'Select MFA Type',
|
|
87
|
+
SETUP_ANOTHER_PASSKEY: 'Setup another Passkey',
|
|
66
88
|
SETUP_EMAIL: 'Setup Email',
|
|
67
89
|
SETUP_TOTP: 'Setup TOTP',
|
|
68
90
|
SHOW_PASSWORD: 'Show password',
|
|
@@ -70,8 +92,12 @@ const defaultTexts = {
|
|
|
70
92
|
SIGN_IN_TAB: 'Sign In',
|
|
71
93
|
SIGN_IN_WITH_AMAZON: 'Sign In with Amazon',
|
|
72
94
|
SIGN_IN_WITH_APPLE: 'Sign In with Apple',
|
|
95
|
+
SIGN_IN_WITH_EMAIL: 'Sign In with Email',
|
|
73
96
|
SIGN_IN_WITH_FACEBOOK: 'Sign In with Facebook',
|
|
74
97
|
SIGN_IN_WITH_GOOGLE: 'Sign In with Google',
|
|
98
|
+
SIGN_IN_WITH_PASSKEY: 'Sign In with Passkey',
|
|
99
|
+
SIGN_IN_WITH_PASSWORD: 'Sign In with Password',
|
|
100
|
+
SIGN_IN_WITH_SMS: 'Sign In with SMS',
|
|
75
101
|
SIGN_IN: 'Sign in to your account',
|
|
76
102
|
SIGN_UP_BUTTON: 'Create a new account',
|
|
77
103
|
SIGNING_IN_BUTTON: 'Signing in',
|
|
@@ -81,6 +107,7 @@ const defaultTexts = {
|
|
|
81
107
|
SUBMITTING: 'Submitting',
|
|
82
108
|
SOFTWARE_TOKEN_MFA: 'Authenticator App (TOTP)',
|
|
83
109
|
UPPERCASE_COPY: 'COPY',
|
|
110
|
+
USERNAME: 'Username',
|
|
84
111
|
VERIFY_CONTACT: 'Verify Contact',
|
|
85
112
|
VERIFY_HEADING: 'Account recovery requires verified contact information',
|
|
86
113
|
VERIFY: 'Verify',
|
|
@@ -92,7 +92,7 @@ const esDict = {
|
|
|
92
92
|
'Sign Up with Google': 'Crear cuenta con Google',
|
|
93
93
|
'Sign Up': 'Crear cuenta',
|
|
94
94
|
'User already exists': 'El usuario ya existe',
|
|
95
|
-
'User does not exist': 'El usuario no existe',
|
|
95
|
+
'User does not exist.': 'El usuario no existe',
|
|
96
96
|
'Username/client id combination not found.': 'El usuario no existe',
|
|
97
97
|
'Username cannot be empty': 'El nombre de usuario no puede estar vacío',
|
|
98
98
|
'Your passwords must match': 'Las contraseñas deben coincidir',
|
|
@@ -111,7 +111,7 @@ const frDict = {
|
|
|
111
111
|
'Sign Up': "S'inscrire",
|
|
112
112
|
SMS: 'SMS',
|
|
113
113
|
'User already exists': "L'utilisateur existe déjà",
|
|
114
|
-
'User does not exist': "L'utilisateur n'existe pas",
|
|
114
|
+
'User does not exist.': "L'utilisateur n'existe pas",
|
|
115
115
|
'Username cannot be empty': "Le nom d'utilisateur doit être renseigné",
|
|
116
116
|
'Username/client id combination not found.': "L'utilisateur n'existe pas",
|
|
117
117
|
'We Emailed You': 'Nous vous avons envoyé un code',
|
|
@@ -2,6 +2,7 @@ import { actions } from 'xstate';
|
|
|
2
2
|
import '@aws-amplify/core/internals/utils';
|
|
3
3
|
import 'aws-amplify/utils';
|
|
4
4
|
import '../../utils/setUserAgent/constants.mjs';
|
|
5
|
+
import { translate, DefaultTexts } from '../../i18n/translations.mjs';
|
|
5
6
|
import '../../types/authenticator/user.mjs';
|
|
6
7
|
import '../../types/authenticator/attributes.mjs';
|
|
7
8
|
import { trimValues } from '../../helpers/authenticator/utils.mjs';
|
|
@@ -14,7 +15,12 @@ const clearActorDoneData = assign({ actorDoneData: undefined });
|
|
|
14
15
|
const clearChallengeName = assign({ challengeName: undefined });
|
|
15
16
|
const clearMissingAttributes = assign({ missingAttributes: undefined });
|
|
16
17
|
const clearError = assign({ remoteError: undefined });
|
|
17
|
-
const clearFormValues = assign({
|
|
18
|
+
const clearFormValues = assign({
|
|
19
|
+
formValues: (context) => ({
|
|
20
|
+
// Preserve username for passwordless flows to avoid "username is required" errors
|
|
21
|
+
username: context.formValues?.username,
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
18
24
|
const clearTouched = assign({ touched: {} });
|
|
19
25
|
const clearUser = assign({ user: undefined });
|
|
20
26
|
const clearValidationError = assign({ validationError: {} });
|
|
@@ -115,7 +121,28 @@ const setRemoteError = assign({
|
|
|
115
121
|
if (data.name === 'NoUserPoolError') {
|
|
116
122
|
return `Configuration error (see console) – please contact the administrator`;
|
|
117
123
|
}
|
|
118
|
-
|
|
124
|
+
const message = data?.message || '';
|
|
125
|
+
// Handle USER_AUTH flow not enabled error
|
|
126
|
+
if (message.includes('USER_AUTH flow not enabled')) {
|
|
127
|
+
return translate(DefaultTexts.PASSWORDLESS_NOT_ENABLED);
|
|
128
|
+
}
|
|
129
|
+
// Handle cannot send code error
|
|
130
|
+
if (message.includes('Cannot send code to either')) {
|
|
131
|
+
return translate(DefaultTexts.CODE_DELIVERY_FAILED);
|
|
132
|
+
}
|
|
133
|
+
// Handle invalid/wrong verification code
|
|
134
|
+
if (message.includes('Invalid code or auth state')) {
|
|
135
|
+
return translate(DefaultTexts.VERIFICATION_CODE_INVALID);
|
|
136
|
+
}
|
|
137
|
+
// Handle expired verification code
|
|
138
|
+
if (message.includes('session is expired')) {
|
|
139
|
+
return translate(DefaultTexts.VERIFICATION_CODE_EXPIRED);
|
|
140
|
+
}
|
|
141
|
+
// Handle passkey authentication canceled
|
|
142
|
+
if (message.includes('ceremony has been canceled')) {
|
|
143
|
+
return translate(DefaultTexts.PASSKEY_AUTHENTICATION_CANCELED);
|
|
144
|
+
}
|
|
145
|
+
return message || data;
|
|
119
146
|
},
|
|
120
147
|
});
|
|
121
148
|
const setUser = assign({ user: (_, { data }) => data });
|
|
@@ -152,8 +179,12 @@ const handleBlur = assign({
|
|
|
152
179
|
}),
|
|
153
180
|
});
|
|
154
181
|
const setUnverifiedUserAttributes = assign({
|
|
155
|
-
unverifiedUserAttributes: (
|
|
156
|
-
|
|
182
|
+
unverifiedUserAttributes: (context, { data }) => {
|
|
183
|
+
// Use fetchedUserAttributes from context if data is not provided
|
|
184
|
+
const attributes = data || context.fetchedUserAttributes;
|
|
185
|
+
if (!attributes)
|
|
186
|
+
return {};
|
|
187
|
+
const { email, phone_number } = attributes;
|
|
157
188
|
const unverifiedUserAttributes = {
|
|
158
189
|
...(email && { email }),
|
|
159
190
|
...(phone_number && { phone_number }),
|
|
@@ -167,11 +198,34 @@ const setSelectedUserAttribute = assign({
|
|
|
167
198
|
});
|
|
168
199
|
// Maps to unexposed `ConfirmSignUpSignUpStep`
|
|
169
200
|
const setConfirmSignUpSignUpStep = assign({ step: 'CONFIRM_SIGN_UP' });
|
|
201
|
+
// Passwordless actions
|
|
202
|
+
const setSelectedAuthMethod = assign({
|
|
203
|
+
selectedAuthMethod: (_, { data }) => data.method,
|
|
204
|
+
});
|
|
205
|
+
const setSelectedAuthMethodFromForm = assign({
|
|
206
|
+
selectedAuthMethod: (_, { data }) => {
|
|
207
|
+
// Extract method from form data if present, default to PASSWORD for form submissions
|
|
208
|
+
return data?.__authMethod || 'PASSWORD';
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
const setSelectAuthMethodStep = assign({
|
|
212
|
+
step: 'SELECT_AUTH_METHOD',
|
|
213
|
+
});
|
|
214
|
+
const setFetchedUserAttributes = assign({
|
|
215
|
+
fetchedUserAttributes: (_, event) => event.data,
|
|
216
|
+
});
|
|
217
|
+
const setHasExistingPasskeys = assign({
|
|
218
|
+
hasExistingPasskeys: (_, event) => event.data,
|
|
219
|
+
});
|
|
220
|
+
const clearHasExistingPasskeys = assign({
|
|
221
|
+
hasExistingPasskeys: false,
|
|
222
|
+
});
|
|
170
223
|
const ACTIONS = {
|
|
171
224
|
clearActorDoneData,
|
|
172
225
|
clearChallengeName,
|
|
173
226
|
clearError,
|
|
174
227
|
clearFormValues,
|
|
228
|
+
clearHasExistingPasskeys,
|
|
175
229
|
clearMissingAttributes,
|
|
176
230
|
clearSelectedUserAttribute,
|
|
177
231
|
clearTouched,
|
|
@@ -183,7 +237,9 @@ const ACTIONS = {
|
|
|
183
237
|
setAllowedMfaTypes,
|
|
184
238
|
setChallengeName,
|
|
185
239
|
setCodeDeliveryDetails,
|
|
240
|
+
setFetchedUserAttributes,
|
|
186
241
|
setFieldErrors,
|
|
242
|
+
setHasExistingPasskeys,
|
|
187
243
|
setMissingAttributes,
|
|
188
244
|
setNextResetPasswordStep,
|
|
189
245
|
setNextSignInStep,
|
|
@@ -191,6 +247,9 @@ const ACTIONS = {
|
|
|
191
247
|
setRemoteError,
|
|
192
248
|
setConfirmAttributeCompleteStep,
|
|
193
249
|
setConfirmSignUpSignUpStep,
|
|
250
|
+
setSelectAuthMethodStep,
|
|
251
|
+
setSelectedAuthMethod,
|
|
252
|
+
setSelectedAuthMethodFromForm,
|
|
194
253
|
setShouldVerifyUserAttributeStep,
|
|
195
254
|
setSelectedUserAttribute,
|
|
196
255
|
setSignInStep,
|