fix: handle bracket notation arrays (#2178)

Co-authored-by: David Nguyen <davidngu28@gmail.com>
This commit is contained in:
Lucas Smith
2025-11-12 16:38:06 +11:00
committed by GitHub
parent 378dd605b9
commit 68a3608aee
43 changed files with 137 additions and 68 deletions

View File

@ -21,7 +21,7 @@ export const downloadRoute = new Hono<HonoEnv>()
* Requires API key authentication via Authorization header. * Requires API key authentication via Authorization header.
*/ */
.get( .get(
'/envelopeItem/:envelopeItemId/download', '/envelope/item/:envelopeItemId/download',
sValidator('param', ZDownloadEnvelopeItemRequestParamsSchema), sValidator('param', ZDownloadEnvelopeItemRequestParamsSchema),
async (c) => { async (c) => {
const logger = c.get('logger'); const logger = c.get('logger');

View File

@ -41,10 +41,14 @@ export const createAttachmentRoute = authenticatedProcedure
type: EnvelopeType.DOCUMENT, type: EnvelopeType.DOCUMENT,
}); });
await createAttachment({ const attachment = await createAttachment({
envelopeId: envelope.id, envelopeId: envelope.id,
teamId, teamId,
userId, userId,
data, data,
}); });
return {
id: attachment.id,
};
}); });

View File

@ -8,7 +8,9 @@ export const ZCreateAttachmentRequestSchema = z.object({
}), }),
}); });
export const ZCreateAttachmentResponseSchema = z.void(); export const ZCreateAttachmentResponseSchema = z.object({
id: z.string(),
});
export type TCreateAttachmentRequest = z.infer<typeof ZCreateAttachmentRequestSchema>; export type TCreateAttachmentRequest = z.infer<typeof ZCreateAttachmentRequestSchema>;
export type TCreateAttachmentResponse = z.infer<typeof ZCreateAttachmentResponseSchema>; export type TCreateAttachmentResponse = z.infer<typeof ZCreateAttachmentResponseSchema>;

View File

@ -1,5 +1,6 @@
import { deleteAttachment } from '@documenso/lib/server-only/envelope-attachment/delete-attachment'; import { deleteAttachment } from '@documenso/lib/server-only/envelope-attachment/delete-attachment';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc'; import { authenticatedProcedure } from '../../trpc';
import { import {
ZDeleteAttachmentRequestSchema, ZDeleteAttachmentRequestSchema,
@ -33,4 +34,6 @@ export const deleteAttachmentRoute = authenticatedProcedure
userId, userId,
teamId, teamId,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,10 +1,12 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
export const ZDeleteAttachmentRequestSchema = z.object({ export const ZDeleteAttachmentRequestSchema = z.object({
id: z.string(), id: z.string(),
}); });
export const ZDeleteAttachmentResponseSchema = z.void(); export const ZDeleteAttachmentResponseSchema = ZSuccessResponseSchema;
export type TDeleteAttachmentRequest = z.infer<typeof ZDeleteAttachmentRequestSchema>; export type TDeleteAttachmentRequest = z.infer<typeof ZDeleteAttachmentRequestSchema>;
export type TDeleteAttachmentResponse = z.infer<typeof ZDeleteAttachmentResponseSchema>; export type TDeleteAttachmentResponse = z.infer<typeof ZDeleteAttachmentResponseSchema>;

View File

@ -1,5 +1,6 @@
import { updateAttachment } from '@documenso/lib/server-only/envelope-attachment/update-attachment'; import { updateAttachment } from '@documenso/lib/server-only/envelope-attachment/update-attachment';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc'; import { authenticatedProcedure } from '../../trpc';
import { import {
ZUpdateAttachmentRequestSchema, ZUpdateAttachmentRequestSchema,
@ -34,4 +35,6 @@ export const updateAttachmentRoute = authenticatedProcedure
teamId, teamId,
data, data,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,7 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
export const ZUpdateAttachmentRequestSchema = z.object({ export const ZUpdateAttachmentRequestSchema = z.object({
id: z.string(), id: z.string(),
data: z.object({ data: z.object({
@ -8,7 +10,7 @@ export const ZUpdateAttachmentRequestSchema = z.object({
}), }),
}); });
export const ZUpdateAttachmentResponseSchema = z.void(); export const ZUpdateAttachmentResponseSchema = ZSuccessResponseSchema;
export type TUpdateAttachmentRequest = z.infer<typeof ZUpdateAttachmentRequestSchema>; export type TUpdateAttachmentRequest = z.infer<typeof ZUpdateAttachmentRequestSchema>;
export type TUpdateAttachmentResponse = z.infer<typeof ZUpdateAttachmentResponseSchema>; export type TUpdateAttachmentResponse = z.infer<typeof ZUpdateAttachmentResponseSchema>;

View File

@ -1,12 +1,12 @@
import { deleteDocument } from '@documenso/lib/server-only/document/delete-document'; import { deleteDocument } from '@documenso/lib/server-only/document/delete-document';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc'; import { authenticatedProcedure } from '../trpc';
import { import {
ZDeleteDocumentRequestSchema, ZDeleteDocumentRequestSchema,
ZDeleteDocumentResponseSchema, ZDeleteDocumentResponseSchema,
deleteDocumentMeta, deleteDocumentMeta,
} from './delete-document.types'; } from './delete-document.types';
import { ZGenericSuccessResponse } from './schema';
export const deleteDocumentRoute = authenticatedProcedure export const deleteDocumentRoute = authenticatedProcedure
.meta(deleteDocumentMeta) .meta(deleteDocumentMeta)

View File

@ -1,7 +1,7 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc'; import type { TrpcRouteMeta } from '../trpc';
import { ZSuccessResponseSchema } from './schema';
export const deleteDocumentMeta: TrpcRouteMeta = { export const deleteDocumentMeta: TrpcRouteMeta = {
openapi: { openapi: {

View File

@ -19,5 +19,6 @@ export const downloadDocumentRoute = authenticatedProcedure
}, },
}); });
// This endpoint is purely for V2 API, which is implemented in the Hono remix server.
throw new Error('NOT_IMPLEMENTED'); throw new Error('NOT_IMPLEMENTED');
}); });

View File

@ -1,12 +1,12 @@
import { resendDocument } from '@documenso/lib/server-only/document/resend-document'; import { resendDocument } from '@documenso/lib/server-only/document/resend-document';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc'; import { authenticatedProcedure } from '../trpc';
import { import {
ZRedistributeDocumentRequestSchema, ZRedistributeDocumentRequestSchema,
ZRedistributeDocumentResponseSchema, ZRedistributeDocumentResponseSchema,
redistributeDocumentMeta, redistributeDocumentMeta,
} from './redistribute-document.types'; } from './redistribute-document.types';
import { ZGenericSuccessResponse } from './schema';
export const redistributeDocumentRoute = authenticatedProcedure export const redistributeDocumentRoute = authenticatedProcedure
.meta(redistributeDocumentMeta) .meta(redistributeDocumentMeta)

View File

@ -1,7 +1,7 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc'; import type { TrpcRouteMeta } from '../trpc';
import { ZSuccessResponseSchema } from './schema';
export const redistributeDocumentMeta: TrpcRouteMeta = { export const redistributeDocumentMeta: TrpcRouteMeta = {
openapi: { openapi: {

View File

@ -1,19 +1,6 @@
import { DocumentVisibility } from '@prisma/client'; import { DocumentVisibility } from '@prisma/client';
import { z } from 'zod'; import { z } from 'zod';
/**
* Required for empty responses since we currently can't 201 requests for our openapi setup.
*
* Without this it will throw an error in Speakeasy SDK when it tries to parse an empty response.
*/
export const ZSuccessResponseSchema = z.object({
success: z.literal(true),
});
export const ZGenericSuccessResponse = {
success: true,
} satisfies z.infer<typeof ZSuccessResponseSchema>;
export const ZDocumentTitleSchema = z export const ZDocumentTitleSchema = z
.string() .string()
.trim() .trim()

View File

@ -21,10 +21,14 @@ export const createAttachmentRoute = authenticatedProcedure
input: { envelopeId, label: data.label }, input: { envelopeId, label: data.label },
}); });
await createAttachment({ const attachment = await createAttachment({
envelopeId, envelopeId,
teamId, teamId,
userId, userId,
data, data,
}); });
return {
id: attachment.id,
};
}); });

View File

@ -20,7 +20,9 @@ export const ZCreateAttachmentRequestSchema = z.object({
}), }),
}); });
export const ZCreateAttachmentResponseSchema = z.void(); export const ZCreateAttachmentResponseSchema = z.object({
id: z.string(),
});
export type TCreateAttachmentRequest = z.infer<typeof ZCreateAttachmentRequestSchema>; export type TCreateAttachmentRequest = z.infer<typeof ZCreateAttachmentRequestSchema>;
export type TCreateAttachmentResponse = z.infer<typeof ZCreateAttachmentResponseSchema>; export type TCreateAttachmentResponse = z.infer<typeof ZCreateAttachmentResponseSchema>;

View File

@ -1,5 +1,6 @@
import { deleteAttachment } from '@documenso/lib/server-only/envelope-attachment/delete-attachment'; import { deleteAttachment } from '@documenso/lib/server-only/envelope-attachment/delete-attachment';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc'; import { authenticatedProcedure } from '../../trpc';
import { import {
ZDeleteAttachmentRequestSchema, ZDeleteAttachmentRequestSchema,
@ -26,4 +27,6 @@ export const deleteAttachmentRoute = authenticatedProcedure
userId, userId,
teamId, teamId,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc'; import type { TrpcRouteMeta } from '../../trpc';
export const deleteAttachmentMeta: TrpcRouteMeta = { export const deleteAttachmentMeta: TrpcRouteMeta = {
@ -16,7 +17,7 @@ export const ZDeleteAttachmentRequestSchema = z.object({
id: z.string(), id: z.string(),
}); });
export const ZDeleteAttachmentResponseSchema = z.void(); export const ZDeleteAttachmentResponseSchema = ZSuccessResponseSchema;
export type TDeleteAttachmentRequest = z.infer<typeof ZDeleteAttachmentRequestSchema>; export type TDeleteAttachmentRequest = z.infer<typeof ZDeleteAttachmentRequestSchema>;
export type TDeleteAttachmentResponse = z.infer<typeof ZDeleteAttachmentResponseSchema>; export type TDeleteAttachmentResponse = z.infer<typeof ZDeleteAttachmentResponseSchema>;

View File

@ -1,5 +1,6 @@
import { updateAttachment } from '@documenso/lib/server-only/envelope-attachment/update-attachment'; import { updateAttachment } from '@documenso/lib/server-only/envelope-attachment/update-attachment';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc'; import { authenticatedProcedure } from '../../trpc';
import { import {
ZUpdateAttachmentRequestSchema, ZUpdateAttachmentRequestSchema,
@ -27,4 +28,6 @@ export const updateAttachmentRoute = authenticatedProcedure
teamId, teamId,
data, data,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc'; import type { TrpcRouteMeta } from '../../trpc';
export const updateAttachmentMeta: TrpcRouteMeta = { export const updateAttachmentMeta: TrpcRouteMeta = {
@ -20,7 +21,7 @@ export const ZUpdateAttachmentRequestSchema = z.object({
}), }),
}); });
export const ZUpdateAttachmentResponseSchema = z.void(); export const ZUpdateAttachmentResponseSchema = ZSuccessResponseSchema;
export type TUpdateAttachmentRequest = z.infer<typeof ZUpdateAttachmentRequestSchema>; export type TUpdateAttachmentRequest = z.infer<typeof ZUpdateAttachmentRequestSchema>;
export type TUpdateAttachmentResponse = z.infer<typeof ZUpdateAttachmentResponseSchema>; export type TUpdateAttachmentResponse = z.infer<typeof ZUpdateAttachmentResponseSchema>;

View File

@ -11,6 +11,7 @@ export const createEnvelopeItemsMeta: TrpcRouteMeta = {
method: 'POST', method: 'POST',
path: '/envelope/item/create-many', path: '/envelope/item/create-many',
summary: 'Create envelope items', summary: 'Create envelope items',
contentTypes: ['multipart/form-data'],
description: 'Create multiple envelope items for an envelope', description: 'Create multiple envelope items for an envelope',
tags: ['Envelope Items'], tags: ['Envelope Items'],
}, },

View File

@ -5,6 +5,7 @@ import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-
import { canEnvelopeItemsBeModified } from '@documenso/lib/utils/envelope'; import { canEnvelopeItemsBeModified } from '@documenso/lib/utils/envelope';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc'; import { authenticatedProcedure } from '../trpc';
import { import {
ZDeleteEnvelopeItemRequestSchema, ZDeleteEnvelopeItemRequestSchema,
@ -100,4 +101,6 @@ export const deleteEnvelopeItemRoute = authenticatedProcedure
}, },
}, },
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc'; import type { TrpcRouteMeta } from '../trpc';
export const deleteEnvelopeItemMeta: TrpcRouteMeta = { export const deleteEnvelopeItemMeta: TrpcRouteMeta = {
@ -17,7 +18,7 @@ export const ZDeleteEnvelopeItemRequestSchema = z.object({
envelopeItemId: z.string(), envelopeItemId: z.string(),
}); });
export const ZDeleteEnvelopeItemResponseSchema = z.void(); export const ZDeleteEnvelopeItemResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeItemRequest = z.infer<typeof ZDeleteEnvelopeItemRequestSchema>; export type TDeleteEnvelopeItemRequest = z.infer<typeof ZDeleteEnvelopeItemRequestSchema>;
export type TDeleteEnvelopeItemResponse = z.infer<typeof ZDeleteEnvelopeItemResponseSchema>; export type TDeleteEnvelopeItemResponse = z.infer<typeof ZDeleteEnvelopeItemResponseSchema>;

View File

@ -6,6 +6,7 @@ import { deleteDocument } from '@documenso/lib/server-only/document/delete-docum
import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template'; import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc'; import { authenticatedProcedure } from '../trpc';
import { import {
ZDeleteEnvelopeRequestSchema, ZDeleteEnvelopeRequestSchema,
@ -65,4 +66,6 @@ export const deleteEnvelopeRoute = authenticatedProcedure
}), }),
) )
.exhaustive(); .exhaustive();
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc'; import type { TrpcRouteMeta } from '../trpc';
export const deleteEnvelopeMeta: TrpcRouteMeta = { export const deleteEnvelopeMeta: TrpcRouteMeta = {
@ -15,7 +16,7 @@ export const ZDeleteEnvelopeRequestSchema = z.object({
envelopeId: z.string(), envelopeId: z.string(),
}); });
export const ZDeleteEnvelopeResponseSchema = z.void(); export const ZDeleteEnvelopeResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeRequest = z.infer<typeof ZDeleteEnvelopeRequestSchema>; export type TDeleteEnvelopeRequest = z.infer<typeof ZDeleteEnvelopeRequestSchema>;
export type TDeleteEnvelopeResponse = z.infer<typeof ZDeleteEnvelopeResponseSchema>; export type TDeleteEnvelopeResponse = z.infer<typeof ZDeleteEnvelopeResponseSchema>;

View File

@ -1,6 +1,7 @@
import { updateDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta'; import { updateDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta';
import { sendDocument } from '@documenso/lib/server-only/document/send-document'; import { sendDocument } from '@documenso/lib/server-only/document/send-document';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc'; import { authenticatedProcedure } from '../trpc';
import { import {
ZDistributeEnvelopeRequestSchema, ZDistributeEnvelopeRequestSchema,
@ -53,4 +54,6 @@ export const distributeEnvelopeRoute = authenticatedProcedure
teamId, teamId,
requestMetadata: ctx.metadata, requestMetadata: ctx.metadata,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -2,6 +2,7 @@ import { z } from 'zod';
import { ZDocumentMetaUpdateSchema } from '@documenso/lib/types/document-meta'; import { ZDocumentMetaUpdateSchema } from '@documenso/lib/types/document-meta';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc'; import type { TrpcRouteMeta } from '../trpc';
export const distributeEnvelopeMeta: TrpcRouteMeta = { export const distributeEnvelopeMeta: TrpcRouteMeta = {
@ -30,7 +31,7 @@ export const ZDistributeEnvelopeRequestSchema = z.object({
}).optional(), }).optional(),
}); });
export const ZDistributeEnvelopeResponseSchema = z.void(); export const ZDistributeEnvelopeResponseSchema = ZSuccessResponseSchema;
export type TDistributeEnvelopeRequest = z.infer<typeof ZDistributeEnvelopeRequestSchema>; export type TDistributeEnvelopeRequest = z.infer<typeof ZDistributeEnvelopeRequestSchema>;
export type TDistributeEnvelopeResponse = z.infer<typeof ZDistributeEnvelopeResponseSchema>; export type TDistributeEnvelopeResponse = z.infer<typeof ZDistributeEnvelopeResponseSchema>;

View File

@ -19,5 +19,6 @@ export const downloadEnvelopeItemRoute = authenticatedProcedure
}, },
}); });
// This endpoint is purely for V2 API, which is implemented in the Hono remix server.
throw new Error('NOT_IMPLEMENTED'); throw new Error('NOT_IMPLEMENTED');
}); });

View File

@ -16,7 +16,6 @@ export const createEnvelopeFieldsMeta: TrpcRouteMeta = {
openapi: { openapi: {
method: 'POST', method: 'POST',
path: '/envelope/field/create-many', path: '/envelope/field/create-many',
contentTypes: ['multipart/form-data'],
summary: 'Create envelope fields', summary: 'Create envelope fields',
description: 'Create multiple fields for an envelope', description: 'Create multiple fields for an envelope',
tags: ['Envelope Fields'], tags: ['Envelope Fields'],

View File

@ -7,6 +7,7 @@ import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-
import { canRecipientFieldsBeModified } from '@documenso/lib/utils/recipients'; import { canRecipientFieldsBeModified } from '@documenso/lib/utils/recipients';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc'; import { authenticatedProcedure } from '../../trpc';
import { import {
ZDeleteEnvelopeFieldRequestSchema, ZDeleteEnvelopeFieldRequestSchema,
@ -115,4 +116,6 @@ export const deleteEnvelopeFieldRoute = authenticatedProcedure
return deletedField; return deletedField;
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc'; import type { TrpcRouteMeta } from '../../trpc';
export const deleteEnvelopeFieldMeta: TrpcRouteMeta = { export const deleteEnvelopeFieldMeta: TrpcRouteMeta = {
@ -16,7 +17,7 @@ export const ZDeleteEnvelopeFieldRequestSchema = z.object({
fieldId: z.number(), fieldId: z.number(),
}); });
export const ZDeleteEnvelopeFieldResponseSchema = z.void(); export const ZDeleteEnvelopeFieldResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeFieldRequest = z.infer<typeof ZDeleteEnvelopeFieldRequestSchema>; export type TDeleteEnvelopeFieldRequest = z.infer<typeof ZDeleteEnvelopeFieldRequestSchema>;
export type TDeleteEnvelopeFieldResponse = z.infer<typeof ZDeleteEnvelopeFieldResponseSchema>; export type TDeleteEnvelopeFieldResponse = z.infer<typeof ZDeleteEnvelopeFieldResponseSchema>;

View File

@ -1,5 +1,6 @@
import { deleteEnvelopeRecipient } from '@documenso/lib/server-only/recipient/delete-envelope-recipient'; import { deleteEnvelopeRecipient } from '@documenso/lib/server-only/recipient/delete-envelope-recipient';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc'; import { authenticatedProcedure } from '../../trpc';
import { import {
ZDeleteEnvelopeRecipientRequestSchema, ZDeleteEnvelopeRecipientRequestSchema,
@ -27,4 +28,6 @@ export const deleteEnvelopeRecipientRoute = authenticatedProcedure
recipientId, recipientId,
requestMetadata: metadata, requestMetadata: metadata,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc'; import type { TrpcRouteMeta } from '../../trpc';
export const deleteEnvelopeRecipientMeta: TrpcRouteMeta = { export const deleteEnvelopeRecipientMeta: TrpcRouteMeta = {
@ -16,7 +17,7 @@ export const ZDeleteEnvelopeRecipientRequestSchema = z.object({
recipientId: z.number(), recipientId: z.number(),
}); });
export const ZDeleteEnvelopeRecipientResponseSchema = z.void(); export const ZDeleteEnvelopeRecipientResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeRecipientRequest = z.infer<typeof ZDeleteEnvelopeRecipientRequestSchema>; export type TDeleteEnvelopeRecipientRequest = z.infer<typeof ZDeleteEnvelopeRecipientRequestSchema>;
export type TDeleteEnvelopeRecipientResponse = z.infer< export type TDeleteEnvelopeRecipientResponse = z.infer<

View File

@ -1,5 +1,6 @@
import { resendDocument } from '@documenso/lib/server-only/document/resend-document'; import { resendDocument } from '@documenso/lib/server-only/document/resend-document';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc'; import { authenticatedProcedure } from '../trpc';
import { import {
ZRedistributeEnvelopeRequestSchema, ZRedistributeEnvelopeRequestSchema,
@ -32,4 +33,6 @@ export const redistributeEnvelopeRoute = authenticatedProcedure
recipients, recipients,
requestMetadata: ctx.metadata, requestMetadata: ctx.metadata,
}); });
return ZGenericSuccessResponse;
}); });

View File

@ -1,5 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc'; import type { TrpcRouteMeta } from '../trpc';
export const redistributeEnvelopeMeta: TrpcRouteMeta = { export const redistributeEnvelopeMeta: TrpcRouteMeta = {
@ -21,7 +22,7 @@ export const ZRedistributeEnvelopeRequestSchema = z.object({
.describe('The IDs of the recipients to redistribute the envelope to.'), .describe('The IDs of the recipients to redistribute the envelope to.'),
}); });
export const ZRedistributeEnvelopeResponseSchema = z.void(); export const ZRedistributeEnvelopeResponseSchema = ZSuccessResponseSchema;
export type TRedistributeEnvelopeRequest = z.infer<typeof ZRedistributeEnvelopeRequestSchema>; export type TRedistributeEnvelopeRequest = z.infer<typeof ZRedistributeEnvelopeRequestSchema>;
export type TRedistributeEnvelopeResponse = z.infer<typeof ZRedistributeEnvelopeResponseSchema>; export type TRedistributeEnvelopeResponse = z.infer<typeof ZRedistributeEnvelopeResponseSchema>;

View File

@ -8,6 +8,7 @@ import { createEnvelopeItemsRoute } from './create-envelope-items';
import { deleteEnvelopeRoute } from './delete-envelope'; import { deleteEnvelopeRoute } from './delete-envelope';
import { deleteEnvelopeItemRoute } from './delete-envelope-item'; import { deleteEnvelopeItemRoute } from './delete-envelope-item';
import { distributeEnvelopeRoute } from './distribute-envelope'; import { distributeEnvelopeRoute } from './distribute-envelope';
import { downloadEnvelopeItemRoute } from './download-envelope-item';
import { duplicateEnvelopeRoute } from './duplicate-envelope'; import { duplicateEnvelopeRoute } from './duplicate-envelope';
import { createEnvelopeFieldsRoute } from './envelope-fields/create-envelope-fields'; import { createEnvelopeFieldsRoute } from './envelope-fields/create-envelope-fields';
import { deleteEnvelopeFieldRoute } from './envelope-fields/delete-envelope-field'; import { deleteEnvelopeFieldRoute } from './envelope-fields/delete-envelope-field';
@ -46,6 +47,7 @@ export const envelopeRouter = router({
createMany: createEnvelopeItemsRoute, createMany: createEnvelopeItemsRoute,
updateMany: updateEnvelopeItemsRoute, updateMany: updateEnvelopeItemsRoute,
delete: deleteEnvelopeItemRoute, delete: deleteEnvelopeItemRoute,
download: downloadEnvelopeItemRoute,
}, },
recipient: { recipient: {
get: getEnvelopeRecipientRoute, get: getEnvelopeRecipientRoute,

View File

@ -10,7 +10,7 @@ import { setFieldsForTemplate } from '@documenso/lib/server-only/field/set-field
import { signFieldWithToken } from '@documenso/lib/server-only/field/sign-field-with-token'; import { signFieldWithToken } from '@documenso/lib/server-only/field/sign-field-with-token';
import { updateEnvelopeFields } from '@documenso/lib/server-only/field/update-envelope-fields'; import { updateEnvelopeFields } from '@documenso/lib/server-only/field/update-envelope-fields';
import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../document-router/schema'; import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../schema';
import { authenticatedProcedure, procedure, router } from '../trpc'; import { authenticatedProcedure, procedure, router } from '../trpc';
import { import {
ZCreateDocumentFieldRequestSchema, ZCreateDocumentFieldRequestSchema,

View File

@ -7,6 +7,7 @@ import { getFolderBreadcrumbs } from '@documenso/lib/server-only/folder/get-fold
import { getFolderById } from '@documenso/lib/server-only/folder/get-folder-by-id'; import { getFolderById } from '@documenso/lib/server-only/folder/get-folder-by-id';
import { updateFolder } from '@documenso/lib/server-only/folder/update-folder'; import { updateFolder } from '@documenso/lib/server-only/folder/update-folder';
import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../schema';
import { authenticatedProcedure, router } from '../trpc'; import { authenticatedProcedure, router } from '../trpc';
import { import {
ZCreateFolderRequestSchema, ZCreateFolderRequestSchema,
@ -16,10 +17,8 @@ import {
ZFindFoldersInternalResponseSchema, ZFindFoldersInternalResponseSchema,
ZFindFoldersRequestSchema, ZFindFoldersRequestSchema,
ZFindFoldersResponseSchema, ZFindFoldersResponseSchema,
ZGenericSuccessResponse,
ZGetFoldersResponseSchema, ZGetFoldersResponseSchema,
ZGetFoldersSchema, ZGetFoldersSchema,
ZSuccessResponseSchema,
ZUpdateFolderRequestSchema, ZUpdateFolderRequestSchema,
ZUpdateFolderResponseSchema, ZUpdateFolderResponseSchema,
} from './schema'; } from './schema';

View File

@ -5,19 +5,6 @@ import { ZFindResultResponse, ZFindSearchParamsSchema } from '@documenso/lib/typ
import { DocumentVisibility } from '@documenso/prisma/generated/types'; import { DocumentVisibility } from '@documenso/prisma/generated/types';
import FolderSchema from '@documenso/prisma/generated/zod/modelSchema/FolderSchema'; import FolderSchema from '@documenso/prisma/generated/zod/modelSchema/FolderSchema';
/**
* Required for empty responses since we currently can't 201 requests for our openapi setup.
*
* Without this it will throw an error in Speakeasy SDK when it tries to parse an empty response.
*/
export const ZSuccessResponseSchema = z.object({
success: z.boolean(),
});
export const ZGenericSuccessResponse = {
success: true,
} satisfies z.infer<typeof ZSuccessResponseSchema>;
export const ZFolderSchema = FolderSchema.pick({ export const ZFolderSchema = FolderSchema.pick({
id: true, id: true,
name: true, name: true,

View File

@ -9,7 +9,7 @@ import { setDocumentRecipients } from '@documenso/lib/server-only/recipient/set-
import { setTemplateRecipients } from '@documenso/lib/server-only/recipient/set-template-recipients'; import { setTemplateRecipients } from '@documenso/lib/server-only/recipient/set-template-recipients';
import { updateEnvelopeRecipients } from '@documenso/lib/server-only/recipient/update-envelope-recipients'; import { updateEnvelopeRecipients } from '@documenso/lib/server-only/recipient/update-envelope-recipients';
import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../document-router/schema'; import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../schema';
import { authenticatedProcedure, procedure, router } from '../trpc'; import { authenticatedProcedure, procedure, router } from '../trpc';
import { findRecipientSuggestionsRoute } from './find-recipient-suggestions'; import { findRecipientSuggestionsRoute } from './find-recipient-suggestions';
import { import {

View File

@ -0,0 +1,14 @@
import { z } from 'zod';
/**
* Required for empty responses since we currently can't 201 requests for our openapi setup.
*
* Without this it will throw an error in Speakeasy SDK when it tries to parse an empty response.
*/
export const ZSuccessResponseSchema = z.object({
success: z.boolean(),
});
export const ZGenericSuccessResponse = {
success: true,
} satisfies z.infer<typeof ZSuccessResponseSchema>;

View File

@ -28,7 +28,7 @@ import { mapFieldToLegacyField } from '@documenso/lib/utils/fields';
import { mapRecipientToLegacyRecipient } from '@documenso/lib/utils/recipients'; import { mapRecipientToLegacyRecipient } from '@documenso/lib/utils/recipients';
import { mapEnvelopeToTemplateLite } from '@documenso/lib/utils/templates'; import { mapEnvelopeToTemplateLite } from '@documenso/lib/utils/templates';
import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../document-router/schema'; import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../schema';
import { authenticatedProcedure, maybeAuthenticatedProcedure, router } from '../trpc'; import { authenticatedProcedure, maybeAuthenticatedProcedure, router } from '../trpc';
import { import {
ZBulkSendTemplateMutationSchema, ZBulkSendTemplateMutationSchema,
@ -177,7 +177,19 @@ export const templateRouter = router({
const { payload, file } = input; const { payload, file } = input;
const { title, folderId } = payload; const {
title,
folderId,
externalId,
visibility,
globalAccessAuth,
globalActionAuth,
publicTitle,
publicDescription,
type,
meta,
attachments,
} = payload;
const { id: templateDocumentDataId } = await putNormalizedPdfFileServerSide(file); const { id: templateDocumentDataId } = await putNormalizedPdfFileServerSide(file);
@ -194,13 +206,22 @@ export const templateRouter = router({
data: { data: {
type: EnvelopeType.TEMPLATE, type: EnvelopeType.TEMPLATE,
title, title,
folderId,
envelopeItems: [ envelopeItems: [
{ {
documentDataId: templateDocumentDataId, documentDataId: templateDocumentDataId,
}, },
], ],
folderId,
externalId: externalId ?? undefined,
visibility,
globalAccessAuth,
globalActionAuth,
templateType: type,
publicTitle,
publicDescription,
}, },
meta,
attachments,
requestMetadata: ctx.metadata, requestMetadata: ctx.metadata,
}); });

View File

@ -79,16 +79,6 @@ export const ZTemplateMetaUpsertSchema = z.object({
allowDictateNextSigner: z.boolean().optional(), allowDictateNextSigner: z.boolean().optional(),
}); });
export const ZCreateTemplatePayloadSchema = z.object({
title: z.string().min(1).trim(),
folderId: z.string().optional(),
});
export const ZCreateTemplateMutationSchema = zodFormData({
payload: zfd.json(ZCreateTemplatePayloadSchema),
file: zfd.file(),
});
export const ZCreateDocumentFromDirectTemplateRequestSchema = z.object({ export const ZCreateDocumentFromDirectTemplateRequestSchema = z.object({
directRecipientName: z.string().max(255).optional(), directRecipientName: z.string().max(255).optional(),
directRecipientEmail: z.string().email().max(254), directRecipientEmail: z.string().email().max(254),
@ -234,6 +224,13 @@ export const ZCreateTemplateResponseSchema = z.object({
id: z.number(), id: z.number(),
}); });
export const ZCreateTemplatePayloadSchema = ZCreateTemplateV2RequestSchema;
export const ZCreateTemplateMutationSchema = zodFormData({
payload: zfd.json(ZCreateTemplatePayloadSchema),
file: zfd.file(),
});
export const ZUpdateTemplateRequestSchema = z.object({ export const ZUpdateTemplateRequestSchema = z.object({
templateId: z.number(), templateId: z.number(),
data: z data: z
@ -280,7 +277,7 @@ export const ZBulkSendTemplateMutationSchema = z.object({
sendImmediately: z.boolean(), sendImmediately: z.boolean(),
}); });
export type TCreateTemplatePayloadSchema = z.infer<typeof ZCreateTemplatePayloadSchema>; export type TCreateTemplatePayloadSchema = z.input<typeof ZCreateTemplatePayloadSchema>;
export type TCreateTemplateMutationSchema = z.infer<typeof ZCreateTemplateMutationSchema>; export type TCreateTemplateMutationSchema = z.infer<typeof ZCreateTemplateMutationSchema>;
export type TDuplicateTemplateMutationSchema = z.infer<typeof ZDuplicateTemplateMutationSchema>; export type TDuplicateTemplateMutationSchema = z.infer<typeof ZDuplicateTemplateMutationSchema>;
export type TDeleteTemplateMutationSchema = z.infer<typeof ZDeleteTemplateMutationSchema>; export type TDeleteTemplateMutationSchema = z.infer<typeof ZDeleteTemplateMutationSchema>;

View File

@ -24,11 +24,17 @@ const getMultipartBody = async (req: Request) => {
const data: Record<string, unknown> = {}; const data: Record<string, unknown> = {};
for (const key of formData.keys()) { for (const [key, value] of formData.entries()) {
const values = formData.getAll(key); // !: Handles cases where our generated SDKs send key[] syntax for arrays.
const normalizedKey = key.endsWith('[]') ? key.slice(0, -2) : key;
// Return array for multiple values, single value otherwise (matches URL-encoded behavior) if (data[normalizedKey] === undefined) {
data[key] = values.length > 1 ? values : values[0]; data[normalizedKey] = value;
} else if (Array.isArray(data[normalizedKey])) {
data[normalizedKey].push(value);
} else {
data[normalizedKey] = [data[normalizedKey], value];
}
} }
return data; return data;