AsyncAPI for WebSockets
DaloyJS already turns every HTTP route into an OpenAPI 3.1 operation. As of 0.37.0 the same contract-first story extends to your real-time surfaces: the @daloyjs/core/asyncapi module emits a standards-compliant AsyncAPI 3.0 document for the WebSocket routes you register with app.ws(). It is built-in and dependency-free — the same posture as the OpenAPI generator — so it adds nothing to your runtime footprint.
Each app.ws() route becomes one AsyncAPI channel (the socket address plus any path parameters) and one or more operations:
- a
receiveoperation for messages the server receives from clients (always emitted — a socket can always be written to), and - an optional
sendoperation for messages the server pushes to clients (emitted only when you declare an outbound schema).
Quick start
Call generateAsyncAPI(app, options) and you get a plain, JSON-serializable AsyncAPI document. Hand it to AsyncAPI Studio, write it to disk for codegen, or serve it from a route.
Describing the messages
WebSocket handlers accept an optional meta block that mirrors the HTTP route meta. It is purely descriptive — it never changes the RFC 6455 handshake or runtime behavior — and the AsyncAPI generator reads it to fill in summaries, tags, and message payloads.
summary/description/tags— surfaced on the generated channel and operations.receive— a Standard Schema describing messages the server receives from clients. Falls back to the handler'srequest.bodyschema (the same schema used for payload-size checks).send— a Standard Schema describing messages the server sends to clients. Adds asendoperation when present.operationId— overrides the channel key that is otherwise derived from the path.
Schemas that expose a toJSONSchema() method (Zod 4, Valibot, ArkType, ...) are converted to JSON Schema for the message payload. Anything else falls back to a permissive {} placeholder rather than throwing, so generation never fails on an unconvertible schema.
Generated document shape
A single app.ws("/chat/:room", ...) route with the meta above produces roughly:
YAML output
asyncapiToYAML(doc) renders the document as YAML 1.2 using the same dependency-free emitter shared with the OpenAPI generator.
CLI
The daloy inspect command can print the AsyncAPI document for any app it can load, mirroring --openapi. Use --format yaml (or --yaml) for YAML output.
Notes
- When the app has no WebSocket routes the document still validates, with empty
channelsandoperationsmaps. - Channel keys are derived from the path (
/chat/:room/feed→chatRoomFeed); collisions are de-duplicated with a numeric suffix. Setmeta.operationIdfor a stable, explicit key. - The generator is read-only: it never mounts a route or changes your socket's security posture. See the WebSocket primitives page for the CSWSH refuse-to-boot guards.