Skip to content

feat(app): validateAction() — framework-level action validation pipeline #624

Description

@SisyphusZheng

Summary

Provide a framework-level validation pipeline for route actions, inspired by Astro Actions' schema→error model. The framework owns the FormData → parse → typed result | 422 re-render plumbing without binding to a specific validation library.

Competitive context

Framework Approach
Astro 7 Built-in Actions with input: schema (zod-like, library-agnostic)
SvelteKit User implements (valibot/zod recipe)
Next.js User implements (zod recipe)
Fresh User implements
openElement User implements — no framework helper

Astro proves that a thin framework-owned validation pipe (schema in → typed data or structured 422 errors out) is a meaningful DX differentiator without becoming an ORM.

Proposed design

// In route module
import { validateAction } from '@openelement/app';
import * as v from 'valibot'; // or zod — user's choice

const ContactSchema = v.object({
  email: v.pipe(v.string(), v.email()),
  message: v.pipe(v.string(), v.minLength(10)),
});

export const action = validateAction(ContactSchema, async (data, ctx) => {
  // data is typed: { email: string; message: string }
  // validation failures auto-return 422 with field errors
  await sendEmail(data);
  return redirect('/thanks');
});

Scope

  • validateAction(schema, handler) helper in @openelement/app
  • Schema protocol: { safeParse(input): { success, data?, error? } } (zod AND valibot compatible)
  • On failure: auto fail(422, { fieldErrors }) with the 0.42 form re-render semantics
  • On success: typed handler receives parsed data
  • No dependency on zod or valibot — protocol-only

Non-goals

  • No built-in validation library
  • No client-side validation (stays user-owned)
  • No schema generation from TypeScript types

Target version

0.43.0 (Universal WC SSR line) or 0.44.0 (Production Runtime)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions