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

@ -44,10 +44,9 @@ export const authRouter = router({
const { name, email, password, signature, url } = input;
if (IS_BILLING_ENABLED() && url && url.length < 6) {
throw new AppError(
AppErrorCode.PREMIUM_PROFILE_URL,
'Only subscribers can have a username shorter than 6 characters',
);
throw new AppError(AppErrorCode.PREMIUM_PROFILE_URL, {
message: 'Only subscribers can have a username shorter than 6 characters',
});
}
const user = await createUser({ name, email, password, signature, url });
@ -66,7 +65,7 @@ export const authRouter = router({
const error = AppError.parseError(err);
if (error.code !== AppErrorCode.UNKNOWN_ERROR) {
throw AppError.parseErrorToTRPCError(error);
throw error;
}
let message =
@ -118,7 +117,7 @@ export const authRouter = router({
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
throw err;
}
}),

View File

@ -1,6 +1,5 @@
import { TRPCError } from '@trpc/server';
import { AppError } from '@documenso/lib/errors/app-error';
import { getFieldById } from '@documenso/lib/server-only/field/get-field-by-id';
import { removeSignedFieldWithToken } from '@documenso/lib/server-only/field/remove-signed-field-with-token';
import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document';
@ -96,7 +95,7 @@ export const fieldRouter = router({
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
throw err;
}
}),

View File

@ -100,10 +100,9 @@ export const profileRouter = router({
);
if (subscriptions.length === 0) {
throw new AppError(
AppErrorCode.PREMIUM_PROFILE_URL,
'Only subscribers can have a username shorter than 6 characters',
);
throw new AppError(AppErrorCode.PREMIUM_PROFILE_URL, {
message: 'Only subscribers can have a username shorter than 6 characters',
});
}
}
@ -123,7 +122,7 @@ export const profileRouter = router({
const error = AppError.parseError(err);
if (error.code !== AppErrorCode.UNKNOWN_ERROR) {
throw AppError.parseErrorToTRPCError(error);
throw error;
}
throw new TRPCError({

View File

@ -76,412 +76,238 @@ export const teamRouter = router({
acceptTeamInvitation: authenticatedProcedure
.input(ZAcceptTeamInvitationMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await acceptTeamInvitation({
teamId: input.teamId,
userId: ctx.user.id,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await acceptTeamInvitation({
teamId: input.teamId,
userId: ctx.user.id,
});
}),
declineTeamInvitation: authenticatedProcedure
.input(ZDeclineTeamInvitationMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await declineTeamInvitation({
teamId: input.teamId,
userId: ctx.user.id,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await declineTeamInvitation({
teamId: input.teamId,
userId: ctx.user.id,
});
}),
createBillingPortal: authenticatedProcedure
.input(ZCreateTeamBillingPortalMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await createTeamBillingPortal({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await createTeamBillingPortal({
userId: ctx.user.id,
...input,
});
}),
createTeam: authenticatedProcedure
.input(ZCreateTeamMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await createTeam({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await createTeam({
userId: ctx.user.id,
...input,
});
}),
createTeamEmailVerification: authenticatedProcedure
.input(ZCreateTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await createTeamEmailVerification({
teamId: input.teamId,
userId: ctx.user.id,
data: {
email: input.email,
name: input.name,
},
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await createTeamEmailVerification({
teamId: input.teamId,
userId: ctx.user.id,
data: {
email: input.email,
name: input.name,
},
});
}),
createTeamMemberInvites: authenticatedProcedure
.input(ZCreateTeamMemberInvitesMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await createTeamMemberInvites({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await createTeamMemberInvites({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
createTeamPendingCheckout: authenticatedProcedure
.input(ZCreateTeamPendingCheckoutMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await createTeamPendingCheckoutSession({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await createTeamPendingCheckoutSession({
userId: ctx.user.id,
...input,
});
}),
deleteTeam: authenticatedProcedure
.input(ZDeleteTeamMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeam({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeam({
userId: ctx.user.id,
...input,
});
}),
deleteTeamEmail: authenticatedProcedure
.input(ZDeleteTeamEmailMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeamEmail({
userId: ctx.user.id,
userEmail: ctx.user.email,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeamEmail({
userId: ctx.user.id,
userEmail: ctx.user.email,
...input,
});
}),
deleteTeamEmailVerification: authenticatedProcedure
.input(ZDeleteTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeamEmailVerification({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeamEmailVerification({
userId: ctx.user.id,
...input,
});
}),
deleteTeamMemberInvitations: authenticatedProcedure
.input(ZDeleteTeamMemberInvitationsMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeamMemberInvitations({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeamMemberInvitations({
userId: ctx.user.id,
...input,
});
}),
deleteTeamMembers: authenticatedProcedure
.input(ZDeleteTeamMembersMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeamMembers({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeamMembers({
userId: ctx.user.id,
...input,
});
}),
deleteTeamPending: authenticatedProcedure
.input(ZDeleteTeamPendingMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeamPending({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeamPending({
userId: ctx.user.id,
...input,
});
}),
deleteTeamTransferRequest: authenticatedProcedure
.input(ZDeleteTeamTransferRequestMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await deleteTeamTransferRequest({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await deleteTeamTransferRequest({
userId: ctx.user.id,
...input,
});
}),
findTeamInvoices: authenticatedProcedure
.input(ZFindTeamInvoicesQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await findTeamInvoices({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await findTeamInvoices({
userId: ctx.user.id,
...input,
});
}),
findTeamMemberInvites: authenticatedProcedure
.input(ZFindTeamMemberInvitesQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await findTeamMemberInvites({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await findTeamMemberInvites({
userId: ctx.user.id,
...input,
});
}),
findTeamMembers: authenticatedProcedure
.input(ZFindTeamMembersQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await findTeamMembers({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
}),
findTeams: authenticatedProcedure.input(ZFindTeamsQuerySchema).query(async ({ input, ctx }) => {
try {
return await findTeams({
return await findTeamMembers({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
}),
throw AppError.parseErrorToTRPCError(err);
}
findTeams: authenticatedProcedure.input(ZFindTeamsQuerySchema).query(async ({ input, ctx }) => {
return await findTeams({
userId: ctx.user.id,
...input,
});
}),
findTeamsPending: authenticatedProcedure
.input(ZFindTeamsPendingQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await findTeamsPending({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await findTeamsPending({
userId: ctx.user.id,
...input,
});
}),
getTeam: authenticatedProcedure.input(ZGetTeamQuerySchema).query(async ({ input, ctx }) => {
try {
return await getTeamById({ teamId: input.teamId, userId: ctx.user.id });
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await getTeamById({ teamId: input.teamId, userId: ctx.user.id });
}),
getTeamEmailByEmail: authenticatedProcedure.query(async ({ ctx }) => {
try {
return await getTeamEmailByEmail({ email: ctx.user.email });
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await getTeamEmailByEmail({ email: ctx.user.email });
}),
getTeamInvitations: authenticatedProcedure.query(async ({ ctx }) => {
try {
return await getTeamInvitations({ email: ctx.user.email });
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await getTeamInvitations({ email: ctx.user.email });
}),
getTeamMembers: authenticatedProcedure
.input(ZGetTeamMembersQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await getTeamMembers({ teamId: input.teamId, userId: ctx.user.id });
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await getTeamMembers({ teamId: input.teamId, userId: ctx.user.id });
}),
getTeamPrices: authenticatedProcedure.query(async () => {
try {
return await getTeamPrices();
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await getTeamPrices();
}),
getTeams: authenticatedProcedure.query(async ({ ctx }) => {
try {
return await getTeams({ userId: ctx.user.id });
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await getTeams({ userId: ctx.user.id });
}),
leaveTeam: authenticatedProcedure
.input(ZLeaveTeamMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await leaveTeam({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await leaveTeam({
userId: ctx.user.id,
...input,
});
}),
updateTeam: authenticatedProcedure
.input(ZUpdateTeamMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await updateTeam({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await updateTeam({
userId: ctx.user.id,
...input,
});
}),
updateTeamEmail: authenticatedProcedure
.input(ZUpdateTeamEmailMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await updateTeamEmail({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await updateTeamEmail({
userId: ctx.user.id,
...input,
});
}),
updateTeamMember: authenticatedProcedure
.input(ZUpdateTeamMemberMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await updateTeamMember({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await updateTeamMember({
userId: ctx.user.id,
...input,
});
}),
updateTeamPublicProfile: authenticatedProcedure
@ -506,7 +332,7 @@ export const teamRouter = router({
const error = AppError.parseError(err);
if (error.code !== AppErrorCode.UNKNOWN_ERROR) {
throw AppError.parseErrorToTRPCError(error);
throw error;
}
throw new TRPCError({
@ -520,48 +346,30 @@ export const teamRouter = router({
requestTeamOwnershipTransfer: authenticatedProcedure
.input(ZRequestTeamOwnerhsipTransferMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
return await requestTeamOwnershipTransfer({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await requestTeamOwnershipTransfer({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
resendTeamEmailVerification: authenticatedProcedure
.input(ZResendTeamEmailVerificationMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
await resendTeamEmailVerification({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
await resendTeamEmailVerification({
userId: ctx.user.id,
...input,
});
}),
resendTeamMemberInvitation: authenticatedProcedure
.input(ZResendTeamMemberInvitationMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
await resendTeamMemberInvitation({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
await resendTeamMemberInvitation({
userId: ctx.user.id,
userName: ctx.user.name ?? '',
...input,
});
}),
updateTeamBrandingSettings: authenticatedProcedure
@ -569,17 +377,11 @@ export const teamRouter = router({
.mutation(async ({ ctx, input }) => {
const { teamId, settings } = input;
try {
return await updateTeamBrandingSettings({
userId: ctx.user.id,
teamId,
settings,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await updateTeamBrandingSettings({
userId: ctx.user.id,
teamId,
settings,
});
}),
updateTeamDocumentSettings: authenticatedProcedure
@ -587,16 +389,10 @@ export const teamRouter = router({
.mutation(async ({ ctx, input }) => {
const { teamId, settings } = input;
try {
return await updateTeamDocumentSettings({
userId: ctx.user.id,
teamId,
settings,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await updateTeamDocumentSettings({
userId: ctx.user.id,
teamId,
settings,
});
}),
});

View File

@ -42,323 +42,214 @@ export const templateRouter = router({
createTemplate: authenticatedProcedure
.input(ZCreateTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { teamId, title, templateDocumentDataId } = input;
const { teamId, title, templateDocumentDataId } = input;
return await createTemplate({
userId: ctx.user.id,
teamId,
title,
templateDocumentDataId,
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to create this template. Please try again later.',
});
}
return await createTemplate({
userId: ctx.user.id,
teamId,
title,
templateDocumentDataId,
});
}),
createDocumentFromDirectTemplate: maybeAuthenticatedProcedure
.input(ZCreateDocumentFromDirectTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const {
directRecipientName,
directRecipientEmail,
directTemplateToken,
directTemplateExternalId,
signedFieldValues,
templateUpdatedAt,
} = input;
const {
directRecipientName,
directRecipientEmail,
directTemplateToken,
directTemplateExternalId,
signedFieldValues,
templateUpdatedAt,
} = input;
const requestMetadata = extractNextApiRequestMetadata(ctx.req);
const requestMetadata = extractNextApiRequestMetadata(ctx.req);
return await createDocumentFromDirectTemplate({
directRecipientName,
directRecipientEmail,
directTemplateToken,
directTemplateExternalId,
signedFieldValues,
templateUpdatedAt,
user: ctx.user
? {
id: ctx.user.id,
name: ctx.user.name || undefined,
email: ctx.user.email,
}
: undefined,
requestMetadata,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await createDocumentFromDirectTemplate({
directRecipientName,
directRecipientEmail,
directTemplateToken,
directTemplateExternalId,
signedFieldValues,
templateUpdatedAt,
user: ctx.user
? {
id: ctx.user.id,
name: ctx.user.name || undefined,
email: ctx.user.email,
}
: undefined,
requestMetadata,
});
}),
createDocumentFromTemplate: authenticatedProcedure
.input(ZCreateDocumentFromTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, teamId, recipients } = input;
const { templateId, teamId, recipients } = input;
const limits = await getServerLimits({ email: ctx.user.email, teamId });
const limits = await getServerLimits({ email: ctx.user.email, teamId });
if (limits.remaining.documents === 0) {
throw new Error('You have reached your document limit.');
}
const requestMetadata = extractNextApiRequestMetadata(ctx.req);
let document: Document = await createDocumentFromTemplate({
templateId,
teamId,
userId: ctx.user.id,
recipients,
requestMetadata,
});
if (input.distributeDocument) {
document = await sendDocument({
documentId: document.id,
userId: ctx.user.id,
teamId,
requestMetadata,
}).catch((err) => {
console.error(err);
throw new AppError('DOCUMENT_SEND_FAILED');
});
}
return document;
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
if (limits.remaining.documents === 0) {
throw new Error('You have reached your document limit.');
}
const requestMetadata = extractNextApiRequestMetadata(ctx.req);
let document: Document = await createDocumentFromTemplate({
templateId,
teamId,
userId: ctx.user.id,
recipients,
requestMetadata,
});
if (input.distributeDocument) {
document = await sendDocument({
documentId: document.id,
userId: ctx.user.id,
teamId,
requestMetadata,
}).catch((err) => {
console.error(err);
throw new AppError('DOCUMENT_SEND_FAILED');
});
}
return document;
}),
duplicateTemplate: authenticatedProcedure
.input(ZDuplicateTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { teamId, templateId } = input;
const { teamId, templateId } = input;
return await duplicateTemplate({
userId: ctx.user.id,
teamId,
templateId,
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to duplicate the template. Please try again later.',
});
}
return await duplicateTemplate({
userId: ctx.user.id,
teamId,
templateId,
});
}),
deleteTemplate: authenticatedProcedure
.input(ZDeleteTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { id, teamId } = input;
const { id, teamId } = input;
const userId = ctx.user.id;
const userId = ctx.user.id;
return await deleteTemplate({ userId, id, teamId });
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to delete this template. Please try again later.',
});
}
return await deleteTemplate({ userId, id, teamId });
}),
getTemplateWithDetailsById: authenticatedProcedure
.input(ZGetTemplateWithDetailsByIdQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await getTemplateWithDetailsById({
id: input.id,
userId: ctx.user.id,
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to find this template. Please try again later.',
});
}
return await getTemplateWithDetailsById({
id: input.id,
userId: ctx.user.id,
});
}),
// Todo: Add API
updateTemplateSettings: authenticatedProcedure
.input(ZUpdateTemplateSettingsMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, teamId, data, meta } = input;
const { templateId, teamId, data, meta } = input;
const userId = ctx.user.id;
const userId = ctx.user.id;
const requestMetadata = extractNextApiRequestMetadata(ctx.req);
const requestMetadata = extractNextApiRequestMetadata(ctx.req);
return await updateTemplateSettings({
userId,
teamId,
templateId,
data,
meta: {
...meta,
language: isValidLanguageCode(meta?.language) ? meta?.language : undefined,
},
requestMetadata,
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update the settings for this template. Please try again later.',
});
}
return await updateTemplateSettings({
userId,
teamId,
templateId,
data,
meta: {
...meta,
language: isValidLanguageCode(meta?.language) ? meta?.language : undefined,
},
requestMetadata,
});
}),
setSigningOrderForTemplate: authenticatedProcedure
.input(ZSetSigningOrderForTemplateMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, teamId, signingOrder } = input;
const { templateId, teamId, signingOrder } = input;
return await updateTemplateSettings({
templateId,
teamId,
data: {},
meta: { signingOrder },
userId: ctx.user.id,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update the settings for this document. Please try again later.',
});
}
return await updateTemplateSettings({
templateId,
teamId,
data: {},
meta: { signingOrder },
userId: ctx.user.id,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
}),
findTemplates: authenticatedProcedure
.input(ZFindTemplatesQuerySchema)
.query(async ({ input, ctx }) => {
try {
return await findTemplates({
userId: ctx.user.id,
...input,
});
} catch (err) {
console.error(err);
throw AppError.parseErrorToTRPCError(err);
}
return await findTemplates({
userId: ctx.user.id,
...input,
});
}),
createTemplateDirectLink: authenticatedProcedure
.input(ZCreateTemplateDirectLinkMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, teamId, directRecipientId } = input;
const { templateId, teamId, directRecipientId } = input;
const userId = ctx.user.id;
const userId = ctx.user.id;
const template = await getTemplateById({ id: templateId, teamId, userId: ctx.user.id });
const template = await getTemplateById({ id: templateId, teamId, userId: ctx.user.id });
const limits = await getServerLimits({ email: ctx.user.email, teamId: template.teamId });
const limits = await getServerLimits({ email: ctx.user.email, teamId: template.teamId });
if (limits.remaining.directTemplates === 0) {
throw new AppError(
AppErrorCode.LIMIT_EXCEEDED,
'You have reached your direct templates limit.',
);
}
return await createTemplateDirectLink({ userId, templateId, directRecipientId });
} catch (err) {
console.error(err);
const error = AppError.parseError(err);
throw AppError.parseErrorToTRPCError(error);
if (limits.remaining.directTemplates === 0) {
throw new AppError(AppErrorCode.LIMIT_EXCEEDED, {
message: 'You have reached your direct templates limit.',
});
}
return await createTemplateDirectLink({ userId, templateId, directRecipientId });
}),
deleteTemplateDirectLink: authenticatedProcedure
.input(ZDeleteTemplateDirectLinkMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId } = input;
const { templateId } = input;
const userId = ctx.user.id;
const userId = ctx.user.id;
return await deleteTemplateDirectLink({ userId, templateId });
} catch (err) {
console.error(err);
const error = AppError.parseError(err);
throw AppError.parseErrorToTRPCError(error);
}
return await deleteTemplateDirectLink({ userId, templateId });
}),
toggleTemplateDirectLink: authenticatedProcedure
.input(ZToggleTemplateDirectLinkMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, enabled } = input;
const { templateId, enabled } = input;
const userId = ctx.user.id;
const userId = ctx.user.id;
return await toggleTemplateDirectLink({ userId, templateId, enabled });
} catch (err) {
console.error(err);
const error = AppError.parseError(err);
throw AppError.parseErrorToTRPCError(error);
}
return await toggleTemplateDirectLink({ userId, templateId, enabled });
}),
moveTemplateToTeam: authenticatedProcedure
.input(ZMoveTemplatesToTeamSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, teamId } = input;
const userId = ctx.user.id;
const { templateId, teamId } = input;
const userId = ctx.user.id;
return await moveTemplateToTeam({
templateId,
teamId,
userId,
});
} catch (err) {
console.error(err);
if (err instanceof TRPCError) {
throw err;
}
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to move this template. Please try again later.',
});
}
return await moveTemplateToTeam({
templateId,
teamId,
userId,
});
}),
updateTemplateTypedSignatureSettings: authenticatedProcedure

View File

@ -1,12 +1,37 @@
import { TRPCError, initTRPC } from '@trpc/server';
import SuperJSON from 'superjson';
import { AppError, genericErrorCodeToTrpcErrorCodeMap } from '@documenso/lib/errors/app-error';
import { isAdmin } from '@documenso/lib/next-auth/guards/is-admin';
import type { TrpcContext } from './context';
const t = initTRPC.context<TrpcContext>().create({
transformer: SuperJSON,
errorFormatter(opts) {
const { shape, error } = opts;
const originalError = error.cause;
let data: Record<string, unknown> = shape.data;
if (originalError instanceof AppError) {
data = {
...data,
appError: AppError.toJSON(originalError),
code: originalError.code,
httpStatus:
originalError.statusCode ??
genericErrorCodeToTrpcErrorCodeMap[originalError.code]?.status ??
500,
};
}
return {
...shape,
data,
};
},
});
/**

View File

@ -98,7 +98,7 @@ export const twoFactorAuthenticationRouter = router({
console.error(err);
}
throw AppError.parseErrorToTRPCError(err);
throw error;
}
}),
});