@amqp-contract/asyncapi 0.1.4 → 0.2.0
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/dist/index.cjs +159 -99
- package/dist/index.d.cts +39 -131
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +39 -131
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +159 -98
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -2
package/dist/index.cjs
CHANGED
|
@@ -1,111 +1,171 @@
|
|
|
1
1
|
|
|
2
|
-
//#region src/
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Users should provide their own schema-to-JSON-Schema converter function
|
|
8
|
-
* specific to their schema library.
|
|
9
|
-
*
|
|
10
|
-
* For Zod users, import and use zodToJsonSchema from @amqp-contract/zod
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* import { zodToJsonSchema } from '@amqp-contract/zod';
|
|
15
|
-
* import { generateAsyncAPI } from '@amqp-contract/asyncapi';
|
|
16
|
-
*
|
|
17
|
-
* // Use zodToJsonSchema for converting Zod schemas
|
|
18
|
-
* const jsonSchema = zodToJsonSchema(zodSchema);
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
function standardSchemaToJsonSchema(_schema) {
|
|
22
|
-
return { type: "object" };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/generator.ts
|
|
27
|
-
/**
|
|
28
|
-
* Generate AsyncAPI 3.0.0 specification from AMQP contract
|
|
29
|
-
*/
|
|
30
|
-
function generateAsyncAPI(contract, options) {
|
|
31
|
-
const channels = {};
|
|
32
|
-
const operations = {};
|
|
33
|
-
const messages = {};
|
|
34
|
-
if (contract.queues) for (const [queueName, queue] of Object.entries(contract.queues)) {
|
|
35
|
-
const binding = { amqp: {
|
|
36
|
-
is: "queue",
|
|
37
|
-
queue: { name: queue.name }
|
|
38
|
-
} };
|
|
39
|
-
if (queue.durable !== void 0) binding.amqp.queue.durable = queue.durable;
|
|
40
|
-
if (queue.exclusive !== void 0) binding.amqp.queue.exclusive = queue.exclusive;
|
|
41
|
-
if (queue.autoDelete !== void 0) binding.amqp.queue.autoDelete = queue.autoDelete;
|
|
42
|
-
channels[queueName] = {
|
|
43
|
-
address: queue.name,
|
|
44
|
-
description: `Queue: ${queue.name}`,
|
|
45
|
-
bindings: binding
|
|
46
|
-
};
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
var AsyncAPIGenerator = class {
|
|
4
|
+
converters;
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
this.converters = options.schemaConverters ?? [];
|
|
47
7
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Generate an AsyncAPI 3.0 document from a contract definition
|
|
10
|
+
*/
|
|
11
|
+
async generate(contract, options) {
|
|
12
|
+
const convertedChannels = {};
|
|
13
|
+
const convertedOperations = {};
|
|
14
|
+
const convertedMessages = {};
|
|
15
|
+
const publisherMessages = /* @__PURE__ */ new Map();
|
|
16
|
+
const consumerMessages = /* @__PURE__ */ new Map();
|
|
17
|
+
if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
|
|
18
|
+
const channelKey = this.getExchangeName(publisher.exchange, contract);
|
|
19
|
+
publisherMessages.set(publisherName, {
|
|
20
|
+
message: publisher.message,
|
|
21
|
+
channelKey
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
|
|
25
|
+
const channelKey = this.getQueueName(consumer.queue, contract);
|
|
26
|
+
consumerMessages.set(consumerName, {
|
|
27
|
+
message: consumer.message,
|
|
28
|
+
channelKey
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (contract.queues) for (const [queueName, queue] of Object.entries(contract.queues)) {
|
|
32
|
+
const channelMessages = {};
|
|
33
|
+
for (const [consumerName, { message, channelKey }] of consumerMessages) if (channelKey === queueName) {
|
|
34
|
+
const messageName = `${consumerName}Message`;
|
|
35
|
+
channelMessages[messageName] = await this.convertMessage(message);
|
|
36
|
+
convertedMessages[messageName] = await this.convertMessage(message);
|
|
54
37
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
38
|
+
const channel = { ...this.queueToChannel(queue) };
|
|
39
|
+
if (Object.keys(channelMessages).length > 0) channel.messages = channelMessages;
|
|
40
|
+
convertedChannels[queueName] = channel;
|
|
41
|
+
}
|
|
42
|
+
if (contract.exchanges) for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {
|
|
43
|
+
const channelMessages = {};
|
|
44
|
+
for (const [publisherName, { message, channelKey }] of publisherMessages) if (channelKey === exchangeName) {
|
|
45
|
+
const messageName = `${publisherName}Message`;
|
|
46
|
+
channelMessages[messageName] = await this.convertMessage(message);
|
|
47
|
+
convertedMessages[messageName] = await this.convertMessage(message);
|
|
48
|
+
}
|
|
49
|
+
const channel = { ...this.exchangeToChannel(exchange) };
|
|
50
|
+
if (Object.keys(channelMessages).length > 0) channel.messages = channelMessages;
|
|
51
|
+
convertedChannels[exchangeName] = channel;
|
|
52
|
+
}
|
|
53
|
+
if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
|
|
54
|
+
const exchangeName = this.getExchangeName(publisher.exchange, contract);
|
|
55
|
+
const messageName = `${publisherName}Message`;
|
|
56
|
+
convertedOperations[publisherName] = {
|
|
57
|
+
action: "send",
|
|
58
|
+
channel: { $ref: `#/channels/${exchangeName}` },
|
|
59
|
+
messages: [{ $ref: `#/channels/${exchangeName}/messages/${messageName}` }],
|
|
60
|
+
summary: `Publish to ${publisher.exchange.name}`,
|
|
61
|
+
...publisher.routingKey && { description: `Routing key: ${publisher.routingKey}` }
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
|
|
65
|
+
const queueName = this.getQueueName(consumer.queue, contract);
|
|
66
|
+
const messageName = `${consumerName}Message`;
|
|
67
|
+
convertedOperations[consumerName] = {
|
|
68
|
+
action: "receive",
|
|
69
|
+
channel: { $ref: `#/channels/${queueName}` },
|
|
70
|
+
messages: [{ $ref: `#/channels/${queueName}/messages/${messageName}` }],
|
|
71
|
+
summary: `Consume from ${consumer.queue.name}`,
|
|
72
|
+
...consumer.prefetch && { description: `Prefetch: ${consumer.prefetch}` }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
...options,
|
|
77
|
+
asyncapi: "3.0.0",
|
|
78
|
+
channels: convertedChannels,
|
|
79
|
+
operations: convertedOperations,
|
|
80
|
+
components: { messages: convertedMessages }
|
|
62
81
|
};
|
|
63
82
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
payload:
|
|
71
|
-
|
|
72
|
-
operations[publisherName] = {
|
|
73
|
-
action: "send",
|
|
74
|
-
channel: { $ref: `#/channels/${publisher.exchange}` },
|
|
75
|
-
messages: [{ $ref: `#/components/messages/${messageName}` }],
|
|
76
|
-
description: `Publish message to ${publisher.exchange}`
|
|
83
|
+
/**
|
|
84
|
+
* Convert a message definition to AsyncAPI MessageObject
|
|
85
|
+
*/
|
|
86
|
+
async convertMessage(message) {
|
|
87
|
+
const payload = message.payload;
|
|
88
|
+
const result = {
|
|
89
|
+
payload: await this.convertSchema(payload, "input"),
|
|
90
|
+
contentType: "application/json"
|
|
77
91
|
};
|
|
92
|
+
if (message.headers) {
|
|
93
|
+
const headersJsonSchema = await this.convertSchema(message.headers, "input");
|
|
94
|
+
if (headersJsonSchema) result["headers"] = headersJsonSchema;
|
|
95
|
+
}
|
|
96
|
+
if (message.summary) result["summary"] = message.summary;
|
|
97
|
+
if (message.description) result["description"] = message.description;
|
|
98
|
+
return result;
|
|
78
99
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Convert a queue definition to AsyncAPI ChannelObject
|
|
102
|
+
*/
|
|
103
|
+
queueToChannel(queue) {
|
|
104
|
+
return {
|
|
105
|
+
address: queue.name,
|
|
106
|
+
title: queue.name,
|
|
107
|
+
description: `AMQP Queue: ${queue.name}`,
|
|
108
|
+
bindings: { amqp: {
|
|
109
|
+
is: "queue",
|
|
110
|
+
queue: {
|
|
111
|
+
name: queue.name,
|
|
112
|
+
durable: queue.durable ?? false,
|
|
113
|
+
exclusive: queue.exclusive ?? false,
|
|
114
|
+
autoDelete: queue.autoDelete ?? false,
|
|
115
|
+
...queue.arguments && { vhost: "/" }
|
|
116
|
+
}
|
|
117
|
+
} }
|
|
86
118
|
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Convert an exchange definition to AsyncAPI ChannelObject
|
|
122
|
+
*/
|
|
123
|
+
exchangeToChannel(exchange) {
|
|
124
|
+
return {
|
|
125
|
+
address: exchange.name,
|
|
126
|
+
title: exchange.name,
|
|
127
|
+
description: `AMQP Exchange: ${exchange.name} (${exchange.type})`,
|
|
128
|
+
bindings: { amqp: {
|
|
129
|
+
is: "routingKey",
|
|
130
|
+
exchange: {
|
|
131
|
+
name: exchange.name,
|
|
132
|
+
type: exchange.type,
|
|
133
|
+
durable: exchange.durable ?? false,
|
|
134
|
+
autoDelete: exchange.autoDelete ?? false,
|
|
135
|
+
...exchange.arguments && { vhost: "/" }
|
|
136
|
+
}
|
|
137
|
+
} }
|
|
92
138
|
};
|
|
93
139
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Get the name/key of an exchange from the contract
|
|
142
|
+
*/
|
|
143
|
+
getExchangeName(exchange, contract) {
|
|
144
|
+
if (contract.exchanges) {
|
|
145
|
+
for (const [name, ex] of Object.entries(contract.exchanges)) if (ex === exchange || ex.name === exchange.name) return name;
|
|
146
|
+
}
|
|
147
|
+
return exchange.name;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get the name/key of a queue from the contract
|
|
151
|
+
*/
|
|
152
|
+
getQueueName(queue, contract) {
|
|
153
|
+
if (contract.queues) {
|
|
154
|
+
for (const [name, q] of Object.entries(contract.queues)) if (q === queue || q.name === queue.name) return name;
|
|
155
|
+
}
|
|
156
|
+
return queue.name;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Convert a Standard Schema to JSON Schema using oRPC converters
|
|
160
|
+
*/
|
|
161
|
+
async convertSchema(schema, strategy) {
|
|
162
|
+
for (const converter of this.converters) if (await converter.condition(schema, { strategy })) {
|
|
163
|
+
const [_required, jsonSchema] = await converter.convert(schema, { strategy });
|
|
164
|
+
return jsonSchema;
|
|
165
|
+
}
|
|
166
|
+
return { type: "object" };
|
|
167
|
+
}
|
|
168
|
+
};
|
|
108
169
|
|
|
109
170
|
//#endregion
|
|
110
|
-
exports.
|
|
111
|
-
exports.standardSchemaToJsonSchema = standardSchemaToJsonSchema;
|
|
171
|
+
exports.AsyncAPIGenerator = AsyncAPIGenerator;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,136 +1,44 @@
|
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
//#region src/index.d.ts
|
|
6
|
+
interface AsyncAPIGeneratorOptions {
|
|
7
|
+
schemaConverters?: ConditionalSchemaConverter[];
|
|
8
|
+
}
|
|
9
|
+
type AsyncAPIGeneratorGenerateOptions = Pick<AsyncAPIObject, "id" | "info" | "servers">;
|
|
10
|
+
declare class AsyncAPIGenerator {
|
|
11
|
+
private readonly converters;
|
|
12
|
+
constructor(options?: AsyncAPIGeneratorOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Generate an AsyncAPI 3.0 document from a contract definition
|
|
15
|
+
*/
|
|
16
|
+
generate(contract: ContractDefinition, options: AsyncAPIGeneratorGenerateOptions): Promise<AsyncAPIObject>;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a message definition to AsyncAPI MessageObject
|
|
19
|
+
*/
|
|
20
|
+
private convertMessage;
|
|
21
|
+
/**
|
|
22
|
+
* Convert a queue definition to AsyncAPI ChannelObject
|
|
23
|
+
*/
|
|
24
|
+
private queueToChannel;
|
|
25
|
+
/**
|
|
26
|
+
* Convert an exchange definition to AsyncAPI ChannelObject
|
|
27
|
+
*/
|
|
28
|
+
private exchangeToChannel;
|
|
29
|
+
/**
|
|
30
|
+
* Get the name/key of an exchange from the contract
|
|
31
|
+
*/
|
|
32
|
+
private getExchangeName;
|
|
33
|
+
/**
|
|
34
|
+
* Get the name/key of a queue from the contract
|
|
35
|
+
*/
|
|
36
|
+
private getQueueName;
|
|
37
|
+
/**
|
|
38
|
+
* Convert a Standard Schema to JSON Schema using oRPC converters
|
|
39
|
+
*/
|
|
40
|
+
private convertSchema;
|
|
15
41
|
}
|
|
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
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Options for generating AsyncAPI specification
|
|
101
|
-
*/
|
|
102
|
-
interface GenerateAsyncAPIOptions {
|
|
103
|
-
info: Omit<AsyncAPIInfo, "title" | "version"> & {
|
|
104
|
-
title?: string;
|
|
105
|
-
version?: string;
|
|
106
|
-
};
|
|
107
|
-
servers?: Record<string, AsyncAPIServer>;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Generate AsyncAPI 3.0.0 specification from AMQP contract
|
|
111
|
-
*/
|
|
112
|
-
declare function generateAsyncAPI(contract: ContractDefinition, options: GenerateAsyncAPIOptions): AsyncAPIDocument;
|
|
113
|
-
//#endregion
|
|
114
|
-
//#region src/schema-converter.d.ts
|
|
115
|
-
/**
|
|
116
|
-
* Convert a Standard Schema to JSON Schema (AsyncAPI format)
|
|
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.
|
|
121
|
-
*
|
|
122
|
-
* For Zod users, import and use zodToJsonSchema from @amqp-contract/zod
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* ```ts
|
|
126
|
-
* import { zodToJsonSchema } from '@amqp-contract/zod';
|
|
127
|
-
* import { generateAsyncAPI } from '@amqp-contract/asyncapi';
|
|
128
|
-
*
|
|
129
|
-
* // Use zodToJsonSchema for converting Zod schemas
|
|
130
|
-
* const jsonSchema = zodToJsonSchema(zodSchema);
|
|
131
|
-
* ```
|
|
132
|
-
*/
|
|
133
|
-
declare function standardSchemaToJsonSchema(_schema: StandardSchemaV1): AsyncAPISchema;
|
|
134
42
|
//#endregion
|
|
135
|
-
export {
|
|
43
|
+
export { AsyncAPIGenerator, AsyncAPIGeneratorGenerateOptions, AsyncAPIGeneratorOptions };
|
|
136
44
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;UAiBiB,wBAAA;qBACI;AADrB;AAIY,KAAA,gCAAA,GAAmC,IAAK,CAAA,cAAL,EAAA,IAAI,GAAA,MAAA,GAAA,SAAA,CAAA;AAEtC,cAAA,iBAAA,CAAiB;EAGP,iBAAA,UAAA;EAQT,WAAA,CAAA,OAAA,CAAA,EARS,wBAQT;EACD;;;EACD,QAAA,CAAA,QAAA,EAFE,kBAEF,EAAA,OAAA,EADC,gCACD,CAAA,EAAP,OAAO,CAAC,cAAD,CAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,136 +1,44 @@
|
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
//#region src/index.d.ts
|
|
6
|
+
interface AsyncAPIGeneratorOptions {
|
|
7
|
+
schemaConverters?: ConditionalSchemaConverter[];
|
|
8
|
+
}
|
|
9
|
+
type AsyncAPIGeneratorGenerateOptions = Pick<AsyncAPIObject, "id" | "info" | "servers">;
|
|
10
|
+
declare class AsyncAPIGenerator {
|
|
11
|
+
private readonly converters;
|
|
12
|
+
constructor(options?: AsyncAPIGeneratorOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Generate an AsyncAPI 3.0 document from a contract definition
|
|
15
|
+
*/
|
|
16
|
+
generate(contract: ContractDefinition, options: AsyncAPIGeneratorGenerateOptions): Promise<AsyncAPIObject>;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a message definition to AsyncAPI MessageObject
|
|
19
|
+
*/
|
|
20
|
+
private convertMessage;
|
|
21
|
+
/**
|
|
22
|
+
* Convert a queue definition to AsyncAPI ChannelObject
|
|
23
|
+
*/
|
|
24
|
+
private queueToChannel;
|
|
25
|
+
/**
|
|
26
|
+
* Convert an exchange definition to AsyncAPI ChannelObject
|
|
27
|
+
*/
|
|
28
|
+
private exchangeToChannel;
|
|
29
|
+
/**
|
|
30
|
+
* Get the name/key of an exchange from the contract
|
|
31
|
+
*/
|
|
32
|
+
private getExchangeName;
|
|
33
|
+
/**
|
|
34
|
+
* Get the name/key of a queue from the contract
|
|
35
|
+
*/
|
|
36
|
+
private getQueueName;
|
|
37
|
+
/**
|
|
38
|
+
* Convert a Standard Schema to JSON Schema using oRPC converters
|
|
39
|
+
*/
|
|
40
|
+
private convertSchema;
|
|
15
41
|
}
|
|
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
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Options for generating AsyncAPI specification
|
|
101
|
-
*/
|
|
102
|
-
interface GenerateAsyncAPIOptions {
|
|
103
|
-
info: Omit<AsyncAPIInfo, "title" | "version"> & {
|
|
104
|
-
title?: string;
|
|
105
|
-
version?: string;
|
|
106
|
-
};
|
|
107
|
-
servers?: Record<string, AsyncAPIServer>;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Generate AsyncAPI 3.0.0 specification from AMQP contract
|
|
111
|
-
*/
|
|
112
|
-
declare function generateAsyncAPI(contract: ContractDefinition, options: GenerateAsyncAPIOptions): AsyncAPIDocument;
|
|
113
|
-
//#endregion
|
|
114
|
-
//#region src/schema-converter.d.ts
|
|
115
|
-
/**
|
|
116
|
-
* Convert a Standard Schema to JSON Schema (AsyncAPI format)
|
|
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.
|
|
121
|
-
*
|
|
122
|
-
* For Zod users, import and use zodToJsonSchema from @amqp-contract/zod
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* ```ts
|
|
126
|
-
* import { zodToJsonSchema } from '@amqp-contract/zod';
|
|
127
|
-
* import { generateAsyncAPI } from '@amqp-contract/asyncapi';
|
|
128
|
-
*
|
|
129
|
-
* // Use zodToJsonSchema for converting Zod schemas
|
|
130
|
-
* const jsonSchema = zodToJsonSchema(zodSchema);
|
|
131
|
-
* ```
|
|
132
|
-
*/
|
|
133
|
-
declare function standardSchemaToJsonSchema(_schema: StandardSchemaV1): AsyncAPISchema;
|
|
134
42
|
//#endregion
|
|
135
|
-
export {
|
|
43
|
+
export { AsyncAPIGenerator, AsyncAPIGeneratorGenerateOptions, AsyncAPIGeneratorOptions };
|
|
136
44
|
//# 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":";;;;;UAiBiB,wBAAA;qBACI;AADrB;AAIY,KAAA,gCAAA,GAAmC,IAAK,CAAA,cAAL,EAAA,IAAI,GAAA,MAAA,GAAA,SAAA,CAAA;AAEtC,cAAA,iBAAA,CAAiB;EAGP,iBAAA,UAAA;EAQT,WAAA,CAAA,OAAA,CAAA,EARS,wBAQT;EACD;;;EACD,QAAA,CAAA,QAAA,EAFE,kBAEF,EAAA,OAAA,EADC,gCACD,CAAA,EAAP,OAAO,CAAC,cAAD,CAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,110 +1,171 @@
|
|
|
1
|
-
//#region src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Users should provide their own schema-to-JSON-Schema converter function
|
|
7
|
-
* specific to their schema library.
|
|
8
|
-
*
|
|
9
|
-
* For Zod users, import and use zodToJsonSchema from @amqp-contract/zod
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* import { zodToJsonSchema } from '@amqp-contract/zod';
|
|
14
|
-
* import { generateAsyncAPI } from '@amqp-contract/asyncapi';
|
|
15
|
-
*
|
|
16
|
-
* // Use zodToJsonSchema for converting Zod schemas
|
|
17
|
-
* const jsonSchema = zodToJsonSchema(zodSchema);
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
function standardSchemaToJsonSchema(_schema) {
|
|
21
|
-
return { type: "object" };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/generator.ts
|
|
26
|
-
/**
|
|
27
|
-
* Generate AsyncAPI 3.0.0 specification from AMQP contract
|
|
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
|
-
};
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
var AsyncAPIGenerator = class {
|
|
3
|
+
converters;
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.converters = options.schemaConverters ?? [];
|
|
46
6
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Generate an AsyncAPI 3.0 document from a contract definition
|
|
9
|
+
*/
|
|
10
|
+
async generate(contract, options) {
|
|
11
|
+
const convertedChannels = {};
|
|
12
|
+
const convertedOperations = {};
|
|
13
|
+
const convertedMessages = {};
|
|
14
|
+
const publisherMessages = /* @__PURE__ */ new Map();
|
|
15
|
+
const consumerMessages = /* @__PURE__ */ new Map();
|
|
16
|
+
if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
|
|
17
|
+
const channelKey = this.getExchangeName(publisher.exchange, contract);
|
|
18
|
+
publisherMessages.set(publisherName, {
|
|
19
|
+
message: publisher.message,
|
|
20
|
+
channelKey
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
|
|
24
|
+
const channelKey = this.getQueueName(consumer.queue, contract);
|
|
25
|
+
consumerMessages.set(consumerName, {
|
|
26
|
+
message: consumer.message,
|
|
27
|
+
channelKey
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (contract.queues) for (const [queueName, queue] of Object.entries(contract.queues)) {
|
|
31
|
+
const channelMessages = {};
|
|
32
|
+
for (const [consumerName, { message, channelKey }] of consumerMessages) if (channelKey === queueName) {
|
|
33
|
+
const messageName = `${consumerName}Message`;
|
|
34
|
+
channelMessages[messageName] = await this.convertMessage(message);
|
|
35
|
+
convertedMessages[messageName] = await this.convertMessage(message);
|
|
53
36
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
37
|
+
const channel = { ...this.queueToChannel(queue) };
|
|
38
|
+
if (Object.keys(channelMessages).length > 0) channel.messages = channelMessages;
|
|
39
|
+
convertedChannels[queueName] = channel;
|
|
40
|
+
}
|
|
41
|
+
if (contract.exchanges) for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {
|
|
42
|
+
const channelMessages = {};
|
|
43
|
+
for (const [publisherName, { message, channelKey }] of publisherMessages) if (channelKey === exchangeName) {
|
|
44
|
+
const messageName = `${publisherName}Message`;
|
|
45
|
+
channelMessages[messageName] = await this.convertMessage(message);
|
|
46
|
+
convertedMessages[messageName] = await this.convertMessage(message);
|
|
47
|
+
}
|
|
48
|
+
const channel = { ...this.exchangeToChannel(exchange) };
|
|
49
|
+
if (Object.keys(channelMessages).length > 0) channel.messages = channelMessages;
|
|
50
|
+
convertedChannels[exchangeName] = channel;
|
|
51
|
+
}
|
|
52
|
+
if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
|
|
53
|
+
const exchangeName = this.getExchangeName(publisher.exchange, contract);
|
|
54
|
+
const messageName = `${publisherName}Message`;
|
|
55
|
+
convertedOperations[publisherName] = {
|
|
56
|
+
action: "send",
|
|
57
|
+
channel: { $ref: `#/channels/${exchangeName}` },
|
|
58
|
+
messages: [{ $ref: `#/channels/${exchangeName}/messages/${messageName}` }],
|
|
59
|
+
summary: `Publish to ${publisher.exchange.name}`,
|
|
60
|
+
...publisher.routingKey && { description: `Routing key: ${publisher.routingKey}` }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
|
|
64
|
+
const queueName = this.getQueueName(consumer.queue, contract);
|
|
65
|
+
const messageName = `${consumerName}Message`;
|
|
66
|
+
convertedOperations[consumerName] = {
|
|
67
|
+
action: "receive",
|
|
68
|
+
channel: { $ref: `#/channels/${queueName}` },
|
|
69
|
+
messages: [{ $ref: `#/channels/${queueName}/messages/${messageName}` }],
|
|
70
|
+
summary: `Consume from ${consumer.queue.name}`,
|
|
71
|
+
...consumer.prefetch && { description: `Prefetch: ${consumer.prefetch}` }
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...options,
|
|
76
|
+
asyncapi: "3.0.0",
|
|
77
|
+
channels: convertedChannels,
|
|
78
|
+
operations: convertedOperations,
|
|
79
|
+
components: { messages: convertedMessages }
|
|
61
80
|
};
|
|
62
81
|
}
|
|
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}`
|
|
82
|
+
/**
|
|
83
|
+
* Convert a message definition to AsyncAPI MessageObject
|
|
84
|
+
*/
|
|
85
|
+
async convertMessage(message) {
|
|
86
|
+
const payload = message.payload;
|
|
87
|
+
const result = {
|
|
88
|
+
payload: await this.convertSchema(payload, "input"),
|
|
89
|
+
contentType: "application/json"
|
|
76
90
|
};
|
|
91
|
+
if (message.headers) {
|
|
92
|
+
const headersJsonSchema = await this.convertSchema(message.headers, "input");
|
|
93
|
+
if (headersJsonSchema) result["headers"] = headersJsonSchema;
|
|
94
|
+
}
|
|
95
|
+
if (message.summary) result["summary"] = message.summary;
|
|
96
|
+
if (message.description) result["description"] = message.description;
|
|
97
|
+
return result;
|
|
77
98
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Convert a queue definition to AsyncAPI ChannelObject
|
|
101
|
+
*/
|
|
102
|
+
queueToChannel(queue) {
|
|
103
|
+
return {
|
|
104
|
+
address: queue.name,
|
|
105
|
+
title: queue.name,
|
|
106
|
+
description: `AMQP Queue: ${queue.name}`,
|
|
107
|
+
bindings: { amqp: {
|
|
108
|
+
is: "queue",
|
|
109
|
+
queue: {
|
|
110
|
+
name: queue.name,
|
|
111
|
+
durable: queue.durable ?? false,
|
|
112
|
+
exclusive: queue.exclusive ?? false,
|
|
113
|
+
autoDelete: queue.autoDelete ?? false,
|
|
114
|
+
...queue.arguments && { vhost: "/" }
|
|
115
|
+
}
|
|
116
|
+
} }
|
|
85
117
|
};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Convert an exchange definition to AsyncAPI ChannelObject
|
|
121
|
+
*/
|
|
122
|
+
exchangeToChannel(exchange) {
|
|
123
|
+
return {
|
|
124
|
+
address: exchange.name,
|
|
125
|
+
title: exchange.name,
|
|
126
|
+
description: `AMQP Exchange: ${exchange.name} (${exchange.type})`,
|
|
127
|
+
bindings: { amqp: {
|
|
128
|
+
is: "routingKey",
|
|
129
|
+
exchange: {
|
|
130
|
+
name: exchange.name,
|
|
131
|
+
type: exchange.type,
|
|
132
|
+
durable: exchange.durable ?? false,
|
|
133
|
+
autoDelete: exchange.autoDelete ?? false,
|
|
134
|
+
...exchange.arguments && { vhost: "/" }
|
|
135
|
+
}
|
|
136
|
+
} }
|
|
91
137
|
};
|
|
92
138
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Get the name/key of an exchange from the contract
|
|
141
|
+
*/
|
|
142
|
+
getExchangeName(exchange, contract) {
|
|
143
|
+
if (contract.exchanges) {
|
|
144
|
+
for (const [name, ex] of Object.entries(contract.exchanges)) if (ex === exchange || ex.name === exchange.name) return name;
|
|
145
|
+
}
|
|
146
|
+
return exchange.name;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get the name/key of a queue from the contract
|
|
150
|
+
*/
|
|
151
|
+
getQueueName(queue, contract) {
|
|
152
|
+
if (contract.queues) {
|
|
153
|
+
for (const [name, q] of Object.entries(contract.queues)) if (q === queue || q.name === queue.name) return name;
|
|
154
|
+
}
|
|
155
|
+
return queue.name;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Convert a Standard Schema to JSON Schema using oRPC converters
|
|
159
|
+
*/
|
|
160
|
+
async convertSchema(schema, strategy) {
|
|
161
|
+
for (const converter of this.converters) if (await converter.condition(schema, { strategy })) {
|
|
162
|
+
const [_required, jsonSchema] = await converter.convert(schema, { strategy });
|
|
163
|
+
return jsonSchema;
|
|
164
|
+
}
|
|
165
|
+
return { type: "object" };
|
|
166
|
+
}
|
|
167
|
+
};
|
|
107
168
|
|
|
108
169
|
//#endregion
|
|
109
|
-
export {
|
|
170
|
+
export { AsyncAPIGenerator };
|
|
110
171
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["channels: Record<string, AsyncAPIChannel>","operations: Record<string, AsyncAPIOperation>","messages: Record<string, AsyncAPIMessageRef>","binding: {\n amqp?: {\n is: \"queue\";\n queue?: {\n name: string;\n durable?: boolean;\n exclusive?: boolean;\n autoDelete?: boolean;\n };\n };\n }","binding: {\n amqp?: {\n is: \"routingKey\";\n exchange?: {\n name: string;\n type: \"topic\" | \"direct\" | \"fanout\" | \"headers\";\n durable?: boolean;\n autoDelete?: boolean;\n };\n };\n }","result: AsyncAPIDocument"],"sources":["../src/schema-converter.ts","../src/generator.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { AsyncAPISchema } from \"./generator.js\";\n\n/**\n * Convert a Standard Schema to JSON Schema (AsyncAPI format)\n *\n * This is a basic converter that returns a generic object schema.\n * Users should provide their own schema-to-JSON-Schema converter function\n * specific to their schema library.\n *\n * For Zod users, import and use zodToJsonSchema from @amqp-contract/zod\n *\n * @example\n * ```ts\n * import { zodToJsonSchema } from '@amqp-contract/zod';\n * import { generateAsyncAPI } from '@amqp-contract/asyncapi';\n *\n * // Use zodToJsonSchema for converting Zod schemas\n * const jsonSchema = zodToJsonSchema(zodSchema);\n * ```\n */\nexport function standardSchemaToJsonSchema(_schema: StandardSchemaV1): AsyncAPISchema {\n // Basic fallback - returns a generic object schema\n // Users should provide their own converter for better results\n return { type: \"object\" };\n}\n","import type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { standardSchemaToJsonSchema } from \"./schema-converter.js\";\n\n/**\n * AsyncAPI 3.0.0 Specification\n */\nexport interface AsyncAPIDocument {\n asyncapi: \"3.0.0\";\n info: AsyncAPIInfo;\n servers?: Record<string, AsyncAPIServer>;\n channels?: Record<string, AsyncAPIChannel>;\n operations?: Record<string, AsyncAPIOperation>;\n components?: AsyncAPIComponents;\n}\n\nexport interface AsyncAPIInfo {\n title: string;\n version: string;\n description?: string;\n termsOfService?: string;\n contact?: {\n name?: string;\n url?: string;\n email?: string;\n };\n license?: {\n name: string;\n url?: string;\n };\n}\n\nexport interface AsyncAPIServer {\n host: string;\n protocol: string;\n description?: string;\n variables?: Record<string, { default: string; description?: string }>;\n}\n\nexport interface AsyncAPIChannel {\n address: string;\n messages?: Record<string, AsyncAPIMessageRef>;\n description?: string;\n bindings?: {\n amqp?: {\n is: \"queue\" | \"routingKey\";\n queue?: {\n name: string;\n durable?: boolean;\n exclusive?: boolean;\n autoDelete?: boolean;\n };\n exchange?: {\n name: string;\n type: \"topic\" | \"direct\" | \"fanout\" | \"headers\";\n durable?: boolean;\n autoDelete?: boolean;\n };\n };\n };\n}\n\nexport interface AsyncAPIOperation {\n action: \"send\" | \"receive\";\n channel: AsyncAPIRef;\n messages?: AsyncAPIMessageRef[];\n description?: string;\n}\n\nexport interface AsyncAPIMessageRef {\n $ref?: string;\n payload?: AsyncAPISchema;\n contentType?: string;\n name?: string;\n title?: string;\n summary?: string;\n description?: string;\n}\n\nexport interface AsyncAPISchema {\n type?: string;\n properties?: Record<string, AsyncAPISchema>;\n required?: string[];\n items?: AsyncAPISchema;\n $ref?: string;\n description?: string;\n format?: string;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n enum?: unknown[];\n}\n\ninterface AsyncAPIRef {\n $ref: string;\n}\n\nexport interface AsyncAPIComponents {\n messages?: Record<string, AsyncAPIMessageRef>;\n schemas?: Record<string, AsyncAPISchema>;\n}\n\n/**\n * Options for generating AsyncAPI specification\n */\nexport interface GenerateAsyncAPIOptions {\n info: Omit<AsyncAPIInfo, \"title\" | \"version\"> & {\n title?: string;\n version?: string;\n };\n servers?: Record<string, AsyncAPIServer>;\n}\n\n/**\n * Generate AsyncAPI 3.0.0 specification from AMQP contract\n */\nexport function generateAsyncAPI(\n contract: ContractDefinition,\n options: GenerateAsyncAPIOptions,\n): AsyncAPIDocument {\n const channels: Record<string, AsyncAPIChannel> = {};\n const operations: Record<string, AsyncAPIOperation> = {};\n const messages: Record<string, AsyncAPIMessageRef> = {};\n\n // Generate channels from queues\n if (contract.queues) {\n for (const [queueName, queue] of Object.entries(contract.queues)) {\n const binding: {\n amqp?: {\n is: \"queue\";\n queue?: {\n name: string;\n durable?: boolean;\n exclusive?: boolean;\n autoDelete?: boolean;\n };\n };\n } = {\n amqp: {\n is: \"queue\",\n queue: {\n name: queue.name,\n },\n },\n };\n\n if (queue.durable !== undefined) {\n binding.amqp!.queue!.durable = queue.durable;\n }\n if (queue.exclusive !== undefined) {\n binding.amqp!.queue!.exclusive = queue.exclusive;\n }\n if (queue.autoDelete !== undefined) {\n binding.amqp!.queue!.autoDelete = queue.autoDelete;\n }\n\n channels[queueName] = {\n address: queue.name,\n description: `Queue: ${queue.name}`,\n bindings: binding,\n };\n }\n }\n\n // Generate channels from exchanges\n if (contract.exchanges) {\n for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {\n const binding: {\n amqp?: {\n is: \"routingKey\";\n exchange?: {\n name: string;\n type: \"topic\" | \"direct\" | \"fanout\" | \"headers\";\n durable?: boolean;\n autoDelete?: boolean;\n };\n };\n } = {\n amqp: {\n is: \"routingKey\",\n exchange: {\n name: exchange.name,\n type: exchange.type,\n },\n },\n };\n\n if (exchange.durable !== undefined) {\n binding.amqp!.exchange!.durable = exchange.durable;\n }\n if (exchange.autoDelete !== undefined) {\n binding.amqp!.exchange!.autoDelete = exchange.autoDelete;\n }\n\n channels[exchangeName] = {\n address: exchange.name,\n description: `Exchange: ${exchange.name} (${exchange.type})`,\n bindings: binding,\n };\n }\n }\n\n // Generate operations from publishers\n if (contract.publishers) {\n for (const [publisherName, publisher] of Object.entries(contract.publishers)) {\n const messageName = `${publisherName}Message`;\n\n messages[messageName] = {\n name: messageName,\n title: `${publisherName} message`,\n contentType: \"application/json\",\n payload: standardSchemaToJsonSchema(publisher.message),\n };\n\n operations[publisherName] = {\n action: \"send\",\n channel: { $ref: `#/channels/${publisher.exchange}` },\n messages: [{ $ref: `#/components/messages/${messageName}` }],\n description: `Publish message to ${publisher.exchange}`,\n };\n }\n }\n\n // Generate operations from consumers\n if (contract.consumers) {\n for (const [consumerName, consumer] of Object.entries(contract.consumers)) {\n const messageName = `${consumerName}Message`;\n\n messages[messageName] = {\n name: messageName,\n title: `${consumerName} message`,\n contentType: \"application/json\",\n payload: standardSchemaToJsonSchema(consumer.message),\n };\n\n operations[consumerName] = {\n action: \"receive\",\n channel: { $ref: `#/channels/${consumer.queue}` },\n messages: [{ $ref: `#/components/messages/${messageName}` }],\n description: `Consume message from ${consumer.queue}`,\n };\n }\n }\n\n const result: AsyncAPIDocument = {\n asyncapi: \"3.0.0\",\n info: {\n title: options.info.title ?? \"AMQP Contract API\",\n version: options.info.version ?? \"1.0.0\",\n ...options.info,\n },\n channels,\n operations,\n components: {\n messages,\n },\n };\n\n if (options.servers) {\n result.servers = options.servers;\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,2BAA2B,SAA2C;AAGpF,QAAO,EAAE,MAAM,UAAU;;;;;;;;AC6F3B,SAAgB,iBACd,UACA,SACkB;CAClB,MAAMA,WAA4C,EAAE;CACpD,MAAMC,aAAgD,EAAE;CACxD,MAAMC,WAA+C,EAAE;AAGvD,KAAI,SAAS,OACX,MAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,SAAS,OAAO,EAAE;EAChE,MAAMC,UAUF,EACF,MAAM;GACJ,IAAI;GACJ,OAAO,EACL,MAAM,MAAM,MACb;GACF,EACF;AAED,MAAI,MAAM,YAAY,OACpB,SAAQ,KAAM,MAAO,UAAU,MAAM;AAEvC,MAAI,MAAM,cAAc,OACtB,SAAQ,KAAM,MAAO,YAAY,MAAM;AAEzC,MAAI,MAAM,eAAe,OACvB,SAAQ,KAAM,MAAO,aAAa,MAAM;AAG1C,WAAS,aAAa;GACpB,SAAS,MAAM;GACf,aAAa,UAAU,MAAM;GAC7B,UAAU;GACX;;AAKL,KAAI,SAAS,UACX,MAAK,MAAM,CAAC,cAAc,aAAa,OAAO,QAAQ,SAAS,UAAU,EAAE;EACzE,MAAMC,UAUF,EACF,MAAM;GACJ,IAAI;GACJ,UAAU;IACR,MAAM,SAAS;IACf,MAAM,SAAS;IAChB;GACF,EACF;AAED,MAAI,SAAS,YAAY,OACvB,SAAQ,KAAM,SAAU,UAAU,SAAS;AAE7C,MAAI,SAAS,eAAe,OAC1B,SAAQ,KAAM,SAAU,aAAa,SAAS;AAGhD,WAAS,gBAAgB;GACvB,SAAS,SAAS;GAClB,aAAa,aAAa,SAAS,KAAK,IAAI,SAAS,KAAK;GAC1D,UAAU;GACX;;AAKL,KAAI,SAAS,WACX,MAAK,MAAM,CAAC,eAAe,cAAc,OAAO,QAAQ,SAAS,WAAW,EAAE;EAC5E,MAAM,cAAc,GAAG,cAAc;AAErC,WAAS,eAAe;GACtB,MAAM;GACN,OAAO,GAAG,cAAc;GACxB,aAAa;GACb,SAAS,2BAA2B,UAAU,QAAQ;GACvD;AAED,aAAW,iBAAiB;GAC1B,QAAQ;GACR,SAAS,EAAE,MAAM,cAAc,UAAU,YAAY;GACrD,UAAU,CAAC,EAAE,MAAM,yBAAyB,eAAe,CAAC;GAC5D,aAAa,sBAAsB,UAAU;GAC9C;;AAKL,KAAI,SAAS,UACX,MAAK,MAAM,CAAC,cAAc,aAAa,OAAO,QAAQ,SAAS,UAAU,EAAE;EACzE,MAAM,cAAc,GAAG,aAAa;AAEpC,WAAS,eAAe;GACtB,MAAM;GACN,OAAO,GAAG,aAAa;GACvB,aAAa;GACb,SAAS,2BAA2B,SAAS,QAAQ;GACtD;AAED,aAAW,gBAAgB;GACzB,QAAQ;GACR,SAAS,EAAE,MAAM,cAAc,SAAS,SAAS;GACjD,UAAU,CAAC,EAAE,MAAM,yBAAyB,eAAe,CAAC;GAC5D,aAAa,wBAAwB,SAAS;GAC/C;;CAIL,MAAMC,SAA2B;EAC/B,UAAU;EACV,MAAM;GACJ,OAAO,QAAQ,KAAK,SAAS;GAC7B,SAAS,QAAQ,KAAK,WAAW;GACjC,GAAG,QAAQ;GACZ;EACD;EACA;EACA,YAAY,EACV,UACD;EACF;AAED,KAAI,QAAQ,QACV,QAAO,UAAU,QAAQ;AAG3B,QAAO"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["convertedChannels: ChannelsObject","convertedOperations: OperationsObject","convertedMessages: MessagesObject","channelMessages: MessagesObject","channel: ChannelObject","result: Record<string, unknown>"],"sources":["../src/index.ts"],"sourcesContent":["import { ConditionalSchemaConverter, JSONSchema } from \"@orpc/openapi\";\nimport {\n AsyncAPIObject,\n ChannelsObject,\n OperationsObject,\n MessagesObject,\n MessageObject,\n ChannelObject,\n} from \"@asyncapi/parser/esm/spec-types/v3\";\nimport type {\n ContractDefinition,\n MessageDefinition,\n QueueDefinition,\n ExchangeDefinition,\n} from \"@amqp-contract/contract\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nexport interface AsyncAPIGeneratorOptions {\n schemaConverters?: ConditionalSchemaConverter[];\n}\n\nexport type AsyncAPIGeneratorGenerateOptions = Pick<AsyncAPIObject, \"id\" | \"info\" | \"servers\">;\n\nexport class AsyncAPIGenerator {\n private readonly converters: ConditionalSchemaConverter[];\n\n constructor(options: AsyncAPIGeneratorOptions = {}) {\n this.converters = options.schemaConverters ?? [];\n }\n\n /**\n * Generate an AsyncAPI 3.0 document from a contract definition\n */\n async generate(\n contract: ContractDefinition,\n options: AsyncAPIGeneratorGenerateOptions,\n ): Promise<AsyncAPIObject> {\n const convertedChannels: ChannelsObject = {};\n const convertedOperations: OperationsObject = {};\n const convertedMessages: MessagesObject = {};\n\n // First, collect all messages from publishers and consumers\n const publisherMessages = new Map<string, { message: MessageDefinition; channelKey: string }>();\n const consumerMessages = new Map<string, { message: MessageDefinition; channelKey: string }>();\n\n // Collect messages from publishers\n if (contract.publishers) {\n for (const [publisherName, publisher] of Object.entries(contract.publishers)) {\n const channelKey = this.getExchangeName(publisher.exchange, contract);\n publisherMessages.set(publisherName, { message: publisher.message, channelKey });\n }\n }\n\n // Collect messages from consumers\n if (contract.consumers) {\n for (const [consumerName, consumer] of Object.entries(contract.consumers)) {\n const channelKey = this.getQueueName(consumer.queue, contract);\n consumerMessages.set(consumerName, { message: consumer.message, channelKey });\n }\n }\n\n // Generate channels from queues with their messages\n if (contract.queues) {\n for (const [queueName, queue] of Object.entries(contract.queues)) {\n const channelMessages: MessagesObject = {};\n\n // Add messages from consumers that reference this queue\n for (const [consumerName, { message, channelKey }] of consumerMessages) {\n if (channelKey === queueName) {\n const messageName = `${consumerName}Message`;\n channelMessages[messageName] = await this.convertMessage(message);\n convertedMessages[messageName] = await this.convertMessage(message);\n }\n }\n\n const channel: ChannelObject = {\n ...this.queueToChannel(queue),\n };\n\n if (Object.keys(channelMessages).length > 0) {\n channel.messages = channelMessages;\n }\n\n convertedChannels[queueName] = channel;\n }\n }\n\n // Generate channels from exchanges with their messages\n if (contract.exchanges) {\n for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {\n const channelMessages: MessagesObject = {};\n\n // Add messages from publishers that reference this exchange\n for (const [publisherName, { message, channelKey }] of publisherMessages) {\n if (channelKey === exchangeName) {\n const messageName = `${publisherName}Message`;\n channelMessages[messageName] = await this.convertMessage(message);\n convertedMessages[messageName] = await this.convertMessage(message);\n }\n }\n\n const channel: ChannelObject = {\n ...this.exchangeToChannel(exchange),\n };\n\n if (Object.keys(channelMessages).length > 0) {\n channel.messages = channelMessages;\n }\n\n convertedChannels[exchangeName] = channel;\n }\n }\n\n // Generate publish operations from publishers\n if (contract.publishers) {\n for (const [publisherName, publisher] of Object.entries(contract.publishers)) {\n const exchangeName = this.getExchangeName(publisher.exchange, contract);\n const messageName = `${publisherName}Message`;\n\n convertedOperations[publisherName] = {\n action: \"send\",\n channel: { $ref: `#/channels/${exchangeName}` },\n messages: [{ $ref: `#/channels/${exchangeName}/messages/${messageName}` }],\n summary: `Publish to ${publisher.exchange.name}`,\n ...(publisher.routingKey && {\n description: `Routing key: ${publisher.routingKey}`,\n }),\n };\n }\n }\n\n // Generate receive operations from consumers\n if (contract.consumers) {\n for (const [consumerName, consumer] of Object.entries(contract.consumers)) {\n const queueName = this.getQueueName(consumer.queue, contract);\n const messageName = `${consumerName}Message`;\n\n convertedOperations[consumerName] = {\n action: \"receive\",\n channel: { $ref: `#/channels/${queueName}` },\n messages: [{ $ref: `#/channels/${queueName}/messages/${messageName}` }],\n summary: `Consume from ${consumer.queue.name}`,\n ...(consumer.prefetch && {\n description: `Prefetch: ${consumer.prefetch}`,\n }),\n };\n }\n }\n\n return {\n ...options,\n asyncapi: \"3.0.0\",\n channels: convertedChannels,\n operations: convertedOperations,\n components: {\n messages: convertedMessages,\n },\n };\n }\n\n /**\n * Convert a message definition to AsyncAPI MessageObject\n */\n private async convertMessage(message: MessageDefinition): Promise<MessageObject> {\n const payload = message.payload;\n\n // Convert payload schema\n const payloadJsonSchema = await this.convertSchema(payload, \"input\");\n\n // Build result with required properties\n const result: Record<string, unknown> = {\n payload: payloadJsonSchema,\n contentType: \"application/json\",\n };\n\n // Add optional properties only if they exist\n if (message.headers) {\n const headersJsonSchema = await this.convertSchema(message.headers, \"input\");\n if (headersJsonSchema) {\n result[\"headers\"] = headersJsonSchema;\n }\n }\n\n if (message.summary) {\n result[\"summary\"] = message.summary;\n }\n\n if (message.description) {\n result[\"description\"] = message.description;\n }\n\n return result as MessageObject;\n }\n\n /**\n * Convert a queue definition to AsyncAPI ChannelObject\n */\n private queueToChannel(queue: QueueDefinition): ChannelObject {\n const result: Record<string, unknown> = {\n address: queue.name,\n title: queue.name,\n description: `AMQP Queue: ${queue.name}`,\n bindings: {\n amqp: {\n is: \"queue\",\n queue: {\n name: queue.name,\n durable: queue.durable ?? false,\n exclusive: queue.exclusive ?? false,\n autoDelete: queue.autoDelete ?? false,\n ...(queue.arguments && { vhost: \"/\" }),\n },\n },\n },\n };\n\n return result as ChannelObject;\n }\n\n /**\n * Convert an exchange definition to AsyncAPI ChannelObject\n */\n private exchangeToChannel(exchange: ExchangeDefinition): ChannelObject {\n const result: Record<string, unknown> = {\n address: exchange.name,\n title: exchange.name,\n description: `AMQP Exchange: ${exchange.name} (${exchange.type})`,\n bindings: {\n amqp: {\n is: \"routingKey\",\n exchange: {\n name: exchange.name,\n type: exchange.type,\n durable: exchange.durable ?? false,\n autoDelete: exchange.autoDelete ?? false,\n ...(exchange.arguments && { vhost: \"/\" }),\n },\n },\n },\n };\n\n return result as ChannelObject;\n }\n\n /**\n * Get the name/key of an exchange from the contract\n */\n private getExchangeName(exchange: ExchangeDefinition, contract: ContractDefinition): string {\n if (contract.exchanges) {\n for (const [name, ex] of Object.entries(contract.exchanges)) {\n if (ex === exchange || ex.name === exchange.name) {\n return name;\n }\n }\n }\n return exchange.name;\n }\n\n /**\n * Get the name/key of a queue from the contract\n */\n private getQueueName(queue: QueueDefinition, contract: ContractDefinition): string {\n if (contract.queues) {\n for (const [name, q] of Object.entries(contract.queues)) {\n if (q === queue || q.name === queue.name) {\n return name;\n }\n }\n }\n return queue.name;\n }\n\n /**\n * Convert a Standard Schema to JSON Schema using oRPC converters\n */\n private async convertSchema(\n schema: StandardSchemaV1,\n strategy: \"input\" | \"output\",\n ): Promise<JSONSchema> {\n // Try each converter until one matches\n for (const converter of this.converters) {\n const matches = await converter.condition(schema, { strategy });\n if (matches) {\n const [_required, jsonSchema] = await converter.convert(schema, { strategy });\n return jsonSchema;\n }\n }\n\n // If no converter matches, return a generic object schema\n // This allows the contract to still be generated even without schema converters\n return { type: \"object\" };\n }\n}\n"],"mappings":";AAuBA,IAAa,oBAAb,MAA+B;CAC7B,AAAiB;CAEjB,YAAY,UAAoC,EAAE,EAAE;AAClD,OAAK,aAAa,QAAQ,oBAAoB,EAAE;;;;;CAMlD,MAAM,SACJ,UACA,SACyB;EACzB,MAAMA,oBAAoC,EAAE;EAC5C,MAAMC,sBAAwC,EAAE;EAChD,MAAMC,oBAAoC,EAAE;EAG5C,MAAM,oCAAoB,IAAI,KAAiE;EAC/F,MAAM,mCAAmB,IAAI,KAAiE;AAG9F,MAAI,SAAS,WACX,MAAK,MAAM,CAAC,eAAe,cAAc,OAAO,QAAQ,SAAS,WAAW,EAAE;GAC5E,MAAM,aAAa,KAAK,gBAAgB,UAAU,UAAU,SAAS;AACrE,qBAAkB,IAAI,eAAe;IAAE,SAAS,UAAU;IAAS;IAAY,CAAC;;AAKpF,MAAI,SAAS,UACX,MAAK,MAAM,CAAC,cAAc,aAAa,OAAO,QAAQ,SAAS,UAAU,EAAE;GACzE,MAAM,aAAa,KAAK,aAAa,SAAS,OAAO,SAAS;AAC9D,oBAAiB,IAAI,cAAc;IAAE,SAAS,SAAS;IAAS;IAAY,CAAC;;AAKjF,MAAI,SAAS,OACX,MAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,SAAS,OAAO,EAAE;GAChE,MAAMC,kBAAkC,EAAE;AAG1C,QAAK,MAAM,CAAC,cAAc,EAAE,SAAS,iBAAiB,iBACpD,KAAI,eAAe,WAAW;IAC5B,MAAM,cAAc,GAAG,aAAa;AACpC,oBAAgB,eAAe,MAAM,KAAK,eAAe,QAAQ;AACjE,sBAAkB,eAAe,MAAM,KAAK,eAAe,QAAQ;;GAIvE,MAAMC,UAAyB,EAC7B,GAAG,KAAK,eAAe,MAAM,EAC9B;AAED,OAAI,OAAO,KAAK,gBAAgB,CAAC,SAAS,EACxC,SAAQ,WAAW;AAGrB,qBAAkB,aAAa;;AAKnC,MAAI,SAAS,UACX,MAAK,MAAM,CAAC,cAAc,aAAa,OAAO,QAAQ,SAAS,UAAU,EAAE;GACzE,MAAMD,kBAAkC,EAAE;AAG1C,QAAK,MAAM,CAAC,eAAe,EAAE,SAAS,iBAAiB,kBACrD,KAAI,eAAe,cAAc;IAC/B,MAAM,cAAc,GAAG,cAAc;AACrC,oBAAgB,eAAe,MAAM,KAAK,eAAe,QAAQ;AACjE,sBAAkB,eAAe,MAAM,KAAK,eAAe,QAAQ;;GAIvE,MAAMC,UAAyB,EAC7B,GAAG,KAAK,kBAAkB,SAAS,EACpC;AAED,OAAI,OAAO,KAAK,gBAAgB,CAAC,SAAS,EACxC,SAAQ,WAAW;AAGrB,qBAAkB,gBAAgB;;AAKtC,MAAI,SAAS,WACX,MAAK,MAAM,CAAC,eAAe,cAAc,OAAO,QAAQ,SAAS,WAAW,EAAE;GAC5E,MAAM,eAAe,KAAK,gBAAgB,UAAU,UAAU,SAAS;GACvE,MAAM,cAAc,GAAG,cAAc;AAErC,uBAAoB,iBAAiB;IACnC,QAAQ;IACR,SAAS,EAAE,MAAM,cAAc,gBAAgB;IAC/C,UAAU,CAAC,EAAE,MAAM,cAAc,aAAa,YAAY,eAAe,CAAC;IAC1E,SAAS,cAAc,UAAU,SAAS;IAC1C,GAAI,UAAU,cAAc,EAC1B,aAAa,gBAAgB,UAAU,cACxC;IACF;;AAKL,MAAI,SAAS,UACX,MAAK,MAAM,CAAC,cAAc,aAAa,OAAO,QAAQ,SAAS,UAAU,EAAE;GACzE,MAAM,YAAY,KAAK,aAAa,SAAS,OAAO,SAAS;GAC7D,MAAM,cAAc,GAAG,aAAa;AAEpC,uBAAoB,gBAAgB;IAClC,QAAQ;IACR,SAAS,EAAE,MAAM,cAAc,aAAa;IAC5C,UAAU,CAAC,EAAE,MAAM,cAAc,UAAU,YAAY,eAAe,CAAC;IACvE,SAAS,gBAAgB,SAAS,MAAM;IACxC,GAAI,SAAS,YAAY,EACvB,aAAa,aAAa,SAAS,YACpC;IACF;;AAIL,SAAO;GACL,GAAG;GACH,UAAU;GACV,UAAU;GACV,YAAY;GACZ,YAAY,EACV,UAAU,mBACX;GACF;;;;;CAMH,MAAc,eAAe,SAAoD;EAC/E,MAAM,UAAU,QAAQ;EAMxB,MAAMC,SAAkC;GACtC,SAJwB,MAAM,KAAK,cAAc,SAAS,QAAQ;GAKlE,aAAa;GACd;AAGD,MAAI,QAAQ,SAAS;GACnB,MAAM,oBAAoB,MAAM,KAAK,cAAc,QAAQ,SAAS,QAAQ;AAC5E,OAAI,kBACF,QAAO,aAAa;;AAIxB,MAAI,QAAQ,QACV,QAAO,aAAa,QAAQ;AAG9B,MAAI,QAAQ,YACV,QAAO,iBAAiB,QAAQ;AAGlC,SAAO;;;;;CAMT,AAAQ,eAAe,OAAuC;AAmB5D,SAlBwC;GACtC,SAAS,MAAM;GACf,OAAO,MAAM;GACb,aAAa,eAAe,MAAM;GAClC,UAAU,EACR,MAAM;IACJ,IAAI;IACJ,OAAO;KACL,MAAM,MAAM;KACZ,SAAS,MAAM,WAAW;KAC1B,WAAW,MAAM,aAAa;KAC9B,YAAY,MAAM,cAAc;KAChC,GAAI,MAAM,aAAa,EAAE,OAAO,KAAK;KACtC;IACF,EACF;GACF;;;;;CAQH,AAAQ,kBAAkB,UAA6C;AAmBrE,SAlBwC;GACtC,SAAS,SAAS;GAClB,OAAO,SAAS;GAChB,aAAa,kBAAkB,SAAS,KAAK,IAAI,SAAS,KAAK;GAC/D,UAAU,EACR,MAAM;IACJ,IAAI;IACJ,UAAU;KACR,MAAM,SAAS;KACf,MAAM,SAAS;KACf,SAAS,SAAS,WAAW;KAC7B,YAAY,SAAS,cAAc;KACnC,GAAI,SAAS,aAAa,EAAE,OAAO,KAAK;KACzC;IACF,EACF;GACF;;;;;CAQH,AAAQ,gBAAgB,UAA8B,UAAsC;AAC1F,MAAI,SAAS,WACX;QAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,SAAS,UAAU,CACzD,KAAI,OAAO,YAAY,GAAG,SAAS,SAAS,KAC1C,QAAO;;AAIb,SAAO,SAAS;;;;;CAMlB,AAAQ,aAAa,OAAwB,UAAsC;AACjF,MAAI,SAAS,QACX;QAAK,MAAM,CAAC,MAAM,MAAM,OAAO,QAAQ,SAAS,OAAO,CACrD,KAAI,MAAM,SAAS,EAAE,SAAS,MAAM,KAClC,QAAO;;AAIb,SAAO,MAAM;;;;;CAMf,MAAc,cACZ,QACA,UACqB;AAErB,OAAK,MAAM,aAAa,KAAK,WAE3B,KADgB,MAAM,UAAU,UAAU,QAAQ,EAAE,UAAU,CAAC,EAClD;GACX,MAAM,CAAC,WAAW,cAAc,MAAM,UAAU,QAAQ,QAAQ,EAAE,UAAU,CAAC;AAC7E,UAAO;;AAMX,SAAO,EAAE,MAAM,UAAU"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amqp-contract/asyncapi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AsyncAPI specification generator for amqp-contract",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"amqp",
|
|
@@ -41,14 +41,21 @@
|
|
|
41
41
|
"dist"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
+
"@orpc/openapi": "1.13.0",
|
|
44
45
|
"@standard-schema/spec": "1.1.0",
|
|
45
|
-
"@amqp-contract/contract": "0.
|
|
46
|
+
"@amqp-contract/contract": "0.2.0"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
49
|
+
"@asyncapi/parser": "3.4.0",
|
|
50
|
+
"@orpc/arktype": "1.13.0",
|
|
51
|
+
"@orpc/valibot": "1.13.0",
|
|
52
|
+
"@orpc/zod": "1.13.0",
|
|
48
53
|
"@types/node": "25.0.3",
|
|
49
54
|
"@vitest/coverage-v8": "4.0.16",
|
|
55
|
+
"arktype": "2.1.29",
|
|
50
56
|
"tsdown": "0.18.2",
|
|
51
57
|
"typescript": "5.9.3",
|
|
58
|
+
"valibot": "1.2.0",
|
|
52
59
|
"vitest": "4.0.16",
|
|
53
60
|
"zod": "4.2.1",
|
|
54
61
|
"@amqp-contract/tsconfig": "0.0.0"
|