@amqp-contract/asyncapi 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/index.cjs +228 -92
- package/dist/index.d.cts +127 -120
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +127 -120
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +228 -91
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +165 -0
- package/package.json +16 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,136 +1,143 @@
|
|
|
1
|
+
import { ConditionalSchemaConverter } from "@orpc/openapi";
|
|
2
|
+
import { AsyncAPIObject } from "@asyncapi/parser/esm/spec-types/v3";
|
|
1
3
|
import { ContractDefinition } from "@amqp-contract/contract";
|
|
2
|
-
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
4
|
|
|
4
|
-
//#region src/
|
|
5
|
-
|
|
6
|
-
* AsyncAPI 3.0.0 Specification
|
|
7
|
-
*/
|
|
8
|
-
interface AsyncAPIDocument {
|
|
9
|
-
asyncapi: "3.0.0";
|
|
10
|
-
info: AsyncAPIInfo;
|
|
11
|
-
servers?: Record<string, AsyncAPIServer>;
|
|
12
|
-
channels?: Record<string, AsyncAPIChannel>;
|
|
13
|
-
operations?: Record<string, AsyncAPIOperation>;
|
|
14
|
-
components?: AsyncAPIComponents;
|
|
15
|
-
}
|
|
16
|
-
interface AsyncAPIInfo {
|
|
17
|
-
title: string;
|
|
18
|
-
version: string;
|
|
19
|
-
description?: string;
|
|
20
|
-
termsOfService?: string;
|
|
21
|
-
contact?: {
|
|
22
|
-
name?: string;
|
|
23
|
-
url?: string;
|
|
24
|
-
email?: string;
|
|
25
|
-
};
|
|
26
|
-
license?: {
|
|
27
|
-
name: string;
|
|
28
|
-
url?: string;
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
interface AsyncAPIServer {
|
|
32
|
-
host: string;
|
|
33
|
-
protocol: string;
|
|
34
|
-
description?: string;
|
|
35
|
-
variables?: Record<string, {
|
|
36
|
-
default: string;
|
|
37
|
-
description?: string;
|
|
38
|
-
}>;
|
|
39
|
-
}
|
|
40
|
-
interface AsyncAPIChannel {
|
|
41
|
-
address: string;
|
|
42
|
-
messages?: Record<string, AsyncAPIMessageRef>;
|
|
43
|
-
description?: string;
|
|
44
|
-
bindings?: {
|
|
45
|
-
amqp?: {
|
|
46
|
-
is: "queue" | "routingKey";
|
|
47
|
-
queue?: {
|
|
48
|
-
name: string;
|
|
49
|
-
durable?: boolean;
|
|
50
|
-
exclusive?: boolean;
|
|
51
|
-
autoDelete?: boolean;
|
|
52
|
-
};
|
|
53
|
-
exchange?: {
|
|
54
|
-
name: string;
|
|
55
|
-
type: "topic" | "direct" | "fanout" | "headers";
|
|
56
|
-
durable?: boolean;
|
|
57
|
-
autoDelete?: boolean;
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
interface AsyncAPIOperation {
|
|
63
|
-
action: "send" | "receive";
|
|
64
|
-
channel: AsyncAPIRef;
|
|
65
|
-
messages?: AsyncAPIMessageRef[];
|
|
66
|
-
description?: string;
|
|
67
|
-
}
|
|
68
|
-
interface AsyncAPIMessageRef {
|
|
69
|
-
$ref?: string;
|
|
70
|
-
payload?: AsyncAPISchema;
|
|
71
|
-
contentType?: string;
|
|
72
|
-
name?: string;
|
|
73
|
-
title?: string;
|
|
74
|
-
summary?: string;
|
|
75
|
-
description?: string;
|
|
76
|
-
}
|
|
77
|
-
interface AsyncAPISchema {
|
|
78
|
-
type?: string;
|
|
79
|
-
properties?: Record<string, AsyncAPISchema>;
|
|
80
|
-
required?: string[];
|
|
81
|
-
items?: AsyncAPISchema;
|
|
82
|
-
$ref?: string;
|
|
83
|
-
description?: string;
|
|
84
|
-
format?: string;
|
|
85
|
-
minimum?: number;
|
|
86
|
-
maximum?: number;
|
|
87
|
-
minLength?: number;
|
|
88
|
-
maxLength?: number;
|
|
89
|
-
pattern?: string;
|
|
90
|
-
enum?: unknown[];
|
|
91
|
-
}
|
|
92
|
-
interface AsyncAPIRef {
|
|
93
|
-
$ref: string;
|
|
94
|
-
}
|
|
95
|
-
interface AsyncAPIComponents {
|
|
96
|
-
messages?: Record<string, AsyncAPIMessageRef>;
|
|
97
|
-
schemas?: Record<string, AsyncAPISchema>;
|
|
98
|
-
}
|
|
5
|
+
//#region src/index.d.ts
|
|
6
|
+
|
|
99
7
|
/**
|
|
100
|
-
* Options for
|
|
8
|
+
* Options for configuring the AsyncAPI generator.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { AsyncAPIGenerator } from '@amqp-contract/asyncapi';
|
|
13
|
+
* import { zodToJsonSchema } from '@orpc/zod';
|
|
14
|
+
*
|
|
15
|
+
* const generator = new AsyncAPIGenerator({
|
|
16
|
+
* schemaConverters: [zodToJsonSchema]
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
101
19
|
*/
|
|
102
|
-
interface
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
20
|
+
interface AsyncAPIGeneratorOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Schema converters for transforming validation schemas to JSON Schema.
|
|
23
|
+
* Supports Zod, Valibot, ArkType, and other Standard Schema v1 compatible libraries.
|
|
24
|
+
*/
|
|
25
|
+
schemaConverters?: ConditionalSchemaConverter[];
|
|
108
26
|
}
|
|
109
27
|
/**
|
|
110
|
-
*
|
|
28
|
+
* Options for generating an AsyncAPI document.
|
|
29
|
+
* These correspond to the top-level AsyncAPI document fields.
|
|
111
30
|
*/
|
|
112
|
-
|
|
113
|
-
//#endregion
|
|
114
|
-
//#region src/schema-converter.d.ts
|
|
31
|
+
type AsyncAPIGeneratorGenerateOptions = Pick<AsyncAPIObject, "id" | "info" | "servers">;
|
|
115
32
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* This is a basic converter that returns a generic object schema.
|
|
119
|
-
* Users should provide their own schema-to-JSON-Schema converter function
|
|
120
|
-
* specific to their schema library.
|
|
33
|
+
* Generator for creating AsyncAPI 3.0 documentation from AMQP contracts.
|
|
121
34
|
*
|
|
122
|
-
*
|
|
35
|
+
* This class converts contract definitions into AsyncAPI 3.0 specification documents,
|
|
36
|
+
* which can be used for API documentation, code generation, and tooling integration.
|
|
123
37
|
*
|
|
124
38
|
* @example
|
|
125
|
-
* ```
|
|
126
|
-
* import {
|
|
127
|
-
* import {
|
|
39
|
+
* ```typescript
|
|
40
|
+
* import { AsyncAPIGenerator } from '@amqp-contract/asyncapi';
|
|
41
|
+
* import { zodToJsonSchema } from '@orpc/zod';
|
|
42
|
+
* import { z } from 'zod';
|
|
43
|
+
*
|
|
44
|
+
* const contract = defineContract({
|
|
45
|
+
* exchanges: {
|
|
46
|
+
* orders: defineExchange('orders', 'topic', { durable: true })
|
|
47
|
+
* },
|
|
48
|
+
* publishers: {
|
|
49
|
+
* orderCreated: definePublisher('orders', z.object({
|
|
50
|
+
* orderId: z.string(),
|
|
51
|
+
* amount: z.number()
|
|
52
|
+
* }), {
|
|
53
|
+
* routingKey: 'order.created'
|
|
54
|
+
* })
|
|
55
|
+
* }
|
|
56
|
+
* });
|
|
128
57
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
58
|
+
* const generator = new AsyncAPIGenerator({
|
|
59
|
+
* schemaConverters: [zodToJsonSchema]
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* const asyncapi = await generator.generate(contract, {
|
|
63
|
+
* id: 'urn:com:example:order-service',
|
|
64
|
+
* info: {
|
|
65
|
+
* title: 'Order Service API',
|
|
66
|
+
* version: '1.0.0',
|
|
67
|
+
* description: 'Async API for order processing'
|
|
68
|
+
* },
|
|
69
|
+
* servers: {
|
|
70
|
+
* production: {
|
|
71
|
+
* host: 'rabbitmq.example.com',
|
|
72
|
+
* protocol: 'amqp',
|
|
73
|
+
* protocolVersion: '0.9.1'
|
|
74
|
+
* }
|
|
75
|
+
* }
|
|
76
|
+
* });
|
|
131
77
|
* ```
|
|
132
78
|
*/
|
|
133
|
-
declare
|
|
79
|
+
declare class AsyncAPIGenerator {
|
|
80
|
+
private readonly converters;
|
|
81
|
+
/**
|
|
82
|
+
* Create a new AsyncAPI generator instance.
|
|
83
|
+
*
|
|
84
|
+
* @param options - Configuration options including schema converters
|
|
85
|
+
*/
|
|
86
|
+
constructor(options?: AsyncAPIGeneratorOptions);
|
|
87
|
+
/**
|
|
88
|
+
* Generate an AsyncAPI 3.0 document from a contract definition.
|
|
89
|
+
*
|
|
90
|
+
* Converts AMQP exchanges, queues, publishers, and consumers into
|
|
91
|
+
* AsyncAPI channels, operations, and messages with proper JSON Schema
|
|
92
|
+
* validation definitions.
|
|
93
|
+
*
|
|
94
|
+
* @param contract - The AMQP contract definition to convert
|
|
95
|
+
* @param options - AsyncAPI document metadata (id, info, servers)
|
|
96
|
+
* @returns Promise resolving to a complete AsyncAPI 3.0 document
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const asyncapi = await generator.generate(contract, {
|
|
101
|
+
* id: 'urn:com:example:api',
|
|
102
|
+
* info: {
|
|
103
|
+
* title: 'My API',
|
|
104
|
+
* version: '1.0.0'
|
|
105
|
+
* },
|
|
106
|
+
* servers: {
|
|
107
|
+
* dev: {
|
|
108
|
+
* host: 'localhost:5672',
|
|
109
|
+
* protocol: 'amqp'
|
|
110
|
+
* }
|
|
111
|
+
* }
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
generate(contract: ContractDefinition, options: AsyncAPIGeneratorGenerateOptions): Promise<AsyncAPIObject>;
|
|
116
|
+
/**
|
|
117
|
+
* Convert a message definition to AsyncAPI MessageObject
|
|
118
|
+
*/
|
|
119
|
+
private convertMessage;
|
|
120
|
+
/**
|
|
121
|
+
* Convert a queue definition to AsyncAPI ChannelObject
|
|
122
|
+
*/
|
|
123
|
+
private queueToChannel;
|
|
124
|
+
/**
|
|
125
|
+
* Convert an exchange definition to AsyncAPI ChannelObject
|
|
126
|
+
*/
|
|
127
|
+
private exchangeToChannel;
|
|
128
|
+
/**
|
|
129
|
+
* Get the name/key of an exchange from the contract
|
|
130
|
+
*/
|
|
131
|
+
private getExchangeName;
|
|
132
|
+
/**
|
|
133
|
+
* Get the name/key of a queue from the contract
|
|
134
|
+
*/
|
|
135
|
+
private getQueueName;
|
|
136
|
+
/**
|
|
137
|
+
* Convert a Standard Schema to JSON Schema using oRPC converters
|
|
138
|
+
*/
|
|
139
|
+
private convertSchema;
|
|
140
|
+
}
|
|
134
141
|
//#endregion
|
|
135
|
-
export {
|
|
142
|
+
export { AsyncAPIGenerator, AsyncAPIGeneratorGenerateOptions, AsyncAPIGeneratorOptions };
|
|
136
143
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA8BA;AAYA;AAiDA;;;;;;;;;UA7DiB,wBAAA;;;;;qBAKI;;;;;;KAOT,gCAAA,GAAmC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiDvC,iBAAA;;;;;;;wBAQU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAiCT,6BACD,mCACR,QAAQ"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,110 +1,247 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/index.ts
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Generator for creating AsyncAPI 3.0 documentation from AMQP contracts.
|
|
4
4
|
*
|
|
5
|
-
* This
|
|
6
|
-
*
|
|
7
|
-
* specific to their schema library.
|
|
8
|
-
*
|
|
9
|
-
* For Zod users, import and use zodToJsonSchema from @amqp-contract/zod
|
|
5
|
+
* This class converts contract definitions into AsyncAPI 3.0 specification documents,
|
|
6
|
+
* which can be used for API documentation, code generation, and tooling integration.
|
|
10
7
|
*
|
|
11
8
|
* @example
|
|
12
|
-
* ```
|
|
13
|
-
* import {
|
|
14
|
-
* import {
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { AsyncAPIGenerator } from '@amqp-contract/asyncapi';
|
|
11
|
+
* import { zodToJsonSchema } from '@orpc/zod';
|
|
12
|
+
* import { z } from 'zod';
|
|
13
|
+
*
|
|
14
|
+
* const contract = defineContract({
|
|
15
|
+
* exchanges: {
|
|
16
|
+
* orders: defineExchange('orders', 'topic', { durable: true })
|
|
17
|
+
* },
|
|
18
|
+
* publishers: {
|
|
19
|
+
* orderCreated: definePublisher('orders', z.object({
|
|
20
|
+
* orderId: z.string(),
|
|
21
|
+
* amount: z.number()
|
|
22
|
+
* }), {
|
|
23
|
+
* routingKey: 'order.created'
|
|
24
|
+
* })
|
|
25
|
+
* }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* const generator = new AsyncAPIGenerator({
|
|
29
|
+
* schemaConverters: [zodToJsonSchema]
|
|
30
|
+
* });
|
|
15
31
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
32
|
+
* const asyncapi = await generator.generate(contract, {
|
|
33
|
+
* id: 'urn:com:example:order-service',
|
|
34
|
+
* info: {
|
|
35
|
+
* title: 'Order Service API',
|
|
36
|
+
* version: '1.0.0',
|
|
37
|
+
* description: 'Async API for order processing'
|
|
38
|
+
* },
|
|
39
|
+
* servers: {
|
|
40
|
+
* production: {
|
|
41
|
+
* host: 'rabbitmq.example.com',
|
|
42
|
+
* protocol: 'amqp',
|
|
43
|
+
* protocolVersion: '0.9.1'
|
|
44
|
+
* }
|
|
45
|
+
* }
|
|
46
|
+
* });
|
|
18
47
|
* ```
|
|
19
48
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
function generateAsyncAPI(contract, options) {
|
|
30
|
-
const channels = {};
|
|
31
|
-
const operations = {};
|
|
32
|
-
const messages = {};
|
|
33
|
-
if (contract.queues) for (const [queueName, queue] of Object.entries(contract.queues)) {
|
|
34
|
-
const binding = { amqp: {
|
|
35
|
-
is: "queue",
|
|
36
|
-
queue: { name: queue.name }
|
|
37
|
-
} };
|
|
38
|
-
if (queue.durable !== void 0) binding.amqp.queue.durable = queue.durable;
|
|
39
|
-
if (queue.exclusive !== void 0) binding.amqp.queue.exclusive = queue.exclusive;
|
|
40
|
-
if (queue.autoDelete !== void 0) binding.amqp.queue.autoDelete = queue.autoDelete;
|
|
41
|
-
channels[queueName] = {
|
|
42
|
-
address: queue.name,
|
|
43
|
-
description: `Queue: ${queue.name}`,
|
|
44
|
-
bindings: binding
|
|
45
|
-
};
|
|
49
|
+
var AsyncAPIGenerator = class {
|
|
50
|
+
converters;
|
|
51
|
+
/**
|
|
52
|
+
* Create a new AsyncAPI generator instance.
|
|
53
|
+
*
|
|
54
|
+
* @param options - Configuration options including schema converters
|
|
55
|
+
*/
|
|
56
|
+
constructor(options = {}) {
|
|
57
|
+
this.converters = options.schemaConverters ?? [];
|
|
46
58
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Generate an AsyncAPI 3.0 document from a contract definition.
|
|
61
|
+
*
|
|
62
|
+
* Converts AMQP exchanges, queues, publishers, and consumers into
|
|
63
|
+
* AsyncAPI channels, operations, and messages with proper JSON Schema
|
|
64
|
+
* validation definitions.
|
|
65
|
+
*
|
|
66
|
+
* @param contract - The AMQP contract definition to convert
|
|
67
|
+
* @param options - AsyncAPI document metadata (id, info, servers)
|
|
68
|
+
* @returns Promise resolving to a complete AsyncAPI 3.0 document
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const asyncapi = await generator.generate(contract, {
|
|
73
|
+
* id: 'urn:com:example:api',
|
|
74
|
+
* info: {
|
|
75
|
+
* title: 'My API',
|
|
76
|
+
* version: '1.0.0'
|
|
77
|
+
* },
|
|
78
|
+
* servers: {
|
|
79
|
+
* dev: {
|
|
80
|
+
* host: 'localhost:5672',
|
|
81
|
+
* protocol: 'amqp'
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
async generate(contract, options) {
|
|
88
|
+
const convertedChannels = {};
|
|
89
|
+
const convertedOperations = {};
|
|
90
|
+
const convertedMessages = {};
|
|
91
|
+
const publisherMessages = /* @__PURE__ */ new Map();
|
|
92
|
+
const consumerMessages = /* @__PURE__ */ new Map();
|
|
93
|
+
if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
|
|
94
|
+
const channelKey = this.getExchangeName(publisher.exchange, contract);
|
|
95
|
+
publisherMessages.set(publisherName, {
|
|
96
|
+
message: publisher.message,
|
|
97
|
+
channelKey
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
|
|
101
|
+
const channelKey = this.getQueueName(consumer.queue, contract);
|
|
102
|
+
consumerMessages.set(consumerName, {
|
|
103
|
+
message: consumer.message,
|
|
104
|
+
channelKey
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (contract.queues) for (const [queueName, queue] of Object.entries(contract.queues)) {
|
|
108
|
+
const channelMessages = {};
|
|
109
|
+
for (const [consumerName, { message, channelKey }] of consumerMessages) if (channelKey === queueName) {
|
|
110
|
+
const messageName = `${consumerName}Message`;
|
|
111
|
+
channelMessages[messageName] = await this.convertMessage(message);
|
|
112
|
+
convertedMessages[messageName] = await this.convertMessage(message);
|
|
53
113
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
114
|
+
const channel = { ...this.queueToChannel(queue) };
|
|
115
|
+
if (Object.keys(channelMessages).length > 0) channel.messages = channelMessages;
|
|
116
|
+
convertedChannels[queueName] = channel;
|
|
117
|
+
}
|
|
118
|
+
if (contract.exchanges) for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {
|
|
119
|
+
const channelMessages = {};
|
|
120
|
+
for (const [publisherName, { message, channelKey }] of publisherMessages) if (channelKey === exchangeName) {
|
|
121
|
+
const messageName = `${publisherName}Message`;
|
|
122
|
+
channelMessages[messageName] = await this.convertMessage(message);
|
|
123
|
+
convertedMessages[messageName] = await this.convertMessage(message);
|
|
124
|
+
}
|
|
125
|
+
const channel = { ...this.exchangeToChannel(exchange) };
|
|
126
|
+
if (Object.keys(channelMessages).length > 0) channel.messages = channelMessages;
|
|
127
|
+
convertedChannels[exchangeName] = channel;
|
|
128
|
+
}
|
|
129
|
+
if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
|
|
130
|
+
const exchangeName = this.getExchangeName(publisher.exchange, contract);
|
|
131
|
+
const messageName = `${publisherName}Message`;
|
|
132
|
+
convertedOperations[publisherName] = {
|
|
133
|
+
action: "send",
|
|
134
|
+
channel: { $ref: `#/channels/${exchangeName}` },
|
|
135
|
+
messages: [{ $ref: `#/channels/${exchangeName}/messages/${messageName}` }],
|
|
136
|
+
summary: `Publish to ${publisher.exchange.name}`,
|
|
137
|
+
...publisher.routingKey && { description: `Routing key: ${publisher.routingKey}` }
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
|
|
141
|
+
const queueName = this.getQueueName(consumer.queue, contract);
|
|
142
|
+
const messageName = `${consumerName}Message`;
|
|
143
|
+
convertedOperations[consumerName] = {
|
|
144
|
+
action: "receive",
|
|
145
|
+
channel: { $ref: `#/channels/${queueName}` },
|
|
146
|
+
messages: [{ $ref: `#/channels/${queueName}/messages/${messageName}` }],
|
|
147
|
+
summary: `Consume from ${consumer.queue.name}`
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
...options,
|
|
152
|
+
asyncapi: "3.0.0",
|
|
153
|
+
channels: convertedChannels,
|
|
154
|
+
operations: convertedOperations,
|
|
155
|
+
components: { messages: convertedMessages }
|
|
61
156
|
};
|
|
62
157
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
payload:
|
|
70
|
-
|
|
71
|
-
operations[publisherName] = {
|
|
72
|
-
action: "send",
|
|
73
|
-
channel: { $ref: `#/channels/${publisher.exchange}` },
|
|
74
|
-
messages: [{ $ref: `#/components/messages/${messageName}` }],
|
|
75
|
-
description: `Publish message to ${publisher.exchange}`
|
|
158
|
+
/**
|
|
159
|
+
* Convert a message definition to AsyncAPI MessageObject
|
|
160
|
+
*/
|
|
161
|
+
async convertMessage(message) {
|
|
162
|
+
const payload = message.payload;
|
|
163
|
+
const result = {
|
|
164
|
+
payload: await this.convertSchema(payload, "input"),
|
|
165
|
+
contentType: "application/json"
|
|
76
166
|
};
|
|
167
|
+
if (message.headers) {
|
|
168
|
+
const headersJsonSchema = await this.convertSchema(message.headers, "input");
|
|
169
|
+
if (headersJsonSchema) result["headers"] = headersJsonSchema;
|
|
170
|
+
}
|
|
171
|
+
if (message.summary) result["summary"] = message.summary;
|
|
172
|
+
if (message.description) result["description"] = message.description;
|
|
173
|
+
return result;
|
|
77
174
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Convert a queue definition to AsyncAPI ChannelObject
|
|
177
|
+
*/
|
|
178
|
+
queueToChannel(queue) {
|
|
179
|
+
return {
|
|
180
|
+
address: queue.name,
|
|
181
|
+
title: queue.name,
|
|
182
|
+
description: `AMQP Queue: ${queue.name}`,
|
|
183
|
+
bindings: { amqp: {
|
|
184
|
+
is: "queue",
|
|
185
|
+
queue: {
|
|
186
|
+
name: queue.name,
|
|
187
|
+
durable: queue.durable ?? false,
|
|
188
|
+
exclusive: queue.exclusive ?? false,
|
|
189
|
+
autoDelete: queue.autoDelete ?? false,
|
|
190
|
+
...queue.arguments && { vhost: "/" }
|
|
191
|
+
}
|
|
192
|
+
} }
|
|
85
193
|
};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Convert an exchange definition to AsyncAPI ChannelObject
|
|
197
|
+
*/
|
|
198
|
+
exchangeToChannel(exchange) {
|
|
199
|
+
return {
|
|
200
|
+
address: exchange.name,
|
|
201
|
+
title: exchange.name,
|
|
202
|
+
description: `AMQP Exchange: ${exchange.name} (${exchange.type})`,
|
|
203
|
+
bindings: { amqp: {
|
|
204
|
+
is: "routingKey",
|
|
205
|
+
exchange: {
|
|
206
|
+
name: exchange.name,
|
|
207
|
+
type: exchange.type,
|
|
208
|
+
durable: exchange.durable ?? false,
|
|
209
|
+
autoDelete: exchange.autoDelete ?? false,
|
|
210
|
+
...exchange.arguments && { vhost: "/" }
|
|
211
|
+
}
|
|
212
|
+
} }
|
|
91
213
|
};
|
|
92
214
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Get the name/key of an exchange from the contract
|
|
217
|
+
*/
|
|
218
|
+
getExchangeName(exchange, contract) {
|
|
219
|
+
if (contract.exchanges) {
|
|
220
|
+
for (const [name, ex] of Object.entries(contract.exchanges)) if (ex === exchange || ex.name === exchange.name) return name;
|
|
221
|
+
}
|
|
222
|
+
return exchange.name;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get the name/key of a queue from the contract
|
|
226
|
+
*/
|
|
227
|
+
getQueueName(queue, contract) {
|
|
228
|
+
if (contract.queues) {
|
|
229
|
+
for (const [name, q] of Object.entries(contract.queues)) if (q === queue || q.name === queue.name) return name;
|
|
230
|
+
}
|
|
231
|
+
return queue.name;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Convert a Standard Schema to JSON Schema using oRPC converters
|
|
235
|
+
*/
|
|
236
|
+
async convertSchema(schema, strategy) {
|
|
237
|
+
for (const converter of this.converters) if (await converter.condition(schema, { strategy })) {
|
|
238
|
+
const [_required, jsonSchema] = await converter.convert(schema, { strategy });
|
|
239
|
+
return jsonSchema;
|
|
240
|
+
}
|
|
241
|
+
return { type: "object" };
|
|
242
|
+
}
|
|
243
|
+
};
|
|
107
244
|
|
|
108
245
|
//#endregion
|
|
109
|
-
export {
|
|
246
|
+
export { AsyncAPIGenerator };
|
|
110
247
|
//# sourceMappingURL=index.mjs.map
|