I am getting a really weird error after trying to redirect on loginSuccess. Basically, here is the flow I have :
- The user fills a login form, then dispatch a 'Login' action.
- Login effect call AuthService, which is responsible to log with Firebase
- If Firebase login is successful, a new action is dispatch: loginSuccess
- LoginSuccess effect should then call my backend ('query me'), in order to get profile infos for the user
- After the call, the effect dispatch UserLoaded action (for the reducer to update the state), then redirect to home page
I am using Apollo GraphQL to communicate with my backend ; everything is working fine if I don't use the router.navigate. But when I use it, I get this error which doesn't really make any sense to me :
ERROR Error: Uncaught (in promise): TypeError: Cannot add property 0, object is not extensible
TypeError: Cannot add property 0, object is not extensible
Here is the responsible code :
loginSuccess$ = createEffect(() =>
this.actions$.pipe(
ofType(AuthLoginActions.loginSuccess),
switchMap(({ credentials }) =>
this.authService.me().pipe(
map((user: MeQuery['me']) => AuthActions.userLoaded({ user })),
catchError((error) => {
return of(AuthActions.error({ error }));
})
)
),
tap(() => this.router.navigate(['/']))
)
);
Here is the AuthService me() :
me(): Observable<MeQuery['me']> {
return this.meGql.watch().valueChanges.pipe(
map((result) => {
console.log('result:');
console.log(result);
return result.data.me;
})
);
}
What I found is that these error could happen when you try to modify immutable objects, but here this is not the case. Really when I delete the router navigation inside the tap, no more error. I'm wondering if this could be a timing issue between the time AuthActions.userLoaded is dispatch and the router navigation.
I also tryed to navigate with an effet on userLoaded action, but had no more success.
EDIT : if I remove the guard on user routes, it works. So here's more code from routes and the guard in question (using angular/fire) :
app.routes.ts
export const appRoutes: Route[] = [
{
path: 'auth',
loadChildren: () =>
import('@booking/booking-frontend-auth-feature-shell').then(
(m) => m.bookingFrontendAuthFeatureShellRoutes
),
},
{
path: '',
loadChildren: userSpaceRoutes,
...canActivate(userSpaceGuard),
},
];
app.guards.ts
export const userSpaceGuard = () =>
pipe(
switchMap(async (user: User | null) => {
console.log('switchMap');
if (!user) {
console.log('no user');
return null;
}
console.log('return transformed user');
// Transform user to get idTokenResult
return {
user: user,
idTokenResult: await user.getIdTokenResult(),
};
}),
map((userInfos: any) => {
console.log('userInfos: ');
console.log(userInfos);
// No user, redirect to login
if (!userInfos?.user) {
console.log('no user');
return [`auth/login`];
}
// If user is admin, redirect to admin space
const claims = userInfos.idTokenResult.claims;
console.log('claims:');
console.log(claims);
if (claims && claims.role === UserRole.Admin) {
console.log('return admin');
return ['admin'];
}
console.log('return true');
return true;
})
);
Any idea ?
Thanks
I finally found the answer by myself, investing a bit more : it was Firebase Auth that was causing the issue. In fact, on loginSuccess I was storing UserCredentials (from Firebase) in my store. Looks like Firebase is trying then to update those credentials at some time, resulting in this immutability error.
I realized that I didn't need those credentials in my store, so I just removed them and now everything is working fine.