diff --git a/docs/README.md b/docs/README.md index a23091f0..5b42bed7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -102,5 +102,6 @@ Connect AI assistants like Claude Code, Cursor, and Windsurf to The Codegen Proj + diff --git a/docs/contributing.md b/docs/contributing.md index ed4eeafd..8745b44b 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -220,5 +220,6 @@ Prefix that follows specification is not enough though. Remember that the title + diff --git a/docs/migrations/v0.md b/docs/migrations/v0.md index 17de6031..e06b7383 100644 --- a/docs/migrations/v0.md +++ b/docs/migrations/v0.md @@ -249,5 +249,6 @@ import * as NodeFetch from 'node-fetch'; + diff --git a/docs/usage.md b/docs/usage.md index 24d3b5e3..943245fb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -9,7 +9,7 @@ $ npm install -g @the-codegen-project/cli $ codegen COMMAND running command... $ codegen (--version) -@the-codegen-project/cli/0.80.0 linux-x64 node-v22.23.1 +@the-codegen-project/cli/0.80.1 linux-x64 node-v22.23.1 $ codegen --help [COMMAND] USAGE $ codegen COMMAND @@ -93,7 +93,7 @@ DESCRIPTION configuration. ``` -_See code: [src/commands/generate.ts](https://github.com/the-codegen-project/cli/blob/v0.80.0/src/commands/generate.ts)_ +_See code: [src/commands/generate.ts](https://github.com/the-codegen-project/cli/blob/v0.80.1/src/commands/generate.ts)_ ## `codegen help [COMMAND]` @@ -167,7 +167,7 @@ DESCRIPTION Initialize The Codegen Project in your project ``` -_See code: [src/commands/init.ts](https://github.com/the-codegen-project/cli/blob/v0.80.0/src/commands/init.ts)_ +_See code: [src/commands/init.ts](https://github.com/the-codegen-project/cli/blob/v0.80.1/src/commands/init.ts)_ ## `codegen telemetry ACTION` @@ -200,7 +200,7 @@ EXAMPLES $ codegen telemetry disable ``` -_See code: [src/commands/telemetry.ts](https://github.com/the-codegen-project/cli/blob/v0.80.0/src/commands/telemetry.ts)_ +_See code: [src/commands/telemetry.ts](https://github.com/the-codegen-project/cli/blob/v0.80.1/src/commands/telemetry.ts)_ ## `codegen version` diff --git a/mcp-server/lib/resources/bundled-docs.ts b/mcp-server/lib/resources/bundled-docs.ts index 92abcb66..e94cd31a 100644 --- a/mcp-server/lib/resources/bundled-docs.ts +++ b/mcp-server/lib/resources/bundled-docs.ts @@ -1,7 +1,7 @@ /** * Auto-generated documentation bundle. * DO NOT EDIT - regenerate with: npm run bundle-docs - * Generated at: 2026-07-27T09:38:13.872Z + * Generated at: 2026-07-30T09:34:12.010Z */ export interface DocEntry { @@ -40,23 +40,23 @@ export const docs: Record = { }, "generators/channels": { title: "Channels", - content: "# Channels\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'channels',\n outputPath: './src/__gen__/', \n language: 'typescript',\n protocols: ['nats']\n }\n ]\n};\n```\n\n`channels` preset with `asyncapi` input generates support functions for each operation based on the selected protocol.\n\nThis generator uses [`payloads`](./payloads.md), [`headers`](./headers.md) and [`parameters`](./parameters.md) generators, in case you dont have any defined, it will automatically include them with default values.\n\nThis is supported through the following inputs: [`asyncapi`](../inputs/asyncapi.md)\n\nIt supports the following languages; [`typescript`](#typescript)\n\nIt supports the following protocols; [`nats`](../protocols/nats.md), [`kafka`](../protocols/kafka.md), [`mqtt`](../protocols/mqtt.md), [`amqp`](../protocols/amqp.md), [`event_source`](../protocols/eventsource.md), [`http_client`](../protocols/http_client.md), [`websocket`](../protocols/websocket.md)\n\n## Options\nThese are the available options for the `channels` generator; \n\n| **Option** | Default | Type | Description |\n|---|---|---|---|\n| asyncapiReverseOperations | `false` | Boolean | Used in conjunction with AsyncAPI input, and reverses the operation actions i.e. send becomes receive and receive becomes send. Often used in testing scenarios to act as the reverse API. |\n| asyncapiGenerateForOperations | `true` | Boolean | Used in conjunction with AsyncAPI input, which if `true` generate the functions upholding how operations are defined. If `false` the functions are generated regardless of what operations define. I.e. `send` and `receive` does not matter. |\n| functionTypeMapping | `{}` | Record\\ | Used in conjunction with AsyncAPI input, can define channel ID along side the type of functions that should be rendered. |\n| kafkaTopicSeparator | `'.'` | String | Used with AsyncAPI to ensure the right character separate topics, example if address is my/resource/path it will be converted to my.resource.path |\n| eventSourceDependency | `'@microsoft/fetch-event-source'` | String | Because @microsoft/fetch-event-source is out-dated in some areas we allow you to change the fork/variant that can be used instead |\n| organization | `'flat'` | `'flat' \\| 'tag' \\| 'path'` | Controls how generated channel functions are organized in the barrel `index.ts`. `flat` re-exports each function directly under its protocol namespace (default, unchanged). `tag` groups them under their API tag (operation tag first, then a v3 channel tag, otherwise an `untagged` bucket). `path` nests them by URL path / channel address segments; the leaf is the HTTP method for OpenAPI and a clean action verb (`publish`, `subscribe`, `jetStreamPublish`, …) for AsyncAPI. Only the barrel shape changes — the per-protocol function code is identical across styles. [See Organization](#organization) |\n\n## TypeScript\nRegardless of protocol, these are the dependencies: \n- If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1\n \nDepending on which protocol, these are the dependencies:\n- `NATS`: https://github.com/nats-io/nats.js v2\n- `Kafka`: https://github.com/tulios/kafkajs v2\n- `MQTT`: https://github.com/mqttjs/MQTT.js v5\n- `AMQP`: https://github.com/amqp-node/amqplib v0\n- `EventSource`: `event_source_fetch`: https://github.com/Azure/fetch-event-source v2, `event_source_express`: https://github.com/expressjs/express v4\n- `HTTP`: none — uses the global `fetch` built into Node.js 18+ (the generated client relies on the native `fetch`/`Headers`; swap in `node-fetch`, `axios`, etc. via the `makeRequest` hook if needed)\n- `WebSocket`: https://github.com/websockets/ws v8\n\nFor TypeScript, the generator creates one file per protocol plus an index file that re-exports all protocols as namespaces. For example;\n\n```ts\n// Import specific functions from a protocol file\nimport {\n jetStreamPublishToSendUserSignedup,\n subscribeToReceiveUserSignedup,\n publishToSendUserSignedup\n} from 'src/__gen__/nats';\n\n// Or import the entire protocol namespace\nimport * as nats from 'src/__gen__/nats';\n\n// Or import all protocols from the index\nimport { nats, kafka, mqtt, amqp, event_source } from 'src/__gen__/index';\n```\n\nThe generated file structure is:\n```\noutputPath/\n├── index.ts # Re-exports all protocol namespaces\n├── nats.ts # NATS-specific functions\n├── kafka.ts # Kafka-specific functions\n├── mqtt.ts # MQTT-specific functions\n├── amqp.ts # AMQP-specific functions\n├── event_source.ts # EventSource-specific functions\n├── http_client.ts # HTTP client-specific functions\n└── websocket.ts # WebSocket-specific functions\n```\n\nEach protocol file contains standalone exported functions for interacting with channels defined in your AsyncAPI document.\n\n### Organization\n\nThe `organization` option controls how the generated functions are surfaced in the barrel `index.ts`. The per-protocol `.ts` files are **identical** across every style — only the re-export shape changes, so switching styles never changes the generated function code.\n\n| Value | Behavior |\n|---|---|\n| `flat` (default) | Every function is re-exported directly under its protocol namespace. Byte-identical to previous versions. |\n| `tag` | Functions are grouped under their API tag. |\n| `path` | Functions are nested by their URL path / channel address segments. |\n\n#### `flat` (default)\n\n```ts\nimport { http_client } from './channels';\nawait http_client.updatePet({ /* ... */ });\n```\n\n#### `tag`\n\nFunctions are grouped one level deep under their first tag. Leaf names are kept **verbatim** (the operationId / generated function name is unchanged).\n\n- **OpenAPI**: the tag comes from the operation's `tags`.\n- **AsyncAPI**: the tag comes from the operation's `tags` first; if the operation has none, the (AsyncAPI v3-only) channel `tags` are used. AsyncAPI v2 channels have no tags. Functions with no resolvable tag fall into an `untagged` bucket.\n\n```ts\nimport { http_client } from './channels';\nawait http_client.pet.updatePet({ /* ... */ }); // OpenAPI, grouped by tag \"pet\"\n\nimport { nats } from './channels';\nawait nats.user.publishToSendUserSignedup({ /* ... */ }); // AsyncAPI operation tagged \"user\"\nawait nats.untagged.publishToSendSystemPing({ /* ... */ }); // operation with no tag\n```\n\n#### `path`\n\nFunctions are nested through the static segments of the URL path (OpenAPI) or channel address (AsyncAPI); `{parameter}` placeholders and empty segments are dropped. The leaf differs by input:\n\n- **OpenAPI**: the leaf is the lowercased HTTP **method** (so `POST /pet` and `PUT /pet` coexist as `pet.post` and `pet.put`).\n- **AsyncAPI**: the leaf is a clean **action verb** derived from the function type — `publish`, `subscribe`, `request`, `reply`, `jetStreamPublish`, `jetStreamPullSubscribe`, `jetStreamPushSubscribe`, etc. — mirroring the OpenAPI method leaf (an address has no HTTP method). If two functions would resolve to the same leaf at the same node, the second falls back to its full function name so nothing is ever dropped.\n\n```ts\nimport { http_client } from './channels';\nawait http_client.pet.put({ /* ... */ }); // PUT /pet\nawait http_client.pet.findByStatus.get({ /* ... */ }); // GET /pet/findByStatus/{status}/{categoryId}\n\nimport { nats } from './channels';\nawait nats.user.signedup.publish({ /* ... */ }); // address user/signedup/{id}\nawait nats.user.signedup.jetStreamPublish({ /* ... */ });\n```\n\nConfigure it per channels generator:\n\n```js\n{\n preset: 'channels',\n outputPath: './src/__gen__/channels',\n protocols: ['http_client'],\n organization: 'tag' // 'flat' | 'tag' | 'path'\n}\n```", + content: "# Channels\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'channels',\n outputPath: './src/__gen__/', \n language: 'typescript',\n protocols: ['nats']\n }\n ]\n};\n```\n\n`channels` preset generates support functions for each operation based on the selected protocol.\n\nThis generator uses [`payloads`](./payloads.md), [`headers`](./headers.md) and [`parameters`](./parameters.md) generators, in case you dont have any defined, it will automatically include them with default values.\n\nThis is supported through the following inputs: [`asyncapi`](../inputs/asyncapi.md), [`openapi`](../inputs/openapi.md)\n\nIt supports the following languages; [`typescript`](#typescript)\n\nIt supports the following protocols; [`nats`](../protocols/nats.md), [`kafka`](../protocols/kafka.md), [`mqtt`](../protocols/mqtt.md), [`amqp`](../protocols/amqp.md), [`event_source`](../protocols/eventsource.md), [`http_client`](../protocols/http_client.md), [`websocket`](../protocols/websocket.md)\n\n## Options\nThese are the available options for the `channels` generator; \n\n| **Option** | Default | Type | Description |\n|---|---|---|---|\n| asyncapiReverseOperations | `false` | Boolean | Used in conjunction with AsyncAPI input, and reverses the operation actions i.e. send becomes receive and receive becomes send. Often used in testing scenarios to act as the reverse API. |\n| asyncapiGenerateForOperations | `true` | Boolean | Used in conjunction with AsyncAPI input, which if `true` generate the functions upholding how operations are defined. If `false` the functions are generated regardless of what operations define. I.e. `send` and `receive` does not matter. |\n| functionTypeMapping | `{}` | Record\\ | Used in conjunction with AsyncAPI input, can define channel ID along side the type of functions that should be rendered. |\n| kafkaTopicSeparator | `'.'` | String | Used with AsyncAPI to ensure the right character separate topics, example if address is my/resource/path it will be converted to my.resource.path |\n| eventSourceDependency | `'@microsoft/fetch-event-source'` | String | Because @microsoft/fetch-event-source is out-dated in some areas we allow you to change the fork/variant that can be used instead |\n| organization | `'flat'` | `'flat' \\| 'tag' \\| 'path'` | Controls how generated channel functions are organized in the barrel `index.ts`. `flat` re-exports each function directly under its protocol namespace (default, unchanged). `tag` groups them under their API tag (operation tag first, then a v3 channel tag, otherwise an `untagged` bucket). `path` nests them by URL path / channel address segments; the leaf is the HTTP method for OpenAPI and a clean action verb (`publish`, `subscribe`, `jetStreamPublish`, …) for AsyncAPI. Only the barrel shape changes — the per-protocol function code is identical across styles. [See Organization](#organization) |\n\n## TypeScript\nRegardless of protocol, these are the dependencies: \n- If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1\n- If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1\n \nDepending on which protocol, these are the dependencies:\n- `NATS`: https://github.com/nats-io/nats.js v2\n- `Kafka`: https://github.com/tulios/kafkajs v2\n- `MQTT`: https://github.com/mqttjs/MQTT.js v5\n- `AMQP`: https://github.com/amqp-node/amqplib v0\n- `EventSource`: `event_source_fetch`: https://github.com/Azure/fetch-event-source v2, `event_source_express`: https://github.com/expressjs/express v4\n- `HTTP`: none — uses the global `fetch` built into Node.js 18+ (the generated client relies on the native `fetch`/`Headers`; swap in `node-fetch`, `axios`, etc. via the `makeRequest` hook if needed)\n- `WebSocket`: https://github.com/websockets/ws v8\n\nFor TypeScript, the generator creates one file per protocol plus an index file that re-exports all protocols as namespaces. For example;\n\n```ts\n// Import specific functions from a protocol file\nimport {\n jetStreamPublishToSendUserSignedup,\n subscribeToReceiveUserSignedup,\n publishToSendUserSignedup\n} from 'src/__gen__/nats';\n\n// Or import the entire protocol namespace\nimport * as nats from 'src/__gen__/nats';\n\n// Or import all protocols from the index\nimport { nats, kafka, mqtt, amqp, event_source } from 'src/__gen__/index';\n```\n\nThe generated file structure is:\n```\noutputPath/\n├── index.ts # Re-exports all protocol namespaces\n├── nats.ts # NATS-specific functions\n├── kafka.ts # Kafka-specific functions\n├── mqtt.ts # MQTT-specific functions\n├── amqp.ts # AMQP-specific functions\n├── event_source.ts # EventSource-specific functions\n├── http_client.ts # HTTP client-specific functions\n└── websocket.ts # WebSocket-specific functions\n```\n\nEach protocol file contains standalone exported functions for interacting with channels defined in your AsyncAPI document.\n\n### Organization\n\nThe `organization` option controls how the generated functions are surfaced in the barrel `index.ts`. The per-protocol `.ts` files are **identical** across every style — only the re-export shape changes, so switching styles never changes the generated function code.\n\n| Value | Behavior |\n|---|---|\n| `flat` (default) | Every function is re-exported directly under its protocol namespace. Byte-identical to previous versions. |\n| `tag` | Functions are grouped under their API tag. |\n| `path` | Functions are nested by their URL path / channel address segments. |\n\n#### `flat` (default)\n\n```ts\nimport { http_client } from './channels';\nawait http_client.updatePet({ /* ... */ });\n```\n\n#### `tag`\n\nFunctions are grouped one level deep under their first tag. Leaf names are kept **verbatim** (the operationId / generated function name is unchanged).\n\n- **OpenAPI**: the tag comes from the operation's `tags`.\n- **AsyncAPI**: the tag comes from the operation's `tags` first; if the operation has none, the (AsyncAPI v3-only) channel `tags` are used. AsyncAPI v2 channels have no tags. Functions with no resolvable tag fall into an `untagged` bucket.\n\n```ts\nimport { http_client } from './channels';\nawait http_client.pet.updatePet({ /* ... */ }); // OpenAPI, grouped by tag \"pet\"\n\nimport { nats } from './channels';\nawait nats.user.publishToSendUserSignedup({ /* ... */ }); // AsyncAPI operation tagged \"user\"\nawait nats.untagged.publishToSendSystemPing({ /* ... */ }); // operation with no tag\n```\n\n#### `path`\n\nFunctions are nested through the static segments of the URL path (OpenAPI) or channel address (AsyncAPI); `{parameter}` placeholders and empty segments are dropped. The leaf differs by input:\n\n- **OpenAPI**: the leaf is the lowercased HTTP **method** (so `POST /pet` and `PUT /pet` coexist as `pet.post` and `pet.put`).\n- **AsyncAPI**: the leaf is a clean **action verb** derived from the function type — `publish`, `subscribe`, `request`, `reply`, `jetStreamPublish`, `jetStreamPullSubscribe`, `jetStreamPushSubscribe`, etc. — mirroring the OpenAPI method leaf (an address has no HTTP method). If two functions would resolve to the same leaf at the same node, the second falls back to its full function name so nothing is ever dropped.\n\n```ts\nimport { http_client } from './channels';\nawait http_client.pet.put({ /* ... */ }); // PUT /pet\nawait http_client.pet.findByStatus.get({ /* ... */ }); // GET /pet/findByStatus/{status}/{categoryId}\n\nimport { nats } from './channels';\nawait nats.user.signedup.publish({ /* ... */ }); // address user/signedup/{id}\nawait nats.user.signedup.jetStreamPublish({ /* ... */ });\n```\n\nConfigure it per channels generator:\n\n```js\n{\n preset: 'channels',\n outputPath: './src/__gen__/channels',\n protocols: ['http_client'],\n organization: 'tag' // 'flat' | 'tag' | 'path'\n}\n```", }, "generators/client": { title: "Client", - content: "# Client\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'client',\n outputPath: './src/__gen__/', \n language: 'typescript',\n protocols: ['nats']\n }\n ]\n};\n```\n\n`client` preset generates a class that makes it easier to interact with a protocol. For message brokers (`nats`) this is a `{Protocol}Client` that manages the connection; for `http` it is a single API client class whose name is derived from the input document title (see [HTTP](#http)).\n\nIt will generate;\n- Support function for connecting to the protocol (message brokers) or holding shared request configuration (HTTP)\n- Simpler functions then those generated by [`channels`](./channels.md) to interact with the given protocols\n- Exporting all generated [`parameters`](./parameters.md)\n- Exporting all generated [`payloads`](./payloads.md)\n\nThis generator uses `channels` generators, in case you dont have any defined, it will automatically include them with default values and dependencies. When a configured protocol has no matching channel functions in the input document, no client is emitted for it.\n\nThis is supported through the following inputs: [`asyncapi`](../inputs/asyncapi.md), [`openapi`](../inputs/openapi.md) (HTTP only)\n\nIt supports the following languages; [`typescript`](#typescript)\n\nIt supports the following protocols; [`nats`](../protocols/nats.md), [`http`](../protocols/http_client.md)\n\n## TypeScript\n\n### Nats\n\nDependencies;\n- `NATS`: https://github.com/nats-io/nats.js v2\n\nFor Nats the `NatsClient` is generated that setups the correct [Nats.js](https://github.com/nats-io/nats.js) clients, marshalling codex, and provide simplier functions to improve DX.\n\nExample;\n```ts\n//Import and export payload models\nimport {Payload} from './payload/Payload';\nexport {Payload};\n\n//Import and export parameter models\nimport {Parameters} from './parameters/Parameters';\n\n//Import channel functions\nimport { Protocols } from './channels/index';\nconst { nats } = Protocols;\n\nimport * as Nats from 'nats';\n\n/**\n * @class NatsClient\n */\nexport class NatsClient {\n /**\n * Disconnect all clients from the server\n */\n async disconnect() {\n ...\n }\n /**\n * Returns whether or not any of the clients are closed\n */\n isClosed() {\n ...\n }\n /**\n * Try to connect to the NATS server with user credentials\n */\n async connectWithUserCreds(userCreds: string, options ? : Nats.ConnectionOptions, codec ? : Nats.Codec < any > ) {\n ...\n }\n /**\n * Try to connect to the NATS server with user and password\n */\n async connectWithUserPass(user: string, pass: string, options ? : Nats.ConnectionOptions, codec ? : Nats.Codec < any > ) {\n ...\n }\n /**\n * Try to connect to the NATS server which has no authentication\n */\n async connectToHost(host: string, options ? : Nats.ConnectionOptions, codec ? : Nats.Codec < any > ) {\n ...\n }\n\n /**\n * Try to connect to the NATS server with the different payloads.\n */\n connect(options: Nats.ConnectionOptions, codec?: Nats.Codec): Promise {\n ...\n }\n \n public async jetStreamPublishToChannel(\n message: Payload, \n parameters: Parameters, \n options: Partial = {}\n ): Promise {\n ...\n }\n jetStreamPullSubscribeToChannel\n jetStreamPushSubscriptionFromChannel\n publishToChannel\n subscribeToChannel\n}\n```\n\n### HTTP\n\nFor `http` a single API client class is generated that wraps the standalone [`http_client`](../protocols/http_client.md) channel functions. You construct it once with the shared request configuration (`baseUrl`, `auth`, `hooks`, retry, ...) and every operation becomes a method that reuses that configuration; any field can still be overridden per call.\n\n```js\nexport default {\n inputType: 'openapi',\n inputPath: './my-api.json',\n generators: [\n {\n preset: 'client',\n outputPath: './src/__gen__/client',\n language: 'typescript',\n protocols: ['http']\n }\n ]\n};\n```\n\nThe class name is derived from the input document title (a `\"Safepay Nordic API\"` title yields `SafepayNordicClient`), falling back to `HttpClient`. Override it explicitly with the `clientName` option.\n\nExample generated usage:\n```ts\nimport {SafepayNordicClient} from './__gen__/client/SafepayNordicClient';\n\nconst safepay = new SafepayNordicClient({\n baseUrl: 'https://api.example.com',\n auth: {type: 'bearer', token: process.env.API_TOKEN ?? ''}\n});\n\n// Shared server/auth are reused; the call only supplies what is operation-specific.\nconst response = await safepay.getV2Documents();\nconsole.log(response.status, response.data);\n```\n\nEach method returns the same `HttpClientResponse` as the underlying channel function, so response metadata (status, headers) is preserved.", + content: "# Client\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'client',\n outputPath: './src/__gen__/', \n language: 'typescript',\n protocols: ['nats']\n }\n ]\n};\n```\n\n`client` preset generates a class that makes it easier to interact with a protocol. For message brokers (`nats`) this is a `{Protocol}Client` that manages the connection; for `http` it is a single API client class whose name is derived from the input document title (see [HTTP](#http)).\n\nIt will generate;\n- Support function for connecting to the protocol (message brokers) or holding shared request configuration (HTTP)\n- Simpler functions then those generated by [`channels`](./channels.md) to interact with the given protocols\n- Exporting all generated [`parameters`](./parameters.md)\n- Exporting all generated [`payloads`](./payloads.md)\n\nThis generator uses `channels` generators, in case you dont have any defined, it will automatically include them with default values and dependencies. When a configured protocol has no matching channel functions in the input document, no client is emitted for it.\n\nThis is supported through the following inputs: [`asyncapi`](../inputs/asyncapi.md), [`openapi`](../inputs/openapi.md) (HTTP only)\n\nIt supports the following languages; [`typescript`](#typescript)\n\nIt supports the following protocols; [`nats`](../protocols/nats.md), [`http`](../protocols/http_client.md)\n\n## TypeScript\n\n### Nats\n\nDependencies;\n- `NATS`: https://github.com/nats-io/nats.js v2\n\nFor Nats the `NatsClient` is generated that setups the correct [Nats.js](https://github.com/nats-io/nats.js) clients, marshalling codex, and provide simplier functions to improve DX.\n\nExample;\n```ts\n//Import and export payload models\nimport {Payload} from './payload/Payload';\nexport {Payload};\n\n//Import and export parameter models\nimport {Parameters} from './parameters/Parameters';\n\n//Import channel functions\nimport { nats } from './channels/index';\n\nimport * as Nats from 'nats';\n\n/**\n * @class NatsClient\n */\nexport class NatsClient {\n /**\n * Disconnect all clients from the server\n */\n async disconnect() {\n ...\n }\n /**\n * Returns whether or not any of the clients are closed\n */\n isClosed() {\n ...\n }\n /**\n * Try to connect to the NATS server with user credentials\n */\n async connectWithUserCreds(userCreds: string, options ? : Nats.ConnectionOptions, codec ? : Nats.Codec < any > ) {\n ...\n }\n /**\n * Try to connect to the NATS server with user and password\n */\n async connectWithUserPass(user: string, pass: string, options ? : Nats.ConnectionOptions, codec ? : Nats.Codec < any > ) {\n ...\n }\n /**\n * Try to connect to the NATS server which has no authentication\n */\n async connectToHost(host: string, options ? : Nats.ConnectionOptions, codec ? : Nats.Codec < any > ) {\n ...\n }\n\n /**\n * Try to connect to the NATS server with the different payloads.\n */\n connect(\n options: Nats.ConnectionOptions,\n codec?: Nats.Codec\n ): Promise<{nc: Nats.NatsConnection, js: Nats.JetStreamClient}> {\n ...\n }\n\n public async jetStreamPublishToChannel({\n message,\n parameters,\n options = {}\n }: {\n message: PayloadInterface | Payload,\n parameters: Parameters,\n options?: Partial\n }): Promise {\n ...\n }\n jetStreamPullSubscribeToChannel\n jetStreamPushSubscriptionFromChannel\n publishToChannel\n subscribeToChannel\n}\n```\n\n### HTTP\n\nFor `http` a single API client class is generated that wraps the standalone [`http_client`](../protocols/http_client.md) channel functions. You construct it once with the shared request configuration (`baseUrl`, `auth`, `hooks`, retry, ...) and every operation becomes a method that reuses that configuration; any field can still be overridden per call.\n\n```js\nexport default {\n inputType: 'openapi',\n inputPath: './my-api.json',\n generators: [\n {\n preset: 'client',\n outputPath: './src/__gen__/client',\n language: 'typescript',\n protocols: ['http']\n }\n ]\n};\n```\n\nThe class name is derived from the input document title (a `\"Safepay Nordic API\"` title yields `SafepayNordicClient`), falling back to `HttpClient`. Override it explicitly with the `clientName` option.\n\nExample generated usage:\n```ts\nimport {SafepayNordicClient} from './__gen__/client/SafepayNordicClient';\n\nconst safepay = new SafepayNordicClient({\n baseUrl: 'https://api.example.com',\n auth: {type: 'bearer', token: process.env.API_TOKEN ?? ''}\n});\n\n// Shared server/auth are reused; the call only supplies what is operation-specific.\nconst response = await safepay.getV2Documents();\nconsole.log(response.status, response.data);\n```\n\nEach method returns the same `HttpClientResponse` as the underlying channel function, so response metadata (status, headers) is preserved.", }, "generators/custom": { title: "Custom generator", - content: "# Custom generator\n\nThis generator is simple, it's a callback that enable you to write any file or do any operation in the code generation process. This preset is available for all languages.\n\n## Imports\n\nThe dependencies you have access to is any native `node` dependency and all dependencies listed in [The Codegen Project](https://github.com/the-codegen-project/cli/blob/8b8fa6f0c5b0c0c63515a8ca439f72872815f491/package.json#L9). Here is an example:\n\n```ts\nimport { JavaFileGenerator } from \"@asyncapi/modelina\";\nexport default {\n ...\n generators: [\n {\n preset: 'custom',\n ...\n renderFunction: ({generator, inputType, asyncapiDocument, openapiDocument, dependencyOutputs}) \n {\n const modelinaGenerator = new JavaFileGenerator({});\n modelinaGenerator.generateCompleteModels(...)\n }\n }\n ]\n};\n```\n\n# Dependencies\n\nIn each generator (don't manually use it unless you use `preset: custom`), you can add `dependencies` property, which takes an array of `id`'s that the rendering engine ensures are rendered before the dependant one. \n\nEach generator has a specific output (except `custom` which is dynamic and under your control), they are documented under each [./generators](./README.md). These outputs can be accessed under `dependencyOutputs`.\n\nThere are two rules though;\n\n1. You are not allowed to have circular dependencies, i.e. two generators both depending on each other.\n2. You are not allowed to have self-dependant generators\n\n## How does it work?\n\nFor example, take two generators, you can chain them together and use one's output in the other, as for example below, to have the console print out `Hello World!`.\n```js\nexport default {\n ...\n generators: [\n {\n preset: 'custom',\n renderFunction: ({dependencyOutputs}) => {\n console.log(dependencyOutputs['bar'])\n },\n dependencies: ['bar']\n },\n {\n preset: 'custom',\n id: 'bar',\n renderFunction: () => {\n return 'Hello World!'\n }\n }\n ]\n};\n```\n\n## Arguments\nIn the `renderFunction` you have access to a bunch of arguments to help you create the callback;\n\n- `generator` - is the generator configuration, where you have access to the `options` and all other information.\n- `inputType` - is the root `inputType` for the input document\n- `asyncapiDocument` - is the parsed AsyncAPI document input (according to the [AsyncAPI parser](https://github.com/asyncapi/parser-js/)), undefined if the `inputType` is not `asyncapi`\n- `openapiDocument` - is the parsed OpenAPI document input (according to the [readme/openapi-parser](https://github.com/readmeio/oas)), undefined if the `inputType` is not `openapi`\n- `dependencyOutputs` - if you have defined any `dependencies`, this is where you can access the output. Checkout the [dependency documentation](#dependencies) for more information.", + content: "# Custom generator\n\nThis generator is simple, it's a callback that enable you to write any file or do any operation in the code generation process. This preset is available for all languages.\n\n## Imports\n\nThe dependencies you have access to is any native `node` dependency and all dependencies listed in [The Codegen Project](https://github.com/the-codegen-project/cli/blob/8b8fa6f0c5b0c0c63515a8ca439f72872815f491/package.json#L9). Here is an example:\n\n```ts\nimport { JavaFileGenerator } from \"@asyncapi/modelina\";\nexport default {\n ...\n generators: [\n {\n preset: 'custom',\n ...\n renderFunction: ({generator, inputType, asyncapiDocument, openapiDocument, jsonSchemaDocument, dependencyOutputs}) => {\n const modelinaGenerator = new JavaFileGenerator({});\n modelinaGenerator.generateCompleteModels(...)\n }\n }\n ]\n};\n```\n\n# Dependencies\n\nIn each generator (don't manually use it unless you use `preset: custom`), you can add `dependencies` property, which takes an array of `id`'s that the rendering engine ensures are rendered before the dependant one. \n\nEach generator has a specific output (except `custom` which is dynamic and under your control), they are documented under each [./generators](./README.md). These outputs can be accessed under `dependencyOutputs`.\n\nThere are two rules though;\n\n1. You are not allowed to have circular dependencies, i.e. two generators both depending on each other.\n2. You are not allowed to have self-dependant generators\n\n## How does it work?\n\nFor example, take two generators, you can chain them together and use one's output in the other, as for example below, to have the console print out `Hello World!`.\n```js\nexport default {\n ...\n generators: [\n {\n preset: 'custom',\n renderFunction: ({dependencyOutputs}) => {\n console.log(dependencyOutputs['bar'])\n },\n dependencies: ['bar']\n },\n {\n preset: 'custom',\n id: 'bar',\n renderFunction: () => {\n return 'Hello World!'\n }\n }\n ]\n};\n```\n\n## Arguments\nIn the `renderFunction` you have access to a bunch of arguments to help you create the callback;\n\n- `generator` - is the generator configuration, where you have access to the `options` and all other information.\n- `inputType` - is the root `inputType` for the input document\n- `asyncapiDocument` - is the parsed AsyncAPI document input (according to the [AsyncAPI parser](https://github.com/asyncapi/parser-js/)), undefined if the `inputType` is not `asyncapi`\n- `openapiDocument` - is the parsed OpenAPI document input (according to the [readme/openapi-parser](https://github.com/readmeio/oas)), undefined if the `inputType` is not `openapi`\n- `jsonSchemaDocument` - is the parsed JSON Schema document input, undefined if the `inputType` is not `jsonschema`\n- `dependencyOutputs` - if you have defined any `dependencies`, this is where you can access the output. Checkout the [dependency documentation](#dependencies) for more information.", }, "generators/headers": { title: "Headers", - content: "# Headers\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'headers',\n outputPath: './src/headers',\n serializationType: 'json',\n includeValidation: true,\n language: 'typescript',\n }\n ]\n};\n```\n\n`headers` preset is for generating models that represent typed models representing headers.\n\nThis is supported through the following inputs: [`asyncapi`](#inputs), [`openapi`](#inputs)\n\nIt supports the following languages; `typescript`\n\n## Inputs\n\n### `asyncapi`\nThe `headers` preset with `asyncapi` input generates all the message headers for each channel in the AsyncAPI document.\n\nThe return type is a map of channels and the model that represent the headers. \n\n### `openapi`\nThe `headers` preset with `openapi` input generates all the headers for each path in the OpenAPI document.\n\nThe return type is a map of paths and the model that represent the headers. \n\n## Typescript\nDependencies: \n- If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1\n\n### Validation\nEach generated class includes built-in JSON Schema validation capabilities through two static methods:\n\n- `validate`: Validates headers against the schema. Use this method when you want to validate data.\n\n```typescript\n// Example\nconst result = UserSignedUpHeaders.validate({ data: headers });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\n- `createValidator`: Creates a reusable validator function. Use this when you need to validate multiple instances of the same type and want to avoid recreating the validator each time.\n\n```typescript\n// Example\nconst validator = UserSignedUpHeaders.createValidator();\nconst result = UserSignedUpHeaders.validate({ data: headers, ajvValidatorFunction: validator });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\nBoth methods support custom Ajv instances and options for advanced validation scenarios.", + content: "# Headers\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'headers',\n outputPath: './src/headers',\n serializationType: 'json',\n includeValidation: true,\n language: 'typescript',\n }\n ]\n};\n```\n\n`headers` preset is for generating models that represent typed models representing headers.\n\nThis is supported through the following inputs: [`asyncapi`](#inputs), [`openapi`](#inputs)\n\nIt supports the following languages; `typescript`\n\n## Inputs\n\n### `asyncapi`\nThe `headers` preset with `asyncapi` input generates all the message headers for each channel in the AsyncAPI document.\n\nThe return type is a map of channels and the model that represent the headers. \n\n### `openapi`\nThe `headers` preset with `openapi` input generates all the headers for each path in the OpenAPI document.\n\nThe return type is a map of paths and the model that represent the headers. \n\n## Options\nThese are the available options for the `headers` generator;\n\n| **Option** | Default | Type | Description |\n|---|---|---|---|\n| id | `'headers-typescript'` | String | Unique identifier for this generator instance. The `channels`/`client` generators reference it as their `headerGeneratorId`. |\n| dependencies | `[]` | String[] | IDs of other generators that must run before this one. |\n| outputPath | `'src/__gen__/headers'` | String | Directory the generated header models are written to. |\n| serializationType | `'json'` | `'json'` | Serialization format used by the generated models. Only `json` is supported. |\n| includeValidation | `true` | Boolean | Include the built-in JSON Schema `validate`/`createValidator` methods. Requires `ajv` and `ajv-formats` (see [Dependencies](#typescript)). |\n\n## Typescript\nDependencies: \n- If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1\n- If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1\n\n### Validation\nEach generated class includes built-in JSON Schema validation capabilities through two static methods:\n\n- `validate`: Validates headers against the schema. Use this method when you want to validate data.\n\n```typescript\n// Example\nconst result = UserSignedUpHeaders.validate({ data: headers });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\n- `createValidator`: Creates a reusable validator function. Use this when you need to validate multiple instances of the same type and want to avoid recreating the validator each time.\n\n```typescript\n// Example\nconst validator = UserSignedUpHeaders.createValidator();\nconst result = UserSignedUpHeaders.validate({ data: headers, ajvValidatorFunction: validator });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\nBoth methods support custom Ajv instances and options for advanced validation scenarios.", }, "generators/models": { title: "🏗️ Models", - content: "# 🏗️ Models\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'models',\n outputPath: './src/models',\n language: 'typescript',\n renderers: [...],\n options: {...}\n }\n ]\n};\n```\n\nThe `models` preset provides native integration with [AsyncAPI Modelina](https://modelina.org) for generating TypeScript models directly from AsyncAPI, OpenAPI, and JSON Schema documents. This generator exposes Modelina's full capabilities, giving you complete control over model generation.\n\nThis is supported through the following inputs: `asyncapi`, `openapi`, `jsonschema`\n\nIt supports the following languages; [`typescript`](#typescript)\n\n## Core Features\n\n- **Native Modelina Integration**: Direct access to Modelina's TypeScript generator\n- **Custom Presets**: Full control over generated code through Modelina's preset system\n- **Flexible Options**: Configure all TypeScript generation options\n- **Production Ready**: Generate models that are immediately usable in your applications\n\n## Configuration\n\n### `renderers`\n\nThe `renderers` property exposes Modelina's [preset system](https://raw.githubusercontent.com/asyncapi/modelina/refs/heads/master/docs/presets.md), allowing you to customize every aspect of the generated models.\n\nPresets can:\n- Add custom content to classes, interfaces, enums, and types\n- Override default rendering behavior\n- Inject validation logic, serialization methods, or custom properties\n- Apply consistent formatting and documentation\n\n### `options`\n\nThe `options` property provides access to all [Modelina TypeScript options](https://github.com/asyncapi/modelina/blob/master/docs/languages/TypeScript.md), including:\n\n- Model types (class, interface, type alias)\n- Enum generation styles\n- Property naming conventions\n- Module system preferences\n- Type mappings and constraints\n\n## Examples\n\n### Basic Usage\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### Using Built-in Presets\n\n```js\nimport { modelina } from '@the-codegen-project/cli';\nconst { TS_COMMON_PRESET } = modelina;\n\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n preset: TS_COMMON_PRESET,\n options: {\n marshalling: true\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### Custom Presets\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n class: {\n self: ({model}) => `class ${model.name} {}`\n },\n interface: {\n self: ({model}) => `interface ${model.name} {}`\n },\n type: {\n self: ({model}) => `type ${model.name} = string;`\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### Advanced Configuration with Options\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n options: {\n modelType: 'interface',\n enumType: 'union',\n mapType: 'indexedObject',\n moduleSystem: 'ESM',\n rawPropertyNames: false,\n useJavascriptReservedKeywords: false\n },\n renderers: [\n {\n interface: {\n property: ({ content, property }) => {\n return `/** ${property.property.description || 'Auto-generated property'} */\\n${content}`;\n }\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### JSON Schema Input\n\n```js\nexport default {\n inputType: 'jsonschema',\n inputPath: 'user-schema.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n options: {\n modelType: 'class',\n enumType: 'enum'\n },\n renderers: [\n {\n class: {\n additionalContent: ({ content, model }) => {\n return `${content}\\n\\n // Custom validation method\\n public validate(): boolean {\\n return true;\\n }`;\n }\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n## Languages\n\n### TypeScript\n\nThe TypeScript implementation provides full access to Modelina's TypeScript generator capabilities.\n\n**Dependencies**: None (generates plain TypeScript)\n\n**Supported Features**:\n- Classes, interfaces, type aliases, and enums\n- Complex nested types and circular references\n- Union types and discriminated unions\n- Optional and required properties\n- Custom property naming and constraints\n- Marshalling and unmarshalling methods (with TS_COMMON_PRESET)\n- JSON Schema validation (with custom presets)\n\n**Common Options**:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `modelType` | `'class' \\| 'interface'` | `'class'` | Type of models to generate |\n| `enumType` | `'enum' \\| 'union'` | `'enum'` | How to render enum types |\n| `mapType` | `'indexedObject' \\| 'record'` | `'record'` | How to render map/dictionary types |\n| `moduleSystem` | `'CJS' \\| 'ESM'` | `'ESM'` | Module system to use |\n| `rawPropertyNames` | `boolean` | `false` | Use raw property names without transformation |\n| `useJavascriptReservedKeywords` | `boolean` | `true` | Allow JavaScript reserved keywords |\n\n**Common Presets**:\n\n| Preset | Description |\n|--------|-------------|\n| `TS_COMMON_PRESET` | Adds marshalling/unmarshalling methods |\n| `TS_DESCRIPTION_PRESET` | Adds JSDoc descriptions from schemas |\n| Custom presets | Define your own rendering behavior |\n\n**Generated Code Structure**:\n\n```typescript\n// Example generated class with TS_COMMON_PRESET\nexport class UserProfile {\n private _id?: string;\n private _email?: string;\n private _name?: string;\n\n constructor(input: {\n id?: string;\n email?: string;\n name?: string;\n }) {\n this._id = input.id;\n this._email = input.email;\n this._name = input.name;\n }\n\n get id(): string | undefined { return this._id; }\n set id(id: string | undefined) { this._id = id; }\n\n get email(): string | undefined { return this._email; }\n set email(email: string | undefined) { this._email = email; }\n\n get name(): string | undefined { return this._name; }\n set name(name: string | undefined) { this._name = name; }\n\n public marshal(): string {\n return JSON.stringify({\n id: this.id,\n email: this.email,\n name: this.name\n });\n }\n\n public static unmarshal(data: string): UserProfile {\n const obj = JSON.parse(data);\n return new UserProfile(obj);\n }\n}\n```\n\n## Integration Examples\n\n### With Channels Generator\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n preset: TS_COMMON_PRESET,\n options: { marshalling: true }\n }\n ],\n outputPath: './src/models'\n },\n {\n preset: 'channels',\n outputPath: './src/channels',\n protocols: ['nats', 'kafka']\n }\n ]\n};\n```\n\n### With Custom Validation\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n class: {\n additionalContent: ({ content, model }) => {\n return `${content}\n \n public validate(): boolean {\n // Custom validation logic\n return true;\n }`;\n }\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n## Resources\n\n- [Modelina Presets Documentation](https://github.com/asyncapi/modelina/blob/master/refs/heads/master/docs/presets.md)\n- [Modelina TypeScript Options](https://github.com/asyncapi/modelina/blob/master/docs/languages/TypeScript.md)\n- [Modelina Examples](https://github.com/asyncapi/modelina/tree/master/examples)", + content: "# 🏗️ Models\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'models',\n outputPath: './src/models',\n language: 'typescript',\n renderers: [...],\n options: {...}\n }\n ]\n};\n```\n\nThe `models` preset provides native integration with [AsyncAPI Modelina](https://modelina.org) for generating TypeScript models directly from AsyncAPI, OpenAPI, and JSON Schema documents. This generator exposes Modelina's full capabilities, giving you complete control over model generation.\n\nThis is supported through the following inputs: `asyncapi`, `openapi`, `jsonschema`\n\nIt supports the following languages; [`typescript`](#typescript)\n\n## Core Features\n\n- **Native Modelina Integration**: Direct access to Modelina's TypeScript generator\n- **Custom Presets**: Full control over generated code through Modelina's preset system\n- **Flexible Options**: Configure all TypeScript generation options\n- **Production Ready**: Generate models that are immediately usable in your applications\n\n## Configuration\n\n### `renderers`\n\nThe `renderers` property exposes Modelina's [preset system](https://raw.githubusercontent.com/asyncapi/modelina/refs/heads/master/docs/presets.md), allowing you to customize every aspect of the generated models.\n\nPresets can:\n- Add custom content to classes, interfaces, enums, and types\n- Override default rendering behavior\n- Inject validation logic, serialization methods, or custom properties\n- Apply consistent formatting and documentation\n\n### `options`\n\nThe `options` property provides access to all [Modelina TypeScript options](https://github.com/asyncapi/modelina/blob/master/docs/languages/TypeScript.md), including:\n\n- Model types (class, interface, type alias)\n- Enum generation styles\n- Property naming conventions\n- Module system preferences\n- Type mappings and constraints\n\n## Examples\n\n### Basic Usage\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### Using Built-in Presets\n\n```js\nimport { modelina } from '@the-codegen-project/cli';\nconst { TS_COMMON_PRESET } = modelina;\n\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n preset: TS_COMMON_PRESET,\n options: {\n marshalling: true\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### Custom Presets\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n class: {\n self: ({model}) => `class ${model.name} {}`\n },\n interface: {\n self: ({model}) => `interface ${model.name} {}`\n },\n type: {\n self: ({model}) => `type ${model.name} = string;`\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### Advanced Configuration with Options\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n options: {\n modelType: 'interface',\n enumType: 'union',\n mapType: 'indexedObject',\n moduleSystem: 'ESM',\n rawPropertyNames: false,\n useJavascriptReservedKeywords: false\n },\n renderers: [\n {\n interface: {\n property: ({ content, property }) => {\n return `/** ${property.property.description || 'Auto-generated property'} */\\n${content}`;\n }\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n### JSON Schema Input\n\n```js\nexport default {\n inputType: 'jsonschema',\n inputPath: 'user-schema.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n options: {\n modelType: 'class',\n enumType: 'enum'\n },\n renderers: [\n {\n class: {\n additionalContent: ({ content, model }) => {\n return `${content}\\n\\n // Custom validation method\\n public validate(): boolean {\\n return true;\\n }`;\n }\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n## Languages\n\n### TypeScript\n\nThe TypeScript implementation provides full access to Modelina's TypeScript generator capabilities.\n\n**Dependencies**: None (generates plain TypeScript)\n\n**Supported Features**:\n- Classes, interfaces, type aliases, and enums\n- Complex nested types and circular references\n- Union types and discriminated unions\n- Optional and required properties\n- Custom property naming and constraints\n- Marshalling and unmarshalling methods (with TS_COMMON_PRESET)\n- JSON Schema validation (with custom presets)\n\n**Common Options**:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `modelType` | `'class' \\| 'interface'` | `'class'` | Type of models to generate |\n| `enumType` | `'enum' \\| 'union'` | `'enum'` | How to render enum types |\n| `mapType` | `'indexedObject' \\| 'map' \\| 'record'` | `'map'` | How to render map/dictionary types |\n| `moduleSystem` | `'CJS' \\| 'ESM'` | `'ESM'` | Module system to use |\n| `rawPropertyNames` | `boolean` | `false` | Use raw property names without transformation |\n| `useJavascriptReservedKeywords` | `boolean` | `true` | Allow JavaScript reserved keywords |\n| `isolatedModules` | `boolean` | `false` | Emit `export type` / `import type` for type-only models. Required for projects using TypeScript's `isolatedModules` (Next.js, SWC, esbuild) |\n\n**Common Presets**:\n\n| Preset | Description |\n|--------|-------------|\n| `TS_COMMON_PRESET` | Adds marshalling/unmarshalling methods |\n| `TS_DESCRIPTION_PRESET` | Adds JSDoc descriptions from schemas |\n| Custom presets | Define your own rendering behavior |\n\n**Generated Code Structure**:\n\n```typescript\n// Example generated class with TS_COMMON_PRESET\nexport class UserProfile {\n private _id?: string;\n private _email?: string;\n private _name?: string;\n\n constructor(input: {\n id?: string;\n email?: string;\n name?: string;\n }) {\n this._id = input.id;\n this._email = input.email;\n this._name = input.name;\n }\n\n get id(): string | undefined { return this._id; }\n set id(id: string | undefined) { this._id = id; }\n\n get email(): string | undefined { return this._email; }\n set email(email: string | undefined) { this._email = email; }\n\n get name(): string | undefined { return this._name; }\n set name(name: string | undefined) { this._name = name; }\n\n public marshal(): string {\n return JSON.stringify({\n id: this.id,\n email: this.email,\n name: this.name\n });\n }\n\n public static unmarshal(data: string): UserProfile {\n const obj = JSON.parse(data);\n return new UserProfile(obj);\n }\n}\n```\n\n## Integration Examples\n\n### With Channels Generator\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n preset: TS_COMMON_PRESET,\n options: { marshalling: true }\n }\n ],\n outputPath: './src/models'\n },\n {\n preset: 'channels',\n outputPath: './src/channels',\n protocols: ['nats', 'kafka']\n }\n ]\n};\n```\n\n### With Custom Validation\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: 'asyncapi.json',\n language: 'typescript',\n generators: [\n {\n preset: 'models',\n renderers: [\n {\n class: {\n additionalContent: ({ content, model }) => {\n return `${content}\n \n public validate(): boolean {\n // Custom validation logic\n return true;\n }`;\n }\n }\n }\n ],\n outputPath: './src/models'\n }\n ]\n};\n```\n\n## Resources\n\n- [Modelina Presets Documentation](https://github.com/asyncapi/modelina/blob/master/refs/heads/master/docs/presets.md)\n- [Modelina TypeScript Options](https://github.com/asyncapi/modelina/blob/master/docs/languages/TypeScript.md)\n- [Modelina Examples](https://github.com/asyncapi/modelina/tree/master/examples)", }, "generators/parameters": { title: "Parameters", @@ -64,7 +64,7 @@ export const docs: Record = { }, "generators/payloads": { title: "🐔 Payloads", - content: "# 🐔 Payloads\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'payloads',\n outputPath: './src/payloads',\n serializationType: 'json', \n language: 'typescript'\n }\n ]\n};\n```\n\n`payloads` preset is for generating models that represent typed models that can be serialized into message payloads for communication use-cases.\n\nThis is supported through the following inputs: `asyncapi`, `openapi`\n\nIt supports the following languages; [`typescript`](#typescript)\n\n## Companion Interface\n\nEvery generated **object** payload file exports **two** symbols: the payload\nclass (``) and a plain-data companion interface (`Interface`)\ndeclared above it. The class constructor takes the interface\n(`constructor(input: Interface)`), so the two always stay in sync.\n\n```typescript\nexport { UserSignedUp, UserSignedUpInterface };\n```\n\nThis lets you pass a **plain object** wherever a channel expects a payload —\nyou do not have to construct the class yourself:\n\n```typescript\n// Both of these are accepted by every generated publish/request helper:\nawait publishToUserSignedup({ message: { displayName: 'Jane', email: 'jane@example.com' }, nc });\nawait publishToUserSignedup({ message: new UserSignedUp({ displayName: 'Jane', email: 'jane@example.com' }), nc });\n```\n\nChannel consumers type their message argument as the union\n`Interface | ` and normalize it to a class instance internally (via\nan `instanceof` guard) before calling `.marshal()`. The plain-object form is\npurely an ergonomic convenience; the generated code always marshals a class\ninstance.\n\nThis applies to **object** payloads only. Non-object payloads\n(unions, primitives, arrays, and enums) keep their `type`/`enum` shape and\nfree-function marshalling — they have no companion interface and are exported as\na single symbol. See the [protocols documentation](../protocols) for how each\nchannel accepts payloads.\n\n## Languages\nEach language has a set of constraints which means that some typed model types are either supported or not, or it might just be the code generation library that does not yet support it.\n\n| | Circular models | Enums | Tuples | Arrays | Nested Arrays | Dictionaries | Json Serialization | Validation |\n|---|---|---|---|---|---|---|---|---|\n| **TypeScript** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |\n\n### TypeScript\n\nDependencies: \n- If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1\n\n#### Validation\nEach generated class includes built-in JSON Schema validation capabilities through two static methods:\n\n- `validate`: Validates data against the schema. Use this method when you want to validate data.\n\n```typescript\n// Example\nconst result = UserSignedUp.validate({ data: userData });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\n- `createValidator`: Creates a reusable validator function. Use this when you need to validate multiple instances of the same type and want to avoid recreating the validator each time.\n\n```typescript\n// Example\nconst validator = UserSignedUp.createValidator();\nconst result = UserSignedUp.validate({ data: userData, ajvValidatorFunction: validator });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\nBoth methods support custom Ajv instances and options for advanced validation scenarios.", + content: "# 🐔 Payloads\n\n```js\nexport default {\n ...,\n generators: [\n {\n preset: 'payloads',\n outputPath: './src/payloads',\n serializationType: 'json', \n language: 'typescript'\n }\n ]\n};\n```\n\n`payloads` preset is for generating models that represent typed models that can be serialized into message payloads for communication use-cases.\n\nThis is supported through the following inputs: `asyncapi`, `openapi`\n\nIt supports the following languages; [`typescript`](#typescript)\n\n## Companion Interface\n\nEvery generated **object** payload file exports **two** symbols: the payload\nclass (``) and a plain-data companion interface (`Interface`)\ndeclared above it. The class constructor takes the interface\n(`constructor(input: Interface)`), so the two always stay in sync.\n\n```typescript\nexport { UserSignedUp, UserSignedUpInterface };\n```\n\nThis lets you pass a **plain object** wherever a channel expects a payload —\nyou do not have to construct the class yourself:\n\n```typescript\n// Both of these are accepted by every generated publish/request helper:\nawait publishToUserSignedup({ message: { displayName: 'Jane', email: 'jane@example.com' }, nc });\nawait publishToUserSignedup({ message: new UserSignedUp({ displayName: 'Jane', email: 'jane@example.com' }), nc });\n```\n\nChannel consumers type their message argument as the union\n`Interface | ` and normalize it to a class instance internally (via\nan `instanceof` guard) before calling `.marshal()`. The plain-object form is\npurely an ergonomic convenience; the generated code always marshals a class\ninstance.\n\nThis applies to **object** payloads only. Non-object payloads\n(unions, primitives, arrays, and enums) keep their `type`/`enum` shape and\nfree-function marshalling — they have no companion interface and are exported as\na single symbol. See the [protocols documentation](../protocols) for how each\nchannel accepts payloads.\n\n## Options\nThese are the available options for the `payloads` generator;\n\n| **Option** | Default | Type | Description |\n|---|---|---|---|\n| id | `'payloads-typescript'` | String | Unique identifier for this generator instance. Other generators reference it as a dependency, and the `channels`/`client` generators use it as their `payloadGeneratorId`. |\n| dependencies | `[]` | String[] | IDs of other generators that must run before this one. |\n| outputPath | `'src/__gen__/payloads'` | String | Directory the generated payload models are written to. |\n| serializationType | `'json'` | `'json'` | Serialization format used by the generated models. Only `json` is supported. |\n| enum | `'enum'` | `'enum' \\| 'union'` | Render enums as TypeScript `enum`s, or as string/number union types. |\n| map | `'record'` | `'indexedObject' \\| 'map' \\| 'record'` | Render dictionary/map types as `Record`, the `Map` class, or an index signature. |\n| useForJavaScript | `true` | Boolean | Apply JavaScript restrictions so the models stay valid when transpiled to JavaScript (for example avoiding reserved keywords as identifiers). |\n| includeValidation | `true` | Boolean | Include the built-in JSON Schema `validate`/`createValidator` methods. Requires `ajv` and `ajv-formats` (see [Dependencies](#typescript)). |\n| rawPropertyNames | `false` | Boolean | Keep the raw property names from the input schema. Consumers then access them with `obj[\"propertyName\"]` instead of `obj.propertyName`. |\n\nThe global [`importExtension`](../configurations.md#import-extensions-node16nodenextverbatimmodulesyntax) option also applies to the imports between generated payload models.\n\n## Languages\nEach language has a set of constraints which means that some typed model types are either supported or not, or it might just be the code generation library that does not yet support it.\n\n| | Circular models | Enums | Tuples | Arrays | Nested Arrays | Dictionaries | Json Serialization | Validation |\n|---|---|---|---|---|---|---|---|---|\n| **TypeScript** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |\n\n### TypeScript\n\nDependencies: \n- If validation enabled, [ajv](https://ajv.js.org/guide/getting-started.html): ^8.17.1\n- If validation enabled, [ajv-formats](https://github.com/ajv-validator/ajv-formats): ^3.0.1\n\n> `ajv-formats` v3 follows RFC 3339 more strictly than v2 did. Most notably,\n> `format: time` now requires a time offset, so `\"10:30:00\"` is rejected while\n> `\"10:30:00Z\"` and `\"10:30:00+02:00\"` are accepted. Pin `ajv-formats@^2` if you\n> need the previous, more lenient behaviour.\n\n#### Validation\nEach generated class includes built-in JSON Schema validation capabilities through two static methods:\n\n- `validate`: Validates data against the schema. Use this method when you want to validate data.\n\n```typescript\n// Example\nconst result = UserSignedUp.validate({ data: userData });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\n- `createValidator`: Creates a reusable validator function. Use this when you need to validate multiple instances of the same type and want to avoid recreating the validator each time.\n\n```typescript\n// Example\nconst validator = UserSignedUp.createValidator();\nconst result = UserSignedUp.validate({ data: userData, ajvValidatorFunction: validator });\nif (!result.valid) {\n console.error('Validation errors:', result.errors);\n}\n```\n\nBoth methods support custom Ajv instances and options for advanced validation scenarios.", }, "generators/types": { title: "Types", @@ -76,15 +76,15 @@ export const docs: Record = { }, "getting-started/generators": { title: "Understanding Generators", - content: "# Understanding Generators\n\nGenerators (also called \"presets\") are the core of **The Codegen Project**. They determine what code gets generated from your inputs. Think of generators as specialized code factories - each one produces a specific type of code that helps you build your application faster.\n\n## What Generators do you have?\n\nEach generator focuses on a specific aspect of your application:\n\n### Model Generators\nThese generators create data models and type definitions:\n\n- [`payloads` preset](../generators/payloads.md) - Type-safe message/payload classes with serialization and validation support\n- [`parameters` preset](../generators/parameters.md) - Type-safe parameter classes for API endpoints that make it easier to work with topics/paths/channels\n- [`headers` preset](../generators/headers.md) - Type-safe header classes for message protocols, with serialization and validation support\n- [`types` preset](../generators/types.md) - Shared type definitions and interfaces, which simplify your code in various ways\n- [`models` preset](../generators/models.md) - General-purpose models from JSON Schema\n\n### Communication Generators\nThese generators create code for interacting with APIs and message brokers:\n\n- [`channels` preset](../generators/channels.md) - Communication functions for message brokers, ensure the right message, headers, and topics/paths/channels are used\n- [`client` preset](../generators/client.md) - Wraps channels into a reusable wrappers, cant get more code then this.\n\n### Custom Generators\n- [`custom` preset](../generators/custom.md) - Your own custom code generation logic\n\n## How Generators Work\n\n### 1. Input Processing\nGenerators take your specifications (AsyncAPI, OpenAPI, or JSON Schema) and extract the relevant information:\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml'\n};\n```\n\n### 2. Code Generation\nBased on the generator configuration, The Codegen Project:\n- Parses your API specification\n- Extracts schemas, operations, channels, and other relevant data\n- Use whatever generators you added and outputs files to your specified directory\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n {\n preset: 'payloads',\n outputPath: './src/payloads',\n language: 'typescript'\n }\n ]\n};\n```\n\n### 3. Generated Output\nEach generator produces different code, so have a look at each generator to get a full picture, but here is a few examples:\n\n**Payload Generator** produces:\n```typescript\nexport class UserSignup {\n constructor(data: UserSignupData) { /* ... */ }\n marshal(): string { /* ... */ }\n static unmarshal(json: string): UserSignup { /* ... */ }\n}\n```\n\n**Channels Generator** produces:\n```typescript\nexport const Protocols = {\n nats: {\n publishToUserSignup: ...,\n subscribeToUserSignup: ...,\n jetStreamPublishToUserSignup: ...\n },\n kafka: {\n publishToUserSignup: ...,\n subscribeToUserSignup: ...\n },\n // ... other protocols\n};\n```\n\n## Input Type Support\n\nDifferent generators work with different input types:\n\n| Generator | AsyncAPI | OpenAPI | JSON Schema |\n|-----------|----------|---------|-------------|\n| `payloads` | ✅ | ✅ | ❌ |\n| `parameters` | ✅ | ✅ | ❌ |\n| `headers` | ✅ | ✅ | ❌ |\n| `types` | ✅ | ✅ | ❌ |\n| `channels` | ✅ | ✅ | ❌ |\n| `client` | ✅ | ✅ | ❌ |\n| `models` | ✅ | ✅ | ✅ |\n| `custom` | ✅ | ✅ | ✅ |\n\n## Language Support\n\nCurrently, The Codegen Project supports:\n\n- **TypeScript** - Full support for all generators\n\nEach language has specific capabilities and constraints. Check the [generator documentation](../generators/README.md) for details.\n\n## Generator Dependencies\n\nSome generators automatically include dependencies on others:\n\n- **`channels`** generator automatically uses `payloads`, `headers`, and `parameters` generators if they're not already configured\n- This ensures you have all the necessary models and types for your channel functions\n\n## Configuration Options\n\nEach generator has its own set of configuration options, for example here is payloads:\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n {\n preset: 'payloads',\n outputPath: './src/payloads',\n language: 'typescript',\n includeValidation: true,\n serializationType: 'json'\n }\n ]\n};\n```\n\n## Next Steps\n\n- **[Explore Generator Documentation](../generators/README.md)** - Detailed docs for each generator\n- **[Learn about Protocol Support](./protocols.md)** - How generators work with messaging protocols\n- **[Check Out Examples](../../examples/)** - See generators in action", + content: "# Understanding Generators\n\nGenerators (also called \"presets\") are the core of **The Codegen Project**. They determine what code gets generated from your inputs. Think of generators as specialized code factories - each one produces a specific type of code that helps you build your application faster.\n\n## What Generators do you have?\n\nEach generator focuses on a specific aspect of your application:\n\n### Model Generators\nThese generators create data models and type definitions:\n\n- [`payloads` preset](../generators/payloads.md) - Type-safe message/payload classes with serialization and validation support\n- [`parameters` preset](../generators/parameters.md) - Type-safe parameter classes for API endpoints that make it easier to work with topics/paths/channels\n- [`headers` preset](../generators/headers.md) - Type-safe header classes for message protocols, with serialization and validation support\n- [`types` preset](../generators/types.md) - Shared type definitions and interfaces, which simplify your code in various ways\n- [`models` preset](../generators/models.md) - General-purpose models from JSON Schema\n\n### Communication Generators\nThese generators create code for interacting with APIs and message brokers:\n\n- [`channels` preset](../generators/channels.md) - Communication functions for message brokers, ensure the right message, headers, and topics/paths/channels are used\n- [`client` preset](../generators/client.md) - Wraps channels into a reusable wrappers, cant get more code then this.\n\n### Custom Generators\n- [`custom` preset](../generators/custom.md) - Your own custom code generation logic\n\n## How Generators Work\n\n### 1. Input Processing\nGenerators take your specifications (AsyncAPI, OpenAPI, or JSON Schema) and extract the relevant information:\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n { preset: 'payloads', outputPath: './src/__gen__/payloads' }\n ]\n};\n```\n\n### 2. Code Generation\nBased on the generator configuration, The Codegen Project:\n- Parses your API specification\n- Extracts schemas, operations, channels, and other relevant data\n- Use whatever generators you added and outputs files to your specified directory\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n {\n preset: 'payloads',\n outputPath: './src/payloads',\n language: 'typescript'\n }\n ]\n};\n```\n\n### 3. Generated Output\nEach generator produces different code, so have a look at each generator to get a full picture, but here is a few examples:\n\n**Payload Generator** produces:\n```typescript\n// A companion interface is exported alongside the class, so you can construct\n// a payload from a plain object.\nexport interface UserSignupInterface { /* ... */ }\nexport class UserSignup {\n constructor(input: UserSignupInterface) { /* ... */ }\n marshal(): string { /* ... */ }\n static unmarshal(json: string | object): UserSignup { /* ... */ }\n}\n```\n\n**Channels Generator** produces:\n```typescript\n// One module per protocol, re-exported from the generated barrel file\nimport * as nats from './nats';\nimport * as kafka from './kafka';\n\nexport { nats, kafka };\n\n// nats.publishToUserSignup({ message, nc })\n// nats.subscribeToUserSignup({ onDataCallback, nc })\n// nats.jetStreamPublishToUserSignup({ message, js })\n// kafka.produceToUserSignup({ message, kafka })\n// kafka.consumeFromUserSignup({ onDataCallback, kafka, options })\n```\n\n## Input Type Support\n\nDifferent generators work with different input types:\n\n| Generator | AsyncAPI | OpenAPI | JSON Schema |\n|-----------|----------|---------|-------------|\n| `payloads` | ✅ | ✅ | ❌ |\n| `parameters` | ✅ | ✅ | ❌ |\n| `headers` | ✅ | ✅ | ❌ |\n| `types` | ✅ | ✅ | ❌ |\n| `channels` | ✅ | ✅ | ❌ |\n| `client` | ✅ | ✅ | ❌ |\n| `models` | ✅ | ✅ | ✅ |\n| `custom` | ✅ | ✅ | ✅ |\n\n## Language Support\n\nCurrently, The Codegen Project supports:\n\n- **TypeScript** - Full support for all generators\n\nEach language has specific capabilities and constraints. Check the [generator documentation](../generators/README.md) for details.\n\n## Generator Dependencies\n\nSome generators automatically include dependencies on others:\n\n- **`channels`** generator automatically uses `payloads`, `headers`, and `parameters` generators if they're not already configured\n- This ensures you have all the necessary models and types for your channel functions\n\n## Configuration Options\n\nEach generator has its own set of configuration options, for example here is payloads:\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n {\n preset: 'payloads',\n outputPath: './src/payloads',\n language: 'typescript',\n includeValidation: true,\n serializationType: 'json'\n }\n ]\n};\n```\n\n## Next Steps\n\n- **[Explore Generator Documentation](../generators/README.md)** - Detailed docs for each generator\n- **[Learn about Protocol Support](./protocols.md)** - How generators work with messaging protocols\n- **[Check Out Examples](../../examples/)** - See generators in action", }, "getting-started/protocols": { title: "Understanding Protocols", - content: "# Understanding Protocols\n\nThe Codegen Project supports multiple messaging protocols, allowing you to generate protocol-specific code for your message-driven applications. This enables type-safe, production-ready communication code for various messaging systems.\n\n## What Are Protocols?\n\nProtocols define how messages are sent and received in distributed systems. The Codegen Project generates protocol-specific functions that handle the low-level details of message communication, so you can focus on your business logic.\n\n## Supported Protocols\n\nThe Codegen Project currently supports these messaging protocols:\n\n| Protocol | Description | Use Cases |\n|----------|-------------|-----------|\n| **[NATS](../protocols/nats.md)** | High-performance, cloud-native messaging system | Microservices, real-time systems, IoT |\n| **[Kafka](../protocols/kafka.md)** | Distributed event streaming platform | Event streaming, log aggregation, real-time analytics |\n| **[MQTT](../protocols/mqtt.md)** | Lightweight messaging protocol for IoT | IoT devices, mobile apps, low-bandwidth scenarios |\n| **[AMQP](../protocols/amqp.md)** | Advanced Message Queuing Protocol | Enterprise messaging, reliable message delivery |\n| **[EventSource](../protocols/eventsource.md)** | Server-Sent Events (SSE) protocol | Real-time web updates, streaming data to browsers |\n| **[HTTP Client](../protocols/http_client.md)** | RESTful API communication | HTTP APIs, REST services |\n| **[WebSocket](../protocols/websocket.md)** | Full-duplex communication protocol | Real-time web applications, bidirectional communication |\n\n## How Protocol Support Works\nEach protocol usually requires specific dependencies and should be installed in your project (if its noy already are). Make sure to check the documentation for each protocol to figure out which one you need!\n\n### 1. Protocol Configuration\n\nProtocols are configured through the [`channels`](../generators/channels.md) generator:\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n {\n preset: 'channels',\n outputPath: './src/__gen__/',\n language: 'typescript',\n protocols: ['nats', 'kafka'] // Specify which protocols to generate\n }\n ]\n};\n```\n\n### 2. Generated Protocol Functions\n\nThe `channels` generator creates protocol-specific functions for each channel in your AsyncAPI specification:\n\n```typescript\nimport { Protocols } from './src/__gen__/index';\n\nconst { nats, kafka } = Protocols;\n\n// NATS functions\nawait nats.publishToUserSignup(connection, message);\nawait nats.subscribeToUserSignup(connection, callback);\n\n// Kafka functions\nawait kafka.publishToUserSignup(producer, message);\nawait kafka.subscribeToUserSignup(consumer, callback);\n```\n\nEach protocol has unique features that are reflected in the generated code:\n\n**NATS** supports:\n- Core publish/subscribe\n- JetStream (persistent messaging)\n- Request/reply patterns\n\n**Kafka** supports:\n- Producer/consumer patterns\n- Consumer groups\n- Topic partitioning\n\n**MQTT** supports:\n- QoS levels (0, 1, 2)\n- Retained messages\n- User properties (headers)\n\n**AMQP** supports:\n- Exchanges and queues\n- Routing patterns\n- Message acknowledgments\n\n## Protocol Selection\n\n### Single Protocol\nGenerate code for one protocol:\n\n```js\n{\n preset: 'channels',\n protocols: ['nats']\n}\n```\nor generate for multiple protocols at once:\n\n```js\n{\n preset: 'channels',\n protocols: ['nats', 'kafka', 'mqtt']\n}\n```\n\n\n## Protocol-Specific Options\n\nSome generators support protocol-specific configuration options:\n\n```js\n{\n preset: 'channels',\n protocols: ['kafka'],\n kafkaTopicSeparator: '.', // Customize topic separator\n eventSourceDependency: '@microsoft/fetch-event-source' // Custom EventSource dependency\n}\n```\n\n## Generated Code Structure\n\nProtocol functions are organized by protocol:\n\n```typescript\nexport const Protocols = {\n nats: {\n publishToUserSignup: ...,\n subscribeToUserSignup: ...,\n jetStreamPublishToUserSignup: ...\n },\n kafka: {\n publishToUserSignup: ...,\n subscribeToUserSignup: ...\n },\n // ... other protocols\n};\n```\n\n## Next Steps\n\n- **[Explore Protocol Documentation](../protocols/)** - Detailed docs for each protocol\n- **[Learn about Channels Generator](../generators/channels.md)** - How to configure protocol generation\n- **[Check Out Examples](../../examples/)** - See the code generation in action\n- **[Understanding Generators](./generators.md)** - Learn how generators work", + content: "# Understanding Protocols\n\nThe Codegen Project supports multiple messaging protocols, allowing you to generate protocol-specific code for your message-driven applications. This enables type-safe, production-ready communication code for various messaging systems.\n\n## What Are Protocols?\n\nProtocols define how messages are sent and received in distributed systems. The Codegen Project generates protocol-specific functions that handle the low-level details of message communication, so you can focus on your business logic.\n\n## Supported Protocols\n\nThe Codegen Project currently supports these messaging protocols:\n\n| Protocol | Description | Use Cases |\n|----------|-------------|-----------|\n| **[NATS](../protocols/nats.md)** | High-performance, cloud-native messaging system | Microservices, real-time systems, IoT |\n| **[Kafka](../protocols/kafka.md)** | Distributed event streaming platform | Event streaming, log aggregation, real-time analytics |\n| **[MQTT](../protocols/mqtt.md)** | Lightweight messaging protocol for IoT | IoT devices, mobile apps, low-bandwidth scenarios |\n| **[AMQP](../protocols/amqp.md)** | Advanced Message Queuing Protocol | Enterprise messaging, reliable message delivery |\n| **[EventSource](../protocols/eventsource.md)** | Server-Sent Events (SSE) protocol | Real-time web updates, streaming data to browsers |\n| **[HTTP Client](../protocols/http_client.md)** | RESTful API communication | HTTP APIs, REST services |\n| **[WebSocket](../protocols/websocket.md)** | Full-duplex communication protocol | Real-time web applications, bidirectional communication |\n\n## How Protocol Support Works\nEach protocol usually requires specific dependencies and should be installed in your project (if its noy already are). Make sure to check the documentation for each protocol to figure out which one you need!\n\n### 1. Protocol Configuration\n\nProtocols are configured through the [`channels`](../generators/channels.md) generator:\n\n```js\nexport default {\n inputType: 'asyncapi',\n inputPath: './my-api.yaml',\n generators: [\n {\n preset: 'channels',\n outputPath: './src/__gen__/',\n language: 'typescript',\n protocols: ['nats', 'kafka'] // Specify which protocols to generate\n }\n ]\n};\n```\n\n### 2. Generated Protocol Functions\n\nThe `channels` generator creates protocol-specific functions for each channel in your AsyncAPI specification:\n\nEach protocol is exported as its own namespace from the generated barrel file,\nand every generated function takes a single object argument:\n\n```typescript\nimport { nats, kafka } from './src/__gen__/channels';\n\n// NATS functions\nawait nats.publishToUserSignup({ message, nc: connection });\nawait nats.subscribeToUserSignup({ onDataCallback: callback, nc: connection });\n\n// Kafka functions — note Kafka uses produceTo/consumeFrom\nawait kafka.produceToUserSignup({ message, kafka: kafkaClient });\nawait kafka.consumeFromUserSignup({\n onDataCallback: callback,\n kafka: kafkaClient,\n options: { fromBeginning: true, groupId: 'my-group' }\n});\n```\n\nThe exact parameters depend on the channel — channels with parameters also take\n`parameters`, and channels with headers accept `headers`. See each protocol's\npage for the full generated signatures.\n\nEach protocol has unique features that are reflected in the generated code:\n\n**NATS** supports:\n- Core publish/subscribe\n- JetStream (persistent messaging)\n- Request/reply patterns\n\n**Kafka** supports:\n- Producer/consumer patterns\n- Consumer groups\n- Topic partitioning\n\n**MQTT** supports:\n- QoS levels (0, 1, 2)\n- Retained messages\n- User properties (headers)\n\n**AMQP** supports:\n- Exchanges and queues\n- Routing patterns\n- Message acknowledgments\n\n## Protocol Selection\n\n### Single Protocol\nGenerate code for one protocol:\n\n```js\n{\n preset: 'channels',\n protocols: ['nats']\n}\n```\nor generate for multiple protocols at once:\n\n```js\n{\n preset: 'channels',\n protocols: ['nats', 'kafka', 'mqtt']\n}\n```\n\n\n## Protocol-Specific Options\n\nSome generators support protocol-specific configuration options:\n\n```js\n{\n preset: 'channels',\n protocols: ['kafka'],\n kafkaTopicSeparator: '.', // Customize topic separator\n eventSourceDependency: '@microsoft/fetch-event-source' // Custom EventSource dependency\n}\n```\n\n## Generated Code Structure\n\nProtocol functions are organized by protocol:\n\n```typescript\nexport const Protocols = {\n nats: {\n publishToUserSignup: ...,\n subscribeToUserSignup: ...,\n jetStreamPublishToUserSignup: ...\n },\n kafka: {\n publishToUserSignup: ...,\n subscribeToUserSignup: ...\n },\n // ... other protocols\n};\n```\n\n## Next Steps\n\n- **[Explore Protocol Documentation](../protocols/)** - Detailed docs for each protocol\n- **[Learn about Channels Generator](../generators/channels.md)** - How to configure protocol generation\n- **[Check Out Examples](../../examples/)** - See the code generation in action\n- **[Understanding Generators](./generators.md)** - Learn how generators work", }, "inputs/asyncapi": { title: "AsyncAPI", - content: "# AsyncAPI\nSupported versions: 2.0 -> 3.1\n\nIf you arrive from the AsyncAPI community, you might be wondering what this project is and how does it relate?\n\nThe Codegen Project was started because of a need for a code generator that;\n1. could easily be integrated into development workflows\n2. can easily be extended or customized to specific use-cases\n3. forms a community across communities in languages and standards\n4. are financially sustainable long term through open source at it's core.\n\nThere is a lot of overlap with existing tooling, however the idea is to form the same level of quality that the OpenAPI Generator provides to OpenAPI community for HTTP, for AsyncAPI and **any** protocol (including HTTP), and the usability of the Apollo GraphQL generator. How are we gonna achieve it? Together.\n\n| **Presets** | AsyncAPI | \n|---|---|\n| [`payloads`](../generators/payloads.md) | ✅ |\n| [`parameters`](../generators/parameters.md) | ✅ |\n| [`headers`](../generators/headers.md) | ✅ |\n| [`types`](../generators/types.md) | ✅ |\n| [`channels`](../generators/channels.md) | ✅ |\n| [`client`](../generators/client.md) | ✅ |\n| [`custom`](../generators/custom.md) | ✅ |\n| [`models`](../generators/custom.md) | ✅ |\n\n## Remote URL inputs\n\n`inputPath` accepts an `http://` or `https://` URL. Optional authentication (bearer token, API key, or custom headers) is configured\nvia the `auth` field. See the [configurations guide](../configurations.md#remote-url-inputs) for examples and the [auth scope and security\nconsiderations](../configurations.md#auth-scope-and-security-considerations) section before using `auth` against a public spec — the configured headers are sent to every `$ref` target as well as the root URL.\n\n## Basic AsyncAPI Document Structure\n\nHere's a complete basic AsyncAPI document example to get you started:\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"User Service API\",\n \"version\": \"1.0.0\",\n \"description\": \"API for user management events\"\n },\n \"channels\": {\n \"userSignedup\": {\n \"address\": \"user/signedup/{userId}/{region}\",\n \"parameters\": {\n \"userId\": {\n \"description\": \"The unique identifier for the user\"\n },\n \"region\": {\n \"description\": \"The geographic region\",\n \"enum\": [\"us-east\", \"us-west\", \"eu-central\"]\n }\n },\n \"messages\": {\n \"UserSignedUp\": {\n \"$ref\": \"#/components/messages/UserSignedUp\"\n }\n }\n }\n },\n \"operations\": {\n \"sendUserSignedup\": {\n \"action\": \"send\",\n \"channel\": {\n \"$ref\": \"#/channels/userSignedup\"\n },\n \"messages\": [\n {\n \"$ref\": \"#/channels/userSignedup/messages/UserSignedUp\"\n }\n ]\n },\n \"receiveUserSignedup\": {\n \"action\": \"receive\",\n \"channel\": {\n \"$ref\": \"#/channels/userSignedup\"\n },\n \"messages\": [\n {\n \"$ref\": \"#/channels/userSignedup/messages/UserSignedUp\"\n }\n ]\n }\n },\n \"components\": {\n \"messages\": {\n \"UserSignedUp\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/UserSignedUpPayload\"\n },\n \"headers\": {\n \"$ref\": \"#/components/schemas/UserHeaders\"\n }\n }\n },\n \"schemas\": {\n \"UserSignedUpPayload\": {\n \"type\": \"object\",\n \"properties\": {\n \"display_name\": {\n \"type\": \"string\",\n \"description\": \"Name of the user\"\n },\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"description\": \"Email of the user\"\n },\n \"created_at\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"When the user was created\"\n }\n },\n \"required\": [\"display_name\", \"email\"]\n },\n \"UserHeaders\": {\n \"type\": \"object\",\n \"properties\": {\n \"correlation_id\": {\n \"type\": \"string\",\n \"description\": \"Correlation ID for tracking\"\n },\n \"source\": {\n \"type\": \"string\",\n \"description\": \"Source system\"\n }\n }\n }\n }\n }\n}\n```\n\n## Multi-message channels\n\nA channel may carry more than one message. Both the payload and header models reflect **all** of them:\n\n- **Payloads** — when two or more messages on a channel carry a payload, the generated payload is a `oneOf` union of every payload. A message with no payload is skipped from the union (with a warning) instead of truncating the rest; when exactly one message carries a payload, a plain (non-union) model is produced.\n- **Headers** — likewise, when two or more messages declare headers, the channel's header model is a `oneOf` union of each message's headers. A single header-bearing message produces the same standalone header model as before; header-less messages alongside header-bearing ones are skipped with a warning. Reply-only messages are excluded from this union — the channel headers model the request side, so a request never carries the reply's headers.\n\nThis means adding a payload-less or header-less message to a multi-message channel no longer silently drops the other messages' models.\n\n## Servers and base URL\n\nWhen a channel is generated for the `http_client` protocol, the document's first `http`/`https` server URL becomes the generated client's default `baseUrl`. Non-HTTP servers (e.g. `nats`, `kafka`) are ignored for the HTTP client. See [HTTP client base URL precedence](../protocols/http_client.md#base-url).\n\n## Extensions\n\nTo customize the code generation through the AsyncAPI document, use the `x-the-codegen-project` [extension object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#specificationExtensions) with the following properties:\n\n### Channel Extensions\n\n`channelName`, string, customize the name of the functions generated for the channel, use this to overwrite the automatically determined name for models and functions. This will be used by the following generators; [payloads](../generators/payloads.md), [parameters](../generators/parameters.md) and [channels](../generators/channels.md). \n\n`functionTypeMapping`, [ChannelFunctionTypes](https://the-codegen-project.org/docs/api/enumerations/ChannelFunctionTypes), customize which generators to generate for the given channel, use this to specify further which functions we render. This will be used by the following generators; [channels](../generators/channels.md). \n\n#### Example: Custom Channel Configuration\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Custom Channel Example\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"user-events\": {\n \"address\": \"events/user/{action}\",\n \"parameters\": {\n \"action\": {\n \"enum\": [\"created\", \"updated\", \"deleted\"]\n }\n },\n \"messages\": {\n \"UserEvent\": {\n \"payload\": {\n \"type\": \"object\",\n \"properties\": {\n \"userId\": {\"type\": \"string\"},\n \"action\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"}\n }\n }\n }\n },\n \"x-the-codegen-project\": {\n \"channelName\": \"UserEventChannel\",\n \"functionTypeMapping\": [\"event_source_express\", \"kafka_publish\"]\n }\n }\n }\n}\n```\n\n### Operation Extensions\n\n`functionTypeMapping`, [ChannelFunctionTypes](https://the-codegen-project.org/docs/api/enumerations/ChannelFunctionTypes), customize which generators to generate for the given operation, use this to specify further which functions we render. This will be used by the following generators; [channels](../generators/channels.md). \n\n#### Example: Custom Operation Configuration\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Custom Operation Example\",\n \"version\": \"1.0.0\"\n },\n \"operations\": {\n \"publishUserEvent\": {\n \"action\": \"send\",\n \"channel\": {\n \"$ref\": \"#/channels/user-events\"\n },\n \"messages\": [\n {\"$ref\": \"#/channels/user-events/messages/UserEvent\"}\n ],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_publish\"]\n }\n },\n \"subscribeToUserEvents\": {\n \"action\": \"receive\",\n \"channel\": {\n \"$ref\": \"#/channels/user-events\"\n },\n \"messages\": [\n {\"$ref\": \"#/channels/user-events/messages/UserEvent\"}\n ],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_subscribe\"]\n }\n }\n }\n}\n```\n\n## Protocol Support\n\n### HTTP Client\n\nUse HTTP bindings to generate HTTP client code. Supports all standard HTTP methods and status codes.\n\n#### Example: REST API with Multiple HTTP Methods\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"User Management API\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"users\": {\n \"address\": \"/users/{userId}\",\n \"parameters\": {\n \"userId\": {\n \"description\": \"User identifier\"\n }\n },\n \"messages\": {\n \"UserRequest\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/User\"\n }\n },\n \"UserResponse\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/User\"\n },\n \"bindings\": {\n \"http\": {\n \"statusCode\": 200\n }\n }\n },\n \"NotFound\": {\n \"payload\": {\n \"type\": \"object\",\n \"properties\": {\n \"error\": {\"type\": \"string\"},\n \"code\": {\"type\": \"string\"}\n }\n },\n \"bindings\": {\n \"http\": {\n \"statusCode\": 404\n }\n }\n }\n }\n }\n },\n \"operations\": {\n \"createUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserRequest\"}],\n \"bindings\": {\n \"http\": {\"method\": \"POST\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n },\n \"getUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [],\n \"bindings\": {\n \"http\": {\"method\": \"GET\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [\n {\"$ref\": \"#/channels/users/messages/UserResponse\"},\n {\"$ref\": \"#/channels/users/messages/NotFound\"}\n ]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n },\n \"updateUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserRequest\"}],\n \"bindings\": {\n \"http\": {\"method\": \"PUT\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n },\n \"deleteUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [],\n \"bindings\": {\n \"http\": {\"method\": \"DELETE\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"User\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\"type\": \"string\"},\n \"name\": {\"type\": \"string\"},\n \"email\": {\"type\": \"string\", \"format\": \"email\"},\n \"created_at\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"name\", \"email\"]\n }\n }\n }\n}\n```\n\n### Kafka\n\nGenerate Kafka producers and consumers with proper serialization.\n\n#### Example: Kafka Event Streaming\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Order Processing Events\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"order-events\": {\n \"address\": \"orders.{eventType}.{region}\",\n \"parameters\": {\n \"eventType\": {\n \"enum\": [\"created\", \"updated\", \"cancelled\", \"completed\"]\n },\n \"region\": {\n \"enum\": [\"us\", \"eu\", \"asia\"]\n }\n },\n \"messages\": {\n \"OrderEvent\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/OrderEvent\"\n },\n \"headers\": {\n \"$ref\": \"#/components/schemas/EventHeaders\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"publishOrderEvent\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/order-events\"},\n \"messages\": [{\"$ref\": \"#/channels/order-events/messages/OrderEvent\"}],\n \"bindings\": {\n \"kafka\": {\n \"clientId\": \"order-service\",\n \"groupId\": \"order-processors\"\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_publish\"]\n }\n },\n \"subscribeToOrderEvents\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/order-events\"},\n \"messages\": [{\"$ref\": \"#/channels/order-events/messages/OrderEvent\"}],\n \"bindings\": {\n \"kafka\": {\n \"groupId\": \"order-processors\",\n \"clientId\": \"order-consumer\"\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_subscribe\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"OrderEvent\": {\n \"type\": \"object\",\n \"properties\": {\n \"orderId\": {\"type\": \"string\"},\n \"customerId\": {\"type\": \"string\"},\n \"amount\": {\"type\": \"number\"},\n \"currency\": {\"type\": \"string\"},\n \"status\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"orderId\", \"customerId\", \"amount\", \"status\"]\n },\n \"EventHeaders\": {\n \"type\": \"object\",\n \"properties\": {\n \"correlationId\": {\"type\": \"string\"},\n \"source\": {\"type\": \"string\"},\n \"version\": {\"type\": \"string\"}\n }\n }\n }\n }\n}\n```\n\n### NATS\n\nGenerate NATS request/reply patterns and pub/sub functionality.\n\n#### Example: NATS Request-Reply Pattern\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"User Service NATS API\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"user-service\": {\n \"address\": \"user.service.{operation}\",\n \"parameters\": {\n \"operation\": {\n \"enum\": [\"get\", \"create\", \"update\", \"delete\"]\n }\n },\n \"messages\": {\n \"UserRequest\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/UserRequest\"\n }\n },\n \"UserResponse\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/UserResponse\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"requestUserOperation\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserRequest\"}],\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"nats_request\"]\n }\n },\n \"replyToUserOperation\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserRequest\"}],\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"nats_reply\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"UserRequest\": {\n \"type\": \"object\",\n \"properties\": {\n \"operation\": {\"type\": \"string\"},\n \"userId\": {\"type\": \"string\"},\n \"data\": {\"type\": \"object\"}\n },\n \"required\": [\"operation\"]\n },\n \"UserResponse\": {\n \"type\": \"object\",\n \"properties\": {\n \"success\": {\"type\": \"boolean\"},\n \"data\": {\"type\": \"object\"},\n \"error\": {\"type\": \"string\"}\n },\n \"required\": [\"success\"]\n }\n }\n }\n}\n```\n\n### MQTT\n\nGenerate MQTT publish/subscribe clients with QoS levels.\n\n#### Example: IoT Device Communications\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"IoT Device Management\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"device-telemetry\": {\n \"address\": \"devices/{deviceId}/telemetry/{sensorType}\",\n \"parameters\": {\n \"deviceId\": {\n \"description\": \"Unique device identifier\"\n },\n \"sensorType\": {\n \"enum\": [\"temperature\", \"humidity\", \"pressure\", \"motion\"]\n }\n },\n \"messages\": {\n \"TelemetryData\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/TelemetryData\"\n }\n }\n }\n },\n \"device-commands\": {\n \"address\": \"devices/{deviceId}/commands\",\n \"parameters\": {\n \"deviceId\": {\n \"description\": \"Unique device identifier\"\n }\n },\n \"messages\": {\n \"DeviceCommand\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/DeviceCommand\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"publishTelemetry\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/device-telemetry\"},\n \"messages\": [{\"$ref\": \"#/channels/device-telemetry/messages/TelemetryData\"}],\n \"bindings\": {\n \"mqtt\": {\n \"qos\": 1,\n \"retain\": false\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"mqtt_publish\"]\n }\n },\n \"subscribeToTelemetry\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/device-telemetry\"},\n \"messages\": [{\"$ref\": \"#/channels/device-telemetry/messages/TelemetryData\"}],\n \"bindings\": {\n \"mqtt\": {\n \"qos\": 1\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"mqtt_subscribe\"]\n }\n },\n \"sendCommand\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/device-commands\"},\n \"messages\": [{\"$ref\": \"#/channels/device-commands/messages/DeviceCommand\"}],\n \"bindings\": {\n \"mqtt\": {\n \"qos\": 2,\n \"retain\": true\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"mqtt_publish\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"TelemetryData\": {\n \"type\": \"object\",\n \"properties\": {\n \"deviceId\": {\"type\": \"string\"},\n \"sensorType\": {\"type\": \"string\"},\n \"value\": {\"type\": \"number\"},\n \"unit\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"location\": {\n \"type\": \"object\",\n \"properties\": {\n \"latitude\": {\"type\": \"number\"},\n \"longitude\": {\"type\": \"number\"}\n }\n }\n },\n \"required\": [\"deviceId\", \"sensorType\", \"value\", \"timestamp\"]\n },\n \"DeviceCommand\": {\n \"type\": \"object\",\n \"properties\": {\n \"command\": {\"type\": \"string\"},\n \"parameters\": {\"type\": \"object\"},\n \"commandId\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"command\", \"commandId\"]\n }\n }\n }\n}\n```\n\n### AMQP\n\nGenerate AMQP producers and consumers for message queuing.\n\n#### Example: Order Processing Queue\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Order Processing Queue\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"order-queue\": {\n \"address\": \"orders.processing\",\n \"messages\": {\n \"OrderMessage\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/Order\"\n },\n \"headers\": {\n \"$ref\": \"#/components/schemas/MessageHeaders\"\n }\n }\n }\n },\n \"order-dlq\": {\n \"address\": \"orders.dead-letter\",\n \"messages\": {\n \"FailedOrderMessage\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/FailedOrder\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"publishOrder\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/order-queue\"},\n \"messages\": [{\"$ref\": \"#/channels/order-queue/messages/OrderMessage\"}],\n \"bindings\": {\n \"amqp\": {\n \"exchange\": {\n \"name\": \"orders\",\n \"type\": \"topic\",\n \"durable\": true\n },\n \"routingKey\": \"order.created\"\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"amqp_publish\"]\n }\n },\n \"consumeOrders\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/order-queue\"},\n \"messages\": [{\"$ref\": \"#/channels/order-queue/messages/OrderMessage\"}],\n \"bindings\": {\n \"amqp\": {\n \"queue\": {\n \"name\": \"order-processing-queue\",\n \"durable\": true,\n \"exclusive\": false,\n \"autoDelete\": false\n },\n \"ack\": true\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"amqp_consume\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"Order\": {\n \"type\": \"object\",\n \"properties\": {\n \"orderId\": {\"type\": \"string\"},\n \"customerId\": {\"type\": \"string\"},\n \"items\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"productId\": {\"type\": \"string\"},\n \"quantity\": {\"type\": \"integer\"},\n \"price\": {\"type\": \"number\"}\n }\n }\n },\n \"totalAmount\": {\"type\": \"number\"},\n \"currency\": {\"type\": \"string\"},\n \"orderDate\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"orderId\", \"customerId\", \"items\", \"totalAmount\"]\n },\n \"FailedOrder\": {\n \"type\": \"object\",\n \"properties\": {\n \"orderId\": {\"type\": \"string\"},\n \"error\": {\"type\": \"string\"},\n \"retryCount\": {\"type\": \"integer\"},\n \"failedAt\": {\"type\": \"string\", \"format\": \"date-time\"}\n }\n },\n \"MessageHeaders\": {\n \"type\": \"object\",\n \"properties\": {\n \"messageId\": {\"type\": \"string\"},\n \"correlationId\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"priority\": {\"type\": \"integer\", \"minimum\": 0, \"maximum\": 255}\n }\n }\n }\n }\n}\n```\n\n### EventSource\n\nGenerate Server-Sent Events (SSE) implementations for real-time updates.\n\n#### Example: Real-time Notifications\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Real-time Notifications\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"user-notifications\": {\n \"address\": \"/events/users/{userId}/notifications\",\n \"parameters\": {\n \"userId\": {\n \"description\": \"User identifier for targeted notifications\"\n }\n },\n \"messages\": {\n \"Notification\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/Notification\"\n }\n },\n \"SystemAlert\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/SystemAlert\"\n }\n }\n }\n },\n \"live-updates\": {\n \"address\": \"/events/live/{topic}\",\n \"parameters\": {\n \"topic\": {\n \"enum\": [\"stock-prices\", \"sports-scores\", \"weather-alerts\"]\n }\n },\n \"messages\": {\n \"LiveUpdate\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/LiveUpdate\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"streamUserNotifications\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/user-notifications\"},\n \"messages\": [\n {\"$ref\": \"#/channels/user-notifications/messages/Notification\"},\n {\"$ref\": \"#/channels/user-notifications/messages/SystemAlert\"}\n ],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"event_source_express\"]\n }\n },\n \"streamLiveUpdates\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/live-updates\"},\n \"messages\": [{\"$ref\": \"#/channels/live-updates/messages/LiveUpdate\"}],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"event_source_express\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"Notification\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\"type\": \"string\"},\n \"userId\": {\"type\": \"string\"},\n \"type\": {\"type\": \"string\", \"enum\": [\"info\", \"warning\", \"error\", \"success\"]},\n \"title\": {\"type\": \"string\"},\n \"message\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"actionUrl\": {\"type\": \"string\", \"format\": \"uri\"},\n \"read\": {\"type\": \"boolean\", \"default\": false}\n },\n \"required\": [\"id\", \"userId\", \"type\", \"title\", \"message\", \"timestamp\"]\n },\n \"SystemAlert\": {\n \"type\": \"object\",\n \"properties\": {\n \"alertId\": {\"type\": \"string\"},\n \"severity\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\", \"critical\"]},\n \"service\": {\"type\": \"string\"},\n \"message\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"resolved\": {\"type\": \"boolean\", \"default\": false}\n },\n \"required\": [\"alertId\", \"severity\", \"service\", \"message\", \"timestamp\"]\n },\n \"LiveUpdate\": {\n \"type\": \"object\",\n \"properties\": {\n \"topic\": {\"type\": \"string\"},\n \"data\": {\"type\": \"object\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"sequence\": {\"type\": \"integer\"}\n },\n \"required\": [\"topic\", \"data\", \"timestamp\"]\n }\n }\n }\n}\n```\n\n## FAQ\n\n### How does it relate to AsyncAPI Generator and templates?\nIt is fairly similar in functionality except in some key areas.\n\nTemplates are similar to presets except you can bind presets together to make it easier to render code down stream.\n\nThe AsyncAPI Generator is like the core of the Codegen Project, however it does not enable different inputs than AsyncAPI documents. \n\n### Can I mix multiple protocols in one document?\nYes! You can define operations with different protocol bindings in the same AsyncAPI document. Use the `x-the-codegen-project` extension to specify which generators to use for each operation.\n\n### How do I handle versioning?\n\nShort answer: Use the `info.version` field in your AsyncAPI document and consider using separate documents for major version changes. You can also use channel addressing patterns to include version information.\n\nLong answer: It's hard to version APIs, there are tons of resources how to handle versioning of your API which is far beyond what we can offer here.\n\n### Can I customize the generated code structure?\nYes, use the `x-the-codegen-project` extension properties to customize channel names, function mappings, and other generation aspects or the configuration file [while taking a look at the different generators](../generators).", + content: "# AsyncAPI\nSupported versions: 2.0 -> 3.1\n\nIf you arrive from the AsyncAPI community, you might be wondering what this project is and how does it relate?\n\nThe Codegen Project was started because of a need for a code generator that;\n1. could easily be integrated into development workflows\n2. can easily be extended or customized to specific use-cases\n3. forms a community across communities in languages and standards\n4. are financially sustainable long term through open source at it's core.\n\nThere is a lot of overlap with existing tooling, however the idea is to form the same level of quality that the OpenAPI Generator provides to OpenAPI community for HTTP, for AsyncAPI and **any** protocol (including HTTP), and the usability of the Apollo GraphQL generator. How are we gonna achieve it? Together.\n\n| **Presets** | AsyncAPI | \n|---|---|\n| [`payloads`](../generators/payloads.md) | ✅ |\n| [`parameters`](../generators/parameters.md) | ✅ |\n| [`headers`](../generators/headers.md) | ✅ |\n| [`types`](../generators/types.md) | ✅ |\n| [`channels`](../generators/channels.md) | ✅ |\n| [`client`](../generators/client.md) | ✅ |\n| [`custom`](../generators/custom.md) | ✅ |\n| [`models`](../generators/custom.md) | ✅ |\n\n## Remote URL inputs\n\n`inputPath` accepts an `http://` or `https://` URL. Optional authentication (bearer token, API key, or custom headers) is configured\nvia the `auth` field. See the [configurations guide](../configurations.md#remote-url-inputs) for examples and the [auth scope and security\nconsiderations](../configurations.md#auth-scope-and-security-considerations) section before using `auth` against a public spec — the configured headers are sent to every `$ref` target as well as the root URL.\n\n## Basic AsyncAPI Document Structure\n\nHere's a complete basic AsyncAPI document example to get you started:\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"User Service API\",\n \"version\": \"1.0.0\",\n \"description\": \"API for user management events\"\n },\n \"channels\": {\n \"userSignedup\": {\n \"address\": \"user/signedup/{userId}/{region}\",\n \"parameters\": {\n \"userId\": {\n \"description\": \"The unique identifier for the user\"\n },\n \"region\": {\n \"description\": \"The geographic region\",\n \"enum\": [\"us-east\", \"us-west\", \"eu-central\"]\n }\n },\n \"messages\": {\n \"UserSignedUp\": {\n \"$ref\": \"#/components/messages/UserSignedUp\"\n }\n }\n }\n },\n \"operations\": {\n \"sendUserSignedup\": {\n \"action\": \"send\",\n \"channel\": {\n \"$ref\": \"#/channels/userSignedup\"\n },\n \"messages\": [\n {\n \"$ref\": \"#/channels/userSignedup/messages/UserSignedUp\"\n }\n ]\n },\n \"receiveUserSignedup\": {\n \"action\": \"receive\",\n \"channel\": {\n \"$ref\": \"#/channels/userSignedup\"\n },\n \"messages\": [\n {\n \"$ref\": \"#/channels/userSignedup/messages/UserSignedUp\"\n }\n ]\n }\n },\n \"components\": {\n \"messages\": {\n \"UserSignedUp\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/UserSignedUpPayload\"\n },\n \"headers\": {\n \"$ref\": \"#/components/schemas/UserHeaders\"\n }\n }\n },\n \"schemas\": {\n \"UserSignedUpPayload\": {\n \"type\": \"object\",\n \"properties\": {\n \"display_name\": {\n \"type\": \"string\",\n \"description\": \"Name of the user\"\n },\n \"email\": {\n \"type\": \"string\",\n \"format\": \"email\",\n \"description\": \"Email of the user\"\n },\n \"created_at\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"When the user was created\"\n }\n },\n \"required\": [\"display_name\", \"email\"]\n },\n \"UserHeaders\": {\n \"type\": \"object\",\n \"properties\": {\n \"correlation_id\": {\n \"type\": \"string\",\n \"description\": \"Correlation ID for tracking\"\n },\n \"source\": {\n \"type\": \"string\",\n \"description\": \"Source system\"\n }\n }\n }\n }\n }\n}\n```\n\n## Multi-message channels\n\nA channel may carry more than one message. Both the payload and header models reflect **all** of them:\n\n- **Payloads** — when two or more messages on a channel carry a payload, the generated payload is a `oneOf` union of every payload. A message with no payload is skipped from the union (with a warning) instead of truncating the rest; when exactly one message carries a payload, a plain (non-union) model is produced.\n- **Headers** — likewise, when two or more messages declare headers, the channel's header model is a `oneOf` union of each message's headers. A single header-bearing message produces the same standalone header model as before; header-less messages alongside header-bearing ones are skipped with a warning. Reply-only messages are excluded from this union — the channel headers model the request side, so a request never carries the reply's headers.\n\nThis means adding a payload-less or header-less message to a multi-message channel no longer silently drops the other messages' models.\n\n## Servers and base URL\n\nWhen a channel is generated for the `http_client` protocol, the document's first `http`/`https` server URL becomes the generated client's default `baseUrl`. Non-HTTP servers (e.g. `nats`, `kafka`) are ignored for the HTTP client. See [HTTP client base URL precedence](../protocols/http_client.md#base-url).\n\n## Extensions\n\nTo customize the code generation through the AsyncAPI document, use the `x-the-codegen-project` [extension object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#specificationExtensions) with the following properties:\n\n### Channel Extensions\n\n`channelName`, string, customize the name of the functions generated for the channel, use this to overwrite the automatically determined name for models and functions. This will be used by the following generators; [payloads](../generators/payloads.md), [parameters](../generators/parameters.md) and [channels](../generators/channels.md). \n\n`functionTypeMapping`, [ChannelFunctionTypes](https://the-codegen-project.org/docs/api/enumerations/ChannelFunctionTypes), customize which generators to generate for the given channel, use this to specify further which functions we render. This will be used by the following generators; [channels](../generators/channels.md). \n\n#### Example: Custom Channel Configuration\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Custom Channel Example\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"user-events\": {\n \"address\": \"events/user/{action}\",\n \"parameters\": {\n \"action\": {\n \"enum\": [\"created\", \"updated\", \"deleted\"]\n }\n },\n \"messages\": {\n \"UserEvent\": {\n \"payload\": {\n \"type\": \"object\",\n \"properties\": {\n \"userId\": {\"type\": \"string\"},\n \"action\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"}\n }\n }\n }\n },\n \"x-the-codegen-project\": {\n \"channelName\": \"UserEventChannel\",\n \"functionTypeMapping\": [\"event_source_express\", \"kafka_publish\"]\n }\n }\n }\n}\n```\n\n### Operation Extensions\n\n`functionTypeMapping`, [ChannelFunctionTypes](https://the-codegen-project.org/docs/api/enumerations/ChannelFunctionTypes), customize which generators to generate for the given operation, use this to specify further which functions we render. This will be used by the following generators; [channels](../generators/channels.md). \n\n#### Example: Custom Operation Configuration\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Custom Operation Example\",\n \"version\": \"1.0.0\"\n },\n \"operations\": {\n \"publishUserEvent\": {\n \"action\": \"send\",\n \"channel\": {\n \"$ref\": \"#/channels/user-events\"\n },\n \"messages\": [\n {\"$ref\": \"#/channels/user-events/messages/UserEvent\"}\n ],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_publish\"]\n }\n },\n \"subscribeToUserEvents\": {\n \"action\": \"receive\",\n \"channel\": {\n \"$ref\": \"#/channels/user-events\"\n },\n \"messages\": [\n {\"$ref\": \"#/channels/user-events/messages/UserEvent\"}\n ],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_subscribe\"]\n }\n }\n }\n}\n```\n\n## Protocol Support\n\n### HTTP Client\n\nUse HTTP bindings to generate HTTP client code. Supports all standard HTTP methods and status codes.\n\n#### Example: REST API with Multiple HTTP Methods\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"User Management API\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"users\": {\n \"address\": \"/users/{userId}\",\n \"parameters\": {\n \"userId\": {\n \"description\": \"User identifier\"\n }\n },\n \"messages\": {\n \"UserRequest\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/User\"\n }\n },\n \"UserResponse\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/User\"\n },\n \"bindings\": {\n \"http\": {\n \"statusCode\": 200\n }\n }\n },\n \"NotFound\": {\n \"payload\": {\n \"type\": \"object\",\n \"properties\": {\n \"error\": {\"type\": \"string\"},\n \"code\": {\"type\": \"string\"}\n }\n },\n \"bindings\": {\n \"http\": {\n \"statusCode\": 404\n }\n }\n }\n }\n }\n },\n \"operations\": {\n \"createUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserRequest\"}],\n \"bindings\": {\n \"http\": {\"method\": \"POST\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n },\n \"getUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [],\n \"bindings\": {\n \"http\": {\"method\": \"GET\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [\n {\"$ref\": \"#/channels/users/messages/UserResponse\"},\n {\"$ref\": \"#/channels/users/messages/NotFound\"}\n ]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n },\n \"updateUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserRequest\"}],\n \"bindings\": {\n \"http\": {\"method\": \"PUT\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n },\n \"deleteUser\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [],\n \"bindings\": {\n \"http\": {\"method\": \"DELETE\"}\n },\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/users\"},\n \"messages\": [{\"$ref\": \"#/channels/users/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"http_client\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"User\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\"type\": \"string\"},\n \"name\": {\"type\": \"string\"},\n \"email\": {\"type\": \"string\", \"format\": \"email\"},\n \"created_at\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"name\", \"email\"]\n }\n }\n }\n}\n```\n\n### Kafka\n\nGenerate Kafka producers and consumers with proper serialization.\n\n#### Example: Kafka Event Streaming\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Order Processing Events\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"order-events\": {\n \"address\": \"orders.{eventType}.{region}\",\n \"parameters\": {\n \"eventType\": {\n \"enum\": [\"created\", \"updated\", \"cancelled\", \"completed\"]\n },\n \"region\": {\n \"enum\": [\"us\", \"eu\", \"asia\"]\n }\n },\n \"messages\": {\n \"OrderEvent\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/OrderEvent\"\n },\n \"headers\": {\n \"$ref\": \"#/components/schemas/EventHeaders\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"publishOrderEvent\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/order-events\"},\n \"messages\": [{\"$ref\": \"#/channels/order-events/messages/OrderEvent\"}],\n \"bindings\": {\n \"kafka\": {\n \"clientId\": \"order-service\",\n \"groupId\": \"order-processors\"\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_publish\"]\n }\n },\n \"subscribeToOrderEvents\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/order-events\"},\n \"messages\": [{\"$ref\": \"#/channels/order-events/messages/OrderEvent\"}],\n \"bindings\": {\n \"kafka\": {\n \"groupId\": \"order-processors\",\n \"clientId\": \"order-consumer\"\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"kafka_subscribe\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"OrderEvent\": {\n \"type\": \"object\",\n \"properties\": {\n \"orderId\": {\"type\": \"string\"},\n \"customerId\": {\"type\": \"string\"},\n \"amount\": {\"type\": \"number\"},\n \"currency\": {\"type\": \"string\"},\n \"status\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"orderId\", \"customerId\", \"amount\", \"status\"]\n },\n \"EventHeaders\": {\n \"type\": \"object\",\n \"properties\": {\n \"correlationId\": {\"type\": \"string\"},\n \"source\": {\"type\": \"string\"},\n \"version\": {\"type\": \"string\"}\n }\n }\n }\n }\n}\n```\n\n### NATS\n\nGenerate NATS request/reply patterns and pub/sub functionality.\n\n#### Example: NATS Request-Reply Pattern\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"User Service NATS API\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"user-service\": {\n \"address\": \"user.service.{operation}\",\n \"parameters\": {\n \"operation\": {\n \"enum\": [\"get\", \"create\", \"update\", \"delete\"]\n }\n },\n \"messages\": {\n \"UserRequest\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/UserRequest\"\n }\n },\n \"UserResponse\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/UserResponse\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"requestUserOperation\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserRequest\"}],\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"nats_request\"]\n }\n },\n \"replyToUserOperation\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserRequest\"}],\n \"reply\": {\n \"channel\": {\"$ref\": \"#/channels/user-service\"},\n \"messages\": [{\"$ref\": \"#/channels/user-service/messages/UserResponse\"}]\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"nats_reply\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"UserRequest\": {\n \"type\": \"object\",\n \"properties\": {\n \"operation\": {\"type\": \"string\"},\n \"userId\": {\"type\": \"string\"},\n \"data\": {\"type\": \"object\"}\n },\n \"required\": [\"operation\"]\n },\n \"UserResponse\": {\n \"type\": \"object\",\n \"properties\": {\n \"success\": {\"type\": \"boolean\"},\n \"data\": {\"type\": \"object\"},\n \"error\": {\"type\": \"string\"}\n },\n \"required\": [\"success\"]\n }\n }\n }\n}\n```\n\n### MQTT\n\nGenerate MQTT publish/subscribe clients with QoS levels.\n\n#### Example: IoT Device Communications\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"IoT Device Management\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"device-telemetry\": {\n \"address\": \"devices/{deviceId}/telemetry/{sensorType}\",\n \"parameters\": {\n \"deviceId\": {\n \"description\": \"Unique device identifier\"\n },\n \"sensorType\": {\n \"enum\": [\"temperature\", \"humidity\", \"pressure\", \"motion\"]\n }\n },\n \"messages\": {\n \"TelemetryData\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/TelemetryData\"\n }\n }\n }\n },\n \"device-commands\": {\n \"address\": \"devices/{deviceId}/commands\",\n \"parameters\": {\n \"deviceId\": {\n \"description\": \"Unique device identifier\"\n }\n },\n \"messages\": {\n \"DeviceCommand\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/DeviceCommand\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"publishTelemetry\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/device-telemetry\"},\n \"messages\": [{\"$ref\": \"#/channels/device-telemetry/messages/TelemetryData\"}],\n \"bindings\": {\n \"mqtt\": {\n \"qos\": 1,\n \"retain\": false\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"mqtt_publish\"]\n }\n },\n \"subscribeToTelemetry\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/device-telemetry\"},\n \"messages\": [{\"$ref\": \"#/channels/device-telemetry/messages/TelemetryData\"}],\n \"bindings\": {\n \"mqtt\": {\n \"qos\": 1\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"mqtt_subscribe\"]\n }\n },\n \"sendCommand\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/device-commands\"},\n \"messages\": [{\"$ref\": \"#/channels/device-commands/messages/DeviceCommand\"}],\n \"bindings\": {\n \"mqtt\": {\n \"qos\": 2,\n \"retain\": true\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"mqtt_publish\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"TelemetryData\": {\n \"type\": \"object\",\n \"properties\": {\n \"deviceId\": {\"type\": \"string\"},\n \"sensorType\": {\"type\": \"string\"},\n \"value\": {\"type\": \"number\"},\n \"unit\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"location\": {\n \"type\": \"object\",\n \"properties\": {\n \"latitude\": {\"type\": \"number\"},\n \"longitude\": {\"type\": \"number\"}\n }\n }\n },\n \"required\": [\"deviceId\", \"sensorType\", \"value\", \"timestamp\"]\n },\n \"DeviceCommand\": {\n \"type\": \"object\",\n \"properties\": {\n \"command\": {\"type\": \"string\"},\n \"parameters\": {\"type\": \"object\"},\n \"commandId\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"command\", \"commandId\"]\n }\n }\n }\n}\n```\n\n### AMQP\n\nGenerate AMQP producers and consumers for message queuing.\n\n#### Example: Order Processing Queue\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Order Processing Queue\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"order-queue\": {\n \"address\": \"orders.processing\",\n \"messages\": {\n \"OrderMessage\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/Order\"\n },\n \"headers\": {\n \"$ref\": \"#/components/schemas/MessageHeaders\"\n }\n }\n }\n },\n \"order-dlq\": {\n \"address\": \"orders.dead-letter\",\n \"messages\": {\n \"FailedOrderMessage\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/FailedOrder\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"publishOrder\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/order-queue\"},\n \"messages\": [{\"$ref\": \"#/channels/order-queue/messages/OrderMessage\"}],\n \"bindings\": {\n \"amqp\": {\n \"exchange\": {\n \"name\": \"orders\",\n \"type\": \"topic\",\n \"durable\": true\n },\n \"routingKey\": \"order.created\"\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"amqp_queue_publish\"]\n }\n },\n \"consumeOrders\": {\n \"action\": \"receive\",\n \"channel\": {\"$ref\": \"#/channels/order-queue\"},\n \"messages\": [{\"$ref\": \"#/channels/order-queue/messages/OrderMessage\"}],\n \"bindings\": {\n \"amqp\": {\n \"queue\": {\n \"name\": \"order-processing-queue\",\n \"durable\": true,\n \"exclusive\": false,\n \"autoDelete\": false\n },\n \"ack\": true\n }\n },\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"amqp_queue_subscribe\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"Order\": {\n \"type\": \"object\",\n \"properties\": {\n \"orderId\": {\"type\": \"string\"},\n \"customerId\": {\"type\": \"string\"},\n \"items\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"productId\": {\"type\": \"string\"},\n \"quantity\": {\"type\": \"integer\"},\n \"price\": {\"type\": \"number\"}\n }\n }\n },\n \"totalAmount\": {\"type\": \"number\"},\n \"currency\": {\"type\": \"string\"},\n \"orderDate\": {\"type\": \"string\", \"format\": \"date-time\"}\n },\n \"required\": [\"orderId\", \"customerId\", \"items\", \"totalAmount\"]\n },\n \"FailedOrder\": {\n \"type\": \"object\",\n \"properties\": {\n \"orderId\": {\"type\": \"string\"},\n \"error\": {\"type\": \"string\"},\n \"retryCount\": {\"type\": \"integer\"},\n \"failedAt\": {\"type\": \"string\", \"format\": \"date-time\"}\n }\n },\n \"MessageHeaders\": {\n \"type\": \"object\",\n \"properties\": {\n \"messageId\": {\"type\": \"string\"},\n \"correlationId\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"priority\": {\"type\": \"integer\", \"minimum\": 0, \"maximum\": 255}\n }\n }\n }\n }\n}\n```\n\n### EventSource\n\nGenerate Server-Sent Events (SSE) implementations for real-time updates.\n\n#### Example: Real-time Notifications\n\n```json\n{\n \"asyncapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Real-time Notifications\",\n \"version\": \"1.0.0\"\n },\n \"channels\": {\n \"user-notifications\": {\n \"address\": \"/events/users/{userId}/notifications\",\n \"parameters\": {\n \"userId\": {\n \"description\": \"User identifier for targeted notifications\"\n }\n },\n \"messages\": {\n \"Notification\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/Notification\"\n }\n },\n \"SystemAlert\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/SystemAlert\"\n }\n }\n }\n },\n \"live-updates\": {\n \"address\": \"/events/live/{topic}\",\n \"parameters\": {\n \"topic\": {\n \"enum\": [\"stock-prices\", \"sports-scores\", \"weather-alerts\"]\n }\n },\n \"messages\": {\n \"LiveUpdate\": {\n \"payload\": {\n \"$ref\": \"#/components/schemas/LiveUpdate\"\n }\n }\n }\n }\n },\n \"operations\": {\n \"streamUserNotifications\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/user-notifications\"},\n \"messages\": [\n {\"$ref\": \"#/channels/user-notifications/messages/Notification\"},\n {\"$ref\": \"#/channels/user-notifications/messages/SystemAlert\"}\n ],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"event_source_express\"]\n }\n },\n \"streamLiveUpdates\": {\n \"action\": \"send\",\n \"channel\": {\"$ref\": \"#/channels/live-updates\"},\n \"messages\": [{\"$ref\": \"#/channels/live-updates/messages/LiveUpdate\"}],\n \"x-the-codegen-project\": {\n \"functionTypeMapping\": [\"event_source_express\"]\n }\n }\n },\n \"components\": {\n \"schemas\": {\n \"Notification\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\"type\": \"string\"},\n \"userId\": {\"type\": \"string\"},\n \"type\": {\"type\": \"string\", \"enum\": [\"info\", \"warning\", \"error\", \"success\"]},\n \"title\": {\"type\": \"string\"},\n \"message\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"actionUrl\": {\"type\": \"string\", \"format\": \"uri\"},\n \"read\": {\"type\": \"boolean\", \"default\": false}\n },\n \"required\": [\"id\", \"userId\", \"type\", \"title\", \"message\", \"timestamp\"]\n },\n \"SystemAlert\": {\n \"type\": \"object\",\n \"properties\": {\n \"alertId\": {\"type\": \"string\"},\n \"severity\": {\"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\", \"critical\"]},\n \"service\": {\"type\": \"string\"},\n \"message\": {\"type\": \"string\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"resolved\": {\"type\": \"boolean\", \"default\": false}\n },\n \"required\": [\"alertId\", \"severity\", \"service\", \"message\", \"timestamp\"]\n },\n \"LiveUpdate\": {\n \"type\": \"object\",\n \"properties\": {\n \"topic\": {\"type\": \"string\"},\n \"data\": {\"type\": \"object\"},\n \"timestamp\": {\"type\": \"string\", \"format\": \"date-time\"},\n \"sequence\": {\"type\": \"integer\"}\n },\n \"required\": [\"topic\", \"data\", \"timestamp\"]\n }\n }\n }\n}\n```\n\n## FAQ\n\n### How does it relate to AsyncAPI Generator and templates?\nIt is fairly similar in functionality except in some key areas.\n\nTemplates are similar to presets except you can bind presets together to make it easier to render code down stream.\n\nThe AsyncAPI Generator is like the core of the Codegen Project, however it does not enable different inputs than AsyncAPI documents. \n\n### Can I mix multiple protocols in one document?\nYes! You can define operations with different protocol bindings in the same AsyncAPI document. Use the `x-the-codegen-project` extension to specify which generators to use for each operation.\n\n### How do I handle versioning?\n\nShort answer: Use the `info.version` field in your AsyncAPI document and consider using separate documents for major version changes. You can also use channel addressing patterns to include version information.\n\nLong answer: It's hard to version APIs, there are tons of resources how to handle versioning of your API which is far beyond what we can offer here.\n\n### Can I customize the generated code structure?\nYes, use the `x-the-codegen-project` extension properties to customize channel names, function mappings, and other generation aspects or the configuration file [while taking a look at the different generators](../generators).", }, "inputs/jsonschema": { title: "JSON Schema", @@ -108,27 +108,27 @@ export const docs: Record = { }, "migrations/v0": { title: "Migrating between v0", - content: "\n\n\n\n- [Migrating between v0](#migrating-between-v0)\n * [Breaking Changes 0.39.0](#breaking-changes-0390)\n + [Functions Parameters](#functions-parameters)\n * [Breaking Changes 0.55.1](#breaking-changes-0551)\n * [Breaking Changes 0.61.0](#breaking-changes-0610)\n + [Channels Multi-File Output](#channels-multi-file-output)\n * [Breaking Changes 0.64.2](#breaking-changes-0642)\n * [Breaking Changes 0.71.0](#breaking-changes-0710)\n + [Library API Type Changes](#library-api-type-changes)\n * [Breaking Changes 0.72.3](#breaking-changes-0723)\n + [OpenAPI Operation Names](#openapi-operation-names)\n * [Breaking Changes 0.72.6](#breaking-changes-0726)\n + [Generated HTTP Client Uses Native fetch](#generated-http-client-uses-native-fetch)\n\n\n\n# Migrating between v0\nThese are all the breaking changes in v0 and how to migrate between them\n\n## Breaking Changes 0.39.0\n\n### Functions Parameters\n\nAll TypeScript functions now [use object parameters](../architectural-decisions/typescript.md#28042025) instead of regular parameters. This change affects `channels` and `client` generators across all protocols.\n\nBefore:\n```typescript\n// Publishing\nawait jetStreamPublishToSendUserSignedup(message, parameters, js);\nawait publishToSendUserSignedup(message, parameters, connection);\n\n// Subscribing\nconst subscriber = await jetStreamPullSubscribeToReceiveUserSignedup(\n onDataCallback,\n parameters,\n js,\n config\n);\n```\n\nAfter:\n```typescript\n// Publishing\nawait jetStreamPublishToSendUserSignedup({\n message,\n parameters,\n js\n});\nawait publishToSendUserSignedup({\n message,\n parameters,\n connection\n});\n\n// Subscribing\nconst subscriber = await jetStreamPullSubscribeToReceiveUserSignedup({\n onDataCallback,\n parameters,\n js,\n config\n});\n```\n\n## Breaking Changes 0.55.1\n\nWe upgraded the AsyncAPI Modelina dependency to the `next` version so for the next few versions it will contain breaking changes as we continue to improve the tool.\n\n## Breaking Changes 0.61.0\n\n### Channels Multi-File Output\n\nThe `channels` generator now outputs one file per protocol instead of a single file with a `Protocols` object. This change improves tree-shaking, reduces bundle size, and provides better code organization.\n\n**Before (v0.60.x and earlier):**\n```typescript\n// Single file with Protocols object containing all protocols\nimport { Protocols } from './channels/index';\nconst { nats } = Protocols;\nconst { publishToSendUserSignedup, subscribeToReceiveUserSignedup } = nats;\n\n// Or destructure directly\nconst { nats: { publishToSendUserSignedup } } = Protocols;\n```\n\n**After (v0.61.0+):**\n```typescript\n// Option 1: Import specific functions directly from protocol file\nimport {\n publishToSendUserSignedup,\n subscribeToReceiveUserSignedup\n} from './channels/nats';\n\n// Option 2: Import the entire protocol as a namespace\nimport * as nats from './channels/nats';\nnats.publishToSendUserSignedup({ ... });\n\n// Option 3: Import from index (protocols are re-exported as namespaces)\nimport { nats, kafka, mqtt } from './channels/index';\nnats.publishToSendUserSignedup({ ... });\n```\n\n**New file structure:**\n```\noutputPath/\n├── index.ts # Re-exports all protocol namespaces\n├── nats.ts # NATS-specific functions\n├── kafka.ts # Kafka-specific functions\n├── mqtt.ts # MQTT-specific functions\n├── amqp.ts # AMQP-specific functions\n├── event_source.ts # EventSource-specific functions\n├── http_client.ts # HTTP client-specific functions\n└── websocket.ts # WebSocket-specific functions\n```\n\n**Migration steps:**\n1. Replace `import { Protocols } from './channels'` with direct imports from protocol files\n2. Remove destructuring of the `Protocols` object\n3. Update function calls - functions are now standalone exports, not object properties\n4. Optionally use namespace imports (`import * as nats from './channels/nats'`) to keep similar syntax\n\n## Breaking Changes 0.64.2\n\nUpgraded node to minimum v22.\n\n## Breaking Changes 0.71.0\n\n### Library API Type Changes\n\nThe `GenerationResult` and `GeneratorResult` types have changed to support browser-based generation (playground). This only affects users consuming the library programmatically - CLI users are not affected.\n\n**Before (v0.70.x and earlier):**\n```typescript\nimport { runGenerators } from '@the-codegen-project/cli';\n\nconst result = await runGenerators(context);\n\n// Accessing results\nconsole.log(result.totalFiles); // number\nconsole.log(result.allFiles); // string[] (absolute paths)\nconsole.log(result.generators[0].filesWritten); // string[] (absolute paths)\n```\n\n**After (v0.71.0+):**\n```typescript\nimport { runGenerators } from '@the-codegen-project/cli';\n\nconst result = await runGenerators(context);\n\n// Accessing results - now includes file content\nconsole.log(result.files.length); // number (replaces totalFiles)\nconsole.log(result.files); // GeneratedFile[]\nconsole.log(result.generators[0].files); // GeneratedFile[]\n\n// GeneratedFile shape:\ninterface GeneratedFile {\n path: string; // Relative path (e.g., 'src/payloads/User.ts')\n content: string; // Full file content\n}\n```\n\n**Migration steps:**\n1. Replace `result.totalFiles` with `result.files.length`\n2. Replace `result.allFiles` with `result.files.map(f => f.path)`\n3. Replace `generator.filesWritten` with `generator.files.map(f => f.path)`\n4. Optionally leverage the new `content` property for in-memory processing\n\n## Breaking Changes 0.72.3\n\n### OpenAPI Operation Names\n\nThe OpenAPI `channels` and `client` (`http_client`) generators previously prepended the HTTP method to the operation name, even when the spec already provided an `operationId`. This produced a duplicated verb (e.g. an `addPet` operation with method `POST` generated `postAddPet`). The `operationId` is now used verbatim as the function name, and the method is only used to synthesize a name when no `operationId` is present.\n\nThis renames the generated functions (and their `*Context` interfaces) for any OpenAPI operation that declares an `operationId`.\n\n**Before (v0.72.2 and earlier):**\n```typescript\nimport { postAddPet, putUpdatePet, getFindPetsByStatusAndCategory } from './channels/http_client';\n\nawait postAddPet({ /* ... */ });\n```\n\n**After (v0.72.3+):**\n```typescript\nimport { addPet, updatePet, findPetsByStatusAndCategory } from './channels/http_client';\n\nawait addPet({ /* ... */ });\n```\n\n**Migration steps:**\n1. Regenerate your code.\n2. Update call sites to drop the leading HTTP verb from function names that came from an `operationId` (e.g. `postAddPet` → `addPet`).\n3. Update any references to the renamed `*Context` interfaces (e.g. `PostAddPetContext` → `AddPetContext`).\n\n## Breaking Changes 0.72.6\n\n### Generated HTTP Client Uses Native fetch\n\nThe generated HTTP client (OpenAPI `http_client` channels and the `http` client) no longer imports `node-fetch`. It now uses the global `fetch`/`Headers` built into the runtime. The `node-fetch` (and `@types/node-fetch`) dependency is no longer needed. This project already requires Node.js 22, which ships a global `fetch`.\n\n**Before (v0.72.5 and earlier):**\n```typescript\n// Generated client imported node-fetch\nimport * as NodeFetch from 'node-fetch';\n// package.json needed:\n// \"node-fetch\": \"^2.6.7\", \"@types/node-fetch\": \"^2.6.11\"\n```\n\n**After (v0.72.6+):**\n```typescript\n// Generated client uses the runtime's global fetch — no import, no dependency.\n// To use a different HTTP implementation (node-fetch, axios, ...), provide it\n// via the makeRequest hook on the client context.\n```\n\n**Migration steps:**\n1. Regenerate your code.\n2. Remove `node-fetch` and `@types/node-fetch` from your project's dependencies if they were only used by the generated client.\n3. Ensure your runtime provides a global `fetch` (Node.js 18+). If you need a custom HTTP implementation, supply it through the `makeRequest` hook instead of relying on the default.", + content: "\n\n\n\n- [Migrating between v0](#migrating-between-v0)\n * [Breaking Changes 0.39.0](#breaking-changes-0390)\n + [Functions Parameters](#functions-parameters)\n * [Breaking Changes 0.55.1](#breaking-changes-0551)\n * [Breaking Changes 0.61.0](#breaking-changes-0610)\n + [Channels Multi-File Output](#channels-multi-file-output)\n * [Breaking Changes 0.64.2](#breaking-changes-0642)\n * [Breaking Changes 0.71.0](#breaking-changes-0710)\n + [Library API Type Changes](#library-api-type-changes)\n * [Breaking Changes 0.72.3](#breaking-changes-0723)\n + [OpenAPI Operation Names](#openapi-operation-names)\n * [Breaking Changes 0.72.6](#breaking-changes-0726)\n + [Generated HTTP Client Uses Native fetch](#generated-http-client-uses-native-fetch)\n\n\n\n# Migrating between v0\nThese are all the breaking changes in v0 and how to migrate between them\n\n## Breaking Changes 0.39.0\n\n### Functions Parameters\n\nAll TypeScript functions now [use object parameters](../architectural-decisions/typescript.md#28042025) instead of regular parameters. This change affects `channels` and `client` generators across all protocols.\n\nBefore:\n```typescript\n// Publishing\nawait jetStreamPublishToSendUserSignedup(message, parameters, js);\nawait publishToSendUserSignedup(message, parameters, connection);\n\n// Subscribing\nconst subscriber = await jetStreamPullSubscribeToReceiveUserSignedup(\n onDataCallback,\n parameters,\n js,\n config\n);\n```\n\nAfter:\n```typescript\n// Publishing\nawait jetStreamPublishToSendUserSignedup({\n message,\n parameters,\n js\n});\nawait publishToSendUserSignedup({\n message,\n parameters,\n nc\n});\n\n// Subscribing\nconst subscriber = await jetStreamPullSubscribeToReceiveUserSignedup({\n onDataCallback,\n parameters,\n js,\n config\n});\n```\n\n## Breaking Changes 0.55.1\n\nWe upgraded the AsyncAPI Modelina dependency to the `next` version so for the next few versions it will contain breaking changes as we continue to improve the tool.\n\n## Breaking Changes 0.61.0\n\n### Channels Multi-File Output\n\nThe `channels` generator now outputs one file per protocol instead of a single file with a `Protocols` object. This change improves tree-shaking, reduces bundle size, and provides better code organization.\n\n**Before (v0.60.x and earlier):**\n```typescript\n// Single file with Protocols object containing all protocols\nimport { Protocols } from './channels/index';\nconst { nats } = Protocols;\nconst { publishToSendUserSignedup, subscribeToReceiveUserSignedup } = nats;\n\n// Or destructure directly\nconst { nats: { publishToSendUserSignedup } } = Protocols;\n```\n\n**After (v0.61.0+):**\n```typescript\n// Option 1: Import specific functions directly from protocol file\nimport {\n publishToSendUserSignedup,\n subscribeToReceiveUserSignedup\n} from './channels/nats';\n\n// Option 2: Import the entire protocol as a namespace\nimport * as nats from './channels/nats';\nnats.publishToSendUserSignedup({ ... });\n\n// Option 3: Import from index (protocols are re-exported as namespaces)\nimport { nats, kafka, mqtt } from './channels/index';\nnats.publishToSendUserSignedup({ ... });\n```\n\n**New file structure:**\n```\noutputPath/\n├── index.ts # Re-exports all protocol namespaces\n├── nats.ts # NATS-specific functions\n├── kafka.ts # Kafka-specific functions\n├── mqtt.ts # MQTT-specific functions\n├── amqp.ts # AMQP-specific functions\n├── event_source.ts # EventSource-specific functions\n├── http_client.ts # HTTP client-specific functions\n└── websocket.ts # WebSocket-specific functions\n```\n\n**Migration steps:**\n1. Replace `import { Protocols } from './channels'` with direct imports from protocol files\n2. Remove destructuring of the `Protocols` object\n3. Update function calls - functions are now standalone exports, not object properties\n4. Optionally use namespace imports (`import * as nats from './channels/nats'`) to keep similar syntax\n\n## Breaking Changes 0.64.2\n\nUpgraded node to minimum v22.\n\n## Breaking Changes 0.71.0\n\n### Library API Type Changes\n\nThe `GenerationResult` and `GeneratorResult` types have changed to support browser-based generation (playground). This only affects users consuming the library programmatically - CLI users are not affected.\n\n**Before (v0.70.x and earlier):**\n```typescript\nimport { runGenerators } from '@the-codegen-project/cli';\n\nconst result = await runGenerators(context);\n\n// Accessing results\nconsole.log(result.totalFiles); // number\nconsole.log(result.allFiles); // string[] (absolute paths)\nconsole.log(result.generators[0].filesWritten); // string[] (absolute paths)\n```\n\n**After (v0.71.0+):**\n```typescript\nimport { runGenerators } from '@the-codegen-project/cli';\n\nconst result = await runGenerators(context);\n\n// Accessing results - now includes file content\nconsole.log(result.files.length); // number (replaces totalFiles)\nconsole.log(result.files); // GeneratedFile[]\nconsole.log(result.generators[0].files); // GeneratedFile[]\n\n// GeneratedFile shape:\ninterface GeneratedFile {\n path: string; // Relative path (e.g., 'src/payloads/User.ts')\n content: string; // Full file content\n}\n```\n\n**Migration steps:**\n1. Replace `result.totalFiles` with `result.files.length`\n2. Replace `result.allFiles` with `result.files.map(f => f.path)`\n3. Replace `generator.filesWritten` with `generator.files.map(f => f.path)`\n4. Optionally leverage the new `content` property for in-memory processing\n\n## Breaking Changes 0.72.3\n\n### OpenAPI Operation Names\n\nThe OpenAPI `channels` and `client` (`http_client`) generators previously prepended the HTTP method to the operation name, even when the spec already provided an `operationId`. This produced a duplicated verb (e.g. an `addPet` operation with method `POST` generated `postAddPet`). The `operationId` is now used verbatim as the function name, and the method is only used to synthesize a name when no `operationId` is present.\n\nThis renames the generated functions (and their `*Context` interfaces) for any OpenAPI operation that declares an `operationId`.\n\n**Before (v0.72.2 and earlier):**\n```typescript\nimport { postAddPet, putUpdatePet, getFindPetsByStatusAndCategory } from './channels/http_client';\n\nawait postAddPet({ /* ... */ });\n```\n\n**After (v0.72.3+):**\n```typescript\nimport { addPet, updatePet, findPetsByStatusAndCategory } from './channels/http_client';\n\nawait addPet({ /* ... */ });\n```\n\n**Migration steps:**\n1. Regenerate your code.\n2. Update call sites to drop the leading HTTP verb from function names that came from an `operationId` (e.g. `postAddPet` → `addPet`).\n3. Update any references to the renamed `*Context` interfaces (e.g. `PostAddPetContext` → `AddPetContext`).\n\n## Breaking Changes 0.72.6\n\n### Generated HTTP Client Uses Native fetch\n\nThe generated HTTP client (OpenAPI `http_client` channels and the `http` client) no longer imports `node-fetch`. It now uses the global `fetch`/`Headers` built into the runtime. The `node-fetch` (and `@types/node-fetch`) dependency is no longer needed. This project already requires Node.js 22, which ships a global `fetch`.\n\n**Before (v0.72.5 and earlier):**\n```typescript\n// Generated client imported node-fetch\nimport * as NodeFetch from 'node-fetch';\n// package.json needed:\n// \"node-fetch\": \"^2.6.7\", \"@types/node-fetch\": \"^2.6.11\"\n```\n\n**After (v0.72.6+):**\n```typescript\n// Generated client uses the runtime's global fetch — no import, no dependency.\n// To use a different HTTP implementation (node-fetch, axios, ...), provide it\n// via the makeRequest hook on the client context.\n```\n\n**Migration steps:**\n1. Regenerate your code.\n2. Remove `node-fetch` and `@types/node-fetch` from your project's dependencies if they were only used by the generated client.\n3. Ensure your runtime provides a global `fetch` (Node.js 18+). If you need a custom HTTP implementation, supply it through the `makeRequest` hook instead of relying on the default.", }, "protocols/amqp": { title: "AMQP", - content: "# AMQP\n`AMQP` is currently available through the generators ([channels](#channels)):\n\n| **Languages** | Publish exchange | Publish queue | Subscribe queue | Subscribe exchange |\n|---|---|---|---|---|\n| TypeScript | ✅ | ✅ | ✅ | |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n publishUserSignups:\n action: send\n channel:\n $ref: '#/channels/userSignups'\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n```\n\n\n```ts\nimport * as Amqp from 'amqplib';\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the channel generator configurations\nimport { Protocols } from './__gen__/channels';\nconst { amqp } = Protocols;\nconst { publishToPublishUserSignupsExchange, publishToPublishUserSignupsQueue, subscribeToConsumeUserSignupsQueue } = amqp;\n\n/**\n * Setup the regular client\n */\nconst client = await Amqp.connect('amqp://localhost');\nconst myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\n\n// Use exchange\nawait publishToPublishUserSignupsExchange(myPayload, client);\n\n// Use queue\nawait publishToPublishUserSignupsQueue(myPayload, client);\nawait subscribeToConsumeUserSignupsQueue((message) => {\n console.log(`Received message: ${message.displayName}, ${message.email}`);\n}, client);\n```\t\n
", + content: "# AMQP\n`AMQP` is currently available through the generators ([channels](#channels)):\n\n| **Languages** | Publish exchange | Publish queue | Subscribe queue | Subscribe exchange |\n|---|---|---|---|---|\n| TypeScript | ✅ | ✅ | ✅ | |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n publishUserSignups:\n action: send\n channel:\n $ref: '#/channels/userSignups'\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n```\n\n\n```ts\nimport * as Amqp from 'amqplib';\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the channel generator configurations\nimport { amqp } from './__gen__/channels';\nconst { publishToPublishUserSignupsExchange, publishToPublishUserSignupsQueue, subscribeToConsumeUserSignupsQueue } = amqp;\n\n/**\n * Setup the regular client\n */\nconst client = await Amqp.connect('amqp://localhost');\nconst myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\n\n// Use exchange\nawait publishToPublishUserSignupsExchange({ message: myPayload, amqp: client });\n\n// Use queue\nawait publishToPublishUserSignupsQueue({ message: myPayload, amqp: client });\nawait subscribeToConsumeUserSignupsQueue({\n onDataCallback: ({ err, msg, headers, amqpMsg }) => {\n if (err) {\n console.error('Error receiving message:', err);\n return;\n }\n console.log(`Received message: ${msg?.displayName}, ${msg?.email}`);\n },\n amqp: client\n});\n```\t\n
", }, "protocols/eventsource": { title: "EventSource", - content: "# EventSource\n`Event Source` is currently available through the generators ([channels](#channels)):\n\n| **Languages** | [client](#client) | [server](#server) |\n|---|---|---|\n| TypeScript | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## Client\n\nThe client generated code is to listen for events from the server and act accordingly. \n\n## Server\n\nThe server generated code is to listen for clients making the connection and being ready to receive events. \n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n\n```\n\n\n```ts\nimport express, { Router } from 'express'\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the channel generator configurations\nimport { Protocols } from './__gen__/channels';\nconst { event_source_client } = Protocols;\nconst { listenForUserSignedup } = event_source_client;\nconst listenCallback = async (\n messageEvent: UserSignedUp | null, \n parameters: UserSignedUpParameters | null,\n error?: string\n) => {\n // Do stuff once you receive the event from the server\n};\nlistenForUserSignedup(listenCallback, {baseUrl: 'http://localhost:3000'})\n\n// Use express to listen for clients registering for events\nconst router = Router()\nconst app = express()\napp.use(express.json({ limit: '3000kb' }))\napp.use(express.urlencoded({ extended: true }))\nregisterSendUserSignedup(router, (req, res, next, parameters, sendEvent) => {\n //Do stuff when client starts listening to the event.\n //For example send a message to the client\n const testMessage = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\n sendEvent(testMessage);\n})\napp.use(router)\napp.listen(3000)\n```\n
", + content: "# EventSource\n`Event Source` is currently available through the generators ([channels](#channels)):\n\n| **Languages** | [client](#client) | [server](#server) |\n|---|---|---|\n| TypeScript | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## Client\n\nThe client generated code is to listen for events from the server and act accordingly. \n\n## Server\n\nThe server generated code is to listen for clients making the connection and being ready to receive events. \n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n\n```\n\n\n```ts\nimport express, { Router } from 'express'\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the channel generator configurations\nimport { event_source } from './__gen__/channels';\nconst { listenForUserSignedup, registerSendUserSignedup } = event_source;\n\n// The client-side listener takes an object callback\nlistenForUserSignedup({\n callback: ({ error, messageEvent }) => {\n // Do stuff once you receive the event from the server\n },\n options: { baseUrl: 'http://localhost:3000' }\n})\n\n// Use express to listen for clients registering for events. The Express\n// handler keeps Express' own positional (req, res, next) convention.\nconst router = Router()\nconst app = express()\napp.use(express.json({ limit: '3000kb' }))\napp.use(express.urlencoded({ extended: true }))\nregisterSendUserSignedup({\n router,\n callback: (req, res, next, parameters, sendEvent) => {\n //Do stuff when client starts listening to the event.\n //For example send a message to the client\n const testMessage = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\n sendEvent(testMessage);\n }\n})\napp.use(router)\napp.listen(3000)\n```\n
", }, "protocols/http_client": { title: "HTTP(S)", - content: "# HTTP(S)\n\nHTTP client generator creates type-safe functions for making HTTP requests based on your API specification. It supports various authentication methods, retry logic, and extensibility hooks.\n\nIt is currently available through the generators ([channels](../generators/channels.md)):\n\nThis is available through [AsyncAPI](../inputs/asyncapi.md) ([requires the HTTP `method` binding for operations and `statusCode` for messages](../inputs/asyncapi.md#http-client)) and directly from [OpenAPI](../inputs/openapi.md) documents (see [From OpenAPI](#from-openapi) below).\n\n## TypeScript\n\n| **Feature** | Is supported? |\n|---|---|\n| Download | ❌ |\n| Upload | ❌ |\n| Retry with backoff | ✅ |\n| OAuth2 Authorization code | ❌ (browser-only) |\n| OAuth2 Implicit | ❌ (browser-only) |\n| OAuth2 Password | ✅ |\n| OAuth2 Client Credentials | ✅ |\n| OAuth2 Token Refresh | ✅ |\n| Username/password Authentication | ✅ |\n| Bearer Authentication | ✅ |\n| Basic Authentication | ✅ |\n| API Key Authentication | ✅ |\n| Request/Response Hooks | ✅ |\n| XML Based API | ❌ |\n| JSON Based API | ✅ |\n| POST | ✅ |\n| GET | ✅ |\n| PATCH | ✅ |\n| DELETE | ✅ |\n| PUT | ✅ |\n| HEAD | ✅ |\n| OPTIONS | ✅ |\n\n## Channels\n\nRead more about the [channels generator here](../generators/channels.md).\n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: User API\n version: 1.0.0\nchannels:\n ping:\n address: /ping\n messages:\n pingRequest:\n $ref: '#/components/messages/PingRequest'\n pongResponse:\n $ref: '#/components/messages/PongResponse'\noperations:\n postPing:\n action: send\n channel:\n $ref: '#/channels/ping'\n bindings:\n http:\n method: POST\n reply:\n channel:\n $ref: '#/channels/ping'\n messages:\n - $ref: '#/channels/ping/messages/pongResponse'\ncomponents:\n messages:\n PingRequest:\n payload:\n type: object\n properties:\n message:\n type: string\n PongResponse:\n payload:\n type: object\n properties:\n response:\n type: string\n bindings:\n http:\n statusCode: 200\n```\n\n\n```ts\n// Location depends on the payload generator configurations\nimport { Ping } from './__gen__/payloads/Ping';\nimport { Pong } from './__gen__/payloads/Pong';\n// Location depends on the channel generator configurations\nimport { Protocols } from './__gen__/channels';\nconst { http_client } = Protocols;\nconst { postPingPostRequest } = http_client;\n\n// Create a request payload\nconst pingMessage = new Ping({ message: 'Hello!' });\n\n// Make a simple request\nconst response = await postPingPostRequest({\n payload: pingMessage,\n baseUrl: 'https://api.example.com'\n});\n\n// Access the response\nconsole.log(response.data.response); // The deserialized Pong\nconsole.log(response.status); // 200\nconsole.log(response.headers); // Response headers\nconsole.log(response.rawData); // Raw JSON response\n```\n
\n\n### From OpenAPI\n\nThe `http_client` protocol is also generated directly from an OpenAPI document (2.0/3.0/3.1). Each path + method becomes one function. Configure the `channels` generator with `inputType: 'openapi'` and `protocols: ['http_client']`.\n\nFunction names come from each operation's `operationId` (camel-cased). When an operation has **no** `operationId`, a name is synthesized from the method and path, e.g. `GET /v2/connect/{referenceId}` → `getV2ConnectReferenceId`. Give your operations `operationId`s for the cleanest client.\n\nAs a consumer you work with three generated pieces: the **call functions** (`http_client.ts`), the **request/response body models** (`payload/`), and the **path/query parameter models** (`parameter/`):\n\n```ts\nimport { http_client } from './__gen__/channels';\nimport { PostV2ConnectRequest } from './__gen__/channels/payload/PostV2ConnectRequest';\nimport { GetV2ConnectReferenceIdParameters } from './__gen__/channels/parameter/GetV2ConnectReferenceIdParameters';\n\n// Request with a body: build the model, pass it as `payload`.\nconst created = await http_client.postV2Connect({\n baseUrl: 'https://api.example.com',\n payload: new PostV2ConnectRequest({ returnUrl: 'https://shop.example/return' })\n});\nconsole.log(created.data.connectUrl); // typed response model\n\n// Request with a path parameter: supply it through the parameter model.\nconst connect = await http_client.getV2ConnectReferenceId({\n baseUrl: 'https://api.example.com',\n parameters: new GetV2ConnectReferenceIdParameters({ referenceId: 'ref_123' })\n});\nconsole.log(connect.data.safepayAccountId);\n```\n\nSee the runnable [`openapi-http-client` example](https://github.com/the-codegen-project/cli/tree/main/examples/openapi-http-client) for a complete, self-contained setup.\n\n## Base URL\n\nEvery generated call accepts an optional `baseUrl`. The value used at runtime follows this precedence, highest first:\n\n1. **`context.baseUrl`** passed to the call (e.g. `getUser({ baseUrl: 'https://api.example.com' })`) — always wins.\n2. **The document's first HTTP(S) server** — when the AsyncAPI `servers` (or OpenAPI `servers`) section declares an `http`/`https` server, its URL becomes the generated default. Non-HTTP servers (nats, kafka, …), relative URLs, and OpenAPI server URLs whose variables have no default are skipped.\n3. **`http://localhost:3000`** — the fallback when the document declares no usable HTTP(S) server.\n\nSo a document with `servers: [{ url: 'https://api.example.com' }]` generates clients that target `https://api.example.com` by default, and you only pass `baseUrl` to override it (for example, to point at a staging environment).\n\n## Authentication\n\nThe HTTP client uses a discriminated union for authentication, providing excellent TypeScript autocomplete support.\n\n### Bearer Token\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'bearer',\n token: 'your-jwt-token'\n }\n});\n```\n\n### Basic Authentication\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'basic',\n username: 'user',\n password: 'pass'\n }\n});\n```\n\n### API Key\n\n```typescript\n// API Key in header (default)\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'apiKey',\n key: 'your-api-key',\n name: 'X-API-Key', // Header name (default: 'X-API-Key')\n in: 'header' // 'header' or 'query'\n }\n});\n\n// API Key in query parameter\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'apiKey',\n key: 'your-api-key',\n name: 'api_key',\n in: 'query'\n }\n});\n```\n\n### OAuth2 Client Credentials\n\nFor server-to-server authentication:\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'oauth2',\n flow: 'client_credentials',\n clientId: 'your-client-id',\n clientSecret: 'your-client-secret',\n tokenUrl: 'https://auth.example.com/oauth/token',\n scopes: ['read', 'write'],\n onTokenRefresh: (tokens) => {\n // Called when tokens are obtained/refreshed\n console.log('New access token:', tokens.accessToken);\n }\n }\n});\n```\n\n### OAuth2 Password Flow\n\nFor legacy applications requiring username/password:\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'oauth2',\n flow: 'password',\n clientId: 'your-client-id',\n username: 'user@example.com',\n password: 'user-password',\n tokenUrl: 'https://auth.example.com/oauth/token',\n onTokenRefresh: (tokens) => {\n // Store tokens for future use\n saveTokens(tokens);\n }\n }\n});\n```\n\n### OAuth2 with Pre-obtained Token\n\nFor tokens obtained via browser-based flows (implicit, authorization code):\n\n```typescript\n// Token obtained from browser OAuth flow\nconst accessToken = getTokenFromBrowserFlow();\n\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'oauth2',\n accessToken: accessToken,\n refreshToken: refreshToken, // Optional: for auto-refresh on 401\n tokenUrl: 'https://auth.example.com/oauth/token',\n clientId: 'your-client-id',\n onTokenRefresh: (tokens) => {\n // Update stored tokens\n updateStoredTokens(tokens);\n }\n }\n});\n```\n\n## Retry with Exponential Backoff\n\nConfigure automatic retry for failed requests:\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n retry: {\n maxRetries: 3, // Maximum retry attempts (default: 3)\n initialDelayMs: 1000, // Initial delay before first retry (default: 1000)\n maxDelayMs: 30000, // Maximum delay between retries (default: 30000)\n backoffMultiplier: 2, // Exponential backoff multiplier (default: 2)\n retryableStatusCodes: [408, 429, 500, 502, 503, 504], // Status codes to retry\n retryOnNetworkError: true, // Retry on network failures\n onRetry: (attempt, delay, error) => {\n console.log(`Retry attempt ${attempt} after ${delay}ms: ${error.message}`);\n }\n }\n});\n```\n\n## Error Handling\n\nNon-OK HTTP responses **throw** a typed `HttpError` instead of returning. `HttpError` extends the built-in `Error` and carries the HTTP `status`, `statusText`, and the parsed response `body`:\n\n```typescript\nexport class HttpError extends Error {\n status: number;\n statusText: string;\n body?: unknown; // the parsed JSON error body, when present\n}\n```\n\nConsume it with an `instanceof` check:\n\n```typescript\nimport { getGetUser, HttpError } from './__gen__/channels/http_client';\n\ntry {\n const response = await getGetUser({ baseUrl: 'https://api.example.com' });\n // response.data is the typed, unmarshalled success payload\n} catch (error) {\n if (error instanceof HttpError) {\n console.error(error.status); // e.g. 404\n console.error(error.statusText); // e.g. 'Not Found'\n console.error(error.body); // parsed error body (unknown)\n }\n}\n```\n\n## Request/Response Hooks\n\nCustomize request behavior with hooks:\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n hooks: {\n // Modify request before sending\n beforeRequest: async (params) => {\n console.log('Making request to:', params.url);\n // Add custom header\n return {\n ...params,\n headers: {\n ...params.headers,\n 'X-Request-ID': generateRequestId()\n }\n };\n },\n\n // Replace the default fetch implementation\n makeRequest: async (params) => {\n // Use axios, got, or any HTTP client\n const axiosResponse = await axios({\n url: params.url,\n method: params.method,\n headers: params.headers,\n data: params.body\n });\n return {\n ok: axiosResponse.status >= 200 && axiosResponse.status < 300,\n status: axiosResponse.status,\n statusText: axiosResponse.statusText,\n headers: axiosResponse.headers,\n json: () => axiosResponse.data\n };\n },\n\n // Process response after receiving\n afterResponse: async (response, params) => {\n console.log(`Response ${response.status} from ${params.url}`);\n return response;\n },\n\n // Handle errors\n onError: async (error, params) => {\n console.error(`Request failed: ${error.message}`);\n // Optionally transform the error\n return error;\n }\n }\n});\n```\n\n## Path Parameters\n\nFor operations with path parameters, the generator creates typed parameter classes:\n\n```typescript\nimport { UserItemsParameters } from './__gen__/parameters/UserItemsParameters';\n\n// Create parameters with type safety\nconst params = new UserItemsParameters({\n userId: 'user-123',\n itemId: 456\n});\n\nconst response = await getGetUserItem({\n baseUrl: 'https://api.example.com',\n parameters: params // Replaces {userId} and {itemId} in path\n});\n```\n\n## Typed Headers\n\nFor operations with defined headers, the generator creates typed header classes:\n\n```typescript\nimport { ItemRequestHeaders } from './__gen__/headers/ItemRequestHeaders';\n\nconst headers = new ItemRequestHeaders({\n xCorrelationId: 'corr-123',\n xRequestId: 'req-456'\n});\n\nconst response = await putUpdateUserItem({\n baseUrl: 'https://api.example.com',\n parameters: params,\n payload: itemData,\n requestHeaders: headers // Type-safe headers\n});\n```\n\n## Additional Headers and Query Parameters\n\nAdd custom headers or query parameters to any request:\n\n```typescript\nconst response = await postPingPostRequest({\n payload: message,\n baseUrl: 'https://api.example.com',\n additionalHeaders: {\n 'X-Custom-Header': 'value',\n 'Accept-Language': 'en-US'\n },\n additionalQueryParams: {\n include: 'metadata',\n format: 'detailed'\n }\n});\n```\n\n## Multi-Status Responses\n\nFor operations that return different payloads based on status code, the generator creates union types:\n\n```yaml\n# AsyncAPI spec with multiple response types\noperations:\n getItem:\n reply:\n messages:\n - $ref: '#/components/messages/ItemResponse' # 200\n - $ref: '#/components/messages/NotFoundError' # 404\n```\n\n```typescript\nconst response = await getItemRequest({\n baseUrl: 'https://api.example.com',\n parameters: params\n});\n\n// Response type is union: ItemResponse | NotFoundError\n// Use response.status to discriminate\nif (response.status === 200) {\n console.log('Item:', response.data); // ItemResponse\n} else if (response.status === 404) {\n console.log('Not found:', response.data); // NotFoundError\n}\n```", + content: "# HTTP(S)\n\nHTTP client generator creates type-safe functions for making HTTP requests based on your API specification. It supports various authentication methods, retry logic, and extensibility hooks.\n\nIt is currently available through the generators ([channels](../generators/channels.md)):\n\nThis is available through [AsyncAPI](../inputs/asyncapi.md) ([requires the HTTP `method` binding for operations and `statusCode` for messages](../inputs/asyncapi.md#http-client)) and directly from [OpenAPI](../inputs/openapi.md) documents (see [From OpenAPI](#from-openapi) below).\n\n## TypeScript\n\n| **Feature** | Is supported? |\n|---|---|\n| Download | ❌ |\n| Upload | ❌ |\n| Retry with backoff | ✅ |\n| OAuth2 Authorization code | ❌ (browser-only) |\n| OAuth2 Implicit | ❌ (browser-only) |\n| OAuth2 Password | ✅ |\n| OAuth2 Client Credentials | ✅ |\n| OAuth2 Token Refresh | ✅ |\n| Username/password Authentication | ✅ |\n| Bearer Authentication | ✅ |\n| Basic Authentication | ✅ |\n| API Key Authentication | ✅ |\n| Request/Response Hooks | ✅ |\n| XML Based API | ❌ |\n| JSON Based API | ✅ |\n| POST | ✅ |\n| GET | ✅ |\n| PATCH | ✅ |\n| DELETE | ✅ |\n| PUT | ✅ |\n| HEAD | ✅ |\n| OPTIONS | ✅ |\n\n## Channels\n\nRead more about the [channels generator here](../generators/channels.md).\n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: User API\n version: 1.0.0\nchannels:\n ping:\n address: /ping\n messages:\n pingRequest:\n $ref: '#/components/messages/PingRequest'\n pongResponse:\n $ref: '#/components/messages/PongResponse'\noperations:\n postPing:\n action: send\n channel:\n $ref: '#/channels/ping'\n bindings:\n http:\n method: POST\n reply:\n channel:\n $ref: '#/channels/ping'\n messages:\n - $ref: '#/channels/ping/messages/pongResponse'\ncomponents:\n messages:\n PingRequest:\n payload:\n type: object\n properties:\n message:\n type: string\n PongResponse:\n payload:\n type: object\n properties:\n response:\n type: string\n bindings:\n http:\n statusCode: 200\n```\n\n\n```ts\n// Location depends on the payload generator configurations\nimport { PingRequest } from './__gen__/payloads/PingRequest';\nimport { PongResponse } from './__gen__/payloads/PongResponse';\n// Location depends on the channel generator configurations\nimport { http_client } from './__gen__/channels';\nconst { postPostPing } = http_client;\n\n// Create a request payload\nconst pingMessage = new PingRequest({ message: 'Hello!' });\n\n// Make a simple request\nconst response = await postPostPing({\n payload: pingMessage,\n baseUrl: 'https://api.example.com'\n});\n\n// Access the response\nconsole.log(response.data.response); // The deserialized Pong\nconsole.log(response.status); // 200\nconsole.log(response.headers); // Response headers\nconsole.log(response.rawData); // Raw JSON response\n```\n
\n\n### From OpenAPI\n\nThe `http_client` protocol is also generated directly from an OpenAPI document (2.0/3.0/3.1). Each path + method becomes one function. Configure the `channels` generator with `inputType: 'openapi'` and `protocols: ['http_client']`.\n\nFunction names come from each operation's `operationId` (camel-cased). When an operation has **no** `operationId`, a name is synthesized from the method and path, e.g. `GET /v2/connect/{referenceId}` → `getV2ConnectReferenceId`. Give your operations `operationId`s for the cleanest client.\n\nAs a consumer you work with three generated pieces: the **call functions** (`http_client.ts`), the **request/response body models** (`payload/`), and the **path/query parameter models** (`parameter/`):\n\n```ts\nimport { http_client } from './__gen__/channels';\nimport { PostV2ConnectRequest } from './__gen__/channels/payload/PostV2ConnectRequest';\nimport { GetV2ConnectReferenceIdParameters } from './__gen__/channels/parameter/GetV2ConnectReferenceIdParameters';\n\n// Request with a body: build the model, pass it as `payload`.\nconst created = await http_client.postV2Connect({\n baseUrl: 'https://api.example.com',\n payload: new PostV2ConnectRequest({ returnUrl: 'https://shop.example/return' })\n});\nconsole.log(created.data.connectUrl); // typed response model\n\n// Request with a path parameter: supply it through the parameter model.\nconst connect = await http_client.getV2ConnectReferenceId({\n baseUrl: 'https://api.example.com',\n parameters: new GetV2ConnectReferenceIdParameters({ referenceId: 'ref_123' })\n});\nconsole.log(connect.data.safepayAccountId);\n```\n\nSee the runnable [`openapi-http-client` example](https://github.com/the-codegen-project/cli/tree/main/examples/openapi-http-client) for a complete, self-contained setup.\n\n## Base URL\n\nEvery generated call accepts an optional `baseUrl`. The value used at runtime follows this precedence, highest first:\n\n1. **`context.baseUrl`** passed to the call (e.g. `getUser({ baseUrl: 'https://api.example.com' })`) — always wins.\n2. **The document's first HTTP(S) server** — when the AsyncAPI `servers` (or OpenAPI `servers`) section declares an `http`/`https` server, its URL becomes the generated default. Non-HTTP servers (nats, kafka, …), relative URLs, and OpenAPI server URLs whose variables have no default are skipped.\n3. **`http://localhost:3000`** — the fallback when the document declares no usable HTTP(S) server.\n\nSo a document with `servers: [{ url: 'https://api.example.com' }]` generates clients that target `https://api.example.com` by default, and you only pass `baseUrl` to override it (for example, to point at a staging environment).\n\n## Authentication\n\nThe HTTP client uses a discriminated union for authentication, providing excellent TypeScript autocomplete support.\n\n### Bearer Token\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'bearer',\n token: 'your-jwt-token'\n }\n});\n```\n\n### Basic Authentication\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'basic',\n username: 'user',\n password: 'pass'\n }\n});\n```\n\n### API Key\n\n```typescript\n// API Key in header (default)\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'apiKey',\n key: 'your-api-key',\n name: 'X-API-Key', // Header name (default: 'X-API-Key')\n in: 'header' // 'header' or 'query'\n }\n});\n\n// API Key in query parameter\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'apiKey',\n key: 'your-api-key',\n name: 'api_key',\n in: 'query'\n }\n});\n```\n\n### OAuth2 Client Credentials\n\nFor server-to-server authentication:\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'oauth2',\n flow: 'client_credentials',\n clientId: 'your-client-id',\n clientSecret: 'your-client-secret',\n tokenUrl: 'https://auth.example.com/oauth/token',\n scopes: ['read', 'write'],\n onTokenRefresh: (tokens) => {\n // Called when tokens are obtained/refreshed\n console.log('New access token:', tokens.accessToken);\n }\n }\n});\n```\n\n### OAuth2 Password Flow\n\nFor legacy applications requiring username/password:\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'oauth2',\n flow: 'password',\n clientId: 'your-client-id',\n username: 'user@example.com',\n password: 'user-password',\n tokenUrl: 'https://auth.example.com/oauth/token',\n onTokenRefresh: (tokens) => {\n // Store tokens for future use\n saveTokens(tokens);\n }\n }\n});\n```\n\n### OAuth2 with Pre-obtained Token\n\nFor tokens obtained via browser-based flows (implicit, authorization code):\n\n```typescript\n// Token obtained from browser OAuth flow\nconst accessToken = getTokenFromBrowserFlow();\n\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n auth: {\n type: 'oauth2',\n accessToken: accessToken,\n refreshToken: refreshToken, // Optional: for auto-refresh on 401\n tokenUrl: 'https://auth.example.com/oauth/token',\n clientId: 'your-client-id',\n onTokenRefresh: (tokens) => {\n // Update stored tokens\n updateStoredTokens(tokens);\n }\n }\n});\n```\n\n## Retry with Exponential Backoff\n\nConfigure automatic retry for failed requests:\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n retry: {\n maxRetries: 3, // Maximum retry attempts (default: 3)\n initialDelayMs: 1000, // Initial delay before first retry (default: 1000)\n maxDelayMs: 30000, // Maximum delay between retries (default: 30000)\n backoffMultiplier: 2, // Exponential backoff multiplier (default: 2)\n retryableStatusCodes: [408, 429, 500, 502, 503, 504], // Status codes to retry\n retryOnNetworkError: true, // Retry on network failures\n onRetry: (attempt, delay, error) => {\n console.log(`Retry attempt ${attempt} after ${delay}ms: ${error.message}`);\n }\n }\n});\n```\n\n## Error Handling\n\nNon-OK HTTP responses **throw** a typed `HttpError` instead of returning. `HttpError` extends the built-in `Error` and carries the HTTP `status`, `statusText`, and the parsed response `body`:\n\n```typescript\nexport class HttpError extends Error {\n status: number;\n statusText: string;\n body?: unknown; // the parsed JSON error body, when present\n}\n```\n\nConsume it with an `instanceof` check:\n\n```typescript\nimport { getGetUser, HttpError } from './__gen__/channels/http_client';\n\ntry {\n const response = await getGetUser({ baseUrl: 'https://api.example.com' });\n // response.data is the typed, unmarshalled success payload\n} catch (error) {\n if (error instanceof HttpError) {\n console.error(error.status); // e.g. 404\n console.error(error.statusText); // e.g. 'Not Found'\n console.error(error.body); // parsed error body (unknown)\n }\n}\n```\n\n## Request/Response Hooks\n\nCustomize request behavior with hooks:\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n hooks: {\n // Modify request before sending\n beforeRequest: async (params) => {\n console.log('Making request to:', params.url);\n // Add custom header\n return {\n ...params,\n headers: {\n ...params.headers,\n 'X-Request-ID': generateRequestId()\n }\n };\n },\n\n // Replace the default fetch implementation\n makeRequest: async (params) => {\n // Use axios, got, or any HTTP client\n const axiosResponse = await axios({\n url: params.url,\n method: params.method,\n headers: params.headers,\n data: params.body\n });\n return {\n ok: axiosResponse.status >= 200 && axiosResponse.status < 300,\n status: axiosResponse.status,\n statusText: axiosResponse.statusText,\n headers: axiosResponse.headers,\n json: () => axiosResponse.data\n };\n },\n\n // Process response after receiving\n afterResponse: async (response, params) => {\n console.log(`Response ${response.status} from ${params.url}`);\n return response;\n },\n\n // Handle errors\n onError: async (error, params) => {\n console.error(`Request failed: ${error.message}`);\n // Optionally transform the error\n return error;\n }\n }\n});\n```\n\n## Path Parameters\n\nFor operations with path parameters, the generator creates typed parameter classes:\n\n```typescript\nimport { UserItemsParameters } from './__gen__/parameters/UserItemsParameters';\n\n// Create parameters with type safety\nconst params = new UserItemsParameters({\n userId: 'user-123',\n itemId: 456\n});\n\nconst response = await getGetUserItem({\n baseUrl: 'https://api.example.com',\n parameters: params // Replaces {userId} and {itemId} in path\n});\n```\n\n## Typed Headers\n\nFor operations with defined headers, the generator creates typed header classes:\n\n```typescript\nimport { ItemRequestHeaders } from './__gen__/headers/ItemRequestHeaders';\n\nconst headers = new ItemRequestHeaders({\n xCorrelationId: 'corr-123',\n xRequestId: 'req-456'\n});\n\nconst response = await putUpdateUserItem({\n baseUrl: 'https://api.example.com',\n parameters: params,\n payload: itemData,\n requestHeaders: headers // Type-safe headers\n});\n```\n\n## Additional Headers and Query Parameters\n\nAdd custom headers or query parameters to any request:\n\n```typescript\nconst response = await postPostPing({\n payload: message,\n baseUrl: 'https://api.example.com',\n additionalHeaders: {\n 'X-Custom-Header': 'value',\n 'Accept-Language': 'en-US'\n },\n additionalQueryParams: {\n include: 'metadata',\n format: 'detailed'\n }\n});\n```\n\n## Multi-Status Responses\n\nFor operations that return different payloads based on status code, the generator creates union types:\n\n```yaml\n# AsyncAPI spec with multiple response types\noperations:\n getItem:\n reply:\n messages:\n - $ref: '#/components/messages/ItemResponse' # 200\n - $ref: '#/components/messages/NotFoundError' # 404\n```\n\n```typescript\nconst response = await getItemRequest({\n baseUrl: 'https://api.example.com',\n parameters: params\n});\n\n// Response type is union: ItemResponse | NotFoundError\n// Use response.status to discriminate\nif (response.status === 200) {\n console.log('Item:', response.data); // ItemResponse\n} else if (response.status === 404) {\n console.log('Not found:', response.data); // NotFoundError\n}\n```", }, "protocols/kafka": { title: "Kafka", - content: "# Kafka\nKafka is currently supported through the following generators ([channels](#channels)):\n\n| **Languages** | Publish | Subscribe\n|---|---|---|\n| TypeScript | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md). If you use \n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n publishUserSignups:\n action: send\n channel:\n $ref: '#/channels/userSignups'\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n\n```\n\n\n```ts\nimport { Kafka } from 'kafkajs';\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the channel generator configurations\nimport { Protocols } from './__gen__/channels';\nconst { kafka } = Protocols;\nconst { consumeFromConsumeUserSignups, produceToPublishUserSignups } = kafka;\n\n/**\n * Setup the regular client\n */\nconst kafkaClient = new Kafka({\n clientId: 'test',\n brokers: ['localhost:9093'],\n});\n\nconst myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\n\n// Consume the messages with the generated channel function\nconst consumerCallback = async (\n err,\n msg: UserSignedUp | undefined, \n parameters: UserSignedUpParameters | undefined, \n kafkaMsg: EachMessagePayload | undefined\n ) => {\n // Do stuff once you consumer from the topic\n};\nconst consumer = await consumeFromConsumeUserSignups(\n consumerCallback,\n myParameters, \n kafkaClient, \n {\n fromBeginning: true, \n groupId: 'testId1'\n }\n);\n\n// Produce the messages with the generated channel function\nconst producer = await produceToPublishUserSignups(myPayload, kafkaClient);\n```\t\n
", + content: "# Kafka\nKafka is currently supported through the following generators ([channels](#channels)):\n\n| **Languages** | Publish | Subscribe\n|---|---|---|\n| TypeScript | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md). If you use \n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n publishUserSignups:\n action: send\n channel:\n $ref: '#/channels/userSignups'\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n\n```\n\n\n```ts\nimport { Kafka } from 'kafkajs';\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the channel generator configurations\nimport { kafka } from './__gen__/channels';\nconst { consumeFromConsumeUserSignups, produceToPublishUserSignups } = kafka;\n\n/**\n * Setup the regular client\n */\nconst kafkaClient = new Kafka({\n clientId: 'test',\n brokers: ['localhost:9093'],\n});\n\nconst myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\n\n// Consume the messages with the generated channel function\nconst consumerCallback = (\n err?: Error,\n msg?: UserSignedup,\n parameters?: UserSignedupParameters,\n headers?: UserSignedupHeaders,\n kafkaMsg?: EachMessagePayload\n ) => {\n // Do stuff once you consume from the topic\n};\nconst consumer = await consumeFromConsumeUserSignups({\n onDataCallback: consumerCallback,\n parameters: myParameters,\n kafka: kafkaClient,\n options: {\n fromBeginning: true,\n groupId: 'testId1'\n }\n});\n\n// Produce the messages with the generated channel function\nconst producer = await produceToPublishUserSignups({\n message: myPayload,\n parameters: myParameters,\n kafka: kafkaClient\n});\n```\t\n
", }, "protocols/mqtt": { title: "MQTT", - content: "# MQTT\n`MQTT` is currently available through the generators ([channels](#channels)):\n\n| **Languages** | publish | subscribe |\n|---|---|---|\n| TypeScript | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## ⚠️ Important: MQTT v5 Required for Headers\n\nWhen using headers with MQTT, you MUST configure your MQTT client to use protocol version 5:\n\n```typescript\n// ✅ REQUIRED for header support\nconst client = await MqttClient.connectAsync(\"mqtt://0.0.0.0:1883\", { \n protocolVersion: 5 \n});\n\n// ❌ Will NOT work with headers (defaults to MQTT v3.1.1)\nconst client = await MqttClient.connectAsync(\"mqtt://0.0.0.0:1883\");\n```\n\n**Why MQTT v5 is Required:**\n- MQTT v3.1.1 (default) does not support user properties\n- MQTT v5 introduces user properties which are used for header transmission\n- Both publish and subscribe operations require MQTT v5 for full header functionality\n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n publishUserSignups:\n action: send\n channel:\n $ref: '#/channels/userSignups'\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n\n```\n\n\n```ts\nimport * as MqttClient from 'mqtt';\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the header generator configurations (if using headers)\nimport { UserSignedUpHeaders } from './__gen__/headers/UserSignedUpHeaders';\n// Location depends on the channel generator configurations\nimport { Protocols } from './__gen__/channels';\nconst { mqtt } = Protocols;\nconst { publishToUserSignedup, subscribeToConsumeUserSignups } = mqtt;\n\n/**\n * Setup the MQTT client with v5 protocol for header support\n */\nconst client = await MqttClient.connectAsync(\"mqtt://0.0.0.0:1883\", { \n protocolVersion: 5 // REQUIRED for headers\n});\n\nconst myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\nconst myHeaders = new UserSignedUpHeaders({ xTestHeader: 'my-header-value' });\n\n// Subscribe to messages with the generated channel function\nawait subscribeToConsumeUserSignups({\n onDataCallback: (params) => {\n const { err, msg, headers, mqttMsg } = params;\n if (err) {\n console.error('Error receiving message:', err);\n return;\n }\n console.log('Received message:', msg);\n console.log('Received headers:', headers); // Available with MQTT v5\n console.log('Raw MQTT packet:', mqttMsg);\n },\n mqtt: client\n});\n\n// Publish messages with the generated channel function\nawait publishToUserSignedup({\n message: myPayload,\n headers: myHeaders, // Headers sent as MQTT v5 user properties\n mqtt: client\n});\n```\t\n
", + content: "# MQTT\n`MQTT` is currently available through the generators ([channels](#channels)):\n\n| **Languages** | publish | subscribe |\n|---|---|---|\n| TypeScript | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## ⚠️ Important: MQTT v5 Required for Headers\n\nWhen using headers with MQTT, you MUST configure your MQTT client to use protocol version 5:\n\n```typescript\n// ✅ REQUIRED for header support\nconst client = await MqttClient.connectAsync(\"mqtt://0.0.0.0:1883\", { \n protocolVersion: 5 \n});\n\n// ❌ Will NOT work with headers (defaults to MQTT v3.1.1)\nconst client = await MqttClient.connectAsync(\"mqtt://0.0.0.0:1883\");\n```\n\n**Why MQTT v5 is Required:**\n- MQTT v3.1.1 (default) does not support user properties\n- MQTT v5 introduces user properties which are used for header transmission\n- Both publish and subscribe operations require MQTT v5 for full header functionality\n\n## Channels\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you the right payload and parameter are used. \n\n\n\n \n \n \n \n\n\n \n \n \n \n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: Account Service\n version: 1.0.0\n description: This service is in charge of processing user signups\nchannels:\n userSignups:\n address: user/signedup\n messages:\n userSignedup:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n publishUserSignups:\n action: send\n channel:\n $ref: '#/channels/userSignups'\n consumeUserSignups:\n action: receive\n channel:\n $ref: '#/channels/userSignups'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n displayName:\n type: string\n description: Name of the user\n email:\n type: string\n format: email\n description: Email of the user\n\n```\n\n\n```ts\nimport * as MqttClient from 'mqtt';\n// Location depends on the payload generator configurations\nimport { UserSignedup } from './__gen__/payloads/UserSignedup';\n// Location depends on the header generator configurations (if using headers)\nimport { UserSignedUpHeaders } from './__gen__/headers/UserSignedUpHeaders';\n// Location depends on the channel generator configurations\nimport { mqtt } from './__gen__/channels';\nconst { publishToUserSignedup, subscribeToConsumeUserSignups } = mqtt;\n\n/**\n * Setup the MQTT client with v5 protocol for header support\n */\nconst client = await MqttClient.connectAsync(\"mqtt://0.0.0.0:1883\", { \n protocolVersion: 5 // REQUIRED for headers\n});\n\nconst myPayload = new UserSignedup({displayName: 'test', email: 'test@test.dk'});\nconst myHeaders = new UserSignedUpHeaders({ xTestHeader: 'my-header-value' });\n\n// Subscribe to messages with the generated channel function\nawait subscribeToConsumeUserSignups({\n onDataCallback: (params) => {\n const { err, msg, headers, mqttMsg } = params;\n if (err) {\n console.error('Error receiving message:', err);\n return;\n }\n console.log('Received message:', msg);\n console.log('Received headers:', headers); // Available with MQTT v5\n console.log('Raw MQTT packet:', mqttMsg);\n },\n mqtt: client\n});\n\n// Publish messages with the generated channel function\nawait publishToUserSignedup({\n message: myPayload,\n headers: myHeaders, // Headers sent as MQTT v5 user properties\n mqtt: client\n});\n```\t\n
", }, "protocols/nats": { title: "NATS", @@ -136,7 +136,7 @@ export const docs: Record = { }, "protocols/websocket": { title: "WebSocket", - content: "# WebSocket\n\nWebSocket is currently supported through the following generators ([channels](#channels)):\n\n| **Languages** | Client Publish | Client Subscribe | Server Register |\n|---|---|---|---|\n| TypeScript | ✅ | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## ⚠️ Important: External Connection Management\n\nThe WebSocket generator assumes that WebSocket connections are managed externally by your application. The generated functions accept already-connected WebSocket instances and focus on message handling rather than connection establishment.\n\n```typescript\n// ✅ You manage the connection\nconst clientWs = new WebSocket('ws://localhost:8080/user/events');\nconst server = new WebSocketServer({ port: 8080 });\n\n// ✅ Generated functions use your connections\nawait publishMessage({ message, parameters, ws: clientWs });\nregisterHandler({ wss: server, onConnection, onMessage });\n```\n\n**Why External Connection Management:**\n- Gives you full control over connection lifecycle\n- Allows custom authentication and authorization\n- Enables connection pooling and reconnection strategies\n- Separates transport concerns from message handling\n\n## Channels\n\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you use the right payload and parameters.\n\n\n\n \n \n \n \n\n\n \n \n\n\n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: User Service\n version: 1.0.0\n description: WebSocket-based user event system\nchannels:\n userEvents:\n address: user/events/{userId}\n parameters:\n userId:\n description: The user identifier\n messages:\n userSignedUp:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n sendUserEvent:\n action: send\n channel:\n $ref: '#/channels/userEvents'\n receiveUserEvent:\n action: receive\n channel:\n $ref: '#/channels/userEvents'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n userId:\n type: string\n email:\n type: string\n required:\n - userId\n - email\n```\n\n\n\n**Client-side publishing:**\n```typescript\nimport { publishToSendUserEvent } from './channels';\nimport { UserSignedUp } from './payloads';\nimport { UserEventsParameters } from './parameters';\nimport WebSocket from 'ws';\n\n// Create connection (your responsibility)\nconst ws = new WebSocket('ws://localhost:8080/user/events/user123');\n\nawait ws.on('open', async () => {\n // Use generated publish function\n await publishToSendUserEvent({\n message: new UserSignedUp({\n userId: 'user123',\n email: 'user@example.com'\n }),\n parameters: new UserEventsParameters({\n userId: 'user123'\n }),\n ws\n });\n});\n```\n\n**Client-side subscribing:**\n```typescript\nimport { subscribeToReceiveUserEvent } from './channels';\n\nws.on('open', () => {\n // Set up subscription\n subscribeToReceiveUserEvent({\n onDataCallback: (params) => {\n const { err, msg, parameters, ws } = params;\n if (err) {\n console.error('Error:', err);\n return;\n }\n \n console.log('Received:', msg?.marshal());\n console.log('User ID:', parameters?.userId);\n },\n parameters: new UserEventsParameters({\n userId: 'user123'\n }),\n ws\n });\n});\n```\n\n**Server-side handling:**\n```typescript\nimport { registerSendUserEvent } from './channels';\nimport WebSocket from 'ws';\n\n// Create server (your responsibility)\nconst wss = new WebSocket.WebSocketServer({ port: 8080 });\n\n// Register message handler\nregisterSendUserEvent({\n wss,\n onConnection: (params) => {\n const { parameters, ws, request } = params;\n console.log(`User ${parameters.userId} connected`);\n \n // Perform authentication, logging, etc.\n },\n onMessage: (params) => {\n const { message, ws } = params;\n console.log('Received message:', message.marshal());\n \n // Process the message\n // Send response if needed\n const response = new UserSignedUp({\n userId: message.userId,\n email: 'updated@example.com'\n });\n ws.send(response.marshal());\n }\n});\n```\n\n
\n\n## Function Types\n\nThe WebSocket generator creates three types of functions:\n\n### Client Functions\n\n**Publish Functions** (`publishTo*`):\n- Send messages from client to server\n- Require connected WebSocket instance\n- Handle message serialization automatically\n- Return Promise for async operation\n\n**Subscribe Functions** (`subscribeTo*`):\n- Listen for messages from server\n- Set up message handlers on WebSocket\n- Handle message parsing and validation\n- Support error handling through callbacks\n\n### Server Functions\n\n**Register Functions** (`register*`):\n- Handle incoming client connections\n- Process messages from clients\n- Support both connection and message callbacks\n- Enable URL parameter extraction\n\n## URL Pattern Matching\n\nThe WebSocket generator automatically creates URL pattern matching for channels with parameters:\n\n```yaml\n# AsyncAPI Channel\nchannels:\n userEvents:\n address: user/events/{userId}/{eventType}\n```\n\n```typescript\n// Generated pattern matching\n// Matches: /user/events/123/signup\n// Extracts: userId=\"123\", eventType=\"signup\"\n\nregisterSendUserEvent({\n wss,\n onConnection: (params) => {\n // Parameters automatically extracted from URL\n const { parameters } = params;\n console.log(parameters.userId); // \"123\"\n console.log(parameters.eventType); // \"signup\"\n },\n onMessage: (params) => {\n // Handle the message\n }\n});\n```\n\n## Error Handling\n\nThe WebSocket generator includes comprehensive error handling:\n\n```typescript\n// Client-side error handling\nsubscribeToReceiveUserEvent({\n onDataCallback: (params) => {\n const { err, msg } = params;\n if (err) {\n // Handle parsing errors, validation errors, etc.\n console.error('Message error:', err.message);\n return;\n }\n // Process successful message\n },\n ws\n});\n\n// Connection state checking\nawait publishToSendUserEvent({\n message,\n parameters,\n ws // Function checks if WebSocket is open\n});\n```\n\n## Best Practices\n\n### Connection Management\n```typescript\n// ✅ Handle connection lifecycle\nconst ws = new WebSocket('ws://localhost:8080/user/events/123');\n\nws.on('open', () => {\n // Set up subscriptions after connection opens\n subscribeToReceiveUserEvent({ ... });\n});\n\nws.on('close', (code, reason) => {\n // Handle disconnection, implement reconnection logic\n});\n\nws.on('error', (error) => {\n // Handle connection errors\n});\n```\n\n### Message Validation\n```typescript\n// ✅ Use validation in production\nsubscribeToReceiveUserEvent({\n onDataCallback: (params) => {\n const { err, msg } = params;\n if (err) {\n // Generated functions include validation errors\n console.error('Invalid message received:', err);\n return;\n }\n // Message is guaranteed to be valid\n },\n skipMessageValidation: false, // Enable validation (default)\n ws\n});\n```\n\n### Server Setup\n```typescript\n// ✅ Proper server setup with error handling\nconst wss = new WebSocket.WebSocketServer({ \n port: 8080,\n verifyClient: (info) => {\n // Implement authentication logic\n return true;\n }\n});\n\nregisterSendUserEvent({\n wss,\n onConnection: (params) => {\n const { parameters, ws, request } = params;\n \n // Validate parameters\n if (!parameters.userId) {\n ws.close(1008, 'Invalid user ID');\n return;\n }\n \n // Set up user session\n },\n onMessage: (params) => {\n const { message, ws } = params;\n \n try {\n // Process message safely\n } catch (error) {\n ws.close(1011, 'Processing error');\n }\n }\n});\n```\n\n## Dependencies\n\nThe generated WebSocket code requires the `ws` library:\n\n```bash\nnpm install ws\nnpm install @types/ws # For TypeScript projects\n```", + content: "# WebSocket\n\nWebSocket is currently supported through the following generators ([channels](#channels)):\n\n| **Languages** | Client Publish | Client Subscribe | Server Register |\n|---|---|---|---|\n| TypeScript | ✅ | ✅ | ✅ |\n\nAll of this is available through [AsyncAPI](../inputs/asyncapi.md).\n\n## ⚠️ Important: External Connection Management\n\nThe WebSocket generator assumes that WebSocket connections are managed externally by your application. The generated functions accept already-connected WebSocket instances and focus on message handling rather than connection establishment.\n\n```typescript\n// ✅ You manage the connection\nconst clientWs = new WebSocket('ws://localhost:8080/user/events');\nconst server = new WebSocketServer({ port: 8080 });\n\n// ✅ Generated functions use your connections\nawait publishMessage({ message, parameters, ws: clientWs });\nregisterHandler({ wss: server, onConnection, onMessage });\n```\n\n**Why External Connection Management:**\n- Gives you full control over connection lifecycle\n- Allows custom authentication and authorization\n- Enables connection pooling and reconnection strategies\n- Separates transport concerns from message handling\n\n## Channels\n\nRead more about the [channels](../generators/channels.md) generator here before continuing.\n\nThis generator provides support functions for each resource ensuring you use the right payload and parameters.\n\n\n\n \n \n \n \n\n\n \n \n\n\n\n
Input (AsyncAPI)Using the code
\n\n```yaml\nasyncapi: 3.0.0\ninfo:\n title: User Service\n version: 1.0.0\n description: WebSocket-based user event system\nchannels:\n userEvents:\n address: user/events/{userId}\n parameters:\n userId:\n description: The user identifier\n messages:\n userSignedUp:\n $ref: '#/components/messages/UserSignedUp'\noperations:\n sendUserEvent:\n action: send\n channel:\n $ref: '#/channels/userEvents'\n receiveUserEvent:\n action: receive\n channel:\n $ref: '#/channels/userEvents'\ncomponents:\n messages:\n UserSignedUp:\n payload:\n type: object\n properties:\n userId:\n type: string\n email:\n type: string\n required:\n - userId\n - email\n```\n\n\n\n**Client-side publishing:**\n```typescript\nimport { publishToSendUserEvent } from './channels';\nimport { UserSignedUp } from './payloads';\nimport { UserEventsParameters } from './parameters';\nimport WebSocket from 'ws';\n\n// Create connection (your responsibility)\nconst ws = new WebSocket('ws://localhost:8080/user/events/user123');\n\nawait ws.on('open', async () => {\n // Use generated publish function\n // Channel parameters are part of the connection URL, so the publish\n // function only takes the message and the socket.\n await publishToSendUserEvent({\n message: new UserSignedUp({\n userId: 'user123',\n email: 'user@example.com'\n }),\n ws\n });\n});\n```\n\n**Client-side subscribing:**\n```typescript\nimport { subscribeToReceiveUserEvent } from './channels';\n\nws.on('open', () => {\n // Set up subscription\n subscribeToReceiveUserEvent({\n onDataCallback: (params) => {\n const { err, msg, parameters, ws } = params;\n if (err) {\n console.error('Error:', err);\n return;\n }\n \n console.log('Received:', msg?.marshal());\n console.log('User ID:', parameters?.userId);\n },\n parameters: new UserEventsParameters({\n userId: 'user123'\n }),\n ws\n });\n});\n```\n\n**Server-side handling:**\n```typescript\nimport { registerSendUserEvent } from './channels';\nimport WebSocket from 'ws';\n\n// Create server (your responsibility)\nconst wss = new WebSocket.WebSocketServer({ port: 8080 });\n\n// Register message handler\nregisterSendUserEvent({\n wss,\n onConnection: (params) => {\n const { parameters, ws, request } = params;\n console.log(`User ${parameters.userId} connected`);\n \n // Perform authentication, logging, etc.\n },\n onMessage: (params) => {\n const { message, ws } = params;\n console.log('Received message:', message.marshal());\n \n // Process the message\n // Send response if needed\n const response = new UserSignedUp({\n userId: message.userId,\n email: 'updated@example.com'\n });\n ws.send(response.marshal());\n }\n});\n```\n\n
\n\n## Function Types\n\nThe WebSocket generator creates three types of functions:\n\n### Client Functions\n\n**Publish Functions** (`publishTo*`):\n- Send messages from client to server\n- Require connected WebSocket instance\n- Handle message serialization automatically\n- Return Promise for async operation\n\n**Subscribe Functions** (`subscribeTo*`):\n- Listen for messages from server\n- Set up message handlers on WebSocket\n- Handle message parsing and validation\n- Support error handling through callbacks\n\n### Server Functions\n\n**Register Functions** (`register*`):\n- Handle incoming client connections\n- Process messages from clients\n- Support both connection and message callbacks\n- Enable URL parameter extraction\n\n## URL Pattern Matching\n\nThe WebSocket generator automatically creates URL pattern matching for channels with parameters:\n\n```yaml\n# AsyncAPI Channel\nchannels:\n userEvents:\n address: user/events/{userId}/{eventType}\n```\n\n```typescript\n// Generated pattern matching\n// Matches: /user/events/123/signup\n// Extracts: userId=\"123\", eventType=\"signup\"\n\nregisterSendUserEvent({\n wss,\n onConnection: (params) => {\n // Parameters automatically extracted from URL\n const { parameters } = params;\n console.log(parameters.userId); // \"123\"\n console.log(parameters.eventType); // \"signup\"\n },\n onMessage: (params) => {\n // Handle the message\n }\n});\n```\n\n## Error Handling\n\nThe WebSocket generator includes comprehensive error handling:\n\n```typescript\n// Client-side error handling\nsubscribeToReceiveUserEvent({\n onDataCallback: (params) => {\n const { err, msg } = params;\n if (err) {\n // Handle parsing errors, validation errors, etc.\n console.error('Message error:', err.message);\n return;\n }\n // Process successful message\n },\n ws\n});\n\n// Connection state checking\nawait publishToSendUserEvent({\n message,\n parameters,\n ws // Function checks if WebSocket is open\n});\n```\n\n## Best Practices\n\n### Connection Management\n```typescript\n// ✅ Handle connection lifecycle\nconst ws = new WebSocket('ws://localhost:8080/user/events/123');\n\nws.on('open', () => {\n // Set up subscriptions after connection opens\n subscribeToReceiveUserEvent({ ... });\n});\n\nws.on('close', (code, reason) => {\n // Handle disconnection, implement reconnection logic\n});\n\nws.on('error', (error) => {\n // Handle connection errors\n});\n```\n\n### Message Validation\n```typescript\n// ✅ Use validation in production\nsubscribeToReceiveUserEvent({\n onDataCallback: (params) => {\n const { err, msg } = params;\n if (err) {\n // Generated functions include validation errors\n console.error('Invalid message received:', err);\n return;\n }\n // Message is guaranteed to be valid\n },\n skipMessageValidation: false, // Enable validation (default)\n ws\n});\n```\n\n### Server Setup\n```typescript\n// ✅ Proper server setup with error handling\nconst wss = new WebSocket.WebSocketServer({ \n port: 8080,\n verifyClient: (info) => {\n // Implement authentication logic\n return true;\n }\n});\n\nregisterSendUserEvent({\n wss,\n onConnection: (params) => {\n const { parameters, ws, request } = params;\n \n // Validate parameters\n if (!parameters.userId) {\n ws.close(1008, 'Invalid user ID');\n return;\n }\n \n // Set up user session\n },\n onMessage: (params) => {\n const { message, ws } = params;\n \n try {\n // Process message safely\n } catch (error) {\n ws.close(1011, 'Processing error');\n }\n }\n});\n```\n\n## Dependencies\n\nThe generated WebSocket code requires the `ws` library:\n\n```bash\nnpm install ws\nnpm install @types/ws # For TypeScript projects\n```", }, "telemetry": { title: "Telemetry", @@ -144,7 +144,7 @@ export const docs: Record = { }, "usage": { title: "CLI Usage", - content: "# CLI Usage\n\n\n```sh-session\n$ npm install -g @the-codegen-project/cli\n$ codegen COMMAND\nrunning command...\n$ codegen (--version)\n@the-codegen-project/cli/0.80.0 linux-x64 node-v22.23.1\n$ codegen --help [COMMAND]\nUSAGE\n $ codegen COMMAND\n...\n```\n\n\n## Table of contents\n\n\n* [CLI Usage](#cli-usage)\n\n\n## Commands\n\n\n* [`codegen autocomplete [SHELL]`](#codegen-autocomplete-shell)\n* [`codegen generate [FILE]`](#codegen-generate-file)\n* [`codegen help [COMMAND]`](#codegen-help-command)\n* [`codegen init`](#codegen-init)\n* [`codegen telemetry ACTION`](#codegen-telemetry-action)\n* [`codegen version`](#codegen-version)\n\n## `codegen autocomplete [SHELL]`\n\nDisplay autocomplete installation instructions.\n\n```\nUSAGE\n $ codegen autocomplete [SHELL] [-r]\n\nARGUMENTS\n SHELL (zsh|bash|powershell) Shell type\n\nFLAGS\n -r, --refresh-cache Refresh cache (ignores displaying instructions)\n\nDESCRIPTION\n Display autocomplete installation instructions.\n\nEXAMPLES\n $ codegen autocomplete\n\n $ codegen autocomplete bash\n\n $ codegen autocomplete zsh\n\n $ codegen autocomplete powershell\n\n $ codegen autocomplete --refresh-cache\n```\n\n_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.45/src/commands/autocomplete/index.ts)_\n\n## `codegen generate [FILE]`\n\nGenerate code based on your configuration, use `init` to get started, `generate` to generate code from the configuration.\n\n```\nUSAGE\n $ codegen generate [FILE] [--json] [--no-color] [--debug | [-q | -v | --silent] | ] [--help] [-w] [-p\n ]\n\nARGUMENTS\n FILE Path or URL to the configuration file, defaults to root of where the command is run\n\nFLAGS\n -p, --watchPath= Optional path to watch for changes when --watch flag is used. If not provided, watches the\n input file from configuration\n -q, --quiet Only show errors and warnings\n -v, --verbose Show detailed output\n -w, --watch Watch for file changes and regenerate code automatically\n --debug Show debug information\n --help Show CLI help.\n --json Output results as JSON for scripting\n --no-color Disable colored output\n --silent Suppress all output except fatal errors\n\nDESCRIPTION\n Generate code based on your configuration, use `init` to get started, `generate` to generate code from the\n configuration.\n```\n\n_See code: [src/commands/generate.ts](https://github.com/the-codegen-project/cli/blob/v0.80.0/src/commands/generate.ts)_\n\n## `codegen help [COMMAND]`\n\nDisplay help for codegen.\n\n```\nUSAGE\n $ codegen help [COMMAND...] [-n]\n\nARGUMENTS\n COMMAND... Command to show help for.\n\nFLAGS\n -n, --nested-commands Include all nested commands in the output.\n\nDESCRIPTION\n Display help for codegen.\n```\n\n_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.0.22/src/commands/help.ts)_\n\n## `codegen init`\n\nInitialize The Codegen Project in your project\n\n```\nUSAGE\n $ codegen init [--json] [--no-color] [--debug | | [--silent | -v | -q]] [--help] [--input-file ]\n [--config-name ] [--input-type asyncapi|openapi|jsonschema] [--output-directory ] [--config-type\n esm|json|yaml|ts] [--languages typescript] [--channels-protocols\n nats|kafka|mqtt|amqp|event_source|http_client|websocket] [--no-tty] [--include-payloads] [--include-headers]\n [--include-client] [--include-parameters] [--include-channels] [--include-types] [--include-models]\n [--gitignore-generated]\n\nFLAGS\n -q, --quiet Only show errors and warnings\n -v, --verbose Show detailed output\n --channels-protocols=