Response API

primate/response exports server response helpers and the types used by custom response functions and frontend integrations.

import response from "primate/response";
import type {
  Deferred,
  ResponseFunction,
  ServeApp,
  ViewResponse,
} from "primate/response";

Helpers return ResponseFunction values that Primate executes with the current serving app and request. See the Responses guide for implicit response conversion and walkthroughs.

response.text()

text(body: string, init?: ResponseInit): ResponseFunction<never>;

Returns a plain-text response function. The default status is 200, and Content-Type is set to text/plain.

response.json()

json<T>(body: T, init?: ResponseInit): ResponseFunction<never, T>;

Serializes body with JSON.stringify when the response function executes. The default status is 200, and Content-Type is set to application/json. Serialization errors propagate through request error handling. The second type parameter retains T for route-client inference.

response.binary()

binary(
  source: Streamable,
  init?: ResponseInit,
): ResponseFunction<never>;

Streams a Blob, readable stream, or @rcompat/fs streamable source. It defaults to application/octet-stream and an attachment filename of default.bin. Named sources use their sanitized, length-limited name in Content-Disposition. Blobs also set Content-Length and use their non-empty MIME type.

response.redirect()

redirect(
  target: RedirectTarget,
  statusOrInit?: Redirection | RedirectInit,
): ResponseFunction<never>;

Redirects to a string or structured same-origin target. The status defaults to 302; the second argument may be a redirect status number or options object. The response has an empty body, Content-Length: 0, and Cache-Control: no-cache.

During client navigation, Primate returns 204 and carries the destination and original redirect status in Primate headers. Ordinary requests receive the configured status and Location header.

Throws: For invalid origin-form paths, control characters, backslashes, non-HTTP(S) protocols, unapproved external origins, invalid byte limits, or a location larger than the configured limit.

RedirectTarget

type RedirectTarget = string | {
  pathname: string;
  query?: Record<
    string,
    boolean | null | number | string | undefined
  >;
};

Structured pathname must start with one /, cannot start with //, and cannot contain a backslash. Path segments and query values are URL-encoded; nullish query values are omitted.

RedirectInit

type RedirectInit = Omit<ResponseInit, "headers" | "status"> & {
  headers?: HeadersInit;
  status?: 300 | 301 | 302 | 303 | 304 | 307 | 308;
  allowExternal?: boolean;
  base?: string | URL;
  maxLocationBytes?: number;
};

allowExternal defaults to false, base defaults to the request URL, and maxLocationBytes defaults to 2048. Generated redirect headers replace any caller-provided values with the same names.

response.view()

function view(
  component: abstract new (...args: any[]) => any,
  props?: Dict,
  options?: ViewOptions,
): ResponseFunction<Dict>;

function view<Props>(
  component: unknown,
  props: Props,
  options?: ViewOptions,
): ResponseFunction<Props>;

function view(
  component: unknown,
  props?: Dict,
  options?: ViewOptions,
): ResponseFunction<Dict>;

function view<Props extends Dict>(
  name: string,
  props?: Props,
  options?: ViewOptions,
): ResponseFunction<Props>;

Renders a component reference or registered view name. Props default to an empty object. Primate selects the frontend integration from the component or filename extension and throws a missing-frontend diagnostic when none matches.

response.page()

page<Props extends Dict>(
  props?: Props,
  options?: ViewOptions,
): ResponseFunction<Props>;

Renders the component collocated with the current route or layout. Props default to an empty object. Calling the returned function outside a matched route/layout context throws a page-context diagnostic.

ViewOptions

Supporting options accepted by response.view() and response.page(); this type is not a named export from primate/response.

interface ViewOptions extends ResponseInit {
  csp?: {
    script_src?: string[];
    style_src?: string[];
  };
  head?: string;
  template?: string;
  partial?: boolean;
  placeholders?: Omit<Dict, "body" | "head">;
}

template selects an HTML template, head adds markup to its head placeholder, and partial: true omits the enclosing template. placeholders cannot replace the reserved body and head entries.

response.error()

error(options?: {
  body?: string;
  template?: string;
  status?: ValidStatus;
}): ResponseFunction<never>;

Renders an error HTML page. Defaults are body "Not Found", template "error.html", and status 404. Development responses also inject the live reload listener. This is an ordinary response and does not throw.

response.abort()

abort(response: Response): never;
abort(options: AbortOptions): never;

type AbortOptions = Omit<ResponseInit, "status"> & {
  body?: BodyInit | null;
  status: ValidStatus;
};

Throws an internal control-flow value carrying a native response. body defaults to null; status is required. Primate handles it without invoking the error route, error logger, or module error observers. A HEAD request keeps status and headers but strips the body. Call response.abort(...) directly; do not prefix it with throw.

response.null()

null(): ResponseFunction<never>;

Returns a response function producing an empty 204 response.

response.defer()

defer<T>(value: T | PromiseLike<T>): Deferred<Awaited<T>>;

Wraps the input in a branded promise used for direct page and layout props. Initial document rendering awaits it. Client navigation sends immediate props first and resolves or rejects the deferred prop through the streamed navigation response. The wrapper observes rejection early without changing the promise consumed by rendering.

Deferred

Named type export representing the server-rendered or client-navigation form of a deferred value.

type Deferred<T> = T | Promise<T>;

response.sse()

sse(
  body: (source: SSESource) => void | (() => void),
  init?: ResponseInit,
): ResponseFunction<never>;

Creates a text/event-stream response. The setup callback runs when the stream starts and may return cleanup, which runs once on server close or client disconnect.

SSESource

type SSESource = {
  close(): void;
  send(data: string): void;
  send(name: string, data: unknown): void;
};

send(data) emits the default event; send(name, data) emits a named event. Data is JSON-serialized. Event names must be non-empty and contain no control characters. Sends after close are ignored; close() is idempotent.

response.ws()

ws(actions: Actions): ResponseFunction<never>;

Upgrades the original request with the @rcompat/http WebSocket actions object. Runtime support and action examples are in the Responses guide.

ResponseFunction

Named type export implemented by every helper result.

type ResponseFunction<Props = never, Result = never> = {
  (
    app: ServeApp,
    transfer: Dict,
    request: RequestFacade,
  ): MaybePromise<View | null | Response | undefined>;
  readonly _props?: Props;
  readonly _result?: Result;
};

_props and _result are optional inference properties and do not contain runtime values. Custom response functions may use the serving context and request to return a native response, rendered view, null, or undefined.

ServeApp

Named type export for the first ResponseFunction argument. It is the full serving application class; response authors most commonly use this response-related subset:

interface ServeApp {
  respond(body: BodyInit | null, init?: ResponseInit): Response;
  media(contentType: string, init?: ResponseInit): ResponseInit;
  view(options: FullViewOptions): Response;
  page(pathname: string): string;
  upgrade(request: Request, actions: Actions): Response | null;
}

The interface above is a focused view, not a separate exported declaration. respond() applies response defaults and content length, while media() sets the requested content type and defaults the status to 200.

ViewResponse

Named type export used by frontend modules to register view response factories.

type ViewResponse = (
  name: string,
  props?: Dict,
  options?: ViewOptions,
) => ResponseFunction;

Browser availability

Response construction is server-side. Browser builds replace helpers with throwing stubs; response.page is not present in the browser runtime object. Do not call response helpers from frontend code.

Previous
Request
Next
Session