Module API
The root primate entrypoint exports the application-facing Module type used
to extend Primate's build, startup, logging, and request lifecycles.
import type { Module } from "primate";Module is type-only; there is no runtime module factory. See the
Modules guide for authoring patterns and full examples.
Module
interface Module {
name: string;
setup(setup: Setup): void;
}nameidentifies the module in diagnostics and must be unique within the configuredmodulesarray.setupruns synchronously when Primate creates the module and registers its callbacks throughSetup. It does not run the callbacks itself.
import type { Module } from "primate";
export default function example(): Module {
return {
name: "example",
setup({ onInit }) {
onInit(app => app.log.info`example initialized`);
},
};
}
Module.name
name: string;Primate rejects duplicate configured module names. Module objects are also deduplicated by name during configuration validation.
Module.setup()
setup(setup: Setup): void;Called once for each module while the application is constructed. Register
hooks during this call. Asynchronous setup is not awaited; asynchronous work
belongs in onInit, onBuild, or onServe.
Setup
The hook registrar passed to Module.setup(). This interface is exposed
through the public Module declaration but is not a separate named export from
primate.
interface Setup {
onInit(hook: InitHook): void;
onBuild(hook: BuildHook): void;
onServe(hook: ServeHook): void;
onHandle(hook: HandleHook): void;
onRoute(hook: RouteHook): void;
onLog(hook: LogHook): void;
onError(hook: ErrorHook): void;
}Each registration method returns void. Multiple callbacks of one kind run in
module/configuration registration order.
setup.onInit()
type InitHook = (app: InitApp) => MaybePromise<void>;
onInit(hook: InitHook): void;Runs during application initialization before the target and build phases. Thrown errors and rejected promises abort initialization.
InitApp is a framework-owned callback object, not an application import. Its
relevant extension surface includes configuration lookup, project/build paths,
the logger, runtime mode, url, secure, and symbol-keyed module state. See
the Modules guide for examples.
setup.onBuild()
type BuildHook = (app: BuildApp) => MaybePromise<void>;
onBuild(hook: BuildHook): void;Runs during the build. BuildApp extends the initialization callback surface
with loader, build-root, entrypoint, post-build, and esbuild plugin registration
capabilities. It is a framework-owned callback type, not a public entrypoint.
Rejected promises abort the build.
setup.onServe()
type ServeHook = (app: ServeApp) => MaybePromise<void>;
onServe(hook: ServeHook): void;Runs once as the built server initializes. ServeApp is a framework-owned
callback object with the shared app surface plus server state such as secure,
url, loaded views, and response/rendering facilities. Rejected promises abort
server initialization.
setup.onHandle()
type HandleHook = (
request: RequestFacade,
next: (request: RequestFacade) => MaybePromise<Response>,
) => MaybePromise<Response>;
onHandle(hook: HandleHook): void;Runs before routing for every request, including static assets. Return a native
Response to stop processing or return next(request) to continue. next may
be called at most once and receives the request passed downstream.
setup.onRoute()
type RouteHook = (
request: RequestFacade,
next: (request: RequestFacade) => MaybePromise<ResponseLike>,
) => MaybePromise<ResponseLike>;
onRoute(hook: RouteHook): void;Runs after route matching and before the handler. It may stop the chain with a
ResponseLike or wrap the result of next(request).
The same one-call and defined-return constraints as route-file hooks apply.
setup.onLog()
type LogHook = (entry: LogEntry) => void;
onLog(hook: LogHook): void;
type LogEntry = {
level: "error" | "warn" | "info" | "trace";
message: string;
};Runs synchronously for every emitted log call, including entries below the configured output threshold. A log hook cannot be asynchronous.
setup.onError()
type ErrorHook = (error: RequestError) => MaybePromise<void>;
onError(hook: ErrorHook): void;Observes unexpected request failures before Primate invokes the error route. Observers run in registration order. An observer's result cannot replace the response; observer failures are logged and do not prevent later observers.
RequestError
Supporting input received by setup.onError(). It is not a
named root primate export.
type RequestError = {
readonly cause: unknown;
readonly frames: readonly RequestErrorFrame[];
readonly phase: RequestErrorPhase;
readonly request: RequestFacade;
readonly route?: string;
};causeis the original thrown value.framescontains mapped application frames relative to the app root.routeis the matched route template when known, never the concrete path.requestretains its request context while observers execute.
RequestErrorPhase
type RequestErrorPhase =
| "match"
| "handler"
| "layout"
| "render"
| "error-handler"
| "handle";
RequestErrorFrame
type RequestErrorFrame = {
readonly file: string;
readonly line: number;
readonly column: number;
readonly function?: string;
};Production frames are mapped through the private server source map when available. Mapping is observational and never changes the error response.