@amqp-contract/asyncapi 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Benoit Travers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # @amqp-contract/asyncapi
2
+
3
+ AsyncAPI 3.0.0 specification generator for amqp-contract.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @amqp-contract/asyncapi
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { generateAsyncAPI } from '@amqp-contract/asyncapi';
15
+ import { contract } from './contract';
16
+
17
+ // Generate AsyncAPI specification
18
+ const asyncAPISpec = generateAsyncAPI(contract, {
19
+ info: {
20
+ title: 'My AMQP API',
21
+ version: '1.0.0',
22
+ description: 'Type-safe AMQP messaging API',
23
+ },
24
+ servers: {
25
+ development: {
26
+ host: 'localhost:5672',
27
+ protocol: 'amqp',
28
+ description: 'Development RabbitMQ server',
29
+ },
30
+ production: {
31
+ host: 'rabbitmq.example.com:5672',
32
+ protocol: 'amqp',
33
+ description: 'Production RabbitMQ server',
34
+ },
35
+ },
36
+ });
37
+
38
+ // Output as JSON
39
+ console.log(JSON.stringify(asyncAPISpec, null, 2));
40
+
41
+ // Or write to file
42
+ import { writeFileSync } from 'fs';
43
+ writeFileSync('asyncapi.json', JSON.stringify(asyncAPISpec, null, 2));
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### `generateAsyncAPI(contract, options)`
49
+
50
+ Generate an AsyncAPI 3.0.0 specification from an AMQP contract.
51
+
52
+ **Parameters:**
53
+ - `contract`: The AMQP contract definition
54
+ - `options`: Configuration options
55
+ - `info`: API information (title, version, description, etc.)
56
+ - `servers`: Server configurations (optional)
57
+
58
+ **Returns:** AsyncAPI 3.0.0 document
59
+
60
+ ## Features
61
+
62
+ - ✅ Full AsyncAPI 3.0.0 support
63
+ - ✅ Channels from exchanges and queues
64
+ - ✅ Operations for publishers and consumers
65
+ - ✅ Message schemas from Zod schemas
66
+ - ✅ AMQP protocol bindings
67
+
68
+ ## License
69
+
70
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,111 @@
1
+
2
+ //#region src/schema-converter.ts
3
+ /**
4
+ * Convert a Standard Schema to JSON Schema (AsyncAPI format)
5
+ *
6
+ * This is a basic converter that returns a generic object schema.
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
+ };
47
+ }
48
+ if (contract.exchanges) for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {
49
+ const binding = { amqp: {
50
+ is: "routingKey",
51
+ exchange: {
52
+ name: exchange.name,
53
+ type: exchange.type
54
+ }
55
+ } };
56
+ if (exchange.durable !== void 0) binding.amqp.exchange.durable = exchange.durable;
57
+ if (exchange.autoDelete !== void 0) binding.amqp.exchange.autoDelete = exchange.autoDelete;
58
+ channels[exchangeName] = {
59
+ address: exchange.name,
60
+ description: `Exchange: ${exchange.name} (${exchange.type})`,
61
+ bindings: binding
62
+ };
63
+ }
64
+ if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
65
+ const messageName = `${publisherName}Message`;
66
+ messages[messageName] = {
67
+ name: messageName,
68
+ title: `${publisherName} message`,
69
+ contentType: "application/json",
70
+ payload: standardSchemaToJsonSchema(publisher.message)
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}`
77
+ };
78
+ }
79
+ if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
80
+ const messageName = `${consumerName}Message`;
81
+ messages[messageName] = {
82
+ name: messageName,
83
+ title: `${consumerName} message`,
84
+ contentType: "application/json",
85
+ payload: standardSchemaToJsonSchema(consumer.message)
86
+ };
87
+ operations[consumerName] = {
88
+ action: "receive",
89
+ channel: { $ref: `#/channels/${consumer.queue}` },
90
+ messages: [{ $ref: `#/components/messages/${messageName}` }],
91
+ description: `Consume message from ${consumer.queue}`
92
+ };
93
+ }
94
+ const result = {
95
+ asyncapi: "3.0.0",
96
+ info: {
97
+ title: options.info.title ?? "AMQP Contract API",
98
+ version: options.info.version ?? "1.0.0",
99
+ ...options.info
100
+ },
101
+ channels,
102
+ operations,
103
+ components: { messages }
104
+ };
105
+ if (options.servers) result.servers = options.servers;
106
+ return result;
107
+ }
108
+
109
+ //#endregion
110
+ exports.generateAsyncAPI = generateAsyncAPI;
111
+ exports.standardSchemaToJsonSchema = standardSchemaToJsonSchema;
@@ -0,0 +1,136 @@
1
+ import { ContractDefinition } from "@amqp-contract/contract";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
+
4
+ //#region src/generator.d.ts
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
+ }
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
+ //#endregion
135
+ export { type AsyncAPIChannel, type AsyncAPIComponents, type AsyncAPIDocument, type AsyncAPIInfo, type AsyncAPIMessageRef, type AsyncAPIOperation, type AsyncAPISchema, type AsyncAPIServer, type GenerateAsyncAPIOptions, generateAsyncAPI, standardSchemaToJsonSchema };
136
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/generator.ts","../src/schema-converter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAMiB,UAAA,gBAAA,CAAgB;EAEzB,QAAA,EAAA,OAAA;EACmB,IAAA,EADnB,YACmB;EAAf,OAAA,CAAA,EAAA,MAAA,CAAA,MAAA,EAAe,cAAf,CAAA;EACgB,QAAA,CAAA,EAAf,MAAe,CAAA,MAAA,EAAA,eAAA,CAAA;EAAf,UAAA,CAAA,EACE,MADF,CAAA,MAAA,EACiB,iBADjB,CAAA;EACiB,UAAA,CAAA,EACf,kBADe;;AACf,UAGE,YAAA,CAHF;EAAkB,KAAA,EAAA,MAAA;EAGhB,OAAA,EAAA,MAAY;EAgBZ,WAAA,CAAA,EAAA,MAAc;EAOd,cAAA,CAAA,EAAA,MAAe;EAuBf,OAAA,CAAA,EAAA;IAOA,IAAA,CAAA,EAAA,MAAA;IAUA,GAAA,CAAA,EAAA,MAAA;IAEa,KAAA,CAAA,EAAA,MAAA;EAAf,CAAA;EAEL,OAAA,CAAA,EAAA;IAAc,IAAA,EAAA,MAAA;IAYd,GAAA,CAAA,EAAA,MAAW;EAIJ,CAAA;;AACJ,UApEI,cAAA,CAoEJ;EACc,IAAA,EAAA,MAAA;EAAf,QAAA,EAAA,MAAA;EAAM,WAAA,CAAA,EAAA,MAAA;EAMD,SAAA,CAAA,EAvEH,MAuEG,CAAA,MAAA,EAAuB;IAC3B,OAAA,EAAA,MAAA;IAAL,WAAA,CAAA,EAAA,MAAA;EAImB,CAAA,CAAA;;AAAT,UAzED,eAAA,CAyEC;EAMF,OAAA,EAAA,MAAA;EACJ,QAAA,CAAA,EA9EC,MA8ED,CAAA,MAAA,EA9EgB,kBA8EhB,CAAA;EACD,WAAA,CAAA,EAAA,MAAA;EACR,QAAA,CAAA,EAAA;IAAgB,IAAA,CAAA,EAAA;;;;QCnGH,OAAA,CAAA,EAAA,OAA0B;;;;;;;;;;;;;UDwCzB,iBAAA;;WAEN;aACE;;;UAII,kBAAA;;YAEL;;;;;;;UAQK,cAAA;;eAEF,eAAe;;UAEpB;;;;;;;;;;;UAYA,WAAA;;;UAIO,kBAAA;aACJ,eAAe;YAChB,eAAe;;;;;UAMV,uBAAA;QACT,KAAK;;;;YAID,eAAe;;;;;iBAMX,gBAAA,WACJ,6BACD,0BACR;;;;;AAlHH;;;;;;;;;;AASA;AAgBA;AAOA;AAuBA;AAOA;AAUA;AAE8B,iBC3Dd,0BAAA,CD2Dc,OAAA,EC3DsB,gBD2DtB,CAAA,EC3DyC,cD2DzC"}
@@ -0,0 +1,136 @@
1
+ import { ContractDefinition } from "@amqp-contract/contract";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
+
4
+ //#region src/generator.d.ts
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
+ }
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
+ //#endregion
135
+ export { type AsyncAPIChannel, type AsyncAPIComponents, type AsyncAPIDocument, type AsyncAPIInfo, type AsyncAPIMessageRef, type AsyncAPIOperation, type AsyncAPISchema, type AsyncAPIServer, type GenerateAsyncAPIOptions, generateAsyncAPI, standardSchemaToJsonSchema };
136
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/generator.ts","../src/schema-converter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAMiB,UAAA,gBAAA,CAAgB;EAEzB,QAAA,EAAA,OAAA;EACmB,IAAA,EADnB,YACmB;EAAf,OAAA,CAAA,EAAA,MAAA,CAAA,MAAA,EAAe,cAAf,CAAA;EACgB,QAAA,CAAA,EAAf,MAAe,CAAA,MAAA,EAAA,eAAA,CAAA;EAAf,UAAA,CAAA,EACE,MADF,CAAA,MAAA,EACiB,iBADjB,CAAA;EACiB,UAAA,CAAA,EACf,kBADe;;AACf,UAGE,YAAA,CAHF;EAAkB,KAAA,EAAA,MAAA;EAGhB,OAAA,EAAA,MAAY;EAgBZ,WAAA,CAAA,EAAA,MAAc;EAOd,cAAA,CAAA,EAAA,MAAe;EAuBf,OAAA,CAAA,EAAA;IAOA,IAAA,CAAA,EAAA,MAAA;IAUA,GAAA,CAAA,EAAA,MAAA;IAEa,KAAA,CAAA,EAAA,MAAA;EAAf,CAAA;EAEL,OAAA,CAAA,EAAA;IAAc,IAAA,EAAA,MAAA;IAYd,GAAA,CAAA,EAAA,MAAW;EAIJ,CAAA;;AACJ,UApEI,cAAA,CAoEJ;EACc,IAAA,EAAA,MAAA;EAAf,QAAA,EAAA,MAAA;EAAM,WAAA,CAAA,EAAA,MAAA;EAMD,SAAA,CAAA,EAvEH,MAuEG,CAAA,MAAA,EAAuB;IAC3B,OAAA,EAAA,MAAA;IAAL,WAAA,CAAA,EAAA,MAAA;EAImB,CAAA,CAAA;;AAAT,UAzED,eAAA,CAyEC;EAMF,OAAA,EAAA,MAAA;EACJ,QAAA,CAAA,EA9EC,MA8ED,CAAA,MAAA,EA9EgB,kBA8EhB,CAAA;EACD,WAAA,CAAA,EAAA,MAAA;EACR,QAAA,CAAA,EAAA;IAAgB,IAAA,CAAA,EAAA;;;;QCnGH,OAAA,CAAA,EAAA,OAA0B;;;;;;;;;;;;;UDwCzB,iBAAA;;WAEN;aACE;;;UAII,kBAAA;;YAEL;;;;;;;UAQK,cAAA;;eAEF,eAAe;;UAEpB;;;;;;;;;;;UAYA,WAAA;;;UAIO,kBAAA;aACJ,eAAe;YAChB,eAAe;;;;;UAMV,uBAAA;QACT,KAAK;;;;YAID,eAAe;;;;;iBAMX,gBAAA,WACJ,6BACD,0BACR;;;;;AAlHH;;;;;;;;;;AASA;AAgBA;AAOA;AAuBA;AAOA;AAUA;AAE8B,iBC3Dd,0BAAA,CD2Dc,OAAA,EC3DsB,gBD2DtB,CAAA,EC3DyC,cD2DzC"}
package/dist/index.mjs ADDED
@@ -0,0 +1,110 @@
1
+ //#region src/schema-converter.ts
2
+ /**
3
+ * Convert a Standard Schema to JSON Schema (AsyncAPI format)
4
+ *
5
+ * This is a basic converter that returns a generic object schema.
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
+ };
46
+ }
47
+ if (contract.exchanges) for (const [exchangeName, exchange] of Object.entries(contract.exchanges)) {
48
+ const binding = { amqp: {
49
+ is: "routingKey",
50
+ exchange: {
51
+ name: exchange.name,
52
+ type: exchange.type
53
+ }
54
+ } };
55
+ if (exchange.durable !== void 0) binding.amqp.exchange.durable = exchange.durable;
56
+ if (exchange.autoDelete !== void 0) binding.amqp.exchange.autoDelete = exchange.autoDelete;
57
+ channels[exchangeName] = {
58
+ address: exchange.name,
59
+ description: `Exchange: ${exchange.name} (${exchange.type})`,
60
+ bindings: binding
61
+ };
62
+ }
63
+ if (contract.publishers) for (const [publisherName, publisher] of Object.entries(contract.publishers)) {
64
+ const messageName = `${publisherName}Message`;
65
+ messages[messageName] = {
66
+ name: messageName,
67
+ title: `${publisherName} message`,
68
+ contentType: "application/json",
69
+ payload: standardSchemaToJsonSchema(publisher.message)
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}`
76
+ };
77
+ }
78
+ if (contract.consumers) for (const [consumerName, consumer] of Object.entries(contract.consumers)) {
79
+ const messageName = `${consumerName}Message`;
80
+ messages[messageName] = {
81
+ name: messageName,
82
+ title: `${consumerName} message`,
83
+ contentType: "application/json",
84
+ payload: standardSchemaToJsonSchema(consumer.message)
85
+ };
86
+ operations[consumerName] = {
87
+ action: "receive",
88
+ channel: { $ref: `#/channels/${consumer.queue}` },
89
+ messages: [{ $ref: `#/components/messages/${messageName}` }],
90
+ description: `Consume message from ${consumer.queue}`
91
+ };
92
+ }
93
+ const result = {
94
+ asyncapi: "3.0.0",
95
+ info: {
96
+ title: options.info.title ?? "AMQP Contract API",
97
+ version: options.info.version ?? "1.0.0",
98
+ ...options.info
99
+ },
100
+ channels,
101
+ operations,
102
+ components: { messages }
103
+ };
104
+ if (options.servers) result.servers = options.servers;
105
+ return result;
106
+ }
107
+
108
+ //#endregion
109
+ export { generateAsyncAPI, standardSchemaToJsonSchema };
110
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@amqp-contract/asyncapi",
3
+ "version": "0.0.1",
4
+ "description": "AsyncAPI specification generator for amqp-contract",
5
+ "keywords": [
6
+ "amqp",
7
+ "typescript",
8
+ "contract",
9
+ "asyncapi",
10
+ "rabbitmq"
11
+ ],
12
+ "homepage": "https://github.com/btravers/amqp-contract#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/btravers/amqp-contract/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/btravers/amqp-contract.git",
19
+ "directory": "packages/asyncapi"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Benoit TRAVERS <benoit.travers.fr@gmail.com>",
23
+ "type": "module",
24
+ "exports": {
25
+ ".": {
26
+ "import": {
27
+ "types": "./dist/index.d.mts",
28
+ "default": "./dist/index.mjs"
29
+ },
30
+ "require": {
31
+ "types": "./dist/index.d.cts",
32
+ "default": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "main": "./dist/index.cjs",
38
+ "module": "./dist/index.mjs",
39
+ "types": "./dist/index.d.mts",
40
+ "files": [
41
+ "dist"
42
+ ],
43
+ "dependencies": {
44
+ "@standard-schema/spec": "1.0.0",
45
+ "@amqp-contract/contract": "0.0.1"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "24.10.2",
49
+ "@vitest/coverage-v8": "4.0.15",
50
+ "tsdown": "0.17.2",
51
+ "typescript": "5.9.3",
52
+ "vitest": "4.0.15",
53
+ "zod": "4.1.13",
54
+ "@amqp-contract/tsconfig": "0.0.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
58
+ "dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest",
61
+ "typecheck": "tsc --noEmit"
62
+ }
63
+ }