Deployment & security
A server function is served at POST /_sigx/fn/<symbol>, where <symbol> is a
content-hashed id derived from the function. You wire that endpoint once per
runtime; everything else — validation, error masking, the security gate — is the
same everywhere.
Development
Zero config. Add the sigxServer() plugin from @sigx/vite/server to your Vite
config and the dev server handles the endpoint from its middleware, loading the
real *.server.ts modules on demand:
// vite.config.ts
import { defineConfig } from 'vite';
import sigx from '@sigx/vite';
import sigxServer from '@sigx/vite/server';
export default defineConfig({
plugins: [sigx(), sigxServer()],
});
sigxServer() options: include (default **/*.server.{ts,tsx}), exclude,
base (default /_sigx/fn), guard (a root-relative module path applied to
every function), origin and maxBodyBytes — the same security knobs described
below, applied in dev too.
Production (Node)
The SSR build emits a registry chunk (dist/server/sigx-server-fns.js) that
maps every symbol to its implementation. Pass it explicitly to
createServerFnHandler from @sigx/server/node and mount the handler before
your document/SSR handler:
import { createServerFnHandler } from '@sigx/server/node';
import { createRequestHandler } from '@sigx/server-renderer';
const { serverFns } = await import('./dist/server/sigx-server-fns.js');
app.use(createServerFnHandler({
functions: serverFns, // the build's registry chunk — never ambient
guard: requireSession, // optional app-wide auth seam
}));
app.use(createRequestHandler({ /* your document handler, unchanged */ }));
createServerFnHandler returns a connect-style (req, res, next?) middleware,
so it drops into Express/Connect/Polka and most Node servers.
Edge (WinterCG)
For fetch-shaped runtimes (Workers, Deno, etc.), use @sigx/server/server.
Match the endpoint and hand the request off; anything else falls through to your
renderer:
import { handleServerFnRequest, matchesServerFn } from '@sigx/server/server';
export default {
async fetch(request) {
if (matchesServerFn(request)) {
return handleServerFnRequest(request, { resolve: (symbol) => registry[symbol] });
}
return renderDocument(request);
},
};
Security defaults
Every server function is a public HTTP endpoint, so the runtime hardens each one by default. You get all of this without opting in:
- POST-only, JSON required. Calls must be
POSTwith a JSON content type. Because that content type is not CORS-safelisted, a cross-site form can't forge one — this is the CSRF gate. The endpoint never emits CORS headers. - Origin check — default
'same-origin': theOriginheader must match the request's origin. - A
guardhook runs before every function, the place for app-wide authentication. - Body & URL limits — bodies are capped at
maxBodyBytes(default 1 MiB) during the read; GET reads are capped atmaxUrlBytes(default 8 KiB →414). - Prototype-pollution-safe parsing on both the client and server sides.
- Production error masking — any non-
ServerFnErrorthrow becomes a generic500; the original never leaves the server. - Structured version-skew
404— a stale client calling a symbol that no longer exists gets a typed 404, not a silent hang.
These are configured through the request-handler options (guard, origin,
maxBodyBytes, maxUrlBytes, onError, timeoutMs, …), which are shared by
the dev plugin, the Node handler and the edge handler.
Relaxing a default — deliberately
A few options weaken a default on purpose. Reach for them only when you mean to:
cache(a GET read) drops the JSON content-type CSRF gate — only mark a functioncachewhen it is genuinely side-effect-free.form: truegives up the JSON-CSRF layer so the function can accept a progressively-enhanced HTML form post; the origin check stays at full strength, andinputis required.public: trueon a read is a promise that its output depends only on its arguments — no cookies, auth or per-user headers.origincan be widened from'same-origin'to'verify-when-present'(to admit Origin-less programmatic clients), an explicit allowlist, orfalsefor a deliberately public API.
Next steps
- Authoring server functions — the definition surface these endpoints serve.
- Server renderer — pair RPC with streaming SSR and hydration.
