Fastify
@cratis/arc.fastify registers an encapsulated plugin that owns Arc’s routes in a Fastify 5 application. Your own parsers, hooks, and routes stay as they are.
Mount the application
Section titled “Mount the application”import Fastify from 'fastify';import cratisArc from '@cratis/arc.fastify';import { shutdownArcHost } from '@cratis/arc.core/hosting';import { arc } from './arc.js';
const app = Fastify();await app.register(cratisArc, { arc });app.get('/health', async () => 'ok');await app.listen({ port: 3000, host: '127.0.0.1' });
process.once('SIGTERM', () => { void shutdownArcHost(arc.server, () => app.close());});arc is the built application from Host adapters. shutdownArcHost starts participant shutdown before closing the listener; host-first closure can dispose live subscription scopes too early. If the registry belongs to your host, pass it as the third argument to explicitly transfer shutdown ownership. See Shutdown participants.
Fastify loads plugins lazily, so Arc’s routes exist once the application is ready: after listen, ready, or the first inject. Do not register your own routes on Arc’s paths; Fastify rejects the duplicate when it loads the plugin.
Bodies and methods
Section titled “Bodies and methods”Inside the plugin, one catch-all content type parser hands every body to Arc as a raw buffer, whatever its content type, including vendor types such as application/vnd.acme+json. Arc decodes it as strict UTF-8 JSON, so invalid UTF-8 answers 400 malformedRequest. Your application’s parsers are not changed.
Command and query routes are registered for GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD, and QUERY; the root /.cratis metadata, identity, and discovery routes are registered for the standard methods without QUERY. Arc answers methods it receives but does not accept with 405 and an Allow header. Other methods are left to Fastify’s routing, often 404.
The handler dispatches only when the raw request path equals the route Fastify matched, on a fixed internal origin, so a crafted Host header cannot select a different operation. context.signal aborts when the client disconnects before the response finishes.
Pass a verified principal
Section titled “Pass a verified principal”app.register(cratisArc, { arc, native }) accepts a callback returning trusted native context for each request. See Native principal.
Observable queries over WebSockets
Section titled “Observable queries over WebSockets”app.register(cratisArc, { arc }) registers HTTP and observable upgrades together (webSockets defaults to true). Set webSockets: false to disable upgrades. A shared @fastify/websocket can be registered before or after Arc; both orders are covered by real upgrade checks. The plugin also supports a Fastify registration prefix, including one inherited from a parent plugin. See WebSockets.
Related
Section titled “Related”- Host adapters
- Express and Hono