UNPKG

@aws-amplify/ui

Version:

`@aws-amplify/ui` contains low-level logic & styles for stand-alone usage or re-use in framework-specific implementations.

147 lines (144 loc) 6.17 kB
import { getActorContext, getActorState } from './actor.mjs'; import { NAVIGABLE_ROUTE_EVENT } from './constants.mjs'; import { getRoute } from './getRoute.mjs'; /** * This file contains helpers that translates xstate internals to more * understandable authenticator contexts. We provide these contexts with * `useAuthenticator` hook/composable/service. */ /** * Creates public facing auth helpers that abstracts out xstate implementation * detail. Each framework implementation can export these helpers so that * developers can send events without having to learn internals. * * ``` * const [state, send] = useActor(...); * const { submit } = getSendEventAliases(send); * submit({ username, password}) * ``` */ const getSendEventAliases = (send) => { const sendToMachine = (type) => { // TODO If these were created during the creation of the machine & provider, // then invalid transitions could be caught via https://xstate.js.org/docs/guides/states.html#state-can-event return (data) => send({ type, data }); }; return { initializeMachine: sendToMachine('INIT'), resendCode: sendToMachine('RESEND'), selectAuthMethod: sendToMachine('SELECT_METHOD'), signOut: sendToMachine('SIGN_OUT'), submitForm: sendToMachine('SUBMIT'), toShowAuthMethods: sendToMachine('SHOW_AUTH_METHODS'), updateForm: sendToMachine('CHANGE'), updateBlur: sendToMachine('BLUR'), // Actions that don't immediately invoke a service but instead transition to a screen // are prefixed with `to*` toFederatedSignIn: sendToMachine('FEDERATED_SIGN_IN'), toForgotPassword: sendToMachine('FORGOT_PASSWORD'), toSignIn: sendToMachine('SIGN_IN'), toSignUp: sendToMachine('SIGN_UP'), skipVerification: sendToMachine('SKIP'), }; }; const getNextSendEventAliases = (send) => { const { toFederatedSignIn, submitForm, resendCode, skipVerification } = getSendEventAliases(send); return { handleSubmit: submitForm, resendConfirmationCode: resendCode, // manual "route" navigation setRoute: (route) => send({ type: NAVIGABLE_ROUTE_EVENT[route] }), skipAttributeVerification: skipVerification, toFederatedSignIn, }; }; const getServiceContextFacade = (state) => { const actorContext = (getActorContext(state) ?? {}); const { allowedMfaTypes, availableAuthMethods, challengeName, codeDeliveryDetails, preferredChallenge, remoteError: error, selectedAuthMethod, validationError: validationErrors, totpSecretCode = null, unverifiedUserAttributes, username, } = actorContext; const { socialProviders = [], loginMechanisms } = state.context?.config ?? {}; const loginMechanism = loginMechanisms?.[0]; // check for user in actorContext prior to state context. actorContext is more "up to date", // but is not available on all states const user = actorContext?.user ?? state.context?.user; const hasValidationErrors = !!(validationErrors && Object.keys(validationErrors).length > 0); const actorState = getActorState(state); const isPending = state.hasTag('pending') || actorState?.hasTag('pending'); const route = getRoute(state, actorState); // Auth status represents the current state of the auth flow // The `configuring` state is used to indicate when the xState machine is loading const authStatus = ((route) => { switch (route) { case 'idle': case 'setup': return 'configuring'; case 'authenticated': return 'authenticated'; default: return 'unauthenticated'; } })(route); const facade = { allowedMfaTypes, authStatus, availableAuthMethods, challengeName, codeDeliveryDetails, error, hasValidationErrors, isPending, loginMechanism, preferredChallenge, route, selectedAuthMethod, socialProviders, totpSecretCode, unverifiedUserAttributes, user, username, validationErrors, // @v6-migration-note // While most of the properties // on `AuthenticatorServiceContextFacade` can resolve to `undefined`, updating // the interface requires material changes in consumers (namely `useAuthenticator`) // which will have implications on the UI layer as typeguards and non-null checks // are required to pass type checking. As the `Authenticator` is behaving as expected // with the `AuthenticatorServiceContextFacade` interface, prefer to cast }; return facade; }; const getNextServiceContextFacade = (state) => { const actorContext = (getActorContext(state) ?? {}); const { allowedMfaTypes, challengeName, codeDeliveryDetails, remoteError: errorMessage, totpSecretCode, unverifiedUserAttributes, username, } = actorContext; const { socialProviders: federatedProviders, loginMechanisms } = state.context?.config ?? {}; const loginMechanism = loginMechanisms?.[0]; const actorState = getActorState(state); const isPending = state.hasTag('pending') || actorState?.hasTag('pending'); // @todo-migration remove this cast for Authenticator.Next const route = getRoute(state, actorState); return { allowedMfaTypes, challengeName, codeDeliveryDetails, errorMessage, federatedProviders, isPending, loginMechanism, route, totpSecretCode, unverifiedUserAttributes, username, }; }; const getServiceFacade = ({ send, state, }) => { const sendEventAliases = getSendEventAliases(send); const serviceContext = getServiceContextFacade(state); return { ...sendEventAliases, ...serviceContext, }; }; const getNextServiceFacade = ({ send, state, }) => ({ ...getNextSendEventAliases(send), ...getNextServiceContextFacade(state), }); export { getNextServiceContextFacade, getNextServiceFacade, getSendEventAliases, getServiceContextFacade, getServiceFacade };