feat: add initial api logging (#1494)

Improve API logging and error handling between client and server side.
This commit is contained in:
David Nguyen
2024-11-28 16:05:37 +07:00
committed by GitHub
parent 04293968c6
commit 98d85b086d
53 changed files with 933 additions and 780 deletions

View File

@ -47,6 +47,8 @@ export const createTeamPendingCheckoutSession = async ({
console.error(e);
// Absorb all the errors incase Stripe throws something sensitive.
throw new AppError(AppErrorCode.UNKNOWN_ERROR, 'Something went wrong.');
throw new AppError(AppErrorCode.UNKNOWN_ERROR, {
message: 'Something went wrong.',
});
}
};

View File

@ -55,10 +55,9 @@ export const createTeamEmailVerification = async ({
});
if (team.teamEmail || team.emailVerification) {
throw new AppError(
AppErrorCode.INVALID_REQUEST,
'Team already has an email or existing email verification.',
);
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Team already has an email or existing email verification.',
});
}
const existingTeamEmail = await tx.teamEmail.findFirst({
@ -68,7 +67,9 @@ export const createTeamEmailVerification = async ({
});
if (existingTeamEmail) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'Email already taken by another team.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'Email already taken by another team.',
});
}
const { token, expiresAt } = createTokenVerification({ hours: 1 });
@ -97,7 +98,9 @@ export const createTeamEmailVerification = async ({
const target = z.array(z.string()).safeParse(err.meta?.target);
if (err.code === 'P2002' && target.success && target.data.includes('email')) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'Email already taken by another team.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'Email already taken by another team.',
});
}
throw err;

View File

@ -69,7 +69,9 @@ export const createTeamMemberInvites = async ({
const currentTeamMember = team.members.find((member) => member.user.id === userId);
if (!currentTeamMember) {
throw new AppError(AppErrorCode.UNAUTHORIZED, 'User not part of team.');
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'User not part of team.',
});
}
const usersToInvite = invitations.filter((invitation) => {
@ -91,10 +93,9 @@ export const createTeamMemberInvites = async ({
);
if (unauthorizedRoleAccess) {
throw new AppError(
AppErrorCode.UNAUTHORIZED,
'User does not have permission to set high level roles',
);
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'User does not have permission to set high level roles',
});
}
const teamMemberInvites = usersToInvite.map(({ email, role }) => ({
@ -127,11 +128,10 @@ export const createTeamMemberInvites = async ({
if (sendEmailResultErrorList.length > 0) {
console.error(JSON.stringify(sendEmailResultErrorList));
throw new AppError(
'EmailDeliveryFailed',
'Failed to send invite emails to one or more users.',
`Failed to send invites to ${sendEmailResultErrorList.length}/${teamMemberInvites.length} users.`,
);
throw new AppError('EmailDeliveryFailed', {
message: 'Failed to send invite emails to one or more users.',
userMessage: `Failed to send invites to ${sendEmailResultErrorList.length}/${teamMemberInvites.length} users.`,
});
}
};

View File

@ -87,7 +87,9 @@ export const createTeam = async ({
});
if (existingUserProfileWithUrl) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'URL already taken.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'URL already taken.',
});
}
await tx.team.create({
@ -131,15 +133,21 @@ export const createTeam = async ({
});
if (existingUserProfileWithUrl) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'URL already taken.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'URL already taken.',
});
}
if (existingTeamWithUrl) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'Team URL already exists.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'Team URL already exists.',
});
}
if (!customerId) {
throw new AppError(AppErrorCode.UNKNOWN_ERROR, 'Missing customer ID for pending teams.');
throw new AppError(AppErrorCode.UNKNOWN_ERROR, {
message: 'Missing customer ID for pending teams.',
});
}
return await tx.teamPending.create({
@ -166,7 +174,9 @@ export const createTeam = async ({
const target = z.array(z.string()).safeParse(err.meta?.target);
if (err.code === 'P2002' && target.success && target.data.includes('url')) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'Team URL already exists.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'Team URL already exists.',
});
}
throw err;

View File

@ -60,11 +60,13 @@ export const deleteTeamMembers = async ({
);
if (!currentTeamMember) {
throw new AppError(AppErrorCode.NOT_FOUND, 'Team member record does not exist');
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Team member record does not exist',
});
}
if (teamMembersToRemove.find((member) => member.userId === team.ownerUserId)) {
throw new AppError(AppErrorCode.UNAUTHORIZED, 'Cannot remove the team owner');
throw new AppError(AppErrorCode.UNAUTHORIZED, { message: 'Cannot remove the team owner' });
}
const isMemberToRemoveHigherRole = teamMembersToRemove.some(
@ -72,7 +74,9 @@ export const deleteTeamMembers = async ({
);
if (isMemberToRemoveHigherRole) {
throw new AppError(AppErrorCode.UNAUTHORIZED, 'Cannot remove a member with a higher role');
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'Cannot remove a member with a higher role',
});
}
// Remove the team members.

View File

@ -24,7 +24,9 @@ export const findTeamInvoices = async ({ userId, teamId }: FindTeamInvoicesOptio
});
if (!team.customerId) {
throw new AppError(AppErrorCode.NOT_FOUND, 'Team has no customer ID.');
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Team has no customer ID.',
});
}
const results = await getInvoices({ customerId: team.customerId });

View File

@ -33,7 +33,9 @@ export const getTeamPublicProfile = async ({
});
if (!team) {
throw new AppError(AppErrorCode.NOT_FOUND, 'Team not found');
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Team not found',
});
}
// Create and return the public profile.
@ -47,7 +49,9 @@ export const getTeamPublicProfile = async ({
});
if (!profile) {
throw new AppError(AppErrorCode.NOT_FOUND, 'Failed to create public profile');
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Failed to create public profile',
});
}
return {

View File

@ -38,16 +38,17 @@ export const resendTeamEmailVerification = async ({
});
if (!team) {
throw new AppError('TeamNotFound', 'User is not a member of the team.');
throw new AppError('TeamNotFound', {
message: 'User is not a member of the team.',
});
}
const { emailVerification } = team;
if (!emailVerification) {
throw new AppError(
'VerificationNotFound',
'No team email verification exists for this team.',
);
throw new AppError('VerificationNotFound', {
message: 'No team email verification exists for this team.',
});
}
const { token, expiresAt } = createTokenVerification({ hours: 1 });

View File

@ -55,7 +55,7 @@ export const resendTeamMemberInvitation = async ({
});
if (!team) {
throw new AppError('TeamNotFound', 'User is not a valid member of the team.');
throw new AppError('TeamNotFound', { message: 'User is not a valid member of the team.' });
}
const teamMemberInvite = await tx.teamMemberInvite.findUniqueOrThrow({
@ -66,7 +66,7 @@ export const resendTeamMemberInvitation = async ({
});
if (!teamMemberInvite) {
throw new AppError('InviteNotFound', 'No invite exists for this user.');
throw new AppError('InviteNotFound', { message: 'No invite exists for this user.' });
}
await sendTeamMemberInviteEmail({

View File

@ -48,11 +48,11 @@ export const updateTeamMember = async ({
const teamMemberToUpdate = team.members.find((member) => member.id === teamMemberId);
if (!teamMemberToUpdate || !currentTeamMember) {
throw new AppError(AppErrorCode.NOT_FOUND, 'Team member does not exist');
throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Team member does not exist' });
}
if (teamMemberToUpdate.userId === team.ownerUserId) {
throw new AppError(AppErrorCode.UNAUTHORIZED, 'Cannot update the owner');
throw new AppError(AppErrorCode.UNAUTHORIZED, { message: 'Cannot update the owner' });
}
const isMemberToUpdateHigherRole = !isTeamRoleWithinUserHierarchy(
@ -61,7 +61,9 @@ export const updateTeamMember = async ({
);
if (isMemberToUpdateHigherRole) {
throw new AppError(AppErrorCode.UNAUTHORIZED, 'Cannot update a member with a higher role');
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'Cannot update a member with a higher role',
});
}
const isNewMemberRoleHigherThanCurrentRole = !isTeamRoleWithinUserHierarchy(
@ -70,10 +72,9 @@ export const updateTeamMember = async ({
);
if (isNewMemberRoleHigherThanCurrentRole) {
throw new AppError(
AppErrorCode.UNAUTHORIZED,
'Cannot give a member a role higher than the user initating the update',
);
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'Cannot give a member a role higher than the user initating the update',
});
}
return await tx.teamMember.update({

View File

@ -24,7 +24,9 @@ export const updateTeam = async ({ userId, teamId, data }: UpdateTeamOptions) =>
});
if (foundPendingTeamWithUrl) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'Team URL already exists.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'Team URL already exists.',
});
}
const team = await tx.team.update({
@ -57,7 +59,9 @@ export const updateTeam = async ({ userId, teamId, data }: UpdateTeamOptions) =>
const target = z.array(z.string()).safeParse(err.meta?.target);
if (err.code === 'P2002' && target.success && target.data.includes('url')) {
throw new AppError(AppErrorCode.ALREADY_EXISTS, 'Team URL already exists.');
throw new AppError(AppErrorCode.ALREADY_EXISTS, {
message: 'Team URL already exists.',
});
}
throw err;