UNPKG

@accounter/server

Version:
123 lines 5.59 kB
import { GraphQLError } from 'graphql'; import { ALLOWED_ROLES, invalidTokenError, mapAuth0Error } from '../helpers/invitations.helper.js'; import { AcceptInvitationsProvider } from '../providers/accept-invitations.provider.js'; import { AuthContextProvider } from '../providers/auth-context.provider.js'; import { Auth0ManagementProvider } from '../providers/auth0-management.provider.js'; import { InvitationsProvider } from '../providers/invitations.provider.js'; export const invitationsResolvers = { Query: { listInvitations: async (_, __, { injector }) => { try { return await injector.get(InvitationsProvider).listInvitations(); } catch (error) { if (error instanceof GraphQLError) { throw error; } throw new GraphQLError('Failed to list invitations', { originalError: error instanceof Error ? error : undefined, extensions: { code: 'INVITATION_LIST_FAILED' }, }); } }, }, Mutation: { createInvitation: async (_, { email, roleId }, { injector }) => { const authContext = await injector.get(AuthContextProvider).getAuthContext(); if (!authContext?.user || !authContext.tenant?.businessId) { throw new GraphQLError('Authentication required', { extensions: { code: 'UNAUTHENTICATED' }, }); } if (authContext.user.roleId !== 'business_owner') { throw new GraphQLError('Requires role: business_owner', { extensions: { code: 'FORBIDDEN' }, }); } if (!ALLOWED_ROLES.has(roleId)) { throw new GraphQLError(`Invalid roleId: ${roleId}`, { extensions: { code: 'BAD_USER_INPUT' }, }); } const normalizedEmail = email.trim().toLowerCase(); const businessId = authContext.tenant.businessId; const invitedByUserId = authContext.user.userId; const existingInvitation = await injector .get(InvitationsProvider) .getInvitationByEmailLoader.load(normalizedEmail); if ((existingInvitation?.length ?? 0) > 0) { throw new GraphQLError('An active invitation already exists for this user', { extensions: { code: 'INVITATION_ALREADY_PENDING' }, }); } let auth0UserId; try { auth0UserId = await injector .get(Auth0ManagementProvider) .createBlockedUser(normalizedEmail); } catch (error) { throw mapAuth0Error(error); } try { return await injector.get(InvitationsProvider).insertInvitation({ email: normalizedEmail, roleId, auth0UserId, invitedByUserId, ownerId: businessId, }); } catch (error) { // If DB operations fail, attempt to clean up the created Auth0 user to prevent dangling resources. await injector .get(Auth0ManagementProvider) .deleteUser(auth0UserId) .catch(cleanupError => { console.error(`Failed to cleanup Auth0 user ${auth0UserId} after DB error:`, cleanupError); }); // Re-throw the original error to ensure the GraphQL operation fails correctly. throw error; } }, acceptInvitation: async (_, { token }, { injector }) => { const authContextProvider = injector.get(AuthContextProvider); const authContext = await authContextProvider.getAuthContext(); const jwtIdentity = authContext ? null : await authContextProvider.getJwtIdentity(); const auth0UserId = authContext?.user?.auth0UserId ?? jwtIdentity?.auth0UserId ?? null; const authenticatedUserEmail = authContext?.user?.email ?? jwtIdentity?.email ?? null; const normalizedToken = token.trim(); if (!normalizedToken) { throw invalidTokenError(); } try { return await injector .get(AcceptInvitationsProvider) .acceptInvitation(normalizedToken, auth0UserId, authenticatedUserEmail); } catch (error) { if (error instanceof GraphQLError) { throw error; } throw new GraphQLError('Failed to accept invitation', { extensions: { code: 'INVITATION_ACCEPT_FAILED' }, }); } }, revokeInvitation: async (_, { id }, { injector }) => { try { return await injector.get(InvitationsProvider).revokeInvitation(id); } catch (error) { if (error instanceof GraphQLError) { throw error; } throw new GraphQLError('Failed to revoke invitation', { originalError: error instanceof Error ? error : undefined, extensions: { code: 'INVITATION_REVOCATION_FAILED' }, }); } }, }, }; //# sourceMappingURL=invitations.resolver.js.map