@achinet/nestjs-async 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/.eslintrc.js +9 -0
- package/.prettierrc +5 -0
- package/CHANGELOG.md +7 -0
- package/README.md +1 -0
- package/dist/asyncapi-document.builder.d.ts +27 -0
- package/dist/asyncapi-document.builder.js +110 -0
- package/dist/asyncapi-document.builder.js.map +1 -0
- package/dist/asyncapi.constants.d.ts +6 -0
- package/dist/asyncapi.constants.js +11 -0
- package/dist/asyncapi.constants.js.map +1 -0
- package/dist/asyncapi.module.d.ts +8 -0
- package/dist/asyncapi.module.js +44 -0
- package/dist/asyncapi.module.js.map +1 -0
- package/dist/binding/asyncapi.amqp.interfaces.d.ts +38 -0
- package/dist/binding/asyncapi.amqp.interfaces.js +3 -0
- package/dist/binding/asyncapi.amqp.interfaces.js.map +1 -0
- package/dist/binding/asyncapi.kafka.interfaces.d.ts +21 -0
- package/dist/binding/asyncapi.kafka.interfaces.js +3 -0
- package/dist/binding/asyncapi.kafka.interfaces.js.map +1 -0
- package/dist/binding/index.d.ts +2 -0
- package/dist/binding/index.js +19 -0
- package/dist/binding/index.js.map +1 -0
- package/dist/decorators/asyncapi-operation-for-meta-key.decorator.d.ts +2 -0
- package/dist/decorators/asyncapi-operation-for-meta-key.decorator.js +38 -0
- package/dist/decorators/asyncapi-operation-for-meta-key.decorator.js.map +1 -0
- package/dist/decorators/asyncapi-operation.decorator.d.ts +2 -0
- package/dist/decorators/asyncapi-operation.decorator.js +10 -0
- package/dist/decorators/asyncapi-operation.decorator.js.map +1 -0
- package/dist/decorators/asyncapi-pub.decorator.d.ts +2 -0
- package/dist/decorators/asyncapi-pub.decorator.js +11 -0
- package/dist/decorators/asyncapi-pub.decorator.js.map +1 -0
- package/dist/decorators/asyncapi-service.decorator.d.ts +1 -0
- package/dist/decorators/asyncapi-service.decorator.js +10 -0
- package/dist/decorators/asyncapi-service.decorator.js.map +1 -0
- package/dist/decorators/asyncapi-sub.decorator.d.ts +2 -0
- package/dist/decorators/asyncapi-sub.decorator.js +11 -0
- package/dist/decorators/asyncapi-sub.decorator.js.map +1 -0
- package/dist/decorators/index.d.ts +4 -0
- package/dist/decorators/index.js +21 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/explorers/asyncapi-class.explorer.d.ts +5 -0
- package/dist/explorers/asyncapi-class.explorer.js +31 -0
- package/dist/explorers/asyncapi-class.explorer.js.map +1 -0
- package/dist/explorers/asyncapi-operation.explorer.d.ts +17 -0
- package/dist/explorers/asyncapi-operation.explorer.js +26 -0
- package/dist/explorers/asyncapi-operation.explorer.js.map +1 -0
- package/dist/explorers/index.d.ts +2 -0
- package/dist/explorers/index.js +19 -0
- package/dist/explorers/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/interface/asyncapi-common.interfaces.d.ts +126 -0
- package/dist/interface/asyncapi-common.interfaces.js +3 -0
- package/dist/interface/asyncapi-common.interfaces.js.map +1 -0
- package/dist/interface/asyncapi-document-options.interface.d.ts +3 -0
- package/dist/interface/asyncapi-document-options.interface.js +3 -0
- package/dist/interface/asyncapi-document-options.interface.js.map +1 -0
- package/dist/interface/asyncapi-message.interface.d.ts +8 -0
- package/dist/interface/asyncapi-message.interface.js +3 -0
- package/dist/interface/asyncapi-message.interface.js.map +1 -0
- package/dist/interface/asyncapi-operation-headers.interface.d.ts +6 -0
- package/dist/interface/asyncapi-operation-headers.interface.js +3 -0
- package/dist/interface/asyncapi-operation-headers.interface.js.map +1 -0
- package/dist/interface/asyncapi-operation-options-raw.interface.d.ts +21 -0
- package/dist/interface/asyncapi-operation-options-raw.interface.js +3 -0
- package/dist/interface/asyncapi-operation-options-raw.interface.js.map +1 -0
- package/dist/interface/asyncapi-operation-options.interface.d.ts +8 -0
- package/dist/interface/asyncapi-operation-options.interface.js +3 -0
- package/dist/interface/asyncapi-operation-options.interface.js.map +1 -0
- package/dist/interface/asyncapi-operation-payload.interface.d.ts +2 -0
- package/dist/interface/asyncapi-operation-payload.interface.js +3 -0
- package/dist/interface/asyncapi-operation-payload.interface.js.map +1 -0
- package/dist/interface/asyncapi-server.interface.d.ts +10 -0
- package/dist/interface/asyncapi-server.interface.js +3 -0
- package/dist/interface/asyncapi-server.interface.js.map +1 -0
- package/dist/interface/asyncapi-template-options.interface.d.ts +7 -0
- package/dist/interface/asyncapi-template-options.interface.js +3 -0
- package/dist/interface/asyncapi-template-options.interface.js.map +1 -0
- package/dist/interface/denormalized-doc-resolvers.interface.d.ts +6 -0
- package/dist/interface/denormalized-doc-resolvers.interface.js +3 -0
- package/dist/interface/denormalized-doc-resolvers.interface.js.map +1 -0
- package/dist/interface/denormalized-doc.interface.d.ts +10 -0
- package/dist/interface/denormalized-doc.interface.js +3 -0
- package/dist/interface/denormalized-doc.interface.js.map +1 -0
- package/dist/interface/generator-options.interface.d.ts +22 -0
- package/dist/interface/generator-options.interface.js +3 -0
- package/dist/interface/generator-options.interface.js.map +1 -0
- package/dist/interface/index.d.ts +11 -0
- package/dist/interface/index.js +28 -0
- package/dist/interface/index.js.map +1 -0
- package/dist/services/asyncapi.explorer.d.ts +12 -0
- package/dist/services/asyncapi.explorer.js +72 -0
- package/dist/services/asyncapi.explorer.js.map +1 -0
- package/dist/services/asyncapi.generator.d.ts +7 -0
- package/dist/services/asyncapi.generator.js +27 -0
- package/dist/services/asyncapi.generator.js.map +1 -0
- package/dist/services/asyncapi.scanner.d.ts +14 -0
- package/dist/services/asyncapi.scanner.js +82 -0
- package/dist/services/asyncapi.scanner.js.map +1 -0
- package/dist/services/asyncapi.transformer.d.ts +4 -0
- package/dist/services/asyncapi.transformer.js +33 -0
- package/dist/services/asyncapi.transformer.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.js +22 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/operation-object.factory.d.ts +9 -0
- package/dist/services/operation-object.factory.js +37 -0
- package/dist/services/operation-object.factory.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +94 -0
- package/src/asyncapi-document.builder.ts +186 -0
- package/src/asyncapi.constants.ts +8 -0
- package/src/asyncapi.module.ts +76 -0
- package/src/binding/asyncapi.amqp.interfaces.ts +48 -0
- package/src/binding/asyncapi.kafka.interfaces.ts +35 -0
- package/src/binding/index.ts +2 -0
- package/src/decorators/asyncapi-operation-for-meta-key.decorator.ts +70 -0
- package/src/decorators/asyncapi-operation.decorator.ts +9 -0
- package/src/decorators/asyncapi-pub.decorator.ts +18 -0
- package/src/decorators/asyncapi-service.decorator.ts +9 -0
- package/src/decorators/asyncapi-sub.decorator.ts +18 -0
- package/src/decorators/index.ts +4 -0
- package/src/explorers/asyncapi-class.explorer.ts +30 -0
- package/src/explorers/asyncapi-operation.explorer.ts +49 -0
- package/src/explorers/index.ts +2 -0
- package/src/index.ts +4 -0
- package/src/interface/asyncapi-common.interfaces.ts +172 -0
- package/src/interface/asyncapi-document-options.interface.ts +3 -0
- package/src/interface/asyncapi-message.interface.ts +10 -0
- package/src/interface/asyncapi-operation-headers.interface.ts +6 -0
- package/src/interface/asyncapi-operation-options-raw.interface.ts +23 -0
- package/src/interface/asyncapi-operation-options.interface.ts +12 -0
- package/src/interface/asyncapi-operation-payload.interface.ts +7 -0
- package/src/interface/asyncapi-server.interface.ts +14 -0
- package/src/interface/asyncapi-template-options.interface.ts +20 -0
- package/src/interface/denormalized-doc-resolvers.interface.ts +6 -0
- package/src/interface/denormalized-doc.interface.ts +10 -0
- package/src/interface/generator-options.interface.ts +21 -0
- package/src/interface/index.ts +12 -0
- package/src/services/asyncapi.explorer.ts +121 -0
- package/src/services/asyncapi.generator.ts +33 -0
- package/src/services/asyncapi.scanner.ts +155 -0
- package/src/services/asyncapi.transformer.ts +39 -0
- package/src/services/index.ts +5 -0
- package/src/services/operation-object.factory.ts +56 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExternalDocumentationObject,
|
|
3
|
+
SecuritySchemeObject,
|
|
4
|
+
TagObject,
|
|
5
|
+
} from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
|
|
6
|
+
import { isUndefined, negate, pickBy } from 'lodash';
|
|
7
|
+
import {
|
|
8
|
+
AsyncApiDocument,
|
|
9
|
+
AsyncSecuritySchemeObject,
|
|
10
|
+
AsyncServerObject,
|
|
11
|
+
} from './interface';
|
|
12
|
+
|
|
13
|
+
export class AsyncApiDocumentBuilder {
|
|
14
|
+
private readonly buildDocumentBase = (): Omit<
|
|
15
|
+
AsyncApiDocument,
|
|
16
|
+
'channels'
|
|
17
|
+
> => ({
|
|
18
|
+
asyncapi: '2.5.0',
|
|
19
|
+
info: {
|
|
20
|
+
title: '',
|
|
21
|
+
description: '',
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
contact: {},
|
|
24
|
+
},
|
|
25
|
+
tags: [],
|
|
26
|
+
servers: {},
|
|
27
|
+
components: {},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
private readonly document: Omit<AsyncApiDocument, 'channels'> =
|
|
31
|
+
this.buildDocumentBase();
|
|
32
|
+
|
|
33
|
+
public setTitle(title: string): this {
|
|
34
|
+
this.document.info.title = title;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public setDescription(description: string): this {
|
|
39
|
+
this.document.info.description = description;
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public setVersion(version: string): this {
|
|
44
|
+
this.document.info.version = version;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public setTermsOfService(termsOfService: string): this {
|
|
49
|
+
this.document.info.termsOfService = termsOfService;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public setContact(name: string, url: string, email: string): this {
|
|
54
|
+
this.document.info.contact = { name, url, email };
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public setLicense(name: string, url: string): this {
|
|
59
|
+
this.document.info.license = { name, url };
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public addServer(name: string, server: AsyncServerObject): this {
|
|
64
|
+
this.document.servers![name] = server;
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public addServers(
|
|
69
|
+
servers: { name: string; server: AsyncServerObject }[],
|
|
70
|
+
): this {
|
|
71
|
+
for (const { name, server } of servers) {
|
|
72
|
+
this.addServer(name, server);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public setExternalDoc(description: string, url: string): this {
|
|
79
|
+
this.document.externalDocs = { description, url };
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public setDefaultContentType(contentType: string) {
|
|
84
|
+
this.document.defaultContentType = contentType;
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public addTag(
|
|
89
|
+
name: string,
|
|
90
|
+
description = '',
|
|
91
|
+
externalDocs?: ExternalDocumentationObject,
|
|
92
|
+
): this {
|
|
93
|
+
this.document.tags = this.document.tags!.concat(
|
|
94
|
+
pickBy(
|
|
95
|
+
{
|
|
96
|
+
name,
|
|
97
|
+
description,
|
|
98
|
+
externalDocs,
|
|
99
|
+
},
|
|
100
|
+
negate(isUndefined),
|
|
101
|
+
) as TagObject,
|
|
102
|
+
);
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public addSecurity(name: string, options: AsyncSecuritySchemeObject): this {
|
|
107
|
+
this.document.components!.securitySchemes = {
|
|
108
|
+
...(this.document.components!.securitySchemes || {}),
|
|
109
|
+
[name]: options,
|
|
110
|
+
};
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public addBearerAuth(
|
|
115
|
+
options: SecuritySchemeObject = {
|
|
116
|
+
type: 'http',
|
|
117
|
+
},
|
|
118
|
+
name = 'bearer',
|
|
119
|
+
): this {
|
|
120
|
+
this.addSecurity(name, {
|
|
121
|
+
scheme: 'bearer',
|
|
122
|
+
bearerFormat: 'JWT',
|
|
123
|
+
...options,
|
|
124
|
+
});
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public addOAuth2(
|
|
129
|
+
options: SecuritySchemeObject = {
|
|
130
|
+
type: 'oauth2',
|
|
131
|
+
},
|
|
132
|
+
name = 'oauth2',
|
|
133
|
+
): this {
|
|
134
|
+
this.addSecurity(name, {
|
|
135
|
+
flows: {},
|
|
136
|
+
...options,
|
|
137
|
+
});
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public addApiKey(
|
|
142
|
+
options: SecuritySchemeObject = {
|
|
143
|
+
type: 'apiKey',
|
|
144
|
+
},
|
|
145
|
+
name = 'api_key',
|
|
146
|
+
): this {
|
|
147
|
+
this.addSecurity(name, {
|
|
148
|
+
in: 'header',
|
|
149
|
+
name,
|
|
150
|
+
...options,
|
|
151
|
+
});
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public addBasicAuth(
|
|
156
|
+
options: SecuritySchemeObject = {
|
|
157
|
+
type: 'http',
|
|
158
|
+
},
|
|
159
|
+
name = 'basic',
|
|
160
|
+
): this {
|
|
161
|
+
this.addSecurity(name, {
|
|
162
|
+
scheme: 'basic',
|
|
163
|
+
...options,
|
|
164
|
+
});
|
|
165
|
+
return this;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public addCookieAuth(
|
|
169
|
+
cookieName = 'connect.sid',
|
|
170
|
+
options: SecuritySchemeObject = {
|
|
171
|
+
type: 'apiKey',
|
|
172
|
+
},
|
|
173
|
+
securityName = 'cookie',
|
|
174
|
+
): this {
|
|
175
|
+
this.addSecurity(securityName, {
|
|
176
|
+
in: 'cookie',
|
|
177
|
+
name: cookieName,
|
|
178
|
+
...options,
|
|
179
|
+
});
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public build(): Omit<AsyncApiDocument, 'components' | 'channels'> {
|
|
184
|
+
return this.document;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INestApplication,
|
|
3
|
+
INestApplicationContext,
|
|
4
|
+
Logger,
|
|
5
|
+
} from '@nestjs/common';
|
|
6
|
+
import { validatePath } from '@nestjs/swagger/dist/utils/validate-path.util';
|
|
7
|
+
import jsyaml from 'js-yaml';
|
|
8
|
+
import {
|
|
9
|
+
AsyncApiDocument,
|
|
10
|
+
AsyncApiDocumentOptions,
|
|
11
|
+
AsyncApiTemplateOptions,
|
|
12
|
+
} from './interface';
|
|
13
|
+
import { AsyncapiGenerator, AsyncapiScanner } from './services';
|
|
14
|
+
|
|
15
|
+
export class AsyncApiModule {
|
|
16
|
+
private static readonly logger = new Logger(AsyncApiModule.name);
|
|
17
|
+
|
|
18
|
+
public static createDocument(
|
|
19
|
+
app: INestApplicationContext,
|
|
20
|
+
config: Omit<AsyncApiDocument, 'channels'>,
|
|
21
|
+
options: AsyncApiDocumentOptions = {},
|
|
22
|
+
): AsyncApiDocument {
|
|
23
|
+
const asyncapiScanner = new AsyncapiScanner();
|
|
24
|
+
const document = asyncapiScanner.scanApplication(app, options);
|
|
25
|
+
|
|
26
|
+
document.components = {
|
|
27
|
+
...(config.components || {}),
|
|
28
|
+
...document.components,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...config,
|
|
33
|
+
...document,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static async composeHtml(
|
|
38
|
+
contract: AsyncApiDocument,
|
|
39
|
+
templateOptions?: AsyncApiTemplateOptions,
|
|
40
|
+
) {
|
|
41
|
+
const generator = new AsyncapiGenerator(templateOptions);
|
|
42
|
+
return generator.generate(contract).catch((err) => {
|
|
43
|
+
this.logger.error(err);
|
|
44
|
+
throw err;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static async setup(
|
|
49
|
+
path: string,
|
|
50
|
+
app: INestApplication,
|
|
51
|
+
document: AsyncApiDocument,
|
|
52
|
+
templateOptions?: AsyncApiTemplateOptions,
|
|
53
|
+
) {
|
|
54
|
+
const httpAdapter = app.getHttpAdapter();
|
|
55
|
+
const finalPath = validatePath(path);
|
|
56
|
+
|
|
57
|
+
const html = await this.composeHtml(document, templateOptions);
|
|
58
|
+
const yamlDocument = jsyaml.dump(document);
|
|
59
|
+
const jsonDocument = JSON.stringify(document);
|
|
60
|
+
|
|
61
|
+
httpAdapter.get(finalPath, (req, res) => {
|
|
62
|
+
res.type('text/html');
|
|
63
|
+
res.send(html);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
httpAdapter.get(finalPath + '-json', (req, res) => {
|
|
67
|
+
res.type('application/json');
|
|
68
|
+
res.send(jsonDocument);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
httpAdapter.get(finalPath + '-yaml', (req, res) => {
|
|
72
|
+
res.type('text/yaml');
|
|
73
|
+
res.send(yamlDocument);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AMPQ binding
|
|
3
|
+
* @see https://github.com/asyncapi/bindings/tree/master/amqp
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This object MUST NOT contain any properties. Its name is reserved for future use.
|
|
8
|
+
*/
|
|
9
|
+
export interface AmqpServerBinding {}
|
|
10
|
+
|
|
11
|
+
export interface AmqpChannelBinding {
|
|
12
|
+
is: string;
|
|
13
|
+
exchange?: {
|
|
14
|
+
name: string;
|
|
15
|
+
type: string;
|
|
16
|
+
durable?: boolean;
|
|
17
|
+
autoDelete?: boolean;
|
|
18
|
+
vhost?: string;
|
|
19
|
+
};
|
|
20
|
+
queue?: {
|
|
21
|
+
name: string;
|
|
22
|
+
durable?: boolean;
|
|
23
|
+
exclusive?: boolean;
|
|
24
|
+
autoDelete?: boolean;
|
|
25
|
+
vhost?: string;
|
|
26
|
+
};
|
|
27
|
+
bindingVersion?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface AmqpOperationBinding {
|
|
31
|
+
expiration?: number;
|
|
32
|
+
userId?: string;
|
|
33
|
+
cc?: string[];
|
|
34
|
+
priority?: number;
|
|
35
|
+
deliveryMode?: number;
|
|
36
|
+
mandatory?: boolean;
|
|
37
|
+
bcc?: string[];
|
|
38
|
+
replyTo?: string;
|
|
39
|
+
timestamp?: boolean;
|
|
40
|
+
ack?: boolean;
|
|
41
|
+
bindingVersion?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface AmqpMessageBinding {
|
|
45
|
+
contentEncoding?: string;
|
|
46
|
+
messageType?: string;
|
|
47
|
+
bindingVersion?: string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kafka binding
|
|
3
|
+
* @see https://github.com/asyncapi/bindings/tree/master/kafka
|
|
4
|
+
*/
|
|
5
|
+
import { SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
|
|
6
|
+
|
|
7
|
+
export interface KafkaServerBinding {
|
|
8
|
+
schemaRegistryUrl: string;
|
|
9
|
+
schemaRegistryVendor: string;
|
|
10
|
+
/**
|
|
11
|
+
* x.y.z
|
|
12
|
+
*/
|
|
13
|
+
bindingVersion: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface KafkaChannelBinding {
|
|
17
|
+
topic: string;
|
|
18
|
+
partitions: number;
|
|
19
|
+
replicas: number;
|
|
20
|
+
/**
|
|
21
|
+
* x.y.z
|
|
22
|
+
*/
|
|
23
|
+
bindingVersion: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface KafkaOperationBinding {
|
|
27
|
+
groupId?: SchemaObject;
|
|
28
|
+
clientId?: SchemaObject;
|
|
29
|
+
bindingVersion?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface KafkaMessageBinding {
|
|
33
|
+
key?: SchemaObject;
|
|
34
|
+
bindingVersion?: string;
|
|
35
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createMethodDecorator } from '@nestjs/swagger/dist/decorators/helpers';
|
|
2
|
+
import {
|
|
3
|
+
AsyncApiOperationHeaders,
|
|
4
|
+
AsyncApiOperationOptions,
|
|
5
|
+
AsyncMessageObject,
|
|
6
|
+
AsyncOperationObject,
|
|
7
|
+
} from '../interface';
|
|
8
|
+
import { OneAsyncApiMessage } from '../interface/asyncapi-message.interface';
|
|
9
|
+
|
|
10
|
+
function makeHeaders(headers?: AsyncApiOperationHeaders) {
|
|
11
|
+
return headers
|
|
12
|
+
? {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: Object.entries(headers)
|
|
15
|
+
.map(([key, value]) => ({
|
|
16
|
+
[key]: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
...value,
|
|
19
|
+
},
|
|
20
|
+
}))
|
|
21
|
+
.reduce((acc, j) => ({ ...acc, ...j }), {}),
|
|
22
|
+
}
|
|
23
|
+
: undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function makeMessage(
|
|
27
|
+
message: OneAsyncApiMessage,
|
|
28
|
+
defaultName: string,
|
|
29
|
+
): AsyncMessageObject {
|
|
30
|
+
return {
|
|
31
|
+
...message,
|
|
32
|
+
name: message.name || defaultName,
|
|
33
|
+
payload: {
|
|
34
|
+
type: message.payload,
|
|
35
|
+
},
|
|
36
|
+
headers: makeHeaders(message.headers),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function AsyncApiOperationForMetaKey(
|
|
41
|
+
metaKey: string,
|
|
42
|
+
options: AsyncApiOperationOptions[],
|
|
43
|
+
): MethodDecorator {
|
|
44
|
+
return (target, propertyKey: string | symbol, descriptor) => {
|
|
45
|
+
const methodName = `${target.constructor.name}#${String(propertyKey)}`;
|
|
46
|
+
|
|
47
|
+
const transformedOptions: AsyncOperationObject[] = options.map((i) => {
|
|
48
|
+
const message = Array.isArray(i.message)
|
|
49
|
+
? {
|
|
50
|
+
oneOf: i.message.map((i, index) =>
|
|
51
|
+
makeMessage(i, `${methodName}#${index}`),
|
|
52
|
+
),
|
|
53
|
+
}
|
|
54
|
+
: makeMessage(i.message, methodName);
|
|
55
|
+
|
|
56
|
+
const transformedOptionInstance = {
|
|
57
|
+
...i,
|
|
58
|
+
message,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return transformedOptionInstance;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return createMethodDecorator(metaKey, transformedOptions)(
|
|
65
|
+
target,
|
|
66
|
+
propertyKey,
|
|
67
|
+
descriptor,
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DECORATORS } from '../asyncapi.constants';
|
|
2
|
+
import { AsyncApiOperationOptions } from '../interface';
|
|
3
|
+
import { AsyncApiOperationForMetaKey } from './asyncapi-operation-for-meta-key.decorator';
|
|
4
|
+
|
|
5
|
+
export function AsyncApiOperation(
|
|
6
|
+
...options: AsyncApiOperationOptions[]
|
|
7
|
+
): MethodDecorator {
|
|
8
|
+
return AsyncApiOperationForMetaKey(DECORATORS.AsyncApiOperation, options);
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DECORATORS } from '../asyncapi.constants';
|
|
2
|
+
import {
|
|
3
|
+
AsyncApiOperationOptions,
|
|
4
|
+
AsyncApiSpecificOperationOptions,
|
|
5
|
+
} from '../interface';
|
|
6
|
+
import { AsyncApiOperationForMetaKey } from './asyncapi-operation-for-meta-key.decorator';
|
|
7
|
+
|
|
8
|
+
export function AsyncApiPub(
|
|
9
|
+
...specificOperationOptions: AsyncApiSpecificOperationOptions[]
|
|
10
|
+
) {
|
|
11
|
+
const options: AsyncApiOperationOptions[] = specificOperationOptions.map(
|
|
12
|
+
(i) => ({
|
|
13
|
+
...i,
|
|
14
|
+
type: 'pub',
|
|
15
|
+
}),
|
|
16
|
+
);
|
|
17
|
+
return AsyncApiOperationForMetaKey(DECORATORS.AsyncApiPub, options);
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createMixedDecorator } from '@nestjs/swagger/dist/decorators/helpers';
|
|
2
|
+
import { DECORATORS } from '../asyncapi.constants';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mark class that has to be scanned for AsyncApi operations
|
|
6
|
+
*/
|
|
7
|
+
export function AsyncApi() {
|
|
8
|
+
return createMixedDecorator(DECORATORS.AsyncApiClass, true);
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DECORATORS } from '../asyncapi.constants';
|
|
2
|
+
import {
|
|
3
|
+
AsyncApiOperationOptions,
|
|
4
|
+
AsyncApiSpecificOperationOptions,
|
|
5
|
+
} from '../interface';
|
|
6
|
+
import { AsyncApiOperationForMetaKey } from './asyncapi-operation-for-meta-key.decorator';
|
|
7
|
+
|
|
8
|
+
export function AsyncApiSub(
|
|
9
|
+
...specificOperationOptions: AsyncApiSpecificOperationOptions[]
|
|
10
|
+
) {
|
|
11
|
+
const options: AsyncApiOperationOptions[] = specificOperationOptions.map(
|
|
12
|
+
(i) => ({
|
|
13
|
+
...i,
|
|
14
|
+
type: 'sub',
|
|
15
|
+
}),
|
|
16
|
+
);
|
|
17
|
+
return AsyncApiOperationForMetaKey(DECORATORS.AsyncApiSub, options);
|
|
18
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
import { CONTROLLER_WATERMARK } from '@nestjs/common/constants';
|
|
3
|
+
import { DECORATORS } from '../asyncapi.constants';
|
|
4
|
+
|
|
5
|
+
let GATEWAY_METADATA;
|
|
6
|
+
try {
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
8
|
+
const wsConstants = require('@nestjs/websockets/constants');
|
|
9
|
+
GATEWAY_METADATA = wsConstants.GATEWAY_METADATA;
|
|
10
|
+
} catch {
|
|
11
|
+
GATEWAY_METADATA = '__gateway__'; // in case @nestjs/websockets is not installed GATEWAY_METADATA value is irrelevant
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const asyncApiClassAnnotationLabels = [
|
|
15
|
+
DECORATORS.AsyncApiClass,
|
|
16
|
+
CONTROLLER_WATERMARK,
|
|
17
|
+
GATEWAY_METADATA,
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
export const exploreAsyncapiClassMetadata = (metatype: Type<unknown>) => {
|
|
21
|
+
return Reflect.getMetadata(DECORATORS.AsyncApiClass, metatype);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const exploreControllerMetadata = (metatype: Type<unknown>) => {
|
|
25
|
+
return Reflect.getMetadata(CONTROLLER_WATERMARK, metatype);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const exploreGatewayMetadata = (metatype: Type<unknown>) => {
|
|
29
|
+
return Reflect.getMetadata(GATEWAY_METADATA, metatype);
|
|
30
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
import { SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
|
|
3
|
+
import { DECORATORS } from '../asyncapi.constants';
|
|
4
|
+
import { AsyncApiOperationOptionsRaw } from '../interface';
|
|
5
|
+
import { OperationObjectFactory } from '../services';
|
|
6
|
+
|
|
7
|
+
const operationObjectFactory = new OperationObjectFactory();
|
|
8
|
+
|
|
9
|
+
export const exploreAsyncApiOperationMetadata = (
|
|
10
|
+
schemas: Record<string, SchemaObject>,
|
|
11
|
+
_instance: object,
|
|
12
|
+
_prototype: Type<unknown>,
|
|
13
|
+
method: object,
|
|
14
|
+
) => {
|
|
15
|
+
const metadataOperations: AsyncApiOperationOptionsRaw[] = Reflect.getMetadata(
|
|
16
|
+
DECORATORS.AsyncApiOperation,
|
|
17
|
+
method,
|
|
18
|
+
);
|
|
19
|
+
const metadataSubs: AsyncApiOperationOptionsRaw[] = Reflect.getMetadata(
|
|
20
|
+
DECORATORS.AsyncApiSub,
|
|
21
|
+
method,
|
|
22
|
+
);
|
|
23
|
+
const metadataPubs: AsyncApiOperationOptionsRaw[] = Reflect.getMetadata(
|
|
24
|
+
DECORATORS.AsyncApiPub,
|
|
25
|
+
method,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const metadataCombined = [
|
|
29
|
+
...(metadataOperations ? Object.values(metadataOperations) : []),
|
|
30
|
+
...(metadataSubs ? Object.values(metadataSubs) : []),
|
|
31
|
+
...(metadataPubs ? Object.values(metadataPubs) : []),
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
return metadataCombined.map((option: AsyncApiOperationOptionsRaw) => {
|
|
35
|
+
const { channel, type } = option;
|
|
36
|
+
|
|
37
|
+
const methodTypeData = {
|
|
38
|
+
...option,
|
|
39
|
+
...operationObjectFactory.create(option, ['application/json'], schemas),
|
|
40
|
+
channel: undefined,
|
|
41
|
+
type: undefined,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
channel,
|
|
46
|
+
[type]: methodTypeData,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
};
|
package/src/index.ts
ADDED