import { decode } from 'decode-formdata' import { isGlobalFormValidationError, isStandardSchemaValidator, standardSchemaValidators, } from '@tanstack/react-form' import { ServerValidateError } from './error' import type { FormAsyncValidateOrFn, FormOptions, FormValidateAsyncFn, FormValidateOrFn, ServerFormState, UnwrapFormAsyncValidateOrFn, } from '@tanstack/react-form' import type { FormDataInfo } from 'decode-formdata' interface CreateServerValidateOptions< TFormData, TOnMount extends undefined | FormValidateOrFn, TOnChange extends undefined | FormValidateOrFn, TOnChangeAsync extends undefined | FormAsyncValidateOrFn, TOnBlur extends undefined | FormValidateOrFn, TOnBlurAsync extends undefined | FormAsyncValidateOrFn, TOnSubmit extends undefined | FormValidateOrFn, TOnSubmitAsync extends undefined | FormAsyncValidateOrFn, TOnDynamic extends undefined | FormValidateOrFn, TOnDynamicAsync extends undefined | FormAsyncValidateOrFn, TOnServer extends undefined | FormAsyncValidateOrFn, TSubmitMeta, > extends FormOptions< TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta > { onServerValidate: TOnServer } export const createServerValidate = < TFormData, TOnMount extends undefined | FormValidateOrFn, TOnChange extends undefined | FormValidateOrFn, TOnChangeAsync extends undefined | FormAsyncValidateOrFn, TOnBlur extends undefined | FormValidateOrFn, TOnBlurAsync extends undefined | FormAsyncValidateOrFn, TOnSubmit extends undefined | FormValidateOrFn, TOnSubmitAsync extends undefined | FormAsyncValidateOrFn, TOnDynamic extends undefined | FormValidateOrFn, TOnDynamicAsync extends undefined | FormAsyncValidateOrFn, TOnServer extends undefined | FormAsyncValidateOrFn, TSubmitMeta, >( defaultOpts: CreateServerValidateOptions< TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta >, ) => async (formData: FormData, info?: FormDataInfo) => { const { onServerValidate } = defaultOpts const runValidator = async ({ value, validationSource, }: { value: TFormData validationSource: 'form' }) => { if (isStandardSchemaValidator(onServerValidate)) { return await standardSchemaValidators.validateAsync( { value, validationSource }, onServerValidate, ) } return (onServerValidate as FormValidateAsyncFn)({ value, signal: undefined as never, formApi: undefined as never, }) } const values = (info ? decode(formData, info) : decode(formData)) as never as TFormData const onServerError = (await runValidator({ value: values, validationSource: 'form', })) as UnwrapFormAsyncValidateOrFn | undefined if (!onServerError) return values const onServerErrorVal = ( isGlobalFormValidationError(onServerError) ? onServerError.form : onServerError ) as UnwrapFormAsyncValidateOrFn const formState: ServerFormState = { errorMap: { onServer: onServerError, }, values, errors: onServerErrorVal ? [onServerErrorVal] : [], } throw new ServerValidateError({ formState, }) } export const initialFormState: ServerFormState = { errorMap: { onServer: undefined, }, values: undefined, errors: [], }