49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import type { BasePayload } from 'payload';
|
|
/** A form-builder field, trimmed to what validation needs. */
|
|
type FormField = {
|
|
blockType?: string;
|
|
label?: string;
|
|
name?: string;
|
|
required?: boolean | null;
|
|
};
|
|
type FormDoc = {
|
|
fields?: FormField[];
|
|
id: number | string;
|
|
/** Per-form notification address, when the client added the field. */
|
|
notificationEmail?: string;
|
|
title?: string;
|
|
};
|
|
/**
|
|
* Validation outcome — codes, not user-facing strings. The frontend turns these
|
|
* into its own copy (see SubmitFailure in submitForm).
|
|
*/
|
|
export type FormValidationResult = {
|
|
/** Offending field, when a single field is at fault. */
|
|
field?: string;
|
|
kind: 'required' | 'too_long' | 'unknown_fields';
|
|
ok: false;
|
|
reason: 'invalid';
|
|
} | {
|
|
cleaned: Record<string, unknown>;
|
|
form: FormDoc;
|
|
ok: true;
|
|
} | {
|
|
ok: false;
|
|
reason: 'not_found';
|
|
};
|
|
/**
|
|
* Checks submitted data against the form's own definition, rather than trusting
|
|
* whatever arrived.
|
|
*
|
|
* The server action is a public endpoint: a caller can skip the rendered form
|
|
* and post arbitrary keys. Without this, unknown fields would be stored,
|
|
* required fields could be missing, and an oversized value could sail through.
|
|
* So we load the form, keep only keys that are real fields, reject when a
|
|
* required one is blank, and cap length.
|
|
*
|
|
* Returns the loaded form on success so the caller doesn't fetch it twice, and
|
|
* a code + offending field on failure so the frontend can point at it.
|
|
*/
|
|
export declare function validateSubmission(payload: BasePayload, formId: string, data: Record<string, unknown>): Promise<FormValidationResult>;
|
|
export {};
|