Express
@cratis/arc.express adds one middleware to an Express 5 application. Arc answers its own routes; everything else goes to your routes and middleware.
Mount the application
Section titled “Mount the application”import express from 'express';import { cratisArc } from '@cratis/arc.express';import { arc } from './arc.js';
const app = express();const middleware = cratisArc(arc);app.use(middleware);app.use(express.json());app.get('/health', (_request, response) => { response.send('ok'); });const listener = app.listen(3000, '127.0.0.1');middleware.injectWebSocket(listener);
process.once('SIGTERM', () => { void middleware.shutdown(listener);});arc is the built application from Host adapters. middleware.shutdown(listener) coordinates participant stop and drain with transport closure. If you supplied your own ServiceRegistry, pass it explicitly as middleware.shutdown(listener, registry); Arc never implicitly disposes a borrowed registry. With the Tasks sample’s artifacts, POST /api/tasks/registration/register-task now reaches Arc, and GET /health reaches your route.
How requests are matched
Section titled “How requests are matched”The middleware compares the raw request path, before any normalization, with Arc’s registered routes. Only an exact match is handled by Arc. Every other request goes to next(), including spellings such as //api/echo, /x/../api/echo, or /api/%2e%2e/api/echo that would only match after normalization. The adapter builds the Fetch API request on a fixed internal origin and never uses the Host header for routing.
An unexpected error inside the adapter is passed to Express with next(error). An unknown path gets Express’s own 404, which carries no Arc correlation header.
context.signal aborts when the client disconnects before the response finishes.
Pass a verified principal
Section titled “Pass a verified principal”cratisArc(arc, native) accepts a second argument: a callback returning trusted native context for each request. Use it with nativePrincipal: true to pass a user your Express session or JWT middleware already verified. See Native principal.
Observable queries over WebSockets
Section titled “Observable queries over WebSockets”Express HTTP middleware does not run on Node upgrade requests. Attach WebSockets to the listener with middleware.injectWebSocket(listener, native?); the middleware cannot see upgrades. Call middleware.shutdown(listener) to close the listener and Arc in the required order. middleware.close(listener) remains listener-only; if participants are registered, closing the listener first can start scope disposal before they stop. See WebSockets.
Related
Section titled “Related”- Host adapters
- Fastify and Hono