feat: add consistent response schemas (#1582)

This commit is contained in:
David Nguyen
2025-01-14 00:43:35 +11:00
committed by GitHub
parent 7d0a9c6439
commit 901be70f97
41 changed files with 532 additions and 619 deletions

View File

@ -12,7 +12,7 @@ import {
DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
SKIP_QUERY_BATCH_META,
} from '@documenso/lib/constants/trpc';
import type { TGetDocumentWithDetailsByIdResponse } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
import type { TDocument } from '@documenso/lib/types/document';
import { DocumentDistributionMethod, DocumentStatus } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
@ -35,7 +35,7 @@ import { useOptionalCurrentTeam } from '~/providers/team';
export type EditDocumentFormProps = {
className?: string;
initialDocument: TGetDocumentWithDetailsByIdResponse;
initialDocument: TDocument;
documentRootPath: string;
isDocumentEnterprise: boolean;
};

View File

@ -9,9 +9,9 @@ import { DateTime } from 'luxon';
import { useSession } from 'next-auth/react';
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import type { TFindDocumentsResponse } from '@documenso/lib/server-only/document/find-documents';
import type { Team } from '@documenso/prisma/client';
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
import type { TFindDocumentsResponse } from '@documenso/trpc/server/document-router/schema';
import type { DataTableColumnDef } from '@documenso/ui/primitives/data-table';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';

View File

@ -1,8 +1,13 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { createOpenApiNextHandler } from 'trpc-openapi';
import type { CreateOpenApiNextHandlerOptions } from 'trpc-openapi/dist/adapters/next';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import {
AppError,
AppErrorCode,
genericErrorCodeToTrpcErrorCodeMap,
} from '@documenso/lib/errors/app-error';
import { buildLogger } from '@documenso/lib/utils/logger';
import type { TRPCError } from '@documenso/trpc/server';
import { createTrpcContext } from '@documenso/trpc/server/context';
@ -41,7 +46,18 @@ export default createOpenApiNextHandler<typeof appRouter>({
});
}
},
responseMeta: () => {},
// Not sure why we need to do this since we handle it in errorFormatter which runs after this.
responseMeta: (opts: CreateOpenApiNextHandlerOptions<typeof appRouter>['responseMeta']) => {
if (opts.errors[0]?.cause instanceof AppError) {
const appError = AppError.parseError(opts.errors[0].cause);
const httpStatus = genericErrorCodeToTrpcErrorCodeMap[appError.code]?.status ?? 400;
return {
status: httpStatus,
};
}
},
});
const errorCodesToAlertOn = [AppErrorCode.UNKNOWN_ERROR, 'INTERNAL_SERVER_ERROR'];

68
package-lock.json generated
View File

@ -34070,36 +34070,6 @@
"zod": "^3.20.2"
}
},
"node_modules/zod-prisma-types": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/zod-prisma-types/-/zod-prisma-types-3.1.8.tgz",
"integrity": "sha512-5oe0ays3ur4u2GtuUqlhgCraKBcsuMaMI8o7VMV4YAnFeOuVid7K2zGvjI19V0ue9PeNF2ICyVREQVohaQm5dw==",
"dev": true,
"dependencies": {
"@prisma/generator-helper": "^5.14.0",
"code-block-writer": "^12.0.0",
"lodash": "^4.17.21",
"zod": "^3.23.8"
},
"bin": {
"zod-prisma-types": "dist/bin.js"
}
},
"node_modules/zod-prisma-types/node_modules/@prisma/debug": {
"version": "5.22.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz",
"integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==",
"dev": true
},
"node_modules/zod-prisma-types/node_modules/@prisma/generator-helper": {
"version": "5.22.0",
"resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-5.22.0.tgz",
"integrity": "sha512-LwqcBQ5/QsuAaLNQZAIVIAJDJBMjHwMwn16e06IYx/3Okj/xEEfw9IvrqB2cJCl3b2mCBlh3eVH0w9WGmi4aHg==",
"dev": true,
"dependencies": {
"@prisma/debug": "5.22.0"
}
},
"node_modules/zod-to-json-schema": {
"version": "3.24.1",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz",
@ -35478,7 +35448,24 @@
"prisma-kysely": "^1.8.0",
"tsx": "^4.11.0",
"typescript": "5.2.2",
"zod-prisma-types": "^3.1.8"
"zod-prisma-types": "3.1.9"
}
},
"packages/prisma/node_modules/@prisma/debug": {
"version": "5.22.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz",
"integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==",
"dev": true,
"license": "Apache-2.0"
},
"packages/prisma/node_modules/@prisma/generator-helper": {
"version": "5.22.0",
"resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-5.22.0.tgz",
"integrity": "sha512-LwqcBQ5/QsuAaLNQZAIVIAJDJBMjHwMwn16e06IYx/3Okj/xEEfw9IvrqB2cJCl3b2mCBlh3eVH0w9WGmi4aHg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "5.22.0"
}
},
"packages/prisma/node_modules/ts-pattern": {
@ -35499,6 +35486,25 @@
"node": ">=14.17"
}
},
"packages/prisma/node_modules/zod-prisma-types": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/zod-prisma-types/-/zod-prisma-types-3.1.9.tgz",
"integrity": "sha512-3AzTtWY2E9nySwLl9QEOgHJYOAX6sKkA36dnu7DD9HhGEOHmLqWx5pects60biMW29VcP57wJZKCp7ZVmJrNtQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@prisma/generator-helper": "^5.14.0",
"code-block-writer": "^12.0.0",
"lodash": "^4.17.21",
"zod": "^3.23.8"
},
"bin": {
"zod-prisma-types": "dist/bin.js"
},
"peerDependencies": {
"prisma": "^4.x.x || ^5.x.x"
}
},
"packages/signing": {
"name": "@documenso/signing",
"version": "0.0.0",

View File

@ -28,7 +28,6 @@ import { setDocumentRecipients } from '@documenso/lib/server-only/recipient/set-
import { updateRecipient } from '@documenso/lib/server-only/recipient/update-recipient';
import { createTeamMemberInvites } from '@documenso/lib/server-only/team/create-team-member-invites';
import { deleteTeamMembers } from '@documenso/lib/server-only/team/delete-team-members';
import type { TCreateDocumentFromTemplateResponse } from '@documenso/lib/server-only/template/create-document-from-template';
import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/create-document-from-template';
import { createDocumentFromTemplateLegacy } from '@documenso/lib/server-only/template/create-document-from-template-legacy';
import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template';
@ -578,7 +577,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
const templateId = Number(params.templateId);
let document: TCreateDocumentFromTemplateResponse | null = null;
let document: Awaited<ReturnType<typeof createDocumentFromTemplate>> | null = null;
try {
document = await createDocumentFromTemplate({

View File

@ -10,6 +10,7 @@ import { prisma } from '@documenso/prisma';
import type { DocumentDistributionMethod, DocumentSigningOrder } from '@documenso/prisma/client';
import type { SupportedLanguageCodes } from '../../constants/i18n';
import { AppError, AppErrorCode } from '../../errors/app-error';
import type { TDocumentEmailSettings } from '../../types/document-email';
export type CreateDocumentMetaOptions = {
@ -47,7 +48,7 @@ export const upsertDocumentMeta = async ({
language,
requestMetadata,
}: CreateDocumentMetaOptions) => {
const { documentMeta: originalDocumentMeta } = await prisma.document.findFirstOrThrow({
const document = await prisma.document.findFirst({
where: {
id: documentId,
...(teamId
@ -71,6 +72,14 @@ export const upsertDocumentMeta = async ({
},
});
if (!document) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Document not found',
});
}
const { documentMeta: originalDocumentMeta } = document;
return await prisma.$transaction(async (tx) => {
const upsertedDocumentMeta = await tx.documentMeta.upsert({
where: {

View File

@ -1,7 +1,5 @@
'use server';
import type { z } from 'zod';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { normalizePdf as makeNormalizedPdf } from '@documenso/lib/server-only/pdf/normalize-pdf';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
@ -11,7 +9,6 @@ import { prisma } from '@documenso/prisma';
import { DocumentSource, DocumentVisibility, WebhookTriggerEvents } from '@documenso/prisma/client';
import type { Team, TeamGlobalSettings } from '@documenso/prisma/client';
import { TeamMemberRole } from '@documenso/prisma/client';
import { DocumentSchema } from '@documenso/prisma/generated/zod';
import {
ZWebhookDocumentSchema,
@ -33,10 +30,6 @@ export type CreateDocumentOptions = {
requestMetadata: ApiRequestMetadata;
};
export const ZCreateDocumentResponseSchema = DocumentSchema;
export type TCreateDocumentResponse = z.infer<typeof ZCreateDocumentResponseSchema>;
export const createDocument = async ({
userId,
title,
@ -47,7 +40,7 @@ export const createDocument = async ({
formValues,
requestMetadata,
timezone,
}: CreateDocumentOptions): Promise<TCreateDocumentResponse> => {
}: CreateDocumentOptions) => {
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,

View File

@ -1,8 +1,7 @@
import { z } from 'zod';
import { prisma } from '@documenso/prisma';
import { DocumentSource, type Prisma } from '@documenso/prisma/client';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { getDocumentWhereInput } from './get-document-by-id';
export interface DuplicateDocumentOptions {
@ -11,24 +10,18 @@ export interface DuplicateDocumentOptions {
teamId?: number;
}
export const ZDuplicateDocumentResponseSchema = z.object({
documentId: z.number(),
});
export type TDuplicateDocumentResponse = z.infer<typeof ZDuplicateDocumentResponseSchema>;
export const duplicateDocument = async ({
documentId,
userId,
teamId,
}: DuplicateDocumentOptions): Promise<TDuplicateDocumentResponse> => {
}: DuplicateDocumentOptions) => {
const documentWhereInput = await getDocumentWhereInput({
documentId,
userId,
teamId,
});
const document = await prisma.document.findUniqueOrThrow({
const document = await prisma.document.findFirst({
where: documentWhereInput,
select: {
title: true,
@ -53,6 +46,12 @@ export const duplicateDocument = async ({
},
});
if (!document) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Document not found',
});
}
const createDocumentArguments: Prisma.DocumentCreateArgs = {
data: {
title: document.title,

View File

@ -1,6 +1,5 @@
import { DateTime } from 'luxon';
import { match } from 'ts-pattern';
import type { z } from 'zod';
import { prisma } from '@documenso/prisma';
import type {
@ -12,16 +11,10 @@ import type {
User,
} from '@documenso/prisma/client';
import { RecipientRole, SigningStatus, TeamMemberRole } from '@documenso/prisma/client';
import {
DocumentSchema,
RecipientSchema,
TeamSchema,
UserSchema,
} from '@documenso/prisma/generated/zod';
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
import { DocumentVisibility } from '../../types/document-visibility';
import { type FindResultResponse, ZFindResultResponse } from '../../types/search-params';
import { type FindResultResponse } from '../../types/search-params';
import { maskRecipientTokensForDocument } from '../../utils/mask-recipient-tokens-for-document';
export type PeriodSelectorValue = '' | '7d' | '14d' | '30d';
@ -43,23 +36,6 @@ export type FindDocumentsOptions = {
query?: string;
};
export const ZFindDocumentsResponseSchema = ZFindResultResponse.extend({
data: DocumentSchema.extend({
user: UserSchema.pick({
id: true,
name: true,
email: true,
}),
recipients: RecipientSchema.array(),
team: TeamSchema.pick({
id: true,
url: true,
}).nullable(),
}).array(), // Todo: openapi remap.
});
export type TFindDocumentsResponse = z.infer<typeof ZFindDocumentsResponseSchema>;
export const findDocuments = async ({
userId,
teamId,
@ -72,7 +48,7 @@ export const findDocuments = async ({
period,
senderIds,
query,
}: FindDocumentsOptions): Promise<TFindDocumentsResponse> => {
}: FindDocumentsOptions) => {
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,

View File

@ -1,13 +1,4 @@
import type { z } from 'zod';
import { prisma } from '@documenso/prisma';
import {
DocumentDataSchema,
DocumentMetaSchema,
DocumentSchema,
FieldSchema,
RecipientSchema,
} from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { getDocumentWhereInput } from './get-document-by-id';
@ -18,22 +9,11 @@ export type GetDocumentWithDetailsByIdOptions = {
teamId?: number;
};
export const ZGetDocumentWithDetailsByIdResponseSchema = DocumentSchema.extend({
documentData: DocumentDataSchema,
documentMeta: DocumentMetaSchema.nullable(),
recipients: RecipientSchema.array(),
fields: FieldSchema.array(),
});
export type TGetDocumentWithDetailsByIdResponse = z.infer<
typeof ZGetDocumentWithDetailsByIdResponseSchema
>;
export const getDocumentWithDetailsById = async ({
documentId,
userId,
teamId,
}: GetDocumentWithDetailsByIdOptions): Promise<TGetDocumentWithDetailsByIdResponse> => {
}: GetDocumentWithDetailsByIdOptions) => {
const documentWhereInput = await getDocumentWhereInput({
documentId,
userId,

View File

@ -1,8 +1,5 @@
import type { z } from 'zod';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { prisma } from '@documenso/prisma';
import { DocumentSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
@ -15,16 +12,12 @@ export type MoveDocumentToTeamOptions = {
requestMetadata: ApiRequestMetadata;
};
export const ZMoveDocumentToTeamResponseSchema = DocumentSchema;
export type TMoveDocumentToTeamResponse = z.infer<typeof ZMoveDocumentToTeamResponseSchema>;
export const moveDocumentToTeam = async ({
documentId,
teamId,
userId,
requestMetadata,
}: MoveDocumentToTeamOptions): Promise<TMoveDocumentToTeamResponse> => {
}: MoveDocumentToTeamOptions) => {
return await prisma.$transaction(async (tx) => {
const document = await tx.document.findFirst({
where: {

View File

@ -1,5 +1,3 @@
import type { z } from 'zod';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
@ -13,11 +11,6 @@ import {
SigningStatus,
WebhookTriggerEvents,
} from '@documenso/prisma/client';
import {
DocumentMetaSchema,
DocumentSchema,
RecipientSchema,
} from '@documenso/prisma/generated/zod';
import { jobs } from '../../jobs/client';
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
@ -37,20 +30,13 @@ export type SendDocumentOptions = {
requestMetadata: ApiRequestMetadata;
};
export const ZSendDocumentResponseSchema = DocumentSchema.extend({
documentMeta: DocumentMetaSchema.nullable(),
recipients: RecipientSchema.array(),
});
export type TSendDocumentResponse = z.infer<typeof ZSendDocumentResponseSchema>;
export const sendDocument = async ({
documentId,
userId,
teamId,
sendEmail,
requestMetadata,
}: SendDocumentOptions): Promise<TSendDocumentResponse> => {
}: SendDocumentOptions) => {
const document = await prisma.document.findUnique({
where: {
id: documentId,

View File

@ -1,5 +1,4 @@
import { match } from 'ts-pattern';
import type { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
@ -9,7 +8,6 @@ import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-
import { prisma } from '@documenso/prisma';
import { DocumentVisibility } from '@documenso/prisma/client';
import { DocumentStatus, TeamMemberRole } from '@documenso/prisma/client';
import { DocumentSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import type { TDocumentAccessAuthTypes, TDocumentActionAuthTypes } from '../../types/document-auth';
@ -29,17 +27,13 @@ export type UpdateDocumentOptions = {
requestMetadata: ApiRequestMetadata;
};
export const ZUpdateDocumentResponseSchema = DocumentSchema;
export type TUpdateDocumentResponse = z.infer<typeof ZUpdateDocumentResponseSchema>;
export const updateDocument = async ({
userId,
teamId,
documentId,
data,
requestMetadata,
}: UpdateDocumentOptions): Promise<TUpdateDocumentResponse> => {
}: UpdateDocumentOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,12 +1,9 @@
import { z } from 'zod';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import type { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
@ -28,19 +25,13 @@ export interface CreateDocumentFieldsOptions {
requestMetadata: ApiRequestMetadata;
}
export const ZCreateDocumentFieldsResponseSchema = z.object({
fields: z.array(FieldSchema),
});
export type TCreateDocumentFieldsResponse = z.infer<typeof ZCreateDocumentFieldsResponseSchema>;
export const createDocumentFields = async ({
userId,
teamId,
documentId,
fields,
requestMetadata,
}: CreateDocumentFieldsOptions): Promise<TCreateDocumentFieldsResponse> => {
}: CreateDocumentFieldsOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,9 +1,6 @@
import { z } from 'zod';
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
import { prisma } from '@documenso/prisma';
import type { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
@ -24,18 +21,12 @@ export interface CreateTemplateFieldsOptions {
}[];
}
export const ZCreateTemplateFieldsResponseSchema = z.object({
fields: z.array(FieldSchema),
});
export type TCreateTemplateFieldsResponse = z.infer<typeof ZCreateTemplateFieldsResponseSchema>;
export const createTemplateFields = async ({
userId,
teamId,
templateId,
fields,
}: CreateTemplateFieldsOptions): Promise<TCreateTemplateFieldsResponse> => {
}: CreateTemplateFieldsOptions) => {
const template = await prisma.template.findFirst({
where: {
id: templateId,

View File

@ -1,7 +1,4 @@
import type { z } from 'zod';
import { prisma } from '@documenso/prisma';
import { FieldSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -13,17 +10,13 @@ export type GetFieldByIdOptions = {
templateId?: number;
};
export const ZGetFieldByIdResponseSchema = FieldSchema;
export type TGetFieldByIdResponse = z.infer<typeof ZGetFieldByIdResponseSchema>;
export const getFieldById = async ({
userId,
teamId,
fieldId,
documentId,
templateId,
}: GetFieldByIdOptions): Promise<TGetFieldByIdResponse> => {
}: GetFieldByIdOptions) => {
const field = await prisma.field.findFirst({
where: {
id: fieldId,

View File

@ -1,5 +1,4 @@
import { isDeepEqual } from 'remeda';
import { z } from 'zod';
import { validateCheckboxField } from '@documenso/lib/advanced-fields-validation/validate-checkbox';
import { validateDropdownField } from '@documenso/lib/advanced-fields-validation/validate-dropdown';
@ -24,7 +23,6 @@ import {
import { prisma } from '@documenso/prisma';
import type { Field } from '@documenso/prisma/client';
import { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
@ -37,19 +35,13 @@ export interface SetFieldsForDocumentOptions {
requestMetadata: ApiRequestMetadata;
}
export const ZSetFieldsForDocumentResponseSchema = z.object({
fields: z.array(FieldSchema),
});
export type TSetFieldsForDocumentResponse = z.infer<typeof ZSetFieldsForDocumentResponseSchema>;
export const setFieldsForDocument = async ({
userId,
teamId,
documentId,
fields,
requestMetadata,
}: SetFieldsForDocumentOptions): Promise<TSetFieldsForDocumentResponse> => {
}: SetFieldsForDocumentOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { validateCheckboxField } from '@documenso/lib/advanced-fields-validation/validate-checkbox';
import { validateDropdownField } from '@documenso/lib/advanced-fields-validation/validate-dropdown';
import { validateNumberField } from '@documenso/lib/advanced-fields-validation/validate-number';
@ -16,7 +14,6 @@ import {
} from '@documenso/lib/types/field-meta';
import { prisma } from '@documenso/prisma';
import { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
export type SetFieldsForTemplateOptions = {
userId: number;
@ -35,18 +32,12 @@ export type SetFieldsForTemplateOptions = {
}[];
};
export const ZSetFieldsForTemplateResponseSchema = z.object({
fields: z.array(FieldSchema),
});
export type TSetFieldsForTemplateResponse = z.infer<typeof ZSetFieldsForTemplateResponseSchema>;
export const setFieldsForTemplate = async ({
userId,
teamId,
templateId,
fields,
}: SetFieldsForTemplateOptions): Promise<TSetFieldsForTemplateResponse> => {
}: SetFieldsForTemplateOptions) => {
const template = await prisma.template.findFirst({
where: {
id: templateId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
@ -9,7 +7,6 @@ import {
} from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import type { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
@ -31,19 +28,13 @@ export interface UpdateDocumentFieldsOptions {
requestMetadata: ApiRequestMetadata;
}
export const ZUpdateDocumentFieldsResponseSchema = z.object({
fields: z.array(FieldSchema),
});
export type TUpdateDocumentFieldsResponse = z.infer<typeof ZUpdateDocumentFieldsResponseSchema>;
export const updateDocumentFields = async ({
userId,
teamId,
documentId,
fields,
requestMetadata,
}: UpdateDocumentFieldsOptions): Promise<TUpdateDocumentFieldsResponse> => {
}: UpdateDocumentFieldsOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,9 +1,6 @@
import { z } from 'zod';
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
import { prisma } from '@documenso/prisma';
import type { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
@ -24,18 +21,12 @@ export interface UpdateTemplateFieldsOptions {
}[];
}
export const ZUpdateTemplateFieldsResponseSchema = z.object({
fields: z.array(FieldSchema),
});
export type TUpdateTemplateFieldsResponse = z.infer<typeof ZUpdateTemplateFieldsResponseSchema>;
export const updateTemplateFields = async ({
userId,
teamId,
templateId,
fields,
}: UpdateTemplateFieldsOptions): Promise<TUpdateTemplateFieldsResponse> => {
}: UpdateTemplateFieldsOptions) => {
const template = await prisma.template.findFirst({
where: {
id: templateId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { TRecipientAccessAuthTypes } from '@documenso/lib/types/document-auth';
@ -11,7 +9,6 @@ import { createRecipientAuthOptions } from '@documenso/lib/utils/document-auth';
import { prisma } from '@documenso/prisma';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { ZRecipientBaseResponseSchema } from '@documenso/trpc/server/recipient-router/schema';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -30,21 +27,13 @@ export interface CreateDocumentRecipientsOptions {
requestMetadata: ApiRequestMetadata;
}
export const ZCreateDocumentRecipientsResponseSchema = z.object({
recipients: ZRecipientBaseResponseSchema.array(),
});
export type TCreateDocumentRecipientsResponse = z.infer<
typeof ZCreateDocumentRecipientsResponseSchema
>;
export const createDocumentRecipients = async ({
userId,
teamId,
documentId,
recipients: recipientsToCreate,
requestMetadata,
}: CreateDocumentRecipientsOptions): Promise<TCreateDocumentRecipientsResponse> => {
}: CreateDocumentRecipientsOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import type { TRecipientAccessAuthTypes } from '@documenso/lib/types/document-auth';
import { type TRecipientActionAuthTypes } from '@documenso/lib/types/document-auth';
@ -8,7 +6,6 @@ import { createRecipientAuthOptions } from '@documenso/lib/utils/document-auth';
import { prisma } from '@documenso/prisma';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { ZRecipientBaseResponseSchema } from '@documenso/trpc/server/recipient-router/schema';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -26,20 +23,12 @@ export interface CreateTemplateRecipientsOptions {
}[];
}
export const ZCreateTemplateRecipientsResponseSchema = z.object({
recipients: ZRecipientBaseResponseSchema.array(),
});
export type TCreateTemplateRecipientsResponse = z.infer<
typeof ZCreateTemplateRecipientsResponseSchema
>;
export const createTemplateRecipients = async ({
userId,
teamId,
templateId,
recipients: recipientsToCreate,
}: CreateTemplateRecipientsOptions): Promise<TCreateTemplateRecipientsResponse> => {
}: CreateTemplateRecipientsOptions) => {
const template = await prisma.template.findFirst({
where: {
id: templateId,

View File

@ -1,7 +1,4 @@
import type { z } from 'zod';
import { prisma } from '@documenso/prisma';
import { FieldSchema, RecipientSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -11,12 +8,6 @@ export type GetRecipientByIdOptions = {
teamId?: number;
};
export const ZGetRecipientByIdResponseSchema = RecipientSchema.extend({
fields: FieldSchema.array(),
});
export type TGetRecipientByIdResponse = z.infer<typeof ZGetRecipientByIdResponseSchema>;
/**
* Get a recipient by ID. This will also return the recipient signing token so
* be careful when using this.
@ -25,7 +16,7 @@ export const getRecipientById = async ({
recipientId,
userId,
teamId,
}: GetRecipientByIdOptions): Promise<TGetRecipientByIdResponse> => {
}: GetRecipientByIdOptions) => {
const recipient = await prisma.recipient.findFirst({
where: {
id: recipientId,

View File

@ -1,7 +1,6 @@
import { createElement } from 'react';
import { msg } from '@lingui/macro';
import { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { mailer } from '@documenso/email/mailer';
@ -23,7 +22,6 @@ import { prisma } from '@documenso/prisma';
import type { Recipient } from '@documenso/prisma/client';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { RecipientSchema } from '@documenso/prisma/generated/zod';
import { getI18nInstance } from '../../client-only/providers/i18n.server';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
@ -42,19 +40,13 @@ export interface SetDocumentRecipientsOptions {
requestMetadata: ApiRequestMetadata;
}
export const ZSetDocumentRecipientsResponseSchema = z.object({
recipients: RecipientSchema.array(),
});
export type TSetDocumentRecipientsResponse = z.infer<typeof ZSetDocumentRecipientsResponseSchema>;
export const setDocumentRecipients = async ({
userId,
teamId,
documentId,
recipients,
requestMetadata,
}: SetDocumentRecipientsOptions): Promise<TSetDocumentRecipientsResponse> => {
}: SetDocumentRecipientsOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import {
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
@ -8,7 +6,6 @@ import {
import { prisma } from '@documenso/prisma';
import type { Recipient } from '@documenso/prisma/client';
import { RecipientRole } from '@documenso/prisma/client';
import { RecipientSchema } from '@documenso/prisma/generated/zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import {
@ -32,18 +29,12 @@ export type SetTemplateRecipientsOptions = {
}[];
};
export const ZSetTemplateRecipientsResponseSchema = z.object({
recipients: RecipientSchema.array(),
});
export type TSetTemplateRecipientsResponse = z.infer<typeof ZSetTemplateRecipientsResponseSchema>;
export const setTemplateRecipients = async ({
userId,
teamId,
templateId,
recipients,
}: SetTemplateRecipientsOptions): Promise<TSetTemplateRecipientsResponse> => {
}: SetTemplateRecipientsOptions) => {
const template = await prisma.template.findFirst({
where: {
id: templateId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { TRecipientAccessAuthTypes } from '@documenso/lib/types/document-auth';
@ -17,7 +15,6 @@ import { prisma } from '@documenso/prisma';
import type { Recipient } from '@documenso/prisma/client';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { ZRecipientResponseSchema } from '@documenso/trpc/server/recipient-router/schema';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientBeModified } from '../../utils/recipients';
@ -30,21 +27,13 @@ export interface UpdateDocumentRecipientsOptions {
requestMetadata: ApiRequestMetadata;
}
export const ZUpdateDocumentRecipientsResponseSchema = z.object({
recipients: ZRecipientResponseSchema.array(),
});
export type TUpdateDocumentRecipientsResponse = z.infer<
typeof ZUpdateDocumentRecipientsResponseSchema
>;
export const updateDocumentRecipients = async ({
userId,
teamId,
documentId,
recipients,
requestMetadata,
}: UpdateDocumentRecipientsOptions): Promise<TUpdateDocumentRecipientsResponse> => {
}: UpdateDocumentRecipientsOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,

View File

@ -1,5 +1,3 @@
import { z } from 'zod';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import type { TRecipientAccessAuthTypes } from '@documenso/lib/types/document-auth';
import {
@ -10,7 +8,6 @@ import { createRecipientAuthOptions } from '@documenso/lib/utils/document-auth';
import { prisma } from '@documenso/prisma';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { ZRecipientResponseSchema } from '@documenso/trpc/server/recipient-router/schema';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -29,20 +26,12 @@ export interface UpdateTemplateRecipientsOptions {
}[];
}
export const ZUpdateTemplateRecipientsResponseSchema = z.object({
recipients: ZRecipientResponseSchema.array(),
});
export type TUpdateTemplateRecipientsResponse = z.infer<
typeof ZUpdateTemplateRecipientsResponseSchema
>;
export const updateTemplateRecipients = async ({
userId,
teamId,
templateId,
recipients,
}: UpdateTemplateRecipientsOptions): Promise<TUpdateTemplateRecipientsResponse> => {
}: UpdateTemplateRecipientsOptions) => {
const template = await prisma.template.findFirst({
where: {
id: templateId,

View File

@ -1,5 +1,3 @@
import type { z } from 'zod';
import { nanoid } from '@documenso/lib/universal/id';
import { prisma } from '@documenso/prisma';
import type { DocumentDistributionMethod } from '@documenso/prisma/client';
@ -13,11 +11,6 @@ import {
SigningStatus,
WebhookTriggerEvents,
} from '@documenso/prisma/client';
import {
DocumentDataSchema,
DocumentSchema,
RecipientSchema,
} from '@documenso/prisma/generated/zod';
import type { SupportedLanguageCodes } from '../../constants/i18n';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -79,15 +72,6 @@ export type CreateDocumentFromTemplateOptions = {
requestMetadata: ApiRequestMetadata;
};
export const ZCreateDocumentFromTemplateResponseSchema = DocumentSchema.extend({
documentData: DocumentDataSchema,
recipients: RecipientSchema.array(),
});
export type TCreateDocumentFromTemplateResponse = z.infer<
typeof ZCreateDocumentFromTemplateResponseSchema
>;
export const createDocumentFromTemplate = async ({
templateId,
externalId,
@ -97,7 +81,7 @@ export const createDocumentFromTemplate = async ({
customDocumentDataId,
override,
requestMetadata,
}: CreateDocumentFromTemplateOptions): Promise<TCreateDocumentFromTemplateResponse> => {
}: CreateDocumentFromTemplateOptions) => {
const template = await prisma.template.findUnique({
where: {
id: templateId,

View File

@ -0,0 +1,118 @@
import type { z } from 'zod';
import {
DocumentDataSchema,
DocumentMetaSchema,
DocumentSchema,
TeamSchema,
UserSchema,
} from '@documenso/prisma/generated/zod';
import { ZFieldSchema } from './field';
import { ZRecipientLiteSchema } from './recipient';
/**
* The full document response schema.
*
* Mainly used for returning a single document from the API.
*/
export const ZDocumentSchema = DocumentSchema.pick({
visibility: true,
status: true,
source: true,
id: true,
externalId: true,
userId: true,
authOptions: true,
formValues: true,
title: true,
documentDataId: true,
createdAt: true,
updatedAt: true,
completedAt: true,
deletedAt: true,
teamId: true,
templateId: true,
}).extend({
// Todo: Maybe we want to alter this a bit since this returns a lot of data.
documentData: DocumentDataSchema.pick({
type: true,
id: true,
data: true,
initialData: true,
}),
documentMeta: DocumentMetaSchema.pick({
signingOrder: true,
distributionMethod: true,
id: true,
subject: true,
message: true,
timezone: true,
password: true,
dateFormat: true,
documentId: true,
redirectUrl: true,
typedSignatureEnabled: true,
language: true,
emailSettings: true,
}).nullable(),
recipients: ZRecipientLiteSchema.array(),
fields: ZFieldSchema.array(),
});
export type TDocument = z.infer<typeof ZDocumentSchema>;
/**
* A lite version of the document response schema without relations.
*/
export const ZDocumentLiteSchema = DocumentSchema.pick({
visibility: true,
status: true,
source: true,
id: true,
externalId: true,
userId: true,
authOptions: true,
formValues: true,
title: true,
documentDataId: true,
createdAt: true,
updatedAt: true,
completedAt: true,
deletedAt: true,
teamId: true,
templateId: true,
});
/**
* A version of the document response schema when returning multiple documents at once from a single API endpoint.
*/
export const ZDocumentManySchema = DocumentSchema.pick({
visibility: true,
status: true,
source: true,
id: true,
externalId: true,
userId: true,
authOptions: true,
formValues: true,
title: true,
documentDataId: true,
createdAt: true,
updatedAt: true,
completedAt: true,
deletedAt: true,
teamId: true,
templateId: true,
}).extend({
user: UserSchema.pick({
id: true,
name: true,
email: true,
}),
recipients: ZRecipientLiteSchema.array(),
team: TeamSchema.pick({
id: true,
url: true,
}).nullable(),
});

View File

@ -0,0 +1,30 @@
import { FieldSchema } from '@documenso/prisma/generated/zod';
/**
* The full field response schema.
*
* If you need to return something different, adjust this file to utilise the:
* - ZFieldSchema
* - ZFieldLiteSchema
* - ZFieldManySchema
*
* Setup similar to:
* - ./documents.ts
* - ./templates.ts
*/
export const ZFieldSchema = FieldSchema.pick({
type: true,
id: true,
secondaryId: true,
documentId: true,
templateId: true,
recipientId: true,
page: true,
positionX: true,
positionY: true,
width: true,
height: true,
customText: true,
inserted: true,
fieldMeta: true,
});

View File

@ -0,0 +1,85 @@
import { TeamSchema, UserSchema } from '@documenso/prisma/generated/zod';
import RecipientSchema from '@documenso/prisma/generated/zod/modelSchema/RecipientSchema';
import { ZFieldSchema } from './field';
/**
* The full recipient response schema.
*
* Mainly used for returning a single recipient from the API.
*/
export const ZRecipientSchema = RecipientSchema.pick({
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
documentDeletedAt: true,
expired: true,
signedAt: true,
authOptions: true,
signingOrder: true,
rejectionReason: true,
}).extend({
fields: ZFieldSchema.array(),
});
/**
* A lite version of the recipient response schema without relations.
*/
export const ZRecipientLiteSchema = RecipientSchema.pick({
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
documentDeletedAt: true,
expired: true,
signedAt: true,
authOptions: true,
signingOrder: true,
rejectionReason: true,
});
/**
* A version of the recipient response schema when returning multiple recipients at once from a single API endpoint.
*/
export const ZRecipientManySchema = RecipientSchema.pick({
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
documentDeletedAt: true,
expired: true,
signedAt: true,
authOptions: true,
signingOrder: true,
rejectionReason: true,
}).extend({
user: UserSchema.pick({
id: true,
name: true,
email: true,
}),
recipients: RecipientSchema.array(),
team: TeamSchema.pick({
id: true,
url: true,
}).nullable(),
});

View File

@ -33,6 +33,6 @@
"prisma-kysely": "^1.8.0",
"tsx": "^4.11.0",
"typescript": "5.2.2",
"zod-prisma-types": "^3.1.8"
"zod-prisma-types": "3.1.9"
}
}
}

View File

@ -7,7 +7,10 @@ generator client {
}
generator zod {
provider = "zod-prisma-types"
provider = "zod-prisma-types"
createInputTypes = false
writeBarrelFiles = true
useMultipleFiles = true
}
datasource db {
@ -294,12 +297,13 @@ enum DocumentVisibility {
ADMIN
}
/// @zod.import(["import { ZDocumentAuthOptionsSchema } from '@documenso/lib/types/document-auth';"])
model Document {
id Int @id @default(autoincrement())
externalId String?
userId Int
externalId String? /// @zod.string.describe("A custom external ID you can use to identify the document.")
userId Int /// @zod.number.describe("The ID of the user that created this document.")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
authOptions Json?
authOptions Json? /// Todo: zod.custom.use(ZDocumentAuthOptionsSchema.describe("Hello"))
formValues Json?
visibility DocumentVisibility @default(EVERYONE)
title String
@ -409,6 +413,7 @@ enum RecipientRole {
APPROVER
}
/// @zod.import(["import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';"])
model Recipient {
id Int @id @default(autoincrement())
documentId Int?
@ -419,8 +424,8 @@ model Recipient {
documentDeletedAt DateTime?
expired DateTime?
signedAt DateTime?
authOptions Json?
signingOrder Int?
authOptions Json? /// Todo: zod.custom.use(ZRecipientAuthOptionsSchema)
signingOrder Int? /// @zod.number.describe("The order in which the recipient should sign the document. Only works if the document is set to sequential signing.")
rejectionReason String?
role RecipientRole @default(SIGNER)
readStatus ReadStatus @default(NOT_OPENED)
@ -459,7 +464,7 @@ model Field {
templateId Int?
recipientId Int
type FieldType
page Int
page Int /// @zod.number.describe("The page number of the field on the document. Starts from 1.")
positionX Decimal @default(0)
positionY Decimal @default(0)
width Decimal @default(-1)
@ -470,7 +475,7 @@ model Field {
template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
signature Signature?
fieldMeta Json?
fieldMeta Json? // Todo: Fix ZFieldMetaSchema before using it here.
@@index([documentId])
@@index([templateId])

View File

@ -8,63 +8,47 @@ import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
import { AppError } from '@documenso/lib/errors/app-error';
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
import { upsertDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta';
import {
ZCreateDocumentResponseSchema,
createDocument,
} from '@documenso/lib/server-only/document/create-document';
import { createDocument } from '@documenso/lib/server-only/document/create-document';
import { deleteDocument } from '@documenso/lib/server-only/document/delete-document';
import {
ZDuplicateDocumentResponseSchema,
duplicateDocument,
} from '@documenso/lib/server-only/document/duplicate-document-by-id';
import { duplicateDocument } from '@documenso/lib/server-only/document/duplicate-document-by-id';
import { findDocumentAuditLogs } from '@documenso/lib/server-only/document/find-document-audit-logs';
import {
ZFindDocumentsResponseSchema,
findDocuments,
} from '@documenso/lib/server-only/document/find-documents';
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import {
ZGetDocumentWithDetailsByIdResponseSchema,
getDocumentWithDetailsById,
} from '@documenso/lib/server-only/document/get-document-with-details-by-id';
import {
ZMoveDocumentToTeamResponseSchema,
moveDocumentToTeam,
} from '@documenso/lib/server-only/document/move-document-to-team';
import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
import { moveDocumentToTeam } from '@documenso/lib/server-only/document/move-document-to-team';
import { resendDocument } from '@documenso/lib/server-only/document/resend-document';
import { searchDocumentsWithKeyword } from '@documenso/lib/server-only/document/search-documents-with-keyword';
import {
ZSendDocumentResponseSchema,
sendDocument,
} from '@documenso/lib/server-only/document/send-document';
import {
ZUpdateDocumentResponseSchema,
updateDocument,
} from '@documenso/lib/server-only/document/update-document';
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
import { symmetricEncrypt } from '@documenso/lib/universal/crypto';
import { DocumentStatus } from '@documenso/prisma/client';
import { authenticatedProcedure, procedure, router } from '../trpc';
import {
ZCreateDocumentMutationSchema,
ZCreateDocumentRequestSchema,
ZDeleteDocumentMutationSchema,
ZDistributeDocumentRequestSchema,
ZDistributeDocumentResponseSchema,
ZDownloadAuditLogsMutationSchema,
ZDownloadCertificateMutationSchema,
ZDuplicateDocumentMutationSchema,
ZDuplicateDocumentRequestSchema,
ZDuplicateDocumentResponseSchema,
ZFindDocumentAuditLogsQuerySchema,
ZFindDocumentsQuerySchema,
ZFindDocumentsRequestSchema,
ZFindDocumentsResponseSchema,
ZGetDocumentByIdQuerySchema,
ZGetDocumentByTokenQuerySchema,
ZGetDocumentWithDetailsByIdQuerySchema,
ZGetDocumentWithDetailsByIdRequestSchema,
ZGetDocumentWithDetailsByIdResponseSchema,
ZMoveDocumentToTeamResponseSchema,
ZMoveDocumentToTeamSchema,
ZResendDocumentMutationSchema,
ZSearchDocumentsMutationSchema,
ZSendDocumentMutationSchema,
ZSetPasswordForDocumentMutationSchema,
ZSetSigningOrderForDocumentMutationSchema,
ZUpdateDocumentRequestSchema,
ZUpdateTypedSignatureSettingsMutationSchema,
ZUpdateDocumentResponseSchema,
} from './schema';
export const documentRouter = router({
@ -111,7 +95,7 @@ export const documentRouter = router({
tags: ['Document'],
},
})
.input(ZFindDocumentsQuerySchema)
.input(ZFindDocumentsRequestSchema)
.output(ZFindDocumentsResponseSchema)
.query(async ({ input, ctx }) => {
const { user, teamId } = ctx;
@ -149,7 +133,7 @@ export const documentRouter = router({
tags: ['Document'],
},
})
.input(ZGetDocumentWithDetailsByIdQuerySchema)
.input(ZGetDocumentWithDetailsByIdRequestSchema)
.output(ZGetDocumentWithDetailsByIdResponseSchema)
.query(async ({ input, ctx }) => {
const { teamId, user } = ctx;
@ -176,8 +160,7 @@ export const documentRouter = router({
// tags: ['Document'],
// },
// })
.input(ZCreateDocumentMutationSchema)
.output(ZCreateDocumentResponseSchema)
.input(ZCreateDocumentRequestSchema)
.mutation(async ({ input, ctx }) => {
const { teamId } = ctx;
const { title, documentDataId, timezone } = input;
@ -353,39 +336,6 @@ export const documentRouter = router({
});
}),
/**
* @deprecated Remove after deployment.
*
* @private
*/
updateTypedSignatureSettings: authenticatedProcedure
.input(ZUpdateTypedSignatureSettingsMutationSchema)
.mutation(async ({ input, ctx }) => {
const { teamId } = ctx;
const { documentId, typedSignatureEnabled } = input;
const document = await getDocumentById({
documentId,
teamId,
userId: ctx.user.id,
}).catch(() => null);
if (!document) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Document not found',
});
}
return await upsertDocumentMeta({
userId: ctx.user.id,
teamId,
documentId,
typedSignatureEnabled,
requestMetadata: ctx.metadata,
});
}),
/**
* @public
*
@ -402,8 +352,8 @@ export const documentRouter = router({
tags: ['Document'],
},
})
.input(ZSendDocumentMutationSchema)
.output(ZSendDocumentResponseSchema)
.input(ZDistributeDocumentRequestSchema)
.output(ZDistributeDocumentResponseSchema)
.mutation(async ({ input, ctx }) => {
const { teamId } = ctx;
const { documentId, meta = {} } = input;
@ -476,7 +426,7 @@ export const documentRouter = router({
tags: ['Document'],
},
})
.input(ZDuplicateDocumentMutationSchema)
.input(ZDuplicateDocumentRequestSchema)
.output(ZDuplicateDocumentResponseSchema)
.mutation(async ({ input, ctx }) => {
const { teamId, user } = ctx;

View File

@ -1,12 +1,17 @@
import { z } from 'zod';
import { SUPPORTED_LANGUAGE_CODES } from '@documenso/lib/constants/i18n';
import {
ZDocumentLiteSchema,
ZDocumentManySchema,
ZDocumentSchema,
} from '@documenso/lib/types/document';
import {
ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth';
import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';
import { ZFindSearchParamsSchema } from '@documenso/lib/types/search-params';
import { ZFindResultResponse, ZFindSearchParamsSchema } from '@documenso/lib/types/search-params';
import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
import {
DocumentDistributionMethod,
@ -17,7 +22,6 @@ import {
FieldType,
} from '@documenso/prisma/client';
// Todo: Refactor all to ZDocumentMeta---
export const ZDocumentMetaTimezoneSchema = z
.string()
.describe('The timezone to use for date fields and signing the document.');
@ -53,7 +57,7 @@ export const ZDocumentMetaTypedSignatureEnabledSchema = z
.boolean()
.describe('Whether to allow typed signatures.');
export const ZFindDocumentsQuerySchema = ZFindSearchParamsSchema.extend({
export const ZFindDocumentsRequestSchema = ZFindSearchParamsSchema.extend({
templateId: z
.number()
.describe('Filter documents by the template ID used to create it.')
@ -70,6 +74,12 @@ export const ZFindDocumentsQuerySchema = ZFindSearchParamsSchema.extend({
orderByDirection: z.enum(['asc', 'desc']).describe('').default('desc'),
});
export const ZFindDocumentsResponseSchema = ZFindResultResponse.extend({
data: ZDocumentManySchema.array(),
});
export type TFindDocumentsResponse = z.infer<typeof ZFindDocumentsResponseSchema>;
export const ZFindDocumentAuditLogsQuerySchema = ZFindSearchParamsSchema.extend({
documentId: z.number().min(1),
cursor: z.string().optional(),
@ -82,11 +92,13 @@ export const ZGetDocumentByIdQuerySchema = z.object({
documentId: z.number(),
});
export const ZDuplicateDocumentMutationSchema = z.object({
export const ZDuplicateDocumentRequestSchema = z.object({
documentId: z.number(),
});
export type TGetDocumentByIdQuerySchema = z.infer<typeof ZGetDocumentByIdQuerySchema>;
export const ZDuplicateDocumentResponseSchema = z.object({
documentId: z.number(),
});
export const ZGetDocumentByTokenQuerySchema = z.object({
token: z.string().min(1),
@ -94,22 +106,18 @@ export const ZGetDocumentByTokenQuerySchema = z.object({
export type TGetDocumentByTokenQuerySchema = z.infer<typeof ZGetDocumentByTokenQuerySchema>;
export const ZGetDocumentWithDetailsByIdQuerySchema = z.object({
export const ZGetDocumentWithDetailsByIdRequestSchema = z.object({
documentId: z.number(),
});
export type TGetDocumentWithDetailsByIdQuerySchema = z.infer<
typeof ZGetDocumentWithDetailsByIdQuerySchema
>;
export const ZGetDocumentWithDetailsByIdResponseSchema = ZDocumentSchema;
export const ZCreateDocumentMutationSchema = z.object({
export const ZCreateDocumentRequestSchema = z.object({
title: z.string().min(1),
documentDataId: z.string().min(1),
timezone: z.string().optional(),
});
export type TCreateDocumentMutationSchema = z.infer<typeof ZCreateDocumentMutationSchema>;
export const ZUpdateDocumentRequestSchema = z.object({
documentId: z.number(),
data: z
@ -139,7 +147,7 @@ export const ZUpdateDocumentRequestSchema = z.object({
.optional(),
});
export type TUpdateDocumentRequestSchema = z.infer<typeof ZUpdateDocumentRequestSchema>;
export const ZUpdateDocumentResponseSchema = ZDocumentLiteSchema;
export const ZSetFieldsForDocumentMutationSchema = z.object({
documentId: z.number(),
@ -161,7 +169,7 @@ export type TSetFieldsForDocumentMutationSchema = z.infer<
typeof ZSetFieldsForDocumentMutationSchema
>;
export const ZSendDocumentMutationSchema = z.object({
export const ZDistributeDocumentRequestSchema = z.object({
documentId: z.number().describe('The ID of the document to send.'),
meta: z
.object({
@ -177,6 +185,8 @@ export const ZSendDocumentMutationSchema = z.object({
.optional(),
});
export const ZDistributeDocumentResponseSchema = ZDocumentLiteSchema;
export const ZSetPasswordForDocumentMutationSchema = z.object({
documentId: z.number(),
password: z.string(),
@ -195,15 +205,6 @@ export type TSetSigningOrderForDocumentMutationSchema = z.infer<
typeof ZSetSigningOrderForDocumentMutationSchema
>;
export const ZUpdateTypedSignatureSettingsMutationSchema = z.object({
documentId: z.number(),
typedSignatureEnabled: z.boolean(),
});
export type TUpdateTypedSignatureSettingsMutationSchema = z.infer<
typeof ZUpdateTypedSignatureSettingsMutationSchema
>;
export const ZResendDocumentMutationSchema = z.object({
documentId: z.number(),
recipients: z
@ -212,8 +213,6 @@ export const ZResendDocumentMutationSchema = z.object({
.describe('The IDs of the recipients to redistribute the document to.'),
});
export type TSendDocumentMutationSchema = z.infer<typeof ZSendDocumentMutationSchema>;
export const ZDeleteDocumentMutationSchema = z.object({
documentId: z.number(),
});
@ -236,3 +235,5 @@ export const ZMoveDocumentToTeamSchema = z.object({
documentId: z.number().describe('The ID of the document to move to a team.'),
teamId: z.number().describe('The ID of the team to move the document to.'),
});
export const ZMoveDocumentToTeamResponseSchema = ZDocumentLiteSchema;

View File

@ -1,60 +1,46 @@
import { z } from 'zod';
import {
ZCreateDocumentFieldsResponseSchema,
createDocumentFields,
} from '@documenso/lib/server-only/field/create-document-fields';
import {
ZCreateTemplateFieldsResponseSchema,
createTemplateFields,
} from '@documenso/lib/server-only/field/create-template-fields';
import { createDocumentFields } from '@documenso/lib/server-only/field/create-document-fields';
import { createTemplateFields } from '@documenso/lib/server-only/field/create-template-fields';
import { deleteDocumentField } from '@documenso/lib/server-only/field/delete-document-field';
import { deleteTemplateField } from '@documenso/lib/server-only/field/delete-template-field';
import {
ZGetFieldByIdResponseSchema,
getFieldById,
} from '@documenso/lib/server-only/field/get-field-by-id';
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 {
ZSetFieldsForDocumentResponseSchema,
setFieldsForDocument,
} from '@documenso/lib/server-only/field/set-fields-for-document';
import {
ZSetFieldsForTemplateResponseSchema,
setFieldsForTemplate,
} from '@documenso/lib/server-only/field/set-fields-for-template';
import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document';
import { setFieldsForTemplate } from '@documenso/lib/server-only/field/set-fields-for-template';
import { signFieldWithToken } from '@documenso/lib/server-only/field/sign-field-with-token';
import {
ZUpdateDocumentFieldsResponseSchema,
updateDocumentFields,
} from '@documenso/lib/server-only/field/update-document-fields';
import {
ZUpdateTemplateFieldsResponseSchema,
updateTemplateFields,
} from '@documenso/lib/server-only/field/update-template-fields';
import { updateDocumentFields } from '@documenso/lib/server-only/field/update-document-fields';
import { updateTemplateFields } from '@documenso/lib/server-only/field/update-template-fields';
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { authenticatedProcedure, procedure, router } from '../trpc';
import {
ZAddFieldsMutationSchema,
ZAddTemplateFieldsMutationSchema,
ZCreateDocumentFieldRequestSchema,
ZCreateDocumentFieldResponseSchema,
ZCreateDocumentFieldsRequestSchema,
ZCreateDocumentFieldsResponseSchema,
ZCreateTemplateFieldRequestSchema,
ZCreateTemplateFieldResponseSchema,
ZCreateTemplateFieldsRequestSchema,
ZCreateTemplateFieldsResponseSchema,
ZDeleteDocumentFieldRequestSchema,
ZDeleteTemplateFieldRequestSchema,
ZGetFieldQuerySchema,
ZGetFieldRequestSchema,
ZGetFieldResponseSchema,
ZRemovedSignedFieldWithTokenMutationSchema,
ZSetDocumentFieldsRequestSchema,
ZSetDocumentFieldsResponseSchema,
ZSetFieldsForTemplateRequestSchema,
ZSetFieldsForTemplateResponseSchema,
ZSignFieldWithTokenMutationSchema,
ZUpdateDocumentFieldRequestSchema,
ZUpdateDocumentFieldResponseSchema,
ZUpdateDocumentFieldsRequestSchema,
ZUpdateDocumentFieldsResponseSchema,
ZUpdateTemplateFieldRequestSchema,
ZUpdateTemplateFieldResponseSchema,
ZUpdateTemplateFieldsRequestSchema,
ZUpdateTemplateFieldsResponseSchema,
} from './schema';
export const fieldRouter = router({
@ -72,8 +58,8 @@ export const fieldRouter = router({
tags: ['Document Fields', 'Template Fields'],
},
})
.input(ZGetFieldQuerySchema)
.output(ZGetFieldByIdResponseSchema)
.input(ZGetFieldRequestSchema)
.output(ZGetFieldResponseSchema)
.query(async ({ input, ctx }) => {
const { teamId } = ctx;
const { fieldId } = input;
@ -229,6 +215,8 @@ export const fieldRouter = router({
/**
* @private
*
* Todo: Refactor to setFieldsForDocument function.
*/
addFields: authenticatedProcedure
// .meta({
@ -239,8 +227,8 @@ export const fieldRouter = router({
// tags: ['Document Fields'],
// },
// })
.input(ZAddFieldsMutationSchema)
.output(ZSetFieldsForDocumentResponseSchema)
.input(ZSetDocumentFieldsRequestSchema)
.output(ZSetDocumentFieldsResponseSchema)
.mutation(async ({ input, ctx }) => {
const { teamId } = ctx;
const { documentId, fields } = input;
@ -403,6 +391,8 @@ export const fieldRouter = router({
/**
* @private
*
* Todo: Refactor to setFieldsForTemplate.
*/
addTemplateFields: authenticatedProcedure
// .meta({
@ -413,7 +403,7 @@ export const fieldRouter = router({
// tags: ['Template Fields'],
// },
// })
.input(ZAddTemplateFieldsMutationSchema)
.input(ZSetFieldsForTemplateRequestSchema)
.output(ZSetFieldsForTemplateResponseSchema)
.mutation(async ({ input, ctx }) => {
const { teamId } = ctx;

View File

@ -1,13 +1,13 @@
import { z } from 'zod';
import { ZRecipientActionAuthSchema } from '@documenso/lib/types/document-auth';
import { ZFieldSchema } from '@documenso/lib/types/field';
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
import { FieldType } from '@documenso/prisma/client';
import { FieldSchema } from '@documenso/prisma/generated/zod';
const ZCreateFieldSchema = z.object({
recipientId: z.number().describe('The ID of the recipient to create the field for.'),
type: FieldSchema.shape.type.describe('The type of the field to create.'),
type: ZFieldSchema.shape.type.describe('The type of the field to create.'),
pageNumber: z.number().describe('The page number the field will be on.'),
pageX: z.number().describe('The X coordinate of where the field will be placed.'),
pageY: z.number().describe('The Y coordinate of where the field will be placed.'),
@ -18,7 +18,7 @@ const ZCreateFieldSchema = z.object({
const ZUpdateFieldSchema = z.object({
id: z.number().describe('The ID of the field to update.'),
type: FieldSchema.shape.type.optional().describe('The type of the field to update.'),
type: ZFieldSchema.shape.type.optional().describe('The type of the field to update.'),
pageNumber: z.number().optional().describe('The page number the field will be on.'),
pageX: z.number().optional().describe('The X coordinate of where the field will be placed.'),
pageY: z.number().optional().describe('The Y coordinate of where the field will be placed.'),
@ -28,59 +28,78 @@ const ZUpdateFieldSchema = z.object({
});
export const ZCreateDocumentFieldRequestSchema = z.object({
documentId: z.number().min(1),
documentId: z.number(),
field: ZCreateFieldSchema,
});
export const ZCreateDocumentFieldResponseSchema = ZFieldSchema;
export const ZCreateDocumentFieldsRequestSchema = z.object({
documentId: z.number().min(1),
documentId: z.number(),
fields: ZCreateFieldSchema.array(),
});
export const ZCreateDocumentFieldsResponseSchema = z.object({
fields: z.array(ZFieldSchema),
});
export const ZUpdateDocumentFieldRequestSchema = z.object({
documentId: z.number().min(1),
documentId: z.number(),
field: ZUpdateFieldSchema,
});
export const ZUpdateDocumentFieldResponseSchema = ZFieldSchema;
export const ZUpdateDocumentFieldsRequestSchema = z.object({
documentId: z.number().min(1),
documentId: z.number(),
fields: ZUpdateFieldSchema.array(),
});
export const ZUpdateDocumentFieldsResponseSchema = z.object({
fields: z.array(ZFieldSchema),
});
export const ZDeleteDocumentFieldRequestSchema = z.object({
fieldId: z.number().min(1),
fieldId: z.number(),
});
export const ZCreateTemplateFieldRequestSchema = z.object({
templateId: z.number().min(1),
templateId: z.number(),
field: ZCreateFieldSchema,
});
export const ZCreateDocumentFieldResponseSchema = FieldSchema;
export const ZUpdateTemplateFieldResponseSchema = FieldSchema;
export const ZUpdateDocumentFieldResponseSchema = FieldSchema;
export const ZCreateTemplateFieldResponseSchema = FieldSchema;
export const ZCreateTemplateFieldResponseSchema = ZFieldSchema;
export const ZCreateTemplateFieldsRequestSchema = z.object({
templateId: z.number().min(1),
templateId: z.number(),
fields: ZCreateFieldSchema.array(),
});
export const ZCreateTemplateFieldsResponseSchema = z.object({
fields: z.array(ZFieldSchema),
});
export const ZUpdateTemplateFieldRequestSchema = z.object({
templateId: z.number().min(1),
templateId: z.number(),
field: ZUpdateFieldSchema,
});
export const ZUpdateTemplateFieldsRequestSchema = z.object({
templateId: z.number().min(1),
templateId: z.number(),
fields: ZUpdateFieldSchema.array(),
});
export const ZDeleteTemplateFieldRequestSchema = z.object({
fieldId: z.number().min(1),
export const ZUpdateTemplateFieldsResponseSchema = z.object({
fields: z.array(ZFieldSchema),
});
export const ZAddFieldsMutationSchema = z.object({
export const ZUpdateTemplateFieldResponseSchema = ZFieldSchema;
export const ZDeleteTemplateFieldRequestSchema = z.object({
fieldId: z.number(),
});
export const ZSetDocumentFieldsRequestSchema = z.object({
documentId: z.number(),
fields: z.array(
z.object({
@ -98,9 +117,11 @@ export const ZAddFieldsMutationSchema = z.object({
),
});
export type TAddFieldsMutationSchema = z.infer<typeof ZAddFieldsMutationSchema>;
export const ZSetDocumentFieldsResponseSchema = z.object({
fields: z.array(ZFieldSchema),
});
export const ZAddTemplateFieldsMutationSchema = z.object({
export const ZSetFieldsForTemplateRequestSchema = z.object({
templateId: z.number(),
fields: z.array(
z.object({
@ -118,7 +139,9 @@ export const ZAddTemplateFieldsMutationSchema = z.object({
),
});
export type TAddTemplateFieldsMutationSchema = z.infer<typeof ZAddTemplateFieldsMutationSchema>;
export const ZSetFieldsForTemplateResponseSchema = z.object({
fields: z.array(ZFieldSchema),
});
export const ZSignFieldWithTokenMutationSchema = z.object({
token: z.string(),
@ -139,15 +162,8 @@ export type TRemovedSignedFieldWithTokenMutationSchema = z.infer<
typeof ZRemovedSignedFieldWithTokenMutationSchema
>;
export const ZGetFieldQuerySchema = z.object({
export const ZGetFieldRequestSchema = z.object({
fieldId: z.number(),
});
export type TGetFieldQuerySchema = z.infer<typeof ZGetFieldQuerySchema>;
export const ZUpdateFieldMutationSchema = z.object({
fieldId: z.number(),
documentId: z.number(),
fieldMeta: ZFieldMetaSchema,
teamId: z.number().optional(),
});
export const ZGetFieldResponseSchema = ZFieldSchema;

View File

@ -2,48 +2,37 @@ import { z } from 'zod';
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token';
import { rejectDocumentWithToken } from '@documenso/lib/server-only/document/reject-document-with-token';
import {
ZCreateDocumentRecipientsResponseSchema,
createDocumentRecipients,
} from '@documenso/lib/server-only/recipient/create-document-recipients';
import {
ZCreateTemplateRecipientsResponseSchema,
createTemplateRecipients,
} from '@documenso/lib/server-only/recipient/create-template-recipients';
import { createDocumentRecipients } from '@documenso/lib/server-only/recipient/create-document-recipients';
import { createTemplateRecipients } from '@documenso/lib/server-only/recipient/create-template-recipients';
import { deleteDocumentRecipient } from '@documenso/lib/server-only/recipient/delete-document-recipient';
import { deleteTemplateRecipient } from '@documenso/lib/server-only/recipient/delete-template-recipient';
import {
ZGetRecipientByIdResponseSchema,
getRecipientById,
} from '@documenso/lib/server-only/recipient/get-recipient-by-id';
import {
ZSetDocumentRecipientsResponseSchema,
setDocumentRecipients,
} from '@documenso/lib/server-only/recipient/set-document-recipients';
import {
ZSetTemplateRecipientsResponseSchema,
setTemplateRecipients,
} from '@documenso/lib/server-only/recipient/set-template-recipients';
import { getRecipientById } from '@documenso/lib/server-only/recipient/get-recipient-by-id';
import { setDocumentRecipients } from '@documenso/lib/server-only/recipient/set-document-recipients';
import { setTemplateRecipients } from '@documenso/lib/server-only/recipient/set-template-recipients';
import { updateDocumentRecipients } from '@documenso/lib/server-only/recipient/update-document-recipients';
import { updateTemplateRecipients } from '@documenso/lib/server-only/recipient/update-template-recipients';
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { authenticatedProcedure, procedure, router } from '../trpc';
import {
ZAddSignersMutationSchema,
ZCompleteDocumentWithTokenMutationSchema,
ZCreateDocumentRecipientRequestSchema,
ZCreateDocumentRecipientResponseSchema,
ZCreateDocumentRecipientsRequestSchema,
ZCreateDocumentRecipientsResponseSchema,
ZCreateTemplateRecipientRequestSchema,
ZCreateTemplateRecipientResponseSchema,
ZCreateTemplateRecipientsRequestSchema,
ZCreateTemplateRecipientsResponseSchema,
ZDeleteDocumentRecipientRequestSchema,
ZDeleteTemplateRecipientRequestSchema,
ZGetRecipientQuerySchema,
ZGetRecipientRequestSchema,
ZGetRecipientResponseSchema,
ZRejectDocumentWithTokenMutationSchema,
ZSetDocumentRecipientsRequestSchema,
ZSetDocumentRecipientsResponseSchema,
ZSetTemplateRecipientsRequestSchema,
ZSetTemplateRecipientsResponseSchema,
ZUpdateDocumentRecipientRequestSchema,
ZUpdateDocumentRecipientResponseSchema,
ZUpdateDocumentRecipientsRequestSchema,
@ -69,8 +58,8 @@ export const recipientRouter = router({
tags: ['Document Recipients', 'Template Recipients'],
},
})
.input(ZGetRecipientQuerySchema)
.output(ZGetRecipientByIdResponseSchema)
.input(ZGetRecipientRequestSchema)
.output(ZGetRecipientResponseSchema)
.query(async ({ input, ctx }) => {
const { teamId } = ctx;
const { recipientId } = input;
@ -464,32 +453,4 @@ export const recipientRouter = router({
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
}),
/**
* Leaving this here and will remove after deployment.
*
* @deprecated Remove after deployment.
*/
addSigners: authenticatedProcedure
.input(ZAddSignersMutationSchema)
.output(ZSetDocumentRecipientsResponseSchema)
.mutation(async ({ input, ctx }) => {
const { teamId } = ctx;
const { documentId, signers } = input;
return await setDocumentRecipients({
userId: ctx.user.id,
documentId,
teamId,
recipients: signers.map((signer) => ({
id: signer.nativeId,
email: signer.email,
name: signer.name,
role: signer.role,
signingOrder: signer.signingOrder,
actionAuth: signer.actionAuth,
})),
requestMetadata: ctx.metadata,
});
}),
});

View File

@ -5,13 +5,15 @@ import {
ZRecipientActionAuthSchema,
ZRecipientActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth';
import { ZRecipientLiteSchema, ZRecipientSchema } from '@documenso/lib/types/recipient';
import { RecipientRole } from '@documenso/prisma/client';
import { FieldSchema, RecipientSchema } from '@documenso/prisma/generated/zod';
export const ZGetRecipientQuerySchema = z.object({
export const ZGetRecipientRequestSchema = z.object({
recipientId: z.number(),
});
export const ZGetRecipientResponseSchema = ZRecipientSchema;
const ZCreateRecipientSchema = z.object({
email: z.string().toLowerCase().email().min(1),
name: z.string(),
@ -31,41 +33,12 @@ const ZUpdateRecipientSchema = z.object({
actionAuth: ZRecipientActionAuthTypesSchema.optional().nullable(),
});
/**
* Use this when returning base recipients from the API.
*/
export const ZRecipientBaseResponseSchema = RecipientSchema.pick({
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
documentDeletedAt: true,
expired: true,
signedAt: true,
authOptions: true,
signingOrder: true,
rejectionReason: true,
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
});
/**
* Use this when returning a full recipient from the API.
*/
export const ZRecipientResponseSchema = ZRecipientBaseResponseSchema.extend({
fields: FieldSchema.array(),
});
export const ZCreateDocumentRecipientRequestSchema = z.object({
documentId: z.number(),
recipient: ZCreateRecipientSchema,
});
export const ZCreateDocumentRecipientResponseSchema = ZRecipientBaseResponseSchema;
export const ZCreateDocumentRecipientResponseSchema = ZRecipientLiteSchema;
export const ZCreateDocumentRecipientsRequestSchema = z.object({
documentId: z.number(),
@ -76,12 +49,16 @@ export const ZCreateDocumentRecipientsRequestSchema = z.object({
}),
});
export const ZCreateDocumentRecipientsResponseSchema = z.object({
recipients: ZRecipientLiteSchema.array(),
});
export const ZUpdateDocumentRecipientRequestSchema = z.object({
documentId: z.number(),
recipient: ZUpdateRecipientSchema,
});
export const ZUpdateDocumentRecipientResponseSchema = ZRecipientResponseSchema;
export const ZUpdateDocumentRecipientResponseSchema = ZRecipientSchema;
export const ZUpdateDocumentRecipientsRequestSchema = z.object({
documentId: z.number(),
@ -95,7 +72,7 @@ export const ZUpdateDocumentRecipientsRequestSchema = z.object({
});
export const ZUpdateDocumentRecipientsResponseSchema = z.object({
recipients: z.array(ZRecipientResponseSchema),
recipients: z.array(ZRecipientSchema),
});
export const ZDeleteDocumentRecipientRequestSchema = z.object({
@ -126,12 +103,16 @@ export const ZSetDocumentRecipientsRequestSchema = z
{ message: 'Signers must have unique emails', path: ['signers__root'] },
);
export const ZSetDocumentRecipientsResponseSchema = z.object({
recipients: ZRecipientLiteSchema.array(),
});
export const ZCreateTemplateRecipientRequestSchema = z.object({
templateId: z.number(),
recipient: ZCreateRecipientSchema,
});
export const ZCreateTemplateRecipientResponseSchema = ZRecipientBaseResponseSchema;
export const ZCreateTemplateRecipientResponseSchema = ZRecipientLiteSchema;
export const ZCreateTemplateRecipientsRequestSchema = z.object({
templateId: z.number(),
@ -142,12 +123,16 @@ export const ZCreateTemplateRecipientsRequestSchema = z.object({
}),
});
export const ZCreateTemplateRecipientsResponseSchema = z.object({
recipients: ZRecipientLiteSchema.array(),
});
export const ZUpdateTemplateRecipientRequestSchema = z.object({
templateId: z.number(),
recipient: ZUpdateRecipientSchema,
});
export const ZUpdateTemplateRecipientResponseSchema = ZRecipientResponseSchema;
export const ZUpdateTemplateRecipientResponseSchema = ZRecipientSchema;
export const ZUpdateTemplateRecipientsRequestSchema = z.object({
templateId: z.number(),
@ -161,11 +146,7 @@ export const ZUpdateTemplateRecipientsRequestSchema = z.object({
});
export const ZUpdateTemplateRecipientsResponseSchema = z.object({
recipients: z.array(ZRecipientResponseSchema).refine((recipients) => {
const emails = recipients.map((recipient) => recipient.email);
return new Set(emails).size === emails.length;
}),
recipients: z.array(ZRecipientSchema),
});
export const ZDeleteTemplateRecipientRequestSchema = z.object({
@ -196,6 +177,10 @@ export const ZSetTemplateRecipientsRequestSchema = z
{ message: 'Recipients must have unique emails', path: ['recipients__root'] },
);
export const ZSetTemplateRecipientsResponseSchema = z.object({
recipients: ZRecipientLiteSchema.array(),
});
export const ZCompleteDocumentWithTokenMutationSchema = z.object({
token: z.string(),
documentId: z.number(),
@ -216,32 +201,3 @@ export const ZRejectDocumentWithTokenMutationSchema = z.object({
export type TRejectDocumentWithTokenMutationSchema = z.infer<
typeof ZRejectDocumentWithTokenMutationSchema
>;
/**
* Legacy schema. Remove after deployment (when addSigners trpc is removed).
*
* @deprecated
*/
export const ZAddSignersMutationSchema = z
.object({
documentId: z.number(),
signers: z.array(
z.object({
nativeId: z.number().optional(),
email: z.string().toLowerCase().email().min(1),
name: z.string(),
role: z.nativeEnum(RecipientRole),
signingOrder: z.number().optional(),
actionAuth: ZRecipientActionAuthTypesSchema.optional().nullable(),
}),
),
})
.refine(
(schema) => {
const emails = schema.signers.map((signer) => signer.email.toLowerCase());
return new Set(emails).size === emails.length;
},
// Dirty hack to handle errors when .root is populated for an array type
{ message: 'Signers must have unique emails', path: ['signers__root'] },
);

View File

@ -2,10 +2,7 @@ import { z } from 'zod';
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import {
ZGetDocumentWithDetailsByIdResponseSchema,
getDocumentWithDetailsById,
} from '@documenso/lib/server-only/document/get-document-with-details-by-id';
import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
import {
ZCreateDocumentFromDirectTemplateResponseSchema,
@ -50,16 +47,17 @@ import type { Document } from '@documenso/prisma/client';
import { authenticatedProcedure, maybeAuthenticatedProcedure, router } from '../trpc';
import {
ZCreateDocumentFromDirectTemplateMutationSchema,
ZCreateDocumentFromTemplateMutationSchema,
ZCreateDocumentFromDirectTemplateRequestSchema,
ZCreateDocumentFromTemplateRequestSchema,
ZCreateDocumentFromTemplateResponseSchema,
ZCreateTemplateDirectLinkMutationSchema,
ZCreateTemplateMutationSchema,
ZDeleteTemplateDirectLinkMutationSchema,
ZDeleteTemplateMutationSchema,
ZDuplicateTemplateMutationSchema,
ZFindTemplatesQuerySchema,
ZGetTemplateByIdQuerySchema,
ZMoveTemplatesToTeamSchema,
ZFindTemplatesRequestSchema,
ZGetTemplateByIdRequestSchema,
ZMoveTemplatesToTeamRequestSchema,
ZToggleTemplateDirectLinkMutationSchema,
ZUpdateTemplateRequestSchema,
} from './schema';
@ -78,7 +76,7 @@ export const templateRouter = router({
tags: ['Template'],
},
})
.input(ZFindTemplatesQuerySchema)
.input(ZFindTemplatesRequestSchema)
.output(ZFindTemplatesResponseSchema)
.query(async ({ input, ctx }) => {
const { teamId } = ctx;
@ -102,7 +100,7 @@ export const templateRouter = router({
tags: ['Template'],
},
})
.input(ZGetTemplateByIdQuerySchema)
.input(ZGetTemplateByIdRequestSchema)
.output(ZGetTemplateByIdResponseSchema)
.query(async ({ input, ctx }) => {
const { teamId } = ctx;
@ -234,8 +232,8 @@ export const templateRouter = router({
tags: ['Template'],
},
})
.input(ZCreateDocumentFromTemplateMutationSchema)
.output(ZGetDocumentWithDetailsByIdResponseSchema)
.input(ZCreateDocumentFromTemplateRequestSchema)
.output(ZCreateDocumentFromTemplateResponseSchema)
.mutation(async ({ ctx, input }) => {
const { teamId } = ctx;
const { templateId, recipients, distributeDocument, customDocumentDataId } = input;
@ -290,7 +288,7 @@ export const templateRouter = router({
// tags: ['Template'],
// },
// })
.input(ZCreateDocumentFromDirectTemplateMutationSchema)
.input(ZCreateDocumentFromDirectTemplateRequestSchema)
.output(ZCreateDocumentFromDirectTemplateResponseSchema)
.mutation(async ({ input, ctx }) => {
const {
@ -415,7 +413,7 @@ export const templateRouter = router({
tags: ['Template'],
},
})
.input(ZMoveTemplatesToTeamSchema)
.input(ZMoveTemplatesToTeamRequestSchema)
.output(ZMoveTemplateToTeamResponseSchema)
.mutation(async ({ input, ctx }) => {
const { templateId, teamId } = input;

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZDocumentSchema } from '@documenso/lib/types/document';
import {
ZDocumentAccessAuthTypesSchema,
ZDocumentActionAuthTypesSchema,
@ -25,7 +26,7 @@ export const ZCreateTemplateMutationSchema = z.object({
templateDocumentDataId: z.string().min(1),
});
export const ZCreateDocumentFromDirectTemplateMutationSchema = z.object({
export const ZCreateDocumentFromDirectTemplateRequestSchema = z.object({
directRecipientName: z.string().optional(),
directRecipientEmail: z.string().email(),
directTemplateToken: z.string().min(1),
@ -34,7 +35,7 @@ export const ZCreateDocumentFromDirectTemplateMutationSchema = z.object({
templateUpdatedAt: z.date(),
});
export const ZCreateDocumentFromTemplateMutationSchema = z.object({
export const ZCreateDocumentFromTemplateRequestSchema = z.object({
templateId: z.number(),
recipients: z
.array(
@ -62,6 +63,8 @@ export const ZCreateDocumentFromTemplateMutationSchema = z.object({
.optional(),
});
export const ZCreateDocumentFromTemplateResponseSchema = ZDocumentSchema;
export const ZDuplicateTemplateMutationSchema = z.object({
templateId: z.number(),
});
@ -138,24 +141,19 @@ export const ZUpdateTemplateRequestSchema = z.object({
.optional(),
});
export const ZFindTemplatesQuerySchema = ZFindSearchParamsSchema.extend({
export const ZFindTemplatesRequestSchema = ZFindSearchParamsSchema.extend({
type: z.nativeEnum(TemplateType).describe('Filter templates by type.').optional(),
});
export const ZGetTemplateByIdQuerySchema = z.object({
templateId: z.number().min(1),
export const ZGetTemplateByIdRequestSchema = z.object({
templateId: z.number(),
});
export const ZMoveTemplatesToTeamSchema = z.object({
export const ZMoveTemplatesToTeamRequestSchema = z.object({
templateId: z.number().describe('The ID of the template to move to.'),
teamId: z.number().describe('The ID of the team to move the template to.'),
});
export type TCreateTemplateMutationSchema = z.infer<typeof ZCreateTemplateMutationSchema>;
export type TCreateDocumentFromTemplateMutationSchema = z.infer<
typeof ZCreateDocumentFromTemplateMutationSchema
>;
export type TDuplicateTemplateMutationSchema = z.infer<typeof ZDuplicateTemplateMutationSchema>;
export type TDeleteTemplateMutationSchema = z.infer<typeof ZDeleteTemplateMutationSchema>;
export type TGetTemplateByIdQuerySchema = z.infer<typeof ZGetTemplateByIdQuerySchema>;
export type TMoveTemplatesToSchema = z.infer<typeof ZMoveTemplatesToTeamSchema>;