Server actions
A 'use server' action is RPC-callable from the client; a plain .server.ts is a server-only utility you never import into a component.
This action also declares export const middleware: a
chain that runs around it on every boundary. The auth middleware reads the
real signed session (from the auth card) and
sets the caller on the request context (read back with actionContext()),
or 401s before the action runs. The action threads
actionSignal(), the request AbortSignal, through
its work so a client disconnect or a superseded render stops it early.
Signed out, the greeter returns a real 401. Sign in first to see it succeed. (This card depends on the auth card; prune both together.)
The action is gated by requireAuth. Sign in to greet; signed out returns a real 401.
HTTP verbs and caching
An action declares its HTTP semantics through reserved sibling exports the
framework reads statically, the same way a page declares
export const revalidate. The read below sets
method = 'GET', so its args ride the URL, it is
CSRF-exempt, and it carries a weak ETag, so a revalidated read whose result has
not changed answers 304. Caching itself is opted into by the
cache export below, not by the verb: a GET without
one is no-store. An action with no
method export is a POST mutation. Seeding is a
separate mechanism and needs no verb: an action invoked during a fully
buffered SSR render has its result serialized into the page, so the first
client call reads that seed instead of making a hydration round-trip. A page
that streams (a Suspense or
<webjs-suspense> boundary) emits no seed
block, so its actions do call out on hydration.
cache = 10 is the max-age in seconds, and it is
private by default. Reach for
{ public: true } only when the data is identical
for every visitor, because a shared cache keys the entry on the URL and args
alone. That is the same safety rule as a page's
export const revalidate. The number is shorthand
for the object form, so
cache = { maxAge: 10, swr: 30 } keeps serving an
expired entry for another thirty seconds while the browser revalidates it in
the background. There is no separate swr export.
tags labels the cached entry and
invalidates on the mutation evicts it by name.
The read reports how many times it actually ran on the server, so press Read twice
inside ten seconds and that count does not move: the second answer came from the
browser cache without reaching the server. Then bump the counter and read again.
The count moves and the value is fresh, because the mutation reported its
invalidated tag and the next read bypassed the stale entry instead of waiting out
the window.
Press Read twice in a row, then bump and read again.