UNPKG

@modular-forms/qwik

Version:

The modular and type-safe form library for Qwik

97 lines (96 loc) 3.95 kB
import { $, implicit$FirstArg, noSerialize } from '@builder.io/qwik'; import { globalActionQrl, } from '@builder.io/qwik-city'; import { AbortMessage } from '@builder.io/qwik-city/middleware/request-handler'; import { isDev } from '@builder.io/qwik/build'; import { decode } from 'decode-formdata'; import { FormError } from '../exceptions'; /** * See {@link formAction$} */ export function formActionQrl(action, arg2) { return globalActionQrl($(async (jsonData, event) => { // Destructure validate function and form data info const { validate, ...formDataInfo } = typeof arg2 === 'object' ? arg2 : { validate: arg2 }; // Get content type of request const type = event.request.headers .get('content-type') ?.split(/[;,]/, 1)[0]; // Get form values from form or JSON data const values = type === 'application/x-www-form-urlencoded' || type === 'multipart/form-data' ? decode(event.sharedMap.get('@actionFormData'), formDataInfo, ({ output }) => output instanceof Blob ? noSerialize(output) : output) : jsonData; // Validate values and get errors if necessary const errors = validate ? await validate(values) : {}; // Create form action store object let formActionStore = { values, errors, response: {}, }; // Try to run submit action if form has no errors if (!Object.keys(errors).length) { try { const result = await action(values, event); // Add result to form action store if necessary if (result && typeof result === 'object') { formActionStore = { values, errors: result.errors || {}, response: { status: result.status, message: result.message, data: result.data, }, }; } // If an abort message was thrown (e.g. a redirect), forward it } catch (error) { if (error instanceof AbortMessage || (isDev && (error?.constructor?.name === 'AbortMessage' || error?.constructor?.name === 'RedirectMessage'))) { throw error; // Otherwise log error and set error response } else { console.error(error); // If it is an expected error, use its error info if (error instanceof FormError) { formActionStore = { values, errors: error.errors, response: { status: 'error', message: error.message, }, }; // Otherwise return a generic message to avoid leaking // sensetive information } else { formActionStore.response = { status: 'error', message: 'An unknown error has occurred.', }; } } } } // Return form action store object return formActionStore; }), { id: action.getHash(), }); } /** * Creates an action for progressively enhanced forms that handles validation * and submission on the server. * * @param action The server action function. * @param arg2 Validation and/or form data info. * * @returns Form action constructor. */ export const formAction$ = implicit$FirstArg(formActionQrl);