server-function-validation
A server function checks every argument against a valibot schema from src/server/validate.ts before it acts, because the parameter types are gone by the time a call arrives. Applies whenever adding a
Files1
View on GitHubSKILL.md.claude/skills/server-function-validation/SKILL.md
GitHubServer functions check what they are sent
A 'use server' function is an HTTP endpoint. Its parameter list is erased at build time, so the arguments that reach it are whatever the caller put in the request body, not what the signature says. The modules under src/server/ then act on those arguments over the table-owner connection, which row-level security does not bind.
Every argument is therefore checked first, at the top of the body:
async function useMintOnServer(token: string, catchId: string, item: Items): Promise<Natures | null> {
'use server';
check(TOKEN, token);
check(ID, catchId);
check(GAME_ID, item);
return useMintOnServerSide(await requireUid(token), catchId, item);
}
check and the schemas both come from src/server/validate.ts. A failing check throws, which is what a malformed call deserves.
The rules
- One line per parameter, in the order the parameters are declared, before anything else in the body.
requireUidcomes after them, orrequireReaderfor a read (seeserver-reads). - Reuse a schema.
IDfor a row key,GAME_IDfor a registry id,CHUNK_COORDINATEandCELLfor where somebody says they are,OFFSETandLOCALEfor the caller's zone,UIDfor an account. A new shape gets a new exported schema invalidate.tsrather than an inline one at the call site. - Bound every list. An array schema carries a
maxLength, since an unbounded list is a request to do unbounded work. - Check the shape, not the rule. A schema says an argument is a chunk inside the world or a text id of a sane length. Whether the player owns that catch, can afford it or may reach that landmark stays in
src/server/. - Nothing is coerced.
checkhands the argument back as it arrived, so theas*normalizers further in still see what the caller actually sent.
Why it is not the transform's job
Adding a check never changes a function's parameters, so it does not move anything: see server-function-order for why that matters.