### Quick Start: Basic WebSocket API Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md This example demonstrates how to set up a basic WebSocket API using AsyncAPIHono, define a channel with Zod payload validation, and register a handler. It also shows how to serve the AsyncAPI documentation. ```APIDOC ## AsyncAPIHono ### Description Creates an AsyncAPI-enabled Hono application for WebSocket routes. ### Usage ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'Chat API', version: '1.0.0', description: 'Real-time chat API using WebSockets', }, servers: { development: { host: 'localhost:3000', protocol: 'ws', description: 'Development server', }, }, }) ``` ## createChannel ### Description Defines a WebSocket channel with a path, description, and schemas for sending and receiving messages. ### Usage ```typescript const chatChannel = createChannel({ path: '/chat/:roomId', description: 'Real-time chat room', send: { payload: z.object({ message: z.string(), userId: z.string(), timestamp: z.number(), }), description: 'Send a chat message to the room', }, receive: { payload: z.object({ message: z.string(), userId: z.string(), timestamp: z.number(), }), description: 'Receive chat messages from the room', }, tags: ['chat'], }) ``` ## Registering a Channel Handler ### Description Registers a channel with its defined schema and associates a handler function to process incoming messages. ### Usage ```typescript app.channel('chatRoom', chatChannel, (ws, message, ctx) => { console.log(`Message in room ${ctx.params.roomId}:`, message) ws.send({ message: `Echo: ${message.message}`, userId: 'system', timestamp: Date.now(), }) }) ``` ## Serving AsyncAPI Documentation ### Description Adds an endpoint to serve the generated AsyncAPI specification. ### Usage ```typescript app.doc('/asyncapi.json') ``` ``` -------------------------------- ### Basic WebSocket Channel Example Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md A simple example demonstrating how to create an AsyncAPIHono app, define a 'ping' channel using `createChannel`, and register a handler for it. ```APIDOC ## Basic WebSocket Channel ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono() const pingChannel = createChannel({ path: '/ping', description: 'Ping-pong channel', receive: { payload: z.object({ ping: z.string() }), }, send: { payload: z.object({ pong: z.string() }), }, }) app.channel('ping', pingChannel, (ws, message) => { ws.send({ pong: message.ping }) }) ``` ``` -------------------------------- ### Install @juice10/hono-zod-asyncapi Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Install the core library along with Hono and Zod. Optionally install @hono/zod-openapi for unified REST and WebSocket applications. ```bash npm install @juice10/hono-zod-asyncapi hono zod # optional – for REST + WebSocket unified apps npm install @hono/zod-openapi ``` -------------------------------- ### Install for Integration with @hono/zod-openapi Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Install the necessary packages for integrating REST and WebSocket APIs. ```bash npm install @juice10/hono-zod-asyncapi @hono/zod-openapi hono zod ``` -------------------------------- ### Channel with Path Parameters Example Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md An example showing how to define a channel with path parameters (e.g., `/users/:userId/notifications`) and access these parameters within the handler using `ctx.params`. ```APIDOC ## Channel with Path Parameters ```typescript const userChannel = createChannel({ path: '/users/:userId/notifications', description: 'User-specific notification channel', send: { payload: z.object({ type: z.enum(['info', 'warning', 'error']), message: z.string(), }), }, }) app.channel('userNotifications', userChannel, (ws, message, ctx) => { console.log(`Notification for user ${ctx.params.userId}`) // Handler logic }) ``` ``` -------------------------------- ### Install @juice10/hono-zod-asyncapi Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Install the package and its dependencies using npm. ```bash npm install @juice10/hono-zod-asyncapi hono zod ``` -------------------------------- ### Modular Architecture Example Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Illustrates how to structure a larger application by defining routes in separate files and then merging them into a main `AsyncAPIHono` instance using `app.route()`. It also shows how to serve the AsyncAPI document. ```APIDOC ## Modular Architecture ```typescript // channels/chat.ts export const chatRoutes = new AsyncAPIHono() chatRoutes.channel('publicChat', publicChatChannel, handler1) chatRoutes.channel('privateChat', privateChatChannel, handler2) // channels/notifications.ts export const notificationRoutes = new AsyncAPIHono() notificationRoutes.channel('userNotifications', notificationChannel, handler) // main.ts import { AsyncAPIHono } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'My API', version: '1.0.0', }, }) app.route('/chat', chatRoutes) app.route('/notifications', notificationRoutes) app.doc('/asyncapi.json') ``` ``` -------------------------------- ### Integration Option 2: Unified API App Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md This example demonstrates using UnifiedAPIHono to create an application that supports both REST (OpenAPI) and WebSocket (AsyncAPI) functionalities within a single Hono instance. It simplifies the setup for applications requiring both types of APIs. ```APIDOC ## UnifiedAPIHono ### Description A Hono application class that integrates both OpenAPI and AsyncAPI capabilities, allowing for a unified approach to building REST and WebSocket APIs. ### Usage ```typescript import { UnifiedAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new UnifiedAPIHono({ openapi: { info: { title: 'My API', version: '1.0.0' }, }, asyncapi: { info: { title: 'My WebSocket API', version: '1.0.0' }, }, }) // Add WebSocket channels const channel = createChannel({ path: '/ws/events', send: { payload: z.object({ event: z.string() }) }, }) app.channel('events', channel) // Serve both docs app.docs('/api/openapi.json', '/api/asyncapi.json') ``` ``` -------------------------------- ### Example AsyncAPI Specification Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md A sample AsyncAPI 3.0 JSON document generated by the package. It outlines channels, operations, messages, and reusable components. ```json { "asyncapi": "3.0.0", "info": { "title": "Chat API", "version": "1.0.0" }, "servers": { "development": { "host": "localhost:3000", "protocol": "ws" } }, "channels": { "chatRoom": { "address": "/chat/{roomId}", "messages": { "chatRoom_send_message": { "$ref": "#/components/messages/chatRoom_send_message" } } } }, "operations": { "send_chatRoom_0": { "action": "send", "channel": { "$ref": "#/channels/chatRoom" }, "messages": [ { "$ref": "#/components/messages/chatRoom_send_message" } ] } }, "components": { "messages": { "chatRoom_send_message": { "payload": { "$ref": "#/components/schemas/schema_0" } } }, "schemas": { "schema_0": { "type": "object", "properties": { "message": { "type": "string" }, "userId": { "type": "string" } }, "required": ["message", "userId"] } } } } ``` -------------------------------- ### Create Unified Configuration Helpers Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Use `createUnifiedInfo` and `createUnifiedServers` to generate consistent configuration objects for both OpenAPI and AsyncAPI specifications. This simplifies setup for APIs serving both REST and WebSocket endpoints. ```typescript import { createUnifiedInfo, createUnifiedServers } from '@juice10/hono-zod-asyncapi' // Create consistent info for both specs const info = createUnifiedInfo({ title: 'My API', version: '1.0.0', description: 'REST and WebSocket API', contact: { name: 'API Team', email: 'api@example.com', }, }) // Create server configs for both HTTP and WebSocket const servers = createUnifiedServers({ http: { url: 'https://api.example.com', description: 'Production HTTP server', }, ws: { host: 'ws.example.com', protocol: 'wss', description: 'Production WebSocket server', }, }) // Use in your apps const restAPI = new OpenAPIHono({ openapi: { ...info.openapi, servers: servers.openapi } }) const wsAPI = new AsyncAPIHono({ info: info.asyncapi, servers: servers.asyncapi }) ``` -------------------------------- ### Quick Start: Create AsyncAPI Hono App Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Initialize an AsyncAPI-enabled Hono app with info and server configurations. Define a WebSocket channel with Zod schemas for message payloads and register a handler for it. Finally, serve the AsyncAPI documentation. ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' // Create an AsyncAPI-enabled Hono app const app = new AsyncAPIHono({ info: { title: 'Chat API', version: '1.0.0', description: 'Real-time chat API using WebSockets', }, servers: { development: { host: 'localhost:3000', protocol: 'ws', description: 'Development server', }, }, }) // Define a channel with Zod schemas const chatChannel = createChannel({ path: '/chat/:roomId', description: 'Real-time chat room', send: { payload: z.object({ message: z.string(), userId: z.string(), timestamp: z.number(), }), description: 'Send a chat message to the room', }, receive: { payload: z.object({ message: z.string(), userId: z.string(), timestamp: z.number(), }), description: 'Receive chat messages from the room', }, tags: ['chat'], }) // Register the channel with a handler app.channel('chatRoom', chatChannel, (ws, message, ctx) => { console.log(`Message in room ${ctx.params.roomId}:`, message) // Send a response ws.send({ message: `Echo: ${message.message}`, userId: 'system', timestamp: Date.now(), }) }) // Serve the AsyncAPI documentation app.doc('/asyncapi.json') export default app ``` -------------------------------- ### Basic WebSocket Channel Implementation Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Register a WebSocket channel using `app.channel()`. This example demonstrates a simple ping-pong channel where incoming messages with a 'ping' property trigger a response with a 'pong' property. ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono() const pingChannel = createChannel({ path: '/ping', description: 'Ping-pong channel', receive: { payload: z.object({ ping: z.string() }), }, send: { payload: z.object({ pong: z.string() }), }, }) app.channel('ping', pingChannel, (ws, message) => { ws.send({ pong: message.ping }) }) ``` -------------------------------- ### Integration Option 1: Merge Separate Apps Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md This example shows how to combine a REST API (OpenAPI) and a WebSocket API (AsyncAPI) into a single application by merging separate Hono instances. It demonstrates serving both OpenAPI and AsyncAPI documentation from different endpoints. ```APIDOC ## mergeAPIDocs ### Description Merges an OpenAPIHono app and an AsyncAPIHono app into a single Hono application, allowing for unified documentation serving. ### Usage ```typescript import { OpenAPIHono, createRoute, z as openAPIZ } from '@hono/zod-openapi' import { AsyncAPIHono, createChannel, z, mergeAPIDocs } from '@juice10/hono-zod-asyncapi' const restAPI = new OpenAPIHono() const wsAPI = new AsyncAPIHono({ info: { title: 'WebSocket API', version: '1.0.0', }, }) // ... (define routes for restAPI and channels for wsAPI) const app = mergeAPIDocs(restAPI, wsAPI) // Serve both documentations app.doc('/api/openapi.json') // OpenAPI spec for REST app.asyncapiDoc('/api/asyncapi.json') // AsyncAPI spec for WebSocket ``` ``` -------------------------------- ### app.channel — Register a channel with a handler Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Registers a channel in the AsyncAPIRegistry and mounts a Hono GET route. The handler receives typed WebSocketData, inferred payload, and ChannelContext. ```APIDOC ## `app.channel` — Register a channel with a handler Registers a channel in the `AsyncAPIRegistry` and, when a `handler` is provided, mounts a Hono GET route that returns HTTP 426 for non-WebSocket requests. The handler receives a typed `WebSocketData` object, the inferred receive payload, and a `ChannelContext` carrying path `params` and request `headers`. ### Example 1: Basic Channel Registration ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'Ping API', version: '1.0.0' } }) const pingChannel = createChannel({ path: '/ping', receive: { payload: z.object({ ping: z.string() }) }, send: { payload: z.object({ pong: z.string(), timestamp: z.number() }) }, }) app.channel('ping', pingChannel, (ws, message, ctx) => { // message is typed as { ping: string } // ws.send() enforces { pong: string; timestamp: number } console.log('headers:', ctx.headers) ws.send({ pong: message.ping, timestamp: Date.now() }) }) ``` ### Example 2: Channel with Path Parameters ```typescript // Channel with path parameters const notifChannel = createChannel({ path: '/users/:userId/notifications', send: { payload: z.object({ type: z.enum(['info', 'warning', 'error']), message: z.string() }) }, }) app.channel('userNotifications', notifChannel, (ws, message, ctx) => { // ctx.params.userId is typed as string console.log(`Notification for user ${ctx.params.userId}`) ws.send({ type: 'info', message: 'Connected' }) }) app.doc('/asyncapi.json') export default app ``` ``` -------------------------------- ### Complex Message Schemas Example Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Demonstrates using `z.discriminatedUnion` to define complex, type-safe message payloads for a channel, allowing for different message structures based on a discriminant field. ```APIDOC ## Complex Message Schemas ```typescript const gameChannel = createChannel({ path: '/game/:gameId', description: 'Real-time game state updates', send: { payload: z.discriminatedUnion('type', [ z.object({ type: z.literal('move'), playerId: z.string(), position: z.object({ x: z.number(), y: z.number() }), }), z.object({ type: z.literal('chat'), playerId: z.string(), message: z.string(), }), ]), }, receive: { payload: z.object({ gameState: z.object({ players: z.array(z.any()), status: z.enum(['waiting', 'playing', 'finished']), }), }), }, }) ``` ``` -------------------------------- ### Register Channel with Handler - app.channel Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Registers a channel with a handler. When a handler is provided, it mounts a Hono GET route that returns HTTP 426 for non-WebSocket requests. The handler receives typed WebSocketData, inferred payload, and ChannelContext. ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'Ping API', version: '1.0.0' } }) const pingChannel = createChannel({ path: '/ping', receive: { payload: z.object({ ping: z.string() }) }, send: { payload: z.object({ pong: z.string(), timestamp: z.number() }) }, }) app.channel('ping', pingChannel, (ws, message, ctx) => { // message is typed as { ping: string } // ws.send() enforces { pong: string; timestamp: number } console.log('headers:', ctx.headers) ws.send({ pong: message.ping, timestamp: Date.now() }) }) // Channel with path parameters const notifChannel = createChannel({ path: '/users/:userId/notifications', send: { payload: z.object({ type: z.enum(['info', 'warning', 'error']), message: z.string() }) }, }) app.channel('userNotifications', notifChannel, (ws, message, ctx) => { // ctx.params.userId is typed as string console.log(`Notification for user ${ctx.params.userId}`) ws.send({ type: 'info', message: 'Connected' }) }) app.doc('/asyncapi.json') export default app ``` -------------------------------- ### Initialize AsyncAPIHono Application Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Initialize the AsyncAPIHono application with API info and server configurations. Use `.doc()` and `.docYAML()` to serve the generated AsyncAPI specification, or `.getAsyncAPIDocument()` to retrieve it programmatically. ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'My WebSocket API', version: '1.0.0', description: 'Real-time API using WebSockets', contact: { name: 'Team', email: 'api@example.com' }, license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' }, }, servers: { development: { host: 'localhost:3000', protocol: 'ws', description: 'Local dev' }, production: { host: 'api.example.com', protocol: 'wss', description: 'Prod' }, }, }) // Serve AsyncAPI spec as JSON app.doc('/asyncapi.json') // Serve AsyncAPI spec as YAML app.docYAML('/asyncapi.yaml') // Retrieve the document programmatically const doc = app.getAsyncAPIDocument() console.log(doc.asyncapi) // "3.0.0" export default app ``` -------------------------------- ### Initialize AsyncAPIHono Application Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Instantiate `AsyncAPIHono` with your API's information and server configurations. This sets up the core application for handling WebSocket communication and serving AsyncAPI documentation. ```typescript const app = new AsyncAPIHono({ info: { title: 'My API', version: '1.0.0', description: 'API description', }, servers: { production: { host: 'api.example.com', protocol: 'wss', description: 'Production server', }, }, }) ``` -------------------------------- ### Configure Custom WebSocket Servers Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Set up development, staging, and production WebSocket servers using helper functions. Ensure the correct server address and protocol are used for each environment. ```typescript import { createWebSocketServer, createSecureWebSocketServer } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'Multi-Environment API', version: '1.0.0', }, servers: { development: createWebSocketServer('localhost:3000', 'Development server'), staging: createSecureWebSocketServer('staging.api.example.com', 'Staging server'), production: createSecureWebSocketServer('api.example.com', 'Production server'), }, }) ``` -------------------------------- ### Create WebSocket Servers with `createWebSocketServer` Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Use these helpers to create `ServerObject` values with pre-set WebSocket protocols. Ensure the correct host and port are provided. ```typescript import { AsyncAPIHono, createWebSocketServer, createSecureWebSocketServer, } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'Multi-Env API', version: '1.0.0' }, servers: { local: createWebSocketServer('localhost:3000', 'Local dev server'), staging: createSecureWebSocketServer('staging.api.example.com', 'Staging'), production: createSecureWebSocketServer('api.example.com', 'Production'), }, }) // Generates servers block: // { // "local": { "host": "localhost:3000", "protocol": "ws", "description": "Local dev server" }, // "staging": { "host": "staging.api.example.com", "protocol": "wss", "description": "Staging" }, // "production": { "host": "api.example.com", "protocol": "wss", "description": "Production" } // } ``` -------------------------------- ### createUnifiedInfo and createUnifiedServers Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Helper functions to create unified configuration objects for both OpenAPI (HTTP) and AsyncAPI (WebSocket) specifications from a single definition. ```APIDOC ## createUnifiedInfo / createUnifiedServers ### Description `createUnifiedInfo` produces matching `InfoObject` values for both OpenAPI and AsyncAPI from a single definition. `createUnifiedServers` produces server configurations for HTTP (`openapi`) and WebSocket (`asyncapi`) from one object. ### Usage ```typescript import { createUnifiedInfo, createUnifiedServers, AsyncAPIHono, } from '@juice10/hono-zod-asyncapi' import { OpenAPIHono } from '@hono/zod-openapi' const info = createUnifiedInfo({ title: 'Commerce API', version: '3.0.0', description: 'REST + WebSocket commerce platform', contact: { name: 'Platform Team', email: 'platform@example.com' }, license: { name: 'Apache-2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' }, }) // info.openapi → { title, version, description, contact, license } // info.asyncapi → { title, version, description, contact, license } const servers = createUnifiedServers({ http: { url: 'https://api.example.com', description: 'Production HTTP' }, ws: { host: 'ws.example.com', protocol: 'wss', description: 'Production WS' }, }) // servers.openapi → { default: { url: 'https://api.example.com', ... } } // servers.asyncapi → { default: { host: 'ws.example.com', protocol: 'wss', ... } } const restAPI = new OpenAPIHono({ openapi: { ...info.openapi, servers: servers.openapi } }) const wsAPI = new AsyncAPIHono({ info: info.asyncapi, servers: servers.asyncapi }) ``` ``` -------------------------------- ### Register and Manage Channels with `AsyncAPIRegistry` Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt The `AsyncAPIRegistry` stores channel definitions and their metadata. Use `createChannel` to define channels with send/receive payloads and tags. Channels can be registered, inspected, merged, and cleared. ```typescript import { AsyncAPIRegistry } from '@juice10/hono-zod-asyncapi' import { createChannel, z } from '@juice10/hono-zod-asyncapi' const registry = new AsyncAPIRegistry() const orderChannel = createChannel({ path: '/orders/:orderId', send: { payload: z.object({ status: z.enum(['pending', 'shipped', 'delivered']) }) }, receive: { payload: z.object({ action: z.enum(['cancel', 'track']) }) }, tags: ['orders'], }) registry.registerChannel('orders', orderChannel) // Inspect a single channel const ch = registry.getChannel('orders') console.log(ch?.operations.send?.operationId) // "send_orders_0" console.log(ch?.operations.receive?.operationId) // "receive_orders_1" // Iterate all channels for (const [id, data] of registry.getAllChannels()) { console.log(id, data.config.path) } // Merge two registries const secondRegistry = new AsyncAPIRegistry() registry.merge(secondRegistry) // Reset registry.clear() ``` -------------------------------- ### createUnifiedInfo and createUnifiedServers for Shared Config Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Utilize createUnifiedInfo and createUnifiedServers to generate matching InfoObject and server configurations for both OpenAPI and AsyncAPI from a single definition. This simplifies managing shared API metadata. ```typescript import { createUnifiedInfo, createUnifiedServers, AsyncAPIHono, } from '@juice10/hono-zod-asyncapi' import { OpenAPIHono } from '@hono/zod-openapi' const info = createUnifiedInfo({ title: 'Commerce API', version: '3.0.0', description: 'REST + WebSocket commerce platform', contact: { name: 'Platform Team', email: 'platform@example.com' }, license: { name: 'Apache-2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' }, }) // info.openapi → { title, version, description, contact, license } // info.asyncapi → { title, version, description, contact, license } const servers = createUnifiedServers({ http: { url: 'https://api.example.com', description: 'Production HTTP' }, ws: { host: 'ws.example.com', protocol: 'wss', description: 'Production WS' }, }) // servers.openapi → { default: { url: 'https://api.example.com', ... } } // servers.asyncapi → { default: { host: 'ws.example.com', protocol: 'wss', ... } } const restAPI = new OpenAPIHono({ openapi: { ...info.openapi, servers: servers.openapi } }) const wsAPI = new AsyncAPIHono({ info: info.asyncapi, servers: servers.asyncapi }) ``` -------------------------------- ### Define Chat Room Channel with createChannel Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Configure a chat room channel using `createChannel`. Define message schemas for sending and receiving, including payload structure, descriptions, and tags. Path parameters like `:roomId` are automatically extracted. ```typescript import { createChannel, z } from '@juice10/hono-zod-asyncapi' const chatRoomChannel = createChannel({ path: '/chat/:roomId', description: 'Real-time chat room', send: { payload: z.object({ type: z.enum(['message', 'system']), userId: z.string().uuid(), username: z.string().min(1).max(50), message: z.string().min(1).max(500), timestamp: z.number(), }), description: 'Broadcast a chat message to the room', summary: 'Chat message', name: 'ChatMessage', }, receive: { payload: z.object({ userId: z.string().uuid(), username: z.string(), message: z.string(), timestamp: z.number(), }), description: 'Message sent by a client', summary: 'Client message', }, tags: ['chat', 'messaging'], }) ``` -------------------------------- ### createWebSocketServer / createSecureWebSocketServer Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Convenience factories that produce ServerObject values with protocol pre-set to ws or wss respectively. ```APIDOC ## `createWebSocketServer` / `createSecureWebSocketServer` — Server config helpers Convenience factories that produce `ServerObject` values with protocol pre-set to `ws` or `wss` respectively. ```typescript import { AsyncAPIHono, createWebSocketServer, createSecureWebSocketServer, } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'Multi-Env API', version: '1.0.0' }, servers: { local: createWebSocketServer('localhost:3000', 'Local dev server'), staging: createSecureWebSocketServer('staging.api.example.com', 'Staging'), production: createSecureWebSocketServer('api.example.com', 'Production'), }, }) // Generates servers block: // { // "local": { "host": "localhost:3000", "protocol": "ws", "description": "Local dev server" }, // "staging": { "host": "staging.api.example.com", "protocol": "wss", "description": "Staging" }, // "production": { "host": "api.example.com", "protocol": "wss", "description": "Production" } // } ``` ``` -------------------------------- ### UnifiedAPIHono Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt A convenience class that combines OpenAPI and AsyncAPI configurations, offering a single entry point for serving both specifications. ```APIDOC ## UnifiedAPIHono ### Description A subclass of `AsyncAPIHono` that accepts both `openapi` and `asyncapi` config blocks and exposes a `.docs(openapiPath, asyncapiPath)` convenience method to serve both specifications at once. ### Usage ```typescript import { UnifiedAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new UnifiedAPIHono({ openapi: { info: { title: 'My API', version: '1.0.0' } }, asyncapi: { info: { title: 'My WS API', version: '1.0.0' }, servers: { ws: { host: 'ws.example.com', protocol: 'wss' } }, }, }) const eventsChannel = createChannel({ path: '/ws/events', send: { payload: z.object({ event: z.string(), payload: z.any() }) }, }) app.channel('events', eventsChannel, (ws, msg) => { ws.send({ event: 'ack', payload: { received: true } }) }) // Serve both docs in one call app.docs('/api/openapi.json', '/api/asyncapi.json') export default app ``` ``` -------------------------------- ### app.route — Compose modular AsyncAPIHono instances Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Merges the AsyncAPIRegistry of a sub-application into the parent and calls Hono's native route() under the hood, allowing modular architectures. ```APIDOC ## `app.route` — Compose modular AsyncAPIHono instances Merges the `AsyncAPIRegistry` of a sub-application into the parent and calls Hono's native `route()` under the hood, allowing fully modular architectures where each feature owns its channels. ### Example: ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' // --- chat.ts --- export const chatRoutes = new AsyncAPIHono() const publicChat = createChannel({ path: '/public', send: { payload: z.object({ message: z.string(), author: z.string() }) }, receive: { payload: z.object({ message: z.string(), author: z.string() }) }, }) chatRoutes.channel('publicChat', publicChat, (ws, msg) => { ws.send({ message: `Echo: ${msg.message}`, author: 'server' }) }) // --- notifications.ts --- export const notifRoutes = new AsyncAPIHono() const notifChannel = createChannel({ path: '/user/:userId', send: { payload: z.object({ title: z.string(), body: z.string() }) }, }) notifRoutes.channel('userNotif', notifChannel, (ws, msg, ctx) => { console.log(`Notif for ${ctx.params.userId}`) }) // --- main.ts --- const app = new AsyncAPIHono({ info: { title: 'Main API', version: '2.0.0' } }) app.route('/chat', chatRoutes) app.route('/notifications', notifRoutes) app.doc('/asyncapi.json') export default app ``` ``` -------------------------------- ### UnifiedAPIHono for Combined Docs Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Use UnifiedAPIHono to accept both openapi and asyncapi config blocks. It provides a .docs() method to serve both specifications simultaneously. ```typescript import { UnifiedAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new UnifiedAPIHono({ openapi: { info: { title: 'My API', version: '1.0.0' } }, asyncapi: { info: { title: 'My WS API', version: '1.0.0' }, servers: { ws: { host: 'ws.example.com', protocol: 'wss' } }, }, }) const eventsChannel = createChannel({ path: '/ws/events', send: { payload: z.object({ event: z.string(), payload: z.any() }) }, }) app.channel('events', eventsChannel, (ws, msg) => { ws.send({ event: 'ack', payload: { received: true } }) }) // Serve both docs in one call app.docs('/api/openapi.json', '/api/asyncapi.json') export default app ``` -------------------------------- ### Compose Modular AsyncAPIHono Instances - app.route Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Merges the AsyncAPIRegistry of a sub-application into the parent and calls Hono's native route() under the hood. This allows for modular architectures where each feature owns its channels. ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' // --- chat.ts --- export const chatRoutes = new AsyncAPIHono() const publicChat = createChannel({ path: '/public', send: { payload: z.object({ message: z.string(), author: z.string() }) }, receive: { payload: z.object({ message: z.string(), author: z.string() }) }, }) chatRoutes.channel('publicChat', publicChat, (ws, msg) => { ws.send({ message: `Echo: ${msg.message}`, author: 'server' }) }) // --- notifications.ts --- export const notifRoutes = new AsyncAPIHono() const notifChannel = createChannel({ path: '/user/:userId', send: { payload: z.object({ title: z.string(), body: z.string() }) }, }) notifRoutes.channel('userNotif', notifChannel, (ws, msg, ctx) => { console.log(`Notif for ${ctx.params.userId}`) }) // --- main.ts --- const app = new AsyncAPIHono({ info: { title: 'Main API', version: '2.0.0' } }) app.route('/chat', chatRoutes) app.route('/notifications', notifRoutes) app.doc('/asyncapi.json') export default app ``` -------------------------------- ### AsyncAPIHono Class Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt The main application class that extends Hono. It manages an internal AsyncAPIRegistry, allows registration of WebSocket channels, and serves the generated AsyncAPI specification. It can be initialized with optional info and servers configuration. ```APIDOC ## AsyncAPIHono ### Description Extends `Hono` with an internal `AsyncAPIRegistry` and methods for registering WebSocket channels and serving the generated AsyncAPI specification. Accepts optional `info` and `servers` at construction time. ### Usage ```typescript import { AsyncAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new AsyncAPIHono({ info: { title: 'My WebSocket API', version: '1.0.0', description: 'Real-time API using WebSockets', contact: { name: 'Team', email: 'api@example.com' }, license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' }, }, servers: { development: { host: 'localhost:3000', protocol: 'ws', description: 'Local dev' }, production: { host: 'api.example.com', protocol: 'wss', description: 'Prod' }, }, }) // Serve AsyncAPI spec as JSON app.doc('/asyncapi.json') // Serve AsyncAPI spec as YAML app.docYAML('/asyncapi.yaml') // Retrieve the document programmatically const doc = app.getAsyncAPIDocument() console.log(doc.asyncapi) // "3.0.0" export default app ``` ### Methods - `doc(path: string)`: Serves the AsyncAPI specification as JSON at the specified path. - `docYAML(path: string)`: Serves the AsyncAPI specification as YAML at the specified path. - `getAsyncAPIDocument()`: Returns the generated AsyncAPI document object programmatically. ``` -------------------------------- ### Integration Option 1: Merge Separate Apps Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Combine REST and WebSocket APIs by creating separate Hono apps for OpenAPI and AsyncAPI, then merging them. This approach allows serving both OpenAPI and AsyncAPI documentation from a single application instance. ```typescript import { OpenAPIHono, createRoute, z as openAPIZ } from '@hono/zod-openapi' import { AsyncAPIHono, createChannel, z, mergeAPIDocs } from '@juice10/hono-zod-asyncapi' // Create REST API with OpenAPI const restAPI = new OpenAPIHono() const getUserRoute = createRoute({ method: 'get', path: '/api/users/:id', responses: { 200: { content: { 'application/json': { schema: openAPIZ.object({ id: openAPIZ.string(), name: openAPIZ.string(), }), }, }, description: 'User details', }, }, }) restAPI.openapi(getUserRoute, (c) => { return c.json({ id: '123', name: 'Alice' }) }) // Create WebSocket API with AsyncAPI const wsAPI = new AsyncAPIHono({ info: { title: 'WebSocket API', version: '1.0.0', }, }) const chatChannel = createChannel({ path: '/ws/chat/:roomId', send: { payload: z.object({ message: z.string(), userId: z.string(), }), }, }) wsAPI.channel('chat', chatChannel, (ws, message, ctx) => { console.log(`Chat message in room ${ctx.params.roomId}`) ws.send({ message: 'Hello!', userId: 'system' }) }) // Merge both APIs const app = mergeAPIDocs(restAPI, wsAPI) // Serve both documentations app.doc('/api/openapi.json') // OpenAPI spec for REST app.asyncapiDoc('/api/asyncapi.json') // AsyncAPI spec for WebSocket export default app ``` -------------------------------- ### mergeAPIDocs Source: https://context7.com/juice10/hono-zod-asyncapi/llms.txt Combines OpenAPI and AsyncAPI apps, serving both OpenAPI and AsyncAPI documentation from a single Hono application. ```APIDOC ## `mergeAPIDocs` — Combine OpenAPI and AsyncAPI apps Takes an existing `OpenAPIHono` instance and an `AsyncAPIHono` instance, merges their routes, and adds `asyncAPIRegistry`, `getAsyncAPIDocument`, `channel`, and `asyncapiDoc` onto the OpenAPI app. The result serves both `/openapi.json` and `/asyncapi.json` from a single Hono application. ```typescript import { OpenAPIHono, createRoute, z as oz } from '@hono/zod-openapi' import { AsyncAPIHono, createChannel, mergeAPIDocs, z } from '@juice10/hono-zod-asyncapi' // REST side const restAPI = new OpenAPIHono() const listUsersRoute = createRoute({ method: 'get', path: '/api/users', tags: ['Users'], responses: { 200: { content: { 'application/json': { schema: oz.object({ users: oz.array(oz.object({ id: oz.string(), name: oz.string() })) }) } }, description: 'User list', }, }, }) restAPI.openapi(listUsersRoute, (c) => c.json({ users: [{ id: '1', name: 'Alice' }] })) // WebSocket side const wsAPI = new AsyncAPIHono({ info: { title: 'WS API', version: '1.0.0' }, servers: { prod: { host: 'api.example.com', protocol: 'wss' } }, }) const chatChannel = createChannel({ path: '/ws/chat/:roomId', send: { payload: z.object({ message: z.string(), userId: z.string() }) }, receive: { payload: z.object({ message: z.string(), userId: z.string() }) }, }) wsAPI.channel('chat', chatChannel, (ws, msg, ctx) => { ws.send({ message: `Echo: ${msg.message}`, userId: 'server' }) }) // Merge const app = mergeAPIDocs(restAPI, wsAPI) app.doc('/api/openapi.json') app.asyncapiDoc('/api/asyncapi.json') export default app ``` ``` -------------------------------- ### AsyncAPIHono Class Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md The main class for creating an AsyncAPI-enabled Hono application. It extends Hono and provides methods for defining WebSocket channels and serving API documentation. ```APIDOC ## AsyncAPIHono The main class that extends Hono with AsyncAPI support. ### Constructor ```typescript new AsyncAPIHono(options?: { info: AsyncAPIDocumentInfo; servers?: AsyncAPIDocumentServers }) ``` ### Methods - **`channel(id, config, handler?)`**: Register a WebSocket channel. - **`doc(path, options?)`**: Serve AsyncAPI document as JSON. - **`docYAML(path, options?)`**: Serve AsyncAPI document as YAML. - **`getAsyncAPIDocument(options?)`**: Get the AsyncAPI document object. - **`route(path, app)`**: Merge routes from another AsyncAPIHono instance. - **`basePath(path)`**: Create a new instance with a base path. ``` -------------------------------- ### Modular Architecture with Route Merging Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Organize your WebSocket channels into separate modules (e.g., `channels/chat.ts`, `channels/notifications.ts`) and merge them into the main application using `app.route()`. This promotes a cleaner and more maintainable codebase. ```typescript // channels/chat.ts export const chatRoutes = new AsyncAPIHono() chatRoutes.channel('publicChat', publicChatChannel, handler1) chatRoutes.channel('privateChat', privateChatChannel, handler2) // channels/notifications.ts export const notificationRoutes = new AsyncAPIHono() notificationRoutes.channel('userNotifications', notificationChannel, handler) // main.ts const app = new AsyncAPIHono({ info: { title: 'My API', version: '1.0.0', }, }) app.route('/chat', chatRoutes) app.route('/notifications', notificationRoutes) app.doc('/asyncapi.json') ``` -------------------------------- ### Integration Option 2: Unified API App Source: https://github.com/juice10/hono-zod-asyncapi/blob/main/README.md Create a single Hono app that handles both REST (OpenAPI) and WebSocket (AsyncAPI) functionalities. This unified approach simplifies configuration and documentation serving. ```typescript import { UnifiedAPIHono, createChannel, z } from '@juice10/hono-zod-asyncapi' const app = new UnifiedAPIHono({ openapi: { info: { title: 'My API', version: '1.0.0' }, }, asyncapi: { info: { title: 'My WebSocket API', version: '1.0.0' }, }, }) // Add WebSocket channels const channel = createChannel({ path: '/ws/events', send: { payload: z.object({ event: z.string() }) }, }) app.channel('events', channel) // Serve both docs app.docs('/api/openapi.json', '/api/asyncapi.json') ```