15. Server functions

Server functions know who's calling. Importing anything from #ucm/server is also what puts a function on the server; placement still needs no annotation.

import { session, setSession, clearSession, rateLimit, HttpError, request } from "#ucm/server";

export async function login(name: string, password: string): Promise<string> {
  if (!(await checkPassword(name, password))) throw new HttpError(401, "wrong name or password");
  rateLimit("login:" + request().ip, { max: 5, per: 60 });   // a 429 with Retry-After beyond that
  setSession({ user: name });                    // stored server-side; the cookie is just an id
  return name;
}
export async function me(): Promise<string> {
  const user = session().user;                   // unknown, expired or revoked sessions come back empty
  if (typeof user !== "string") throw new HttpError(401, "sign in first");
  return user;
}

The same module provides tables and transactions and jobs.

15.1 Request context

15.2 Sessions

session(), setSession(data), clearSession() and revokeSessions(match).

15.3 Rate limits and errors

15.4 Streaming

A server function can be an async function*, and browser code iterates it with for await, as if it were local:

15.5 Plain HTTP endpoints

ucm start <app> --http app.api (or ucm dev) serves every function under app.api at /api/…, e.g. app.api.hooks.stripe at /api/hooks/stripe, for webhooks and outside API clients. --http ns=/prefix picks another prefix.

15.6 Testing

withRequest(init, fn) runs fn as if answering a request (method, url, headers, cookies, ip), with sessions in memory, and returns its value plus the Set-Cookie headers it produced. See testing.

built from 5890e54f