Files
documenso/packages/trpc/utils/zod-form-data.ts
ephraimduncan 138d663c25 chore: merge main, resolve biome formatting conflicts
Merge origin/main into feat/external-2fa-codes. Resolve formatting
conflicts caused by biome rollout; preserve both feature streams:
PR's external 2FA token + signing-session 2FA proof additions plus
main's RateLimit/RecipientExpired/signingReminders/date-auto-insert.

In complete-document-with-token.ts, drop the duplicate early
field-fetching block introduced when main moved that logic later
with date auto-insert support; keep the EXTERNAL_TWO_FACTOR_AUTH
check using derivedRecipientActionAuth.
2026-05-12 11:46:11 +00:00

49 lines
1.7 KiB
TypeScript

import { APP_DOCUMENT_UPLOAD_SIZE_LIMIT } from '@documenso/lib/constants/app';
import { megabytesToBytes } from '@documenso/lib/universal/unit-convertions';
import type { ZodRawShape } from 'zod';
import z from 'zod';
import { zfd } from 'zod-form-data';
/**
* A `zfd.file()` schema with a max file size constraint based on
* `APP_DOCUMENT_UPLOAD_SIZE_LIMIT`. Use this instead of bare `zfd.file()`
* to ensure server-side file size validation.
*/
export const zfdFile = () => {
const maxBytes = megabytesToBytes(APP_DOCUMENT_UPLOAD_SIZE_LIMIT);
return zfd.file().refine((file) => file.size <= maxBytes, {
message: `File cannot be larger than ${APP_DOCUMENT_UPLOAD_SIZE_LIMIT}MB`,
});
};
/**
* This helper takes the place of the `z.object` at the root of your schema.
* It wraps your schema in a `z.preprocess` that extracts all the data out of a `FormData`
* and transforms it into a regular object.
* If the `FormData` contains multiple entries with the same field name,
* it will automatically turn that field into an array.
*
* This is used instead of `zfd.formData()` because it receives `undefined`
* somewhere in the pipeline of our openapi schema generation and throws
* an error. This provides the same functionality as `zfd.formData()` but
* can be considered somewhat safer.
*/
export const zodFormData = <T extends ZodRawShape>(schema: T) => {
return z.preprocess((data) => {
if (data instanceof FormData) {
const formData: Record<string, unknown> = {};
for (const key of data.keys()) {
const values = data.getAll(key);
formData[key] = values.length > 1 ? values : values[0];
}
return formData;
}
return data;
}, z.object(schema));
};