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.
*/
.get(
'/envelopeItem/:envelopeItemId/download',
'/envelope/item/:envelopeItemId/download',
sValidator('param', ZDownloadEnvelopeItemRequestParamsSchema),
async (c) => {
const logger = c.get('logger');

View File

@ -41,10 +41,14 @@ export const createAttachmentRoute = authenticatedProcedure
type: EnvelopeType.DOCUMENT,
});
await createAttachment({
const attachment = await createAttachment({
envelopeId: envelope.id,
teamId,
userId,
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 TCreateAttachmentResponse = z.infer<typeof ZCreateAttachmentResponseSchema>;

View File

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

View File

@ -1,10 +1,12 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
export const ZDeleteAttachmentRequestSchema = z.object({
id: z.string(),
});
export const ZDeleteAttachmentResponseSchema = z.void();
export const ZDeleteAttachmentResponseSchema = ZSuccessResponseSchema;
export type TDeleteAttachmentRequest = z.infer<typeof ZDeleteAttachmentRequestSchema>;
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 { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc';
import {
ZUpdateAttachmentRequestSchema,
@ -34,4 +35,6 @@ export const updateAttachmentRoute = authenticatedProcedure
teamId,
data,
});
return ZGenericSuccessResponse;
});

View File

@ -1,5 +1,7 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
export const ZUpdateAttachmentRequestSchema = z.object({
id: z.string(),
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 TUpdateAttachmentResponse = z.infer<typeof ZUpdateAttachmentResponseSchema>;

View File

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

View File

@ -1,7 +1,7 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc';
import { ZSuccessResponseSchema } from './schema';
export const deleteDocumentMeta: TrpcRouteMeta = {
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');
});

View File

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

View File

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

View File

@ -1,19 +1,6 @@
import { DocumentVisibility } from '@prisma/client';
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
.string()
.trim()

View File

@ -21,10 +21,14 @@ export const createAttachmentRoute = authenticatedProcedure
input: { envelopeId, label: data.label },
});
await createAttachment({
const attachment = await createAttachment({
envelopeId,
teamId,
userId,
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 TCreateAttachmentResponse = z.infer<typeof ZCreateAttachmentResponseSchema>;

View File

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

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc';
export const deleteAttachmentMeta: TrpcRouteMeta = {
@ -16,7 +17,7 @@ export const ZDeleteAttachmentRequestSchema = z.object({
id: z.string(),
});
export const ZDeleteAttachmentResponseSchema = z.void();
export const ZDeleteAttachmentResponseSchema = ZSuccessResponseSchema;
export type TDeleteAttachmentRequest = z.infer<typeof ZDeleteAttachmentRequestSchema>;
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 { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc';
import {
ZUpdateAttachmentRequestSchema,
@ -27,4 +28,6 @@ export const updateAttachmentRoute = authenticatedProcedure
teamId,
data,
});
return ZGenericSuccessResponse;
});

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc';
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 TUpdateAttachmentResponse = z.infer<typeof ZUpdateAttachmentResponseSchema>;

View File

@ -11,6 +11,7 @@ export const createEnvelopeItemsMeta: TrpcRouteMeta = {
method: 'POST',
path: '/envelope/item/create-many',
summary: 'Create envelope items',
contentTypes: ['multipart/form-data'],
description: 'Create multiple envelope items for an envelope',
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 { prisma } from '@documenso/prisma';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc';
import {
ZDeleteEnvelopeItemRequestSchema,
@ -100,4 +101,6 @@ export const deleteEnvelopeItemRoute = authenticatedProcedure
},
},
});
return ZGenericSuccessResponse;
});

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc';
export const deleteEnvelopeItemMeta: TrpcRouteMeta = {
@ -17,7 +18,7 @@ export const ZDeleteEnvelopeItemRequestSchema = z.object({
envelopeItemId: z.string(),
});
export const ZDeleteEnvelopeItemResponseSchema = z.void();
export const ZDeleteEnvelopeItemResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeItemRequest = z.infer<typeof ZDeleteEnvelopeItemRequestSchema>;
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 { prisma } from '@documenso/prisma';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc';
import {
ZDeleteEnvelopeRequestSchema,
@ -65,4 +66,6 @@ export const deleteEnvelopeRoute = authenticatedProcedure
}),
)
.exhaustive();
return ZGenericSuccessResponse;
});

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc';
export const deleteEnvelopeMeta: TrpcRouteMeta = {
@ -15,7 +16,7 @@ export const ZDeleteEnvelopeRequestSchema = z.object({
envelopeId: z.string(),
});
export const ZDeleteEnvelopeResponseSchema = z.void();
export const ZDeleteEnvelopeResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeRequest = z.infer<typeof ZDeleteEnvelopeRequestSchema>;
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 { sendDocument } from '@documenso/lib/server-only/document/send-document';
import { ZGenericSuccessResponse } from '../schema';
import { authenticatedProcedure } from '../trpc';
import {
ZDistributeEnvelopeRequestSchema,
@ -53,4 +54,6 @@ export const distributeEnvelopeRoute = authenticatedProcedure
teamId,
requestMetadata: ctx.metadata,
});
return ZGenericSuccessResponse;
});

View File

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

View File

@ -16,7 +16,6 @@ export const createEnvelopeFieldsMeta: TrpcRouteMeta = {
openapi: {
method: 'POST',
path: '/envelope/field/create-many',
contentTypes: ['multipart/form-data'],
summary: 'Create envelope fields',
description: 'Create multiple fields for an envelope',
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 { prisma } from '@documenso/prisma';
import { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc';
import {
ZDeleteEnvelopeFieldRequestSchema,
@ -115,4 +116,6 @@ export const deleteEnvelopeFieldRoute = authenticatedProcedure
return deletedField;
});
return ZGenericSuccessResponse;
});

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../../schema';
import type { TrpcRouteMeta } from '../../trpc';
export const deleteEnvelopeFieldMeta: TrpcRouteMeta = {
@ -16,7 +17,7 @@ export const ZDeleteEnvelopeFieldRequestSchema = z.object({
fieldId: z.number(),
});
export const ZDeleteEnvelopeFieldResponseSchema = z.void();
export const ZDeleteEnvelopeFieldResponseSchema = ZSuccessResponseSchema;
export type TDeleteEnvelopeFieldRequest = z.infer<typeof ZDeleteEnvelopeFieldRequestSchema>;
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 { ZGenericSuccessResponse } from '../../schema';
import { authenticatedProcedure } from '../../trpc';
import {
ZDeleteEnvelopeRecipientRequestSchema,
@ -27,4 +28,6 @@ export const deleteEnvelopeRecipientRoute = authenticatedProcedure
recipientId,
requestMetadata: metadata,
});
return ZGenericSuccessResponse;
});

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZSuccessResponseSchema } from '../schema';
import type { TrpcRouteMeta } from '../trpc';
export const redistributeEnvelopeMeta: TrpcRouteMeta = {
@ -21,7 +22,7 @@ export const ZRedistributeEnvelopeRequestSchema = z.object({
.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 TRedistributeEnvelopeResponse = z.infer<typeof ZRedistributeEnvelopeResponseSchema>;

View File

@ -8,6 +8,7 @@ import { createEnvelopeItemsRoute } from './create-envelope-items';
import { deleteEnvelopeRoute } from './delete-envelope';
import { deleteEnvelopeItemRoute } from './delete-envelope-item';
import { distributeEnvelopeRoute } from './distribute-envelope';
import { downloadEnvelopeItemRoute } from './download-envelope-item';
import { duplicateEnvelopeRoute } from './duplicate-envelope';
import { createEnvelopeFieldsRoute } from './envelope-fields/create-envelope-fields';
import { deleteEnvelopeFieldRoute } from './envelope-fields/delete-envelope-field';
@ -46,6 +47,7 @@ export const envelopeRouter = router({
createMany: createEnvelopeItemsRoute,
updateMany: updateEnvelopeItemsRoute,
delete: deleteEnvelopeItemRoute,
download: downloadEnvelopeItemRoute,
},
recipient: {
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 { 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 {
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 { updateFolder } from '@documenso/lib/server-only/folder/update-folder';
import { ZGenericSuccessResponse, ZSuccessResponseSchema } from '../schema';
import { authenticatedProcedure, router } from '../trpc';
import {
ZCreateFolderRequestSchema,
@ -16,10 +17,8 @@ import {
ZFindFoldersInternalResponseSchema,
ZFindFoldersRequestSchema,
ZFindFoldersResponseSchema,
ZGenericSuccessResponse,
ZGetFoldersResponseSchema,
ZGetFoldersSchema,
ZSuccessResponseSchema,
ZUpdateFolderRequestSchema,
ZUpdateFolderResponseSchema,
} from './schema';

View File

@ -5,19 +5,6 @@ import { ZFindResultResponse, ZFindSearchParamsSchema } from '@documenso/lib/typ
import { DocumentVisibility } from '@documenso/prisma/generated/types';
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({
id: 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 { 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 { findRecipientSuggestionsRoute } from './find-recipient-suggestions';
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 { 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 {
ZBulkSendTemplateMutationSchema,
@ -177,7 +177,19 @@ export const templateRouter = router({
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);
@ -194,13 +206,22 @@ export const templateRouter = router({
data: {
type: EnvelopeType.TEMPLATE,
title,
folderId,
envelopeItems: [
{
documentDataId: templateDocumentDataId,
},
],
folderId,
externalId: externalId ?? undefined,
visibility,
globalAccessAuth,
globalActionAuth,
templateType: type,
publicTitle,
publicDescription,
},
meta,
attachments,
requestMetadata: ctx.metadata,
});

View File

@ -79,16 +79,6 @@ export const ZTemplateMetaUpsertSchema = z.object({
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({
directRecipientName: z.string().max(255).optional(),
directRecipientEmail: z.string().email().max(254),
@ -234,6 +224,13 @@ export const ZCreateTemplateResponseSchema = z.object({
id: z.number(),
});
export const ZCreateTemplatePayloadSchema = ZCreateTemplateV2RequestSchema;
export const ZCreateTemplateMutationSchema = zodFormData({
payload: zfd.json(ZCreateTemplatePayloadSchema),
file: zfd.file(),
});
export const ZUpdateTemplateRequestSchema = z.object({
templateId: z.number(),
data: z
@ -280,7 +277,7 @@ export const ZBulkSendTemplateMutationSchema = z.object({
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 TDuplicateTemplateMutationSchema = z.infer<typeof ZDuplicateTemplateMutationSchema>;
export type TDeleteTemplateMutationSchema = z.infer<typeof ZDeleteTemplateMutationSchema>;

View File

@ -24,11 +24,17 @@ const getMultipartBody = async (req: Request) => {
const data: Record<string, unknown> = {};
for (const key of formData.keys()) {
const values = formData.getAll(key);
for (const [key, value] of formData.entries()) {
// !: 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)
data[key] = values.length > 1 ? values : values[0];
if (data[normalizedKey] === undefined) {
data[normalizedKey] = value;
} else if (Array.isArray(data[normalizedKey])) {
data[normalizedKey].push(value);
} else {
data[normalizedKey] = [data[normalizedKey], value];
}
}
return data;