import { InvitationTicketClaims, LoggerType, UserRoleIdEnum, getErrorMessage } from '@bit-ui-libs/common'; import { jwtDecode } from 'jwt-decode'; import { Result, err, ok } from 'neverthrow'; import { useServicesStore } from '../../stores'; const INVITE_CLAIMS_KEYS = ['id', 'email', 'iat', 'exp']; type isFirstOrgUserTicketResult = Result<{ orgId: string }, unknown>; // and checks if it's a "First Organization User" invitation export async function isFirstOrgUserTicket(ticket: string, logger?: LoggerType): Promise { try { // We're not sure what it is yet, so check it manually and verify it's type is InvitationTicketClaims logger?.debug('Verifying that ticket is "InvitationTicketClaims"'); const decodedJwt = jwtDecode>(ticket); logger?.debug('Decoded JWT:', JSON.stringify(decodedJwt)); const decodedKeys = Object.keys(decodedJwt); if (!INVITE_CLAIMS_KEYS.every((key) => decodedKeys.includes(key))) { logger?.warn( 'Ticket is NOT "InvitationTicketClaims", missing key:', INVITE_CLAIMS_KEYS.find((key) => !decodedKeys.includes(key)) ); return err(null); } const claims = decodedJwt as InvitationTicketClaims; logger?.debug('Calling userProfileService.getInviteById:', claims.id); const invite = await useServicesStore.getState().endUser.getInviteById(claims.id); logger?.debug('Invite:', JSON.stringify(invite)); if (!invite.orgId) { logger?.warn('For some reason, Organization ID is missing, therefore NOT first org user ticket'); return err(null); } if (!invite.roleIds.some((id) => parseInt(id) === UserRoleIdEnum.FirstOrgUser)) { logger?.warn('Could not find FirstOrgUser Role ID (id=1), therefore NOT first org user ticket'); return err(null); } return ok({ orgId: invite.orgId }); } catch (error) { logger?.error(error); return err(getErrorMessage(error)); } }