[]previous and next page

Input schemas

input takes any Standard Schema v1: an object with a ~standard member whose validate(value) returns { value } or { issues } (synchronously or as a promise).

For agentsUpdated

input takes any Standard Schema v1: an object with a ~standard member whose validate(value) returns { value } or { issues } (synchronously or as a promise). Zod, Valibot and ArkType implement it, and so does the small schema() helper above. The handler's input type is the schema's output type; the callable's argument type is its input type. serverFn throws a TypeError at definition time when input is not a Standard Schema. Without input, the handler receives the untrusted value as unknown.

The argument is optional exactly when undefined is a valid input: a function without input, or with a schema of an optional value, is called as stats(); a schema that does not accept undefined makes the argument required, and getNote() is a type error. The browser stub has the same rule, so a call that compiles in a loader compiles in an event handler.

src/server/calls.tsts
import { getNote, stats } from "./notes";

/** `stats` has no input schema: no argument. `getNote` has one that needs a value: the argument is required. */
export async function overview(): Promise<[number, string]> {
  const total = await stats();
  const first = await getNote({ id: "1" });
  return [total, first.title];
}

A schema that reports issues makes the handler answer 400 and the function does not run. The thrown ValidationError is an HttpError with status 400 and the message Invalid input; its issues are { message, path } pairs. What leaves the server is bounded by ISSUE_LIMITS: at most 20 issues, 200 characters per message and 16 path segments. Path segments may be strings or numbers (a { key } segment is reduced to its key, a symbol to its description). A schema that throws instead of reporting issues is an unexpected error and answers 500.

src/server/noisy.tsts
import { serverFn } from "@shadow-js/dusk/server";
import { schema } from "../schema";

/** A schema that reports far more than a client can use. */
const noisy = schema<never>(() => ({
  issues: Array.from({ length: 30 }, () => ({
    message: "m".repeat(300),
    path: Array.from({ length: 20 }, (_, index) => index),
  })),
}));

export const refuse = serverFn({ input: noisy }, async (): Promise<string> => "unreachable");

The client rebuilds the error as an HttpError from @shadow-js/dusk with status 400 and data: { issues }, so a form can show the messages next to its fields.