@alore/auth-react-native-ui
Version:
React Native UI for Alore Auth
809 lines (748 loc) • 34.3 kB
text/typescript
import { AloreAuthError } from '@alore/auth-react-native-sdk/src/AloreAuthError';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Passkey } from 'react-native-passkey';
import { assign, createMachine, DoneInvokeEvent, interpret, State } from 'xstate';
import { AuthMachineContext, AuthMachineEvents, AuthMachineServices } from './types';
const initialContext: AuthMachineContext = {
locale: 'en',
authMethods: {
google: false,
passkey: false,
password: false,
},
};
export const authMachine = createMachine(
{
/** #no-spell-check @xstate-layout N4IgpgJg5mDOIC5QEMCuAXAFgWWQY0wEsA7MAYgCUBRAZSoBUB9AYQHkA5eqgDXoG0ADAF1EoAA4B7WIXSEJxUSAAeiACwAmADQgAnogCc+gHQCAzAHZzANgCsA-ao03TARgC+b7Wiy4CJMEYk+LIAbuQAkuzh9OEAggAy4QBaVIIiSCCS0rLyiioI6qrmRoUCABzqpvrqAi6mVTbaegXq6kb6AkX6FuY2+lbW6h5eGDj4RKRGwYRhgcQyhMgANkZhAE6EAGY6sUsSa2A06MjoqLBkEPIBJCESANYB3mN+k9OzJAvLq2Ab27v7h2Op1gCBuEjwJzkxDSaUUWQWuQy+RcAjMRnMLlUphsFRc5nULgqTUQtjK7Vq+jsWNMZRx5mGICevgmjzwoWu81kX3WWx2ewORxOZzIPzW+yMYiWJ02+wAtlNRsz-FM2TMOZ8Vjy-vzAUKQWCITlocJYRl4Ua8ogUZ0jDTVA4bHUrGUyvViQhHVYSnj6vo6jTqkNPIzFeNlW91VyVoQIEtyPFWABxSKMGhcAAKpvEUgRCiRVtMAyMZX0rtUzoqAnUvXdHRsRkcmMchmsqhcVgZTLDr1V705i2jsfIadiFCY6diNBoAGkqABNRgJ5PsLOZHMW-MIFx44wCcxFH3WGyqASNXRWqvGV1WVQ2cyU0sVfSd0MvVnsuYawJDyhUZNpqgKFTDNV3NKFLQQDFTGLQxKVMcoqiqd1t2dIxnVRHFy36KsbBfHxu3fNVPyjb841-f8uCAgDMxcdJs2ycDNzKOoYMMTCalvDFkMqMl9HMCorD3dQBm3Mo8OeFkVQ-D4SJjMjqAowDgKoTN1DotcGMRUB8j9YwUQqMpyxsdQ+gsZD4PrSlzFMYS7w0exxKVHsPz2KASCMMBZWQQgliOMAxDIAAhWJmGnUD10Y7TEEdAk0NUQzChcYyrCsUx3VpXd7w4lEqisQpHIIqSiNc9zPO83z0H8sgADEGGYAAJVMEn4YQ4QirTlCtP16wsVpnCSv1DPSl10SsbpKhMlKT1w4MuzfIrZhK4gPK8ny-ICkcx0YCcp1nBcl0icLNLzKKCmsXc70JdRXVaAkymQ9toLbAl234jEbFSgr5ojIwlqMA50A2MAQhIKAaGWdALiuOZbgeBV8O+3sAj+gGgZB4gwYh0FiFuQ0oRhVqzXak7Oq3OtbXxEzXD6QlVAekzi06ctzBwvLn1m19JJ+lGwEBwhgdB8Glkh0VxUlaU5XhiTwyR36JDc5bUf59HMeF7HccheQCfUsCOuRbqKb66nBrp88tzMJ7jN01xtxPekOYRrnZb+sRkFgWAAHd9ggdagpCsLCfo3MIJM9tbSsFw-RvZ1Szy7ibT9Ez1A6AQI7MMSHel5zivl9zXfdr21h9yqAoANUA8Jqv2pNDsDjTg83SOqwbBwMUS-FHDSs2XDuowksEzF91qPFVC+p2XNz5atR0UH4knqHJjBOG5vHnOFe+X4Z4xueFfV8FNeNIQjob06m7ae0D3bwosWQx0XGLNtelMRwiiKDtM6cwjFsnjfeVn+fRZrAlFKdAMo1jyhXjLCe69p7-13gaA+2s2rHQgpHHuLdL6P2vl3Zo-oyQfT6hlG8lIgwjEdlAtepVVpLHUJsZAv46DsAACIsFYEw1IdddYk3yK0E8xYyiohsk2eolhkIpWKA4Esdg9wtkJGPCh3915lR8rQ+h5cKCVwXFQbAsRwjxEYOoaqsRj4blOrdAQ-DBEEk7j0ZCzELHbmTrSOw+Ikqjw-oVbmP9lE0LoX7UKJjIqkz6hYl0VjhG2O7vFCxPEzCFGcNZdmZCs5f2Rj-WBGMqDUNUQvDksNHicwUWkmBPw-6ZOyXQveeMtYmk4cTCCjpXBxQSm2ZKqVawYhMKnYS11CyGVPPI7Oij3IZKgFk8qOTAHAIluAqWn8FrFJGaU7YoNxkqMqQgo0SCiYoM3K0eCli4kRNEd3DExRrCYh6NUfE9tknzK8evA4sAwDEAgKs6hzAJAQHIJcReON7gFPIUMxZis4AvLeeU8qnzvlVMQbUnW9S9kmVCQIo5NiTm4LvPWPoQ9Ki2HitiQZqS5br3zrAB4Oh1pGFgMcNYkNfl5IBXMzxzsf5kopVSmlyA6Wwq2fC5BJ9gmCIbIZCOLMbyOlPO6DiqgSg4jKEPAR1pbkhiBcSl2btyVgEpSXaltKRZrDFEA8WoDJaQOBSSvOmqOW6q5TyzZ+N+U7MFfkGK98bwtKSsJdp3cFX1kEn6KsAj7wBqJQsy1y12XaqpXJcgABVOgQFIjpjjeOScM55yLhriuOpuyzHJ2MK0AY95eh5VcNK1OXog12GkZHPiM07ksugVa92Nr-JGDOD8cIxAxAYFyTDJl5r1VsutdG3Vna1jdt7egXljqj65pdYga6zF0R7kufxQkNYzYEkEkYGwdJjz7kLM6BtqqUnho1a2sd7aJ1Tr7VMk1YCIGFItZerVOqb3PMnT2jAs6anzoRXm0mbrmkaFad6nBXUizYVsKeXh9pSFnvuay0lo6P1iA7V+u96AaCoDwHgOA5xqqRHCDQRqO0M3V2XIEvWiAbLVDQo01EzEygnorfedEzZ+jYgGBWMNDyW3vqpVGnQFA4CoGFv2pegLz0CcjWh4TaGxOwAkzOh1-6aPcOij3d18UwNepSpBgoXq0KpX3H0R0Gh36NsRs2+TV70MSiU+JyTD6QFPuZbZyh9mhO6pE8p1Tf7D6aYaXUXTnq2lGZqLu1wBJSx4u6L0fjssDhuRpT8Fa5VfbBQCQu0xpNSToldB0Vw5YND7mlS4vdhQbKlefiZZLH5UuEHS0Anxvt2A8BaoBxdZMGP2ipL0FmrYtBmyxLUYsNJ+LlgjhfRrRFmutcy2tEuZBEysCTPEKgWbqN5aCfra6aFygnjxTihw7pbyFHDrSTErGBiOnm7MRblU2vUN9owlhClSP0AoLEGIHBGDaN0fEELjdrBklcFWOLjjDJnmaHbYw+7n5VhpFbJKj2AjPYyxO4gyBZSAiqjlgOPX8s8NPMUYSUF2yR3qxdpKZIDKVHKxHMaGP-pgDSy9zDPxcf4-e1QZhjAvtpl+-99ggOdF6NB2Y1wEjtzjTYrUYSF3ahemMgq1jzFCjdTZ1joBOO8cE42gLz7f5vui-CADoHUvaICtJ0umk0FnBjULPaDEOF3SFn4iUNixX92nkpLrjnLWufPNee88qUn-nLxfcSvX1LwUR58kF7ZQd7dbhY8WZOthCTGWcI4T3KV6wB-6NZE7QfOcZbDxCsZ1CRSGrFu5s1sfw3x+r0npYKenVp-21aCzDZzrdPqHE8wnuwloUMtx962IM42dXk94PS2fGl2WDGA+vt1GaIl8D6XpMm7QRLPFVxV0kJm3qPFEop4FWFHsdUCvIeMvL9XxAdfq2ie754b3F0N0cQOA6IST3D6YvasVjVofoOwdwDxLzBfSvV7cqFfJYNfI0X2agD7VhdhD-K0FmNoVKCoD6d6FKZiQA4SckGkAYU8Y9LEe-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-2LGsGslSmfhPD3FocE0aOwaVtuM-qvBvDbHbGEjxFpHjllUcBqygk4jqBEanmcO3knmYewOgZZnYf4YQe7hqDJHtFRDxDbn7r-JLLs2W18WQBwZqHxD7jGkxGSmThvm7jsGkY3RjPqx7k0Z3o71UWcY0DJH2VdFRCfMjmQnxGglRF6Hpx7nEPwrse8w5LpMUJ8mhQbokZDnsj3WPDK0MEERSlvgEX6uMjxu3GJOCZCr0dinrWPEji6BQjsW6HaAGueJPHimdAaYmrtXQD0bGk-MDracbPbArUO1TldHbFLAJMLEGeWrfoKaRRYgLVEjrW6ulXl2LCALZi6FlxWeuu5zsowGccEgsXuNSnsBaai06DaGuiP23HuemlOdqvOewwioI3dhwchxPrTlLGeP3Gme3RkXJBvHxANvvFvE+evTqoczWoBecAZxdFaFxGJIdKXVPDV1qHLHqFpH3HSbtuqsWOYdi3aD4lFOxEMFvGlTYgHwEVwMMlcA3oycWqXywf8mYZSndpJedArDGnnrUBAJMANqjm6H3Qzs5ZYJ8INz53EZrMkZqBiWtBv24ribG0qERy7NosIJsn+M5JyaWGYcnxMGXN6itOMk90bMeP7qiOcHq3+Kf0QJf2QOVZatuMJFY2uwVTVpHldEAKaV4UlVqHxBdH+K0J8nNb9f6eHmEJ+rhzozVsZmNvsA+KurEd5fWdOngmsFXRRBfjvGPS4epFSr7up2PCrH+MBJOORO5PyzvM3B4wsTwasxpCDTxAuxpHPl5rggJP3H+P1Jr19NROIDoMpdjKPDOpMg0HVs9wsbcdQssH4nmezNDPDLWGcfbEiccU4efjxPLfinPjiwVSqGi1lbJa5a50abzb3xSmMFbspB+usnMwu0pnRBRAScrtsCuq+eGb0bxFtA6FfaPwsAZdYomy8ZMhKefkDyfqsqWrObWZVZDlskBpxFsBqH3X4iMwsc+r3BFdqxFYA8Re+ZEquddHYq-P3UkWqCypo-gi+J3P3HvHI8cxMvCrwz+fgAffyBxvrAEVKDMF-MJM0v6z0oxv0kKqQ-JaIomtKoapGYE7oyLobGmIEQQ1FSyrGfKDFWYmfjylJdZOQ8U+Wtur45wcfgZ2SerHXdRA0rUAVWKDbrnszYEPBsIEhsgBhpwZrbaGmPsFizIaMzKfLpKZDTMAVKHvmKzpmCdq-QC7GhyvXqSmsm6RTYQFxG6cn0JFRtyjDUAUPvQAkDEATpINEmPD9UoZ-e0DjE2FU+13DjGnKD4hLEM1bIACMJB0AyvZQl175frbxUmTD7DtANgoBMBVPCxn2n32v+J+hUpWyPYYwsArQahtBMAwAfOZuXPtAeF7RWuOgSwluuudaqvc8j9jwaQf3Q63AgA */
id: 'authMachine',
predictableActionArguments: true,
tsTypes: {} as import('./index.typegen').Typegen0,
schema: {
context: {} as AuthMachineContext,
services: {} as AuthMachineServices,
events: {} as AuthMachineEvents,
},
states: {
inactive: {
entry: [
assign({
sessionUser: () => undefined,
CCRPublicKey: () => undefined,
error: () => undefined,
googleOtpCode: () => undefined,
googleUser: () => undefined,
RCRPublicKey: () => undefined,
salt: () => undefined,
sessionId: () => undefined,
userEmail: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
registerUser: () => undefined,
}),
() => AsyncStorage.removeItem('authState'),
],
on: {
INITIALIZE: {
target: 'active',
},
},
},
active: {
states: {
initial: {
states: {
verifyAloreStatus: {
invoke: {
src: 'healthCheck',
onDone: {
target: 'idle',
actions: 'resetError',
},
onError: {
target: '#authMachine.error',
actions: 'assignError',
},
},
},
idle: {
on: {
LOGIN_STEP: '#authMachine.active.login',
START_PASSKEY_LOGIN: '#authMachine.active.login.passkeyStep',
REGISTER_STEP: [
{
target: '#authMachine.active.register',
cond: 'requireEmailVerification',
},
{
target: '#authMachine.active.register.usernameStep',
cond: 'requireUsername',
},
'#authMachine.active.register.passkeyStep.idle',
],
},
},
},
entry: assign({
sessionUser: () => undefined,
CCRPublicKey: () => undefined,
googleOtpCode: () => undefined,
googleUser: () => undefined,
RCRPublicKey: () => undefined,
salt: () => undefined,
sessionId: () => undefined,
userEmail: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
registerUser: () => undefined,
}),
initial: 'verifyAloreStatus',
},
login: {
states: {
emailStep: {
on: {
BACK: { target: '#authMachine.active.initial' },
FETCH_SALT: {
target: '#authMachine.active.login.retrievingSalt',
actions: assign({
googleOtpCode: () => undefined,
googleUser: () => undefined,
registerUser: () => undefined,
sessionId: () => undefined,
}),
},
START_PASSKEY_LOGIN: {
target: '#authMachine.active.login.passkeyStep',
},
},
exit: 'resetError',
},
retrievingSalt: {
invoke: {
src: 'retrieveSalt',
onDone: {
target: '#authMachine.active.login.passwordStep',
actions: assign({
salt: (_context, event) => event.data,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.login.emailStep',
actions: 'assignError',
},
},
entry: 'resetError',
},
passwordStep: {
on: {
BACK: {
target: '#authMachine.active.login.emailStep',
actions: assign({
googleUser: () => undefined,
registerUser: () => undefined,
error: () => undefined,
}),
},
VERIFY_LOGIN: '#authMachine.active.login.verifyingLogin',
},
exit: 'resetError',
},
verifyingLogin: {
invoke: {
src: 'verifyLogin',
onDone: [
{
target: 'email2fa',
actions: assign({
sessionId: (_, event) => event.data.sessionId,
error: () => undefined,
}),
},
],
onError: {
target: '#authMachine.active.login.passwordStep',
actions: 'assignError',
},
},
entry: 'resetError',
},
email2fa: {
on: {
RESEND_CODE: '#authMachine.active.login.resendingEmailCode',
VERIFY_EMAIL_2FA: '#authMachine.active.login.verifyingEmail2fa',
BACK: {
target: '#authMachine.active.login.passwordStep',
actions: 'resetError',
},
},
exit: 'resetError',
},
verifyingEmail2fa: {
invoke: {
src: 'verifyEmail2fa',
onError: {
target: '#authMachine.active.login.email2fa',
actions: 'assignError',
},
onDone: {
target: '#authMachine.active.signedOn',
actions: assign({
sessionUser: (_, event) => event.data,
error: () => undefined,
}),
},
},
entry: 'resetError',
},
resendingEmailCode: {
invoke: {
src: 'verifyLogin',
onDone: {
target: '#authMachine.active.login.email2fa',
actions: assign({
sessionId: (_, event) => event.data.sessionId,
error: () => undefined,
}),
},
},
entry: 'resetError',
},
passkeyStep: {
states: {
start: {
invoke: {
src: 'startPasskeyAuth',
onDone: {
target: '#authMachine.active.login.passkeyStep.idle',
actions: assign({
RCRPublicKey: (_context, event) => event.data.requestChallengeResponse,
sessionId: (_, event) => event.data.sessionId,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.initial',
actions: 'assignError',
},
},
},
idle: {
on: {
USER_INPUT_PASSKEY_LOGIN: '#authMachine.active.login.passkeyStep.userInput',
},
},
userInput: {
invoke: {
src: 'userInputLoginPasskey',
onDone: {
target: '#authMachine.active.login.passkeyStep.userInputSuccess',
actions: assign({
passkeyLoginResult: (_context, event) => event.data,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.initial',
actions: 'assignError',
},
},
},
userInputSuccess: {
on: {
FINISH_PASSKEY_LOGIN: '#authMachine.active.login.passkeyStep.passkeyResult',
},
},
passkeyResult: {
invoke: {
src: 'finishPasskeyAuth',
onDone: {
target: '#authMachine.active.signedOn',
actions: assign({
sessionUser: (_context, event) => event.data,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.initial.idle',
actions: 'assignError',
},
},
},
},
exit: assign({
CCRPublicKey: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
RCRPublicKey: () => undefined,
}),
initial: 'start',
},
},
initial: 'emailStep',
},
register: {
states: {
emailStep: {
on: {
BACK: '#authMachine.active.initial.idle',
NEXT: '#authMachine.active.register.usernameStep',
GOOGLE_LOGIN: {
target: '#authMachine.active.register.googleRegister',
},
SEND_REGISTRATION_EMAIL: 'sendingEmail',
},
exit: 'resetError',
},
usernameStep: {
on: {
BACK: { target: '#authMachine.active.register.emailStep' },
SEND_REGISTRATION_EMAIL: [
{
target: '#authMachine.active.register.sendingEmail',
cond: 'requireEmailVerification',
},
'passwordStep',
],
},
exit: 'resetError',
},
sendingEmail: {
invoke: {
src: 'sendConfirmationEmail',
onDone: {
target: '#authMachine.active.register.emailValidationStep',
actions: assign({
salt: (_context, event) => event.data?.salt,
sessionId: (_context, event) => event.data?.sessionId,
error: () => undefined,
}),
},
onError: {
target: 'emailStep',
actions: 'assignError',
},
},
entry: assign({
error: () => undefined,
sessionId: () => undefined,
}),
},
emailValidationStep: {
on: {
VERIFY_EMAIL: 'verifyingEmail',
BACK: {
target: '#authMachine.active.register.usernameStep',
actions: 'resetError',
},
RESEND_CODE: '#authMachine.active.register.resendingRegistrationEmail',
},
exit: 'resetError',
},
verifyingEmail: {
invoke: {
src: 'verifyEmail',
onDone: [
{
target: '#authMachine.active.register.passkeyStep.idle',
actions: 'resetError',
cond: 'isPasskeyMethod',
},
{
target: '#authMachine.active.register.passwordStep',
actions: 'resetError',
},
],
onError: {
target: '#authMachine.active.register.emailValidationStep',
actions: 'assignError',
},
},
entry: 'resetError',
},
passwordStep: {
on: {
BACK: {
target: '#authMachine.active.register.usernameStep',
},
COMPLETE_REGISTRATION: '#authMachine.active.register.completingRegistration',
},
exit: 'resetError',
},
completingRegistration: {
invoke: {
src: 'completeRegistration',
onDone: {
target: '#authMachine.active.signedOn',
actions: assign({
sessionUser: (_, event) => event.data,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.register.passwordStep',
actions: 'assignError',
},
},
entry: 'resetError',
},
resendingRegistrationEmail: {
invoke: {
src: 'sendConfirmationEmail',
onDone: {
target: '#authMachine.active.register.emailValidationStep',
actions: assign({
salt: (_context, event) => event.data?.salt,
sessionId: (_context, event) => event.data?.sessionId,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.register.emailValidationStep',
actions: 'assignError',
},
},
entry: assign({
error: () => undefined,
sessionId: () => undefined,
}),
},
// TODO: add google register
googleRegister: {
invoke: {
src: 'googleLogin',
onDone: [
{
target: '#authMachine.active.register.passwordStep',
actions: assign({
registerUser: (_, event) => event.data?.registerUser,
}),
cond: 'isNewUser',
},
// {
// target: 'idle',
// actions: assign({
// googleOtpCode: (_, event) => event.data.googleOtpCode,
// salt: (_, event) => event.data.salt,
// googleUser: (_, event) => event.data.googleUser,
// }),
// },
],
onError: {
target: '#authMachine.active.register.usernameStep',
actions: 'assignError',
},
},
entry: assign({
googleUser: () => undefined,
registerUser: () => undefined,
}),
},
passkeyStep: {
states: {
start: {
invoke: {
src: 'startRegisterPasskey',
onDone: {
target: '#authMachine.active.register.passkeyStep.idle',
actions: assign({
CCRPublicKey: (_context, event) => event.data.ccr,
sessionId: (_, event) => event.data.sessionId,
userId: (_, event) => event.data.userId,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.initial.idle',
actions: 'assignError',
},
},
},
idle: {
on: {
USER_INPUT_PASSKEY_REGISTER:
'#authMachine.active.register.passkeyStep.userInput',
START_PASSKEY_REGISTER: {
target: '#authMachine.active.register.passkeyStep.start',
},
},
},
userInput: {
invoke: {
src: 'userInputRegisterPasskey',
onDone: {
target: '#authMachine.active.register.passkeyStep.userInputSuccess',
actions: assign({
passkeyRegistrationResult: (_context, event) => event.data,
error: () => undefined,
}),
},
onError: {
target: '#authMachine.active.initial.idle',
actions: 'assignError',
},
},
},
userInputSuccess: {
on: {
FINISH_PASSKEY_REGISTER:
'#authMachine.active.register.passkeyStep.passkeyResult',
},
},
passkeyResult: {
invoke: {
src: 'finishRegisterPasskey',
onDone: {
target: '#authMachine.active.register.passkeyStep.success',
actions: 'resetError',
},
onError: {
target: '#authMachine.active.initial.idle',
actions: 'assignError',
},
},
},
success: {
type: 'final',
on: {
START_PASSKEY_LOGIN: {
target: '#authMachine.active.login.passkeyStep',
actions: assign({
userEmail: (context, event) =>
event.payload ? event.payload.email : context.userEmail,
isFirstLogin: () => true,
}),
},
},
},
},
exit: assign({
error: () => undefined,
CCRPublicKey: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
RCRPublicKey: () => undefined,
}),
initial: 'start',
},
},
initial: 'emailStep',
},
signedOn: {
type: 'final',
entry: assign({
googleUser: () => undefined,
registerUser: () => undefined,
CCRPublicKey: () => undefined,
RCRPublicKey: () => undefined,
error: () => undefined,
googleOtpCode: () => undefined,
passkeyRegistrationResult: () => undefined,
salt: () => undefined,
userEmail: () => undefined,
passkeyLoginResult: () => undefined,
sessionId: () => undefined,
}),
on: {
LOGOUT: {
target: '#authMachine.inactive',
actions: assign({
sessionUser: () => undefined,
CCRPublicKey: () => undefined,
error: () => undefined,
googleOtpCode: () => undefined,
googleUser: () => undefined,
RCRPublicKey: () => undefined,
salt: () => undefined,
sessionId: () => undefined,
userEmail: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
registerUser: () => undefined,
}),
},
INACTIVATE_USER: 'inactivatingUser',
},
},
inactivatingUser: {
invoke: {
src: 'inactivateUser',
onDone: {
target: '#authMachine.inactive',
actions: assign({
sessionUser: () => undefined,
CCRPublicKey: () => undefined,
error: () => undefined,
googleOtpCode: () => undefined,
googleUser: () => undefined,
RCRPublicKey: () => undefined,
salt: () => undefined,
sessionId: () => undefined,
userEmail: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
registerUser: () => undefined,
}),
},
onError: {
target: '#authMachine.active.signedOn',
actions: 'assignError',
},
},
},
},
initial: 'initial',
},
error: {},
},
initial: 'inactive',
on: {
RESET_CONTEXT: {
target: '#authMachine.inactive',
actions: assign({
sessionUser: () => undefined,
CCRPublicKey: () => undefined,
error: () => undefined,
googleOtpCode: () => undefined,
googleUser: () => undefined,
RCRPublicKey: () => undefined,
salt: () => undefined,
sessionId: () => undefined,
userEmail: () => undefined,
passkeyLoginResult: () => undefined,
passkeyRegistrationResult: () => undefined,
registerUser: () => undefined,
}),
},
},
},
{
services: {
healthCheck: async (_context, _event) => {
throw new Error('Not implemented');
},
startPasskeyAuth: async (_context, _event) => {
throw new Error('Not implemented');
},
userInputLoginPasskey: async (_context, _event) => {
throw new Error('Not implemented');
},
finishPasskeyAuth: async (_context, _event) => {
throw new Error('Not implemented');
},
completeRegistration: async (_context, _event) => {
throw new Error('Not implemented');
},
sendConfirmationEmail: async (_context, _event) => {
throw new Error('Not implemented');
},
startRegisterPasskey: async (_context, _event) => {
throw new Error('Not implemented');
},
retrieveSalt: async (_context, _event) => {
throw new Error('Not implemented');
},
finishRegisterPasskey: async (_context, _event) => {
throw new Error('Not implemented');
},
userInputRegisterPasskey: async (_context, _event) => {
throw new Error('Not implemented');
},
googleLogin: async (_context, _event) => {
throw new Error('Not implemented');
},
verifyEmail: async (_context, _event) => {
throw new Error('Not implemented');
},
verifyLogin: async (_context, _event) => {
throw new Error('Not implemented');
},
verifyEmail2fa: async (_context, _event) => {
throw new Error('Not implemented');
},
inactivateUser: async (_context, _event) => {
throw new Error('Not implemented');
},
},
guards: {},
actions: {},
},
);
export const getResolvedState = async () => {
const state = await AsyncStorage.getItem('authState');
let resolvedState;
if (state) {
const stateDefinition = JSON.parse(state);
const previousState = State.create(stateDefinition);
// @ts-ignore
resolvedState = authMachine.resolveState(previousState);
}
return resolvedState;
};
export const authService = (
services: {},
context: AuthMachineContext,
resolvedState?: Awaited<ReturnType<typeof getResolvedState>>,
) => {
const mergedContext = {
...authMachine.context,
...initialContext,
...context,
};
return interpret(
authMachine.withConfig(
{
services,
guards: {
// @ts-ignore
isNewUser: (_, event) => !!event.data.isNewUser,
// @ts-ignore
isPasskeyMethod: (context, _) =>
!!context.authProviderConfigs?.enablePasskeys && Passkey.isSupported(),
requireEmailVerification: (context, _) => {
return !!context.authProviderConfigs?.requireEmailVerification;
},
requireUsername: (context, _) => {
return !!context.authProviderConfigs?.requireUsername;
},
},
actions: {
resetError: assign((_, event) => {
return { error: undefined };
}),
assignError: assign((_, event) => {
const { data: rawError } = event as DoneInvokeEvent<any>;
if (!rawError) {
return { error: { type: 'UNKNOWN_ERROR', message: 'No data found' } };
}
if (rawError instanceof AloreAuthError) {
return {
error: {
type: rawError.type,
message: rawError.message,
},
};
}
return {
error: {
type: 'UNKNOWN_ERROR',
message:
rawError?.error ||
rawError?.message ||
rawError?.data ||
(typeof rawError === 'string' ? rawError : 'Unknown error'),
},
};
}),
},
},
mergedContext,
),
)
.onTransition(async (state) => {
if (state.changed && state.matches('active.signedOn')) {
await AsyncStorage.setItem('authState', JSON.stringify(state));
}
})
.start(resolvedState);
};