@riktajs/swagger 0.10.2 → 0.11.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 +1253 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +498 -0
- package/dist/index.d.ts +498 -7
- package/dist/index.js +1163 -6
- package/dist/index.js.map +1 -0
- package/package.json +13 -6
- package/dist/constants.d.ts +0 -11
- package/dist/constants.js +0 -11
- package/dist/decorators/api-body.decorator.d.ts +0 -4
- package/dist/decorators/api-body.decorator.js +0 -11
- package/dist/decorators/api-exclude.decorator.d.ts +0 -9
- package/dist/decorators/api-exclude.decorator.js +0 -31
- package/dist/decorators/api-header.decorator.d.ts +0 -4
- package/dist/decorators/api-header.decorator.js +0 -12
- package/dist/decorators/api-operation.decorator.d.ts +0 -4
- package/dist/decorators/api-operation.decorator.js +0 -11
- package/dist/decorators/api-param.decorator.d.ts +0 -4
- package/dist/decorators/api-param.decorator.js +0 -12
- package/dist/decorators/api-property.decorator.d.ts +0 -11
- package/dist/decorators/api-property.decorator.js +0 -20
- package/dist/decorators/api-query.decorator.d.ts +0 -4
- package/dist/decorators/api-query.decorator.js +0 -12
- package/dist/decorators/api-response.decorator.d.ts +0 -15
- package/dist/decorators/api-response.decorator.js +0 -45
- package/dist/decorators/api-security.decorator.d.ts +0 -8
- package/dist/decorators/api-security.decorator.js +0 -35
- package/dist/decorators/api-tags.decorator.d.ts +0 -3
- package/dist/decorators/api-tags.decorator.js +0 -22
- package/dist/decorators/index.d.ts +0 -10
- package/dist/decorators/index.js +0 -10
- package/dist/openapi/generator.d.ts +0 -49
- package/dist/openapi/generator.js +0 -409
- package/dist/openapi/index.d.ts +0 -2
- package/dist/openapi/index.js +0 -2
- package/dist/openapi/zod-to-openapi.d.ts +0 -5
- package/dist/openapi/zod-to-openapi.js +0 -115
- package/dist/plugin/index.d.ts +0 -1
- package/dist/plugin/index.js +0 -1
- package/dist/plugin/swagger.plugin.d.ts +0 -38
- package/dist/plugin/swagger.plugin.js +0 -126
- package/dist/types.d.ts +0 -338
- package/dist/types.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,1163 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/constants.ts
|
|
5
|
+
var API_TAGS_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiTags");
|
|
6
|
+
var API_OPERATION_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiOperation");
|
|
7
|
+
var API_RESPONSE_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiResponse");
|
|
8
|
+
var API_PROPERTY_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiProperty");
|
|
9
|
+
var API_BODY_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiBody");
|
|
10
|
+
var API_PARAM_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiParam");
|
|
11
|
+
var API_QUERY_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiQuery");
|
|
12
|
+
var API_HEADER_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiHeader");
|
|
13
|
+
var API_SECURITY_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiSecurity");
|
|
14
|
+
var API_EXCLUDE_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiExclude");
|
|
15
|
+
var API_DEPRECATED_METADATA = /* @__PURE__ */ Symbol.for("rikta:swagger:apiDeprecated");
|
|
16
|
+
|
|
17
|
+
// src/index.ts
|
|
18
|
+
import { CONTROLLER_METADATA, ROUTES_METADATA, PARAM_METADATA, HTTP_CODE_METADATA, GUARDS_METADATA, ZOD_SCHEMA_METADATA } from "@riktajs/core";
|
|
19
|
+
|
|
20
|
+
// src/decorators/api-tags.decorator.ts
|
|
21
|
+
import "reflect-metadata";
|
|
22
|
+
function ApiTags(...tags) {
|
|
23
|
+
return (target, propertyKey, descriptor) => {
|
|
24
|
+
if (propertyKey !== void 0 && descriptor !== void 0) {
|
|
25
|
+
const existingTags = Reflect.getMetadata(API_TAGS_METADATA, target, propertyKey) ?? [];
|
|
26
|
+
Reflect.defineMetadata(API_TAGS_METADATA, [
|
|
27
|
+
...existingTags,
|
|
28
|
+
...tags
|
|
29
|
+
], target, propertyKey);
|
|
30
|
+
} else {
|
|
31
|
+
const existingTags = Reflect.getMetadata(API_TAGS_METADATA, target) ?? [];
|
|
32
|
+
Reflect.defineMetadata(API_TAGS_METADATA, [
|
|
33
|
+
...existingTags,
|
|
34
|
+
...tags
|
|
35
|
+
], target);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
__name(ApiTags, "ApiTags");
|
|
40
|
+
function getApiTags(target, propertyKey) {
|
|
41
|
+
if (propertyKey !== void 0) {
|
|
42
|
+
const methodTags = Reflect.getMetadata(API_TAGS_METADATA, target.prototype, propertyKey) ?? [];
|
|
43
|
+
const classTags = Reflect.getMetadata(API_TAGS_METADATA, target) ?? [];
|
|
44
|
+
return [
|
|
45
|
+
.../* @__PURE__ */ new Set([
|
|
46
|
+
...classTags,
|
|
47
|
+
...methodTags
|
|
48
|
+
])
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
return Reflect.getMetadata(API_TAGS_METADATA, target) ?? [];
|
|
52
|
+
}
|
|
53
|
+
__name(getApiTags, "getApiTags");
|
|
54
|
+
|
|
55
|
+
// src/decorators/api-operation.decorator.ts
|
|
56
|
+
import "reflect-metadata";
|
|
57
|
+
function ApiOperation(options) {
|
|
58
|
+
return (target, propertyKey, descriptor) => {
|
|
59
|
+
Reflect.defineMetadata(API_OPERATION_METADATA, options, target, propertyKey);
|
|
60
|
+
return descriptor;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
__name(ApiOperation, "ApiOperation");
|
|
64
|
+
function getApiOperation(target, propertyKey) {
|
|
65
|
+
return Reflect.getMetadata(API_OPERATION_METADATA, target.prototype, propertyKey);
|
|
66
|
+
}
|
|
67
|
+
__name(getApiOperation, "getApiOperation");
|
|
68
|
+
|
|
69
|
+
// src/decorators/api-response.decorator.ts
|
|
70
|
+
import "reflect-metadata";
|
|
71
|
+
function ApiResponse(options) {
|
|
72
|
+
return (target, propertyKey, descriptor) => {
|
|
73
|
+
const existingResponses = Reflect.getMetadata(API_RESPONSE_METADATA, target, propertyKey) ?? [];
|
|
74
|
+
Reflect.defineMetadata(API_RESPONSE_METADATA, [
|
|
75
|
+
...existingResponses,
|
|
76
|
+
options
|
|
77
|
+
], target, propertyKey);
|
|
78
|
+
return descriptor;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
__name(ApiResponse, "ApiResponse");
|
|
82
|
+
function ApiOkResponse(options = {}) {
|
|
83
|
+
return ApiResponse({
|
|
84
|
+
...options,
|
|
85
|
+
status: 200
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
__name(ApiOkResponse, "ApiOkResponse");
|
|
89
|
+
function ApiCreatedResponse(options = {}) {
|
|
90
|
+
return ApiResponse({
|
|
91
|
+
...options,
|
|
92
|
+
status: 201
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
__name(ApiCreatedResponse, "ApiCreatedResponse");
|
|
96
|
+
function ApiAcceptedResponse(options = {}) {
|
|
97
|
+
return ApiResponse({
|
|
98
|
+
...options,
|
|
99
|
+
status: 202
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
__name(ApiAcceptedResponse, "ApiAcceptedResponse");
|
|
103
|
+
function ApiNoContentResponse(options = {}) {
|
|
104
|
+
return ApiResponse({
|
|
105
|
+
...options,
|
|
106
|
+
status: 204
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
__name(ApiNoContentResponse, "ApiNoContentResponse");
|
|
110
|
+
function ApiBadRequestResponse(options = {}) {
|
|
111
|
+
return ApiResponse({
|
|
112
|
+
...options,
|
|
113
|
+
status: 400,
|
|
114
|
+
description: options.description ?? "Bad Request"
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
__name(ApiBadRequestResponse, "ApiBadRequestResponse");
|
|
118
|
+
function ApiUnauthorizedResponse(options = {}) {
|
|
119
|
+
return ApiResponse({
|
|
120
|
+
...options,
|
|
121
|
+
status: 401,
|
|
122
|
+
description: options.description ?? "Unauthorized"
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
__name(ApiUnauthorizedResponse, "ApiUnauthorizedResponse");
|
|
126
|
+
function ApiForbiddenResponse(options = {}) {
|
|
127
|
+
return ApiResponse({
|
|
128
|
+
...options,
|
|
129
|
+
status: 403,
|
|
130
|
+
description: options.description ?? "Forbidden"
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
__name(ApiForbiddenResponse, "ApiForbiddenResponse");
|
|
134
|
+
function ApiNotFoundResponse(options = {}) {
|
|
135
|
+
return ApiResponse({
|
|
136
|
+
...options,
|
|
137
|
+
status: 404,
|
|
138
|
+
description: options.description ?? "Not Found"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
__name(ApiNotFoundResponse, "ApiNotFoundResponse");
|
|
142
|
+
function ApiConflictResponse(options = {}) {
|
|
143
|
+
return ApiResponse({
|
|
144
|
+
...options,
|
|
145
|
+
status: 409,
|
|
146
|
+
description: options.description ?? "Conflict"
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
__name(ApiConflictResponse, "ApiConflictResponse");
|
|
150
|
+
function ApiUnprocessableEntityResponse(options = {}) {
|
|
151
|
+
return ApiResponse({
|
|
152
|
+
...options,
|
|
153
|
+
status: 422,
|
|
154
|
+
description: options.description ?? "Unprocessable Entity"
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
__name(ApiUnprocessableEntityResponse, "ApiUnprocessableEntityResponse");
|
|
158
|
+
function ApiInternalServerErrorResponse(options = {}) {
|
|
159
|
+
return ApiResponse({
|
|
160
|
+
...options,
|
|
161
|
+
status: 500,
|
|
162
|
+
description: options.description ?? "Internal Server Error"
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
__name(ApiInternalServerErrorResponse, "ApiInternalServerErrorResponse");
|
|
166
|
+
function getApiResponses(target, propertyKey) {
|
|
167
|
+
return Reflect.getMetadata(API_RESPONSE_METADATA, target.prototype, propertyKey) ?? [];
|
|
168
|
+
}
|
|
169
|
+
__name(getApiResponses, "getApiResponses");
|
|
170
|
+
|
|
171
|
+
// src/decorators/api-body.decorator.ts
|
|
172
|
+
import "reflect-metadata";
|
|
173
|
+
function ApiBody(options) {
|
|
174
|
+
return (target, propertyKey, descriptor) => {
|
|
175
|
+
Reflect.defineMetadata(API_BODY_METADATA, {
|
|
176
|
+
...options,
|
|
177
|
+
required: options.required ?? true
|
|
178
|
+
}, target, propertyKey);
|
|
179
|
+
return descriptor;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
__name(ApiBody, "ApiBody");
|
|
183
|
+
function getApiBody(target, propertyKey) {
|
|
184
|
+
return Reflect.getMetadata(API_BODY_METADATA, target.prototype, propertyKey);
|
|
185
|
+
}
|
|
186
|
+
__name(getApiBody, "getApiBody");
|
|
187
|
+
|
|
188
|
+
// src/decorators/api-param.decorator.ts
|
|
189
|
+
import "reflect-metadata";
|
|
190
|
+
function ApiParam(options) {
|
|
191
|
+
return (target, propertyKey, descriptor) => {
|
|
192
|
+
const existingParams = Reflect.getMetadata(API_PARAM_METADATA, target, propertyKey) ?? [];
|
|
193
|
+
Reflect.defineMetadata(API_PARAM_METADATA, [
|
|
194
|
+
...existingParams,
|
|
195
|
+
{
|
|
196
|
+
...options,
|
|
197
|
+
required: options.required ?? true
|
|
198
|
+
}
|
|
199
|
+
], target, propertyKey);
|
|
200
|
+
return descriptor;
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
__name(ApiParam, "ApiParam");
|
|
204
|
+
function getApiParams(target, propertyKey) {
|
|
205
|
+
return Reflect.getMetadata(API_PARAM_METADATA, target.prototype, propertyKey) ?? [];
|
|
206
|
+
}
|
|
207
|
+
__name(getApiParams, "getApiParams");
|
|
208
|
+
|
|
209
|
+
// src/decorators/api-query.decorator.ts
|
|
210
|
+
import "reflect-metadata";
|
|
211
|
+
function ApiQuery(options) {
|
|
212
|
+
return (target, propertyKey, descriptor) => {
|
|
213
|
+
const existingQueries = Reflect.getMetadata(API_QUERY_METADATA, target, propertyKey) ?? [];
|
|
214
|
+
Reflect.defineMetadata(API_QUERY_METADATA, [
|
|
215
|
+
...existingQueries,
|
|
216
|
+
{
|
|
217
|
+
...options,
|
|
218
|
+
required: options.required ?? false
|
|
219
|
+
}
|
|
220
|
+
], target, propertyKey);
|
|
221
|
+
return descriptor;
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
__name(ApiQuery, "ApiQuery");
|
|
225
|
+
function getApiQueries(target, propertyKey) {
|
|
226
|
+
return Reflect.getMetadata(API_QUERY_METADATA, target.prototype, propertyKey) ?? [];
|
|
227
|
+
}
|
|
228
|
+
__name(getApiQueries, "getApiQueries");
|
|
229
|
+
|
|
230
|
+
// src/decorators/api-header.decorator.ts
|
|
231
|
+
import "reflect-metadata";
|
|
232
|
+
function ApiHeader(options) {
|
|
233
|
+
return (target, propertyKey, descriptor) => {
|
|
234
|
+
const existingHeaders = Reflect.getMetadata(API_HEADER_METADATA, target, propertyKey) ?? [];
|
|
235
|
+
Reflect.defineMetadata(API_HEADER_METADATA, [
|
|
236
|
+
...existingHeaders,
|
|
237
|
+
options
|
|
238
|
+
], target, propertyKey);
|
|
239
|
+
return descriptor;
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
__name(ApiHeader, "ApiHeader");
|
|
243
|
+
function getApiHeaders(target, propertyKey) {
|
|
244
|
+
return Reflect.getMetadata(API_HEADER_METADATA, target.prototype, propertyKey) ?? [];
|
|
245
|
+
}
|
|
246
|
+
__name(getApiHeaders, "getApiHeaders");
|
|
247
|
+
|
|
248
|
+
// src/decorators/api-security.decorator.ts
|
|
249
|
+
import "reflect-metadata";
|
|
250
|
+
function ApiSecurity(name, scopes = []) {
|
|
251
|
+
return (target, propertyKey, descriptor) => {
|
|
252
|
+
const security = name ? {
|
|
253
|
+
name,
|
|
254
|
+
scopes
|
|
255
|
+
} : null;
|
|
256
|
+
if (propertyKey !== void 0 && descriptor !== void 0) {
|
|
257
|
+
Reflect.defineMetadata(API_SECURITY_METADATA, security, target, propertyKey);
|
|
258
|
+
} else {
|
|
259
|
+
Reflect.defineMetadata(API_SECURITY_METADATA, security, target);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
__name(ApiSecurity, "ApiSecurity");
|
|
264
|
+
function ApiBearerAuth(name = "bearerAuth") {
|
|
265
|
+
return ApiSecurity(name);
|
|
266
|
+
}
|
|
267
|
+
__name(ApiBearerAuth, "ApiBearerAuth");
|
|
268
|
+
function ApiBasicAuth(name = "basicAuth") {
|
|
269
|
+
return ApiSecurity(name);
|
|
270
|
+
}
|
|
271
|
+
__name(ApiBasicAuth, "ApiBasicAuth");
|
|
272
|
+
function ApiOAuth2(scopes = [], name = "oauth2") {
|
|
273
|
+
return ApiSecurity(name, scopes);
|
|
274
|
+
}
|
|
275
|
+
__name(ApiOAuth2, "ApiOAuth2");
|
|
276
|
+
function ApiCookieAuth(name = "cookieAuth") {
|
|
277
|
+
return ApiSecurity(name);
|
|
278
|
+
}
|
|
279
|
+
__name(ApiCookieAuth, "ApiCookieAuth");
|
|
280
|
+
function getApiSecurity(target, propertyKey) {
|
|
281
|
+
if (propertyKey !== void 0) {
|
|
282
|
+
const methodSecurity = Reflect.getMetadata(API_SECURITY_METADATA, target.prototype, propertyKey);
|
|
283
|
+
if (methodSecurity !== void 0) {
|
|
284
|
+
return methodSecurity;
|
|
285
|
+
}
|
|
286
|
+
return Reflect.getMetadata(API_SECURITY_METADATA, target);
|
|
287
|
+
}
|
|
288
|
+
return Reflect.getMetadata(API_SECURITY_METADATA, target);
|
|
289
|
+
}
|
|
290
|
+
__name(getApiSecurity, "getApiSecurity");
|
|
291
|
+
|
|
292
|
+
// src/decorators/api-property.decorator.ts
|
|
293
|
+
import "reflect-metadata";
|
|
294
|
+
function ApiProperty(options = {}) {
|
|
295
|
+
return (target, propertyKey) => {
|
|
296
|
+
const existingProperties = Reflect.getMetadata(API_PROPERTY_METADATA, target.constructor) ?? [];
|
|
297
|
+
Reflect.defineMetadata(API_PROPERTY_METADATA, [
|
|
298
|
+
...existingProperties,
|
|
299
|
+
{
|
|
300
|
+
propertyKey,
|
|
301
|
+
options
|
|
302
|
+
}
|
|
303
|
+
], target.constructor);
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
__name(ApiProperty, "ApiProperty");
|
|
307
|
+
function ApiPropertyOptional(options = {}) {
|
|
308
|
+
return ApiProperty({
|
|
309
|
+
...options,
|
|
310
|
+
required: false
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
__name(ApiPropertyOptional, "ApiPropertyOptional");
|
|
314
|
+
function ApiHideProperty() {
|
|
315
|
+
return (target, propertyKey) => {
|
|
316
|
+
const existingProperties = Reflect.getMetadata(API_PROPERTY_METADATA, target.constructor) ?? [];
|
|
317
|
+
Reflect.defineMetadata(API_PROPERTY_METADATA, [
|
|
318
|
+
...existingProperties,
|
|
319
|
+
{
|
|
320
|
+
propertyKey,
|
|
321
|
+
options: {
|
|
322
|
+
_hidden: true
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
], target.constructor);
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
__name(ApiHideProperty, "ApiHideProperty");
|
|
329
|
+
function getApiProperties(target) {
|
|
330
|
+
return Reflect.getMetadata(API_PROPERTY_METADATA, target) ?? [];
|
|
331
|
+
}
|
|
332
|
+
__name(getApiProperties, "getApiProperties");
|
|
333
|
+
|
|
334
|
+
// src/decorators/api-exclude.decorator.ts
|
|
335
|
+
import "reflect-metadata";
|
|
336
|
+
function ApiExcludeEndpoint() {
|
|
337
|
+
return (target, propertyKey, descriptor) => {
|
|
338
|
+
Reflect.defineMetadata(API_EXCLUDE_METADATA, true, target, propertyKey);
|
|
339
|
+
return descriptor;
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
__name(ApiExcludeEndpoint, "ApiExcludeEndpoint");
|
|
343
|
+
function ApiExcludeController() {
|
|
344
|
+
return (target) => {
|
|
345
|
+
Reflect.defineMetadata(API_EXCLUDE_METADATA, true, target);
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
__name(ApiExcludeController, "ApiExcludeController");
|
|
349
|
+
function isApiExcluded(target, propertyKey) {
|
|
350
|
+
if (Reflect.getMetadata(API_EXCLUDE_METADATA, target) === true) {
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
if (propertyKey !== void 0) {
|
|
354
|
+
return Reflect.getMetadata(API_EXCLUDE_METADATA, target.prototype, propertyKey) === true;
|
|
355
|
+
}
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
__name(isApiExcluded, "isApiExcluded");
|
|
359
|
+
function ApiDeprecated(message) {
|
|
360
|
+
return (target, propertyKey, descriptor) => {
|
|
361
|
+
Reflect.defineMetadata(API_DEPRECATED_METADATA, {
|
|
362
|
+
deprecated: true,
|
|
363
|
+
message
|
|
364
|
+
}, target, propertyKey);
|
|
365
|
+
return descriptor;
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
__name(ApiDeprecated, "ApiDeprecated");
|
|
369
|
+
function getApiDeprecated(target, propertyKey) {
|
|
370
|
+
return Reflect.getMetadata(API_DEPRECATED_METADATA, target.prototype, propertyKey);
|
|
371
|
+
}
|
|
372
|
+
__name(getApiDeprecated, "getApiDeprecated");
|
|
373
|
+
|
|
374
|
+
// src/openapi/generator.ts
|
|
375
|
+
import "reflect-metadata";
|
|
376
|
+
import {
|
|
377
|
+
ParamType,
|
|
378
|
+
getControllerMetadata,
|
|
379
|
+
getRoutes,
|
|
380
|
+
getParamMetadata as getCoreParamMetadata,
|
|
381
|
+
getHttpCode,
|
|
382
|
+
getClassMetadata,
|
|
383
|
+
getMethodMetadata
|
|
384
|
+
} from "@riktajs/core";
|
|
385
|
+
|
|
386
|
+
// src/openapi/zod-to-openapi.ts
|
|
387
|
+
import { z } from "zod";
|
|
388
|
+
function isZodSchema(value) {
|
|
389
|
+
return value !== null && typeof value === "object" && ("_zod" in value || "_def" in value) && "safeParse" in value && typeof value.safeParse === "function";
|
|
390
|
+
}
|
|
391
|
+
__name(isZodSchema, "isZodSchema");
|
|
392
|
+
function jsonSchemaToOpenApi(jsonSchema) {
|
|
393
|
+
if (typeof jsonSchema === "boolean") {
|
|
394
|
+
return jsonSchema ? {} : {
|
|
395
|
+
not: {}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
const result = {};
|
|
399
|
+
const schema = jsonSchema;
|
|
400
|
+
if (Array.isArray(schema.type)) {
|
|
401
|
+
const types = schema.type;
|
|
402
|
+
const nullIndex = types.indexOf("null");
|
|
403
|
+
if (nullIndex !== -1) {
|
|
404
|
+
result.nullable = true;
|
|
405
|
+
const nonNullTypes = types.filter((t) => t !== "null");
|
|
406
|
+
if (nonNullTypes.length === 1) {
|
|
407
|
+
result.type = nonNullTypes[0];
|
|
408
|
+
} else if (nonNullTypes.length > 1) {
|
|
409
|
+
result.oneOf = nonNullTypes.map((t) => ({
|
|
410
|
+
type: t
|
|
411
|
+
}));
|
|
412
|
+
}
|
|
413
|
+
} else if (types.length === 1) {
|
|
414
|
+
result.type = types[0];
|
|
415
|
+
}
|
|
416
|
+
} else if (schema.type) {
|
|
417
|
+
result.type = schema.type;
|
|
418
|
+
}
|
|
419
|
+
const simpleProps = [
|
|
420
|
+
"format",
|
|
421
|
+
"description",
|
|
422
|
+
"default",
|
|
423
|
+
"example",
|
|
424
|
+
"enum",
|
|
425
|
+
"minimum",
|
|
426
|
+
"maximum",
|
|
427
|
+
"exclusiveMinimum",
|
|
428
|
+
"exclusiveMaximum",
|
|
429
|
+
"minLength",
|
|
430
|
+
"maxLength",
|
|
431
|
+
"pattern",
|
|
432
|
+
"minItems",
|
|
433
|
+
"maxItems",
|
|
434
|
+
"uniqueItems",
|
|
435
|
+
"minProperties",
|
|
436
|
+
"maxProperties",
|
|
437
|
+
"required",
|
|
438
|
+
"readOnly",
|
|
439
|
+
"writeOnly",
|
|
440
|
+
"deprecated"
|
|
441
|
+
];
|
|
442
|
+
for (const prop of simpleProps) {
|
|
443
|
+
if (schema[prop] !== void 0) {
|
|
444
|
+
result[prop] = schema[prop];
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (schema.items) {
|
|
448
|
+
if (Array.isArray(schema.items)) {
|
|
449
|
+
result.items = {
|
|
450
|
+
oneOf: schema.items.map(jsonSchemaToOpenApi)
|
|
451
|
+
};
|
|
452
|
+
} else {
|
|
453
|
+
result.items = jsonSchemaToOpenApi(schema.items);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (schema.properties) {
|
|
457
|
+
result.properties = {};
|
|
458
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
459
|
+
result.properties[key] = jsonSchemaToOpenApi(value);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (schema.additionalProperties !== void 0) {
|
|
463
|
+
if (typeof schema.additionalProperties === "boolean") {
|
|
464
|
+
result.additionalProperties = schema.additionalProperties;
|
|
465
|
+
} else {
|
|
466
|
+
result.additionalProperties = jsonSchemaToOpenApi(schema.additionalProperties);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (schema.allOf) {
|
|
470
|
+
result.allOf = schema.allOf.map(jsonSchemaToOpenApi);
|
|
471
|
+
}
|
|
472
|
+
if (schema.oneOf) {
|
|
473
|
+
result.oneOf = schema.oneOf.map(jsonSchemaToOpenApi);
|
|
474
|
+
}
|
|
475
|
+
if (schema.anyOf) {
|
|
476
|
+
result.anyOf = schema.anyOf.map(jsonSchemaToOpenApi);
|
|
477
|
+
}
|
|
478
|
+
if (schema.not) {
|
|
479
|
+
result.not = jsonSchemaToOpenApi(schema.not);
|
|
480
|
+
}
|
|
481
|
+
if (schema.const !== void 0) {
|
|
482
|
+
result.enum = [
|
|
483
|
+
schema.const
|
|
484
|
+
];
|
|
485
|
+
}
|
|
486
|
+
return result;
|
|
487
|
+
}
|
|
488
|
+
__name(jsonSchemaToOpenApi, "jsonSchemaToOpenApi");
|
|
489
|
+
function zodToOpenApi(schema) {
|
|
490
|
+
const jsonSchema = z.toJSONSchema(schema, {
|
|
491
|
+
// Target OpenAPI 3.0 Schema Object format
|
|
492
|
+
target: "openapi-3.0",
|
|
493
|
+
// Allow unrepresentable types to be converted to {} instead of throwing
|
|
494
|
+
unrepresentable: "any",
|
|
495
|
+
// Custom override for types that need special handling
|
|
496
|
+
override: /* @__PURE__ */ __name((ctx) => {
|
|
497
|
+
const def = ctx.zodSchema._zod?.def;
|
|
498
|
+
if (!def) return;
|
|
499
|
+
if (def.type === "date") {
|
|
500
|
+
ctx.jsonSchema.type = "string";
|
|
501
|
+
ctx.jsonSchema.format = "date-time";
|
|
502
|
+
}
|
|
503
|
+
if (def.type === "bigint") {
|
|
504
|
+
ctx.jsonSchema.type = "integer";
|
|
505
|
+
ctx.jsonSchema.format = "int64";
|
|
506
|
+
}
|
|
507
|
+
}, "override")
|
|
508
|
+
});
|
|
509
|
+
return jsonSchemaToOpenApi(jsonSchema);
|
|
510
|
+
}
|
|
511
|
+
__name(zodToOpenApi, "zodToOpenApi");
|
|
512
|
+
function toOpenApiSchema(schemaOrOpenApi) {
|
|
513
|
+
if (!schemaOrOpenApi) {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
if (isZodSchema(schemaOrOpenApi)) {
|
|
517
|
+
return zodToOpenApi(schemaOrOpenApi);
|
|
518
|
+
}
|
|
519
|
+
return schemaOrOpenApi;
|
|
520
|
+
}
|
|
521
|
+
__name(toOpenApiSchema, "toOpenApiSchema");
|
|
522
|
+
|
|
523
|
+
// src/openapi/generator.ts
|
|
524
|
+
var DEFAULT_SWAGGER_CONFIG = {
|
|
525
|
+
info: {
|
|
526
|
+
title: "API Documentation",
|
|
527
|
+
version: "1.0.0"
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
var OpenApiGenerator = class {
|
|
531
|
+
static {
|
|
532
|
+
__name(this, "OpenApiGenerator");
|
|
533
|
+
}
|
|
534
|
+
config;
|
|
535
|
+
controllers = [];
|
|
536
|
+
globalSecuritySchemes = /* @__PURE__ */ new Map();
|
|
537
|
+
constructor(config = {}) {
|
|
538
|
+
const info = config.info ?? {
|
|
539
|
+
title: config.title ?? DEFAULT_SWAGGER_CONFIG.info?.title ?? "API Documentation",
|
|
540
|
+
version: config.version ?? DEFAULT_SWAGGER_CONFIG.info?.version ?? "1.0.0",
|
|
541
|
+
description: config.description,
|
|
542
|
+
contact: config.contact,
|
|
543
|
+
license: config.license,
|
|
544
|
+
termsOfService: config.termsOfService
|
|
545
|
+
};
|
|
546
|
+
const { title, version, description, contact, license, termsOfService, ...restConfig } = config;
|
|
547
|
+
this.config = {
|
|
548
|
+
...DEFAULT_SWAGGER_CONFIG,
|
|
549
|
+
...restConfig,
|
|
550
|
+
info
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Add a controller to be documented
|
|
555
|
+
*/
|
|
556
|
+
addController(controller) {
|
|
557
|
+
this.controllers.push(controller);
|
|
558
|
+
return this;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Add multiple controllers
|
|
562
|
+
*/
|
|
563
|
+
addControllers(controllers) {
|
|
564
|
+
this.controllers.push(...controllers);
|
|
565
|
+
return this;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Add a global security scheme
|
|
569
|
+
*/
|
|
570
|
+
addSecurityScheme(name, scheme) {
|
|
571
|
+
this.globalSecuritySchemes.set(name, scheme);
|
|
572
|
+
return this;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Generate the OpenAPI specification document
|
|
576
|
+
*/
|
|
577
|
+
generate() {
|
|
578
|
+
const paths = {};
|
|
579
|
+
const tags = [];
|
|
580
|
+
const seenTags = /* @__PURE__ */ new Set();
|
|
581
|
+
for (const controller of this.controllers) {
|
|
582
|
+
if (this.isControllerExcluded(controller)) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
const controllerMeta = this.getControllerMeta(controller);
|
|
586
|
+
if (!controllerMeta) continue;
|
|
587
|
+
const controllerTags = this.getControllerTags(controller);
|
|
588
|
+
const controllerDeprecated = this.isControllerDeprecated(controller);
|
|
589
|
+
for (const tag of controllerTags) {
|
|
590
|
+
if (!seenTags.has(tag)) {
|
|
591
|
+
seenTags.add(tag);
|
|
592
|
+
tags.push({
|
|
593
|
+
name: tag
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const routes = this.getControllerRoutes(controller);
|
|
598
|
+
for (const route of routes) {
|
|
599
|
+
if (this.isEndpointExcluded(controller, route.handlerName)) {
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
const fullPath = this.normalizePath(controllerMeta.prefix, route.path);
|
|
603
|
+
const method = route.method.toLowerCase();
|
|
604
|
+
if (!paths[fullPath]) {
|
|
605
|
+
paths[fullPath] = {};
|
|
606
|
+
}
|
|
607
|
+
const operation = this.buildOperation(controller, route, controllerTags, controllerDeprecated);
|
|
608
|
+
paths[fullPath][method] = operation;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
const securitySchemes = this.buildSecuritySchemes();
|
|
612
|
+
const document = {
|
|
613
|
+
openapi: "3.0.3",
|
|
614
|
+
info: this.config.info,
|
|
615
|
+
paths
|
|
616
|
+
};
|
|
617
|
+
if (tags.length > 0) {
|
|
618
|
+
document.tags = tags;
|
|
619
|
+
}
|
|
620
|
+
if (this.config.servers && this.config.servers.length > 0) {
|
|
621
|
+
document.servers = this.config.servers;
|
|
622
|
+
}
|
|
623
|
+
if (Object.keys(securitySchemes).length > 0) {
|
|
624
|
+
document.components = {
|
|
625
|
+
...document.components,
|
|
626
|
+
securitySchemes
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
if (this.config.externalDocs) {
|
|
630
|
+
document.externalDocs = this.config.externalDocs;
|
|
631
|
+
}
|
|
632
|
+
return document;
|
|
633
|
+
}
|
|
634
|
+
// ============================================================================
|
|
635
|
+
// Private: Metadata Getters (using core helpers)
|
|
636
|
+
// ============================================================================
|
|
637
|
+
getControllerMeta(controller) {
|
|
638
|
+
return getControllerMetadata(controller);
|
|
639
|
+
}
|
|
640
|
+
getControllerRoutes(controller) {
|
|
641
|
+
return getRoutes(controller);
|
|
642
|
+
}
|
|
643
|
+
getControllerTags(controller) {
|
|
644
|
+
return getClassMetadata(API_TAGS_METADATA, controller) || [];
|
|
645
|
+
}
|
|
646
|
+
isControllerExcluded(controller) {
|
|
647
|
+
return getClassMetadata(API_EXCLUDE_METADATA, controller) === true;
|
|
648
|
+
}
|
|
649
|
+
isControllerDeprecated(controller) {
|
|
650
|
+
return getClassMetadata(API_DEPRECATED_METADATA, controller) === true;
|
|
651
|
+
}
|
|
652
|
+
isEndpointExcluded(controller, handlerName) {
|
|
653
|
+
return getMethodMetadata(API_EXCLUDE_METADATA, controller, handlerName) === true;
|
|
654
|
+
}
|
|
655
|
+
isEndpointDeprecated(controller, handlerName) {
|
|
656
|
+
const controllerLevel = getClassMetadata(API_DEPRECATED_METADATA, controller);
|
|
657
|
+
const methodLevel = getMethodMetadata(API_DEPRECATED_METADATA, controller, handlerName);
|
|
658
|
+
return controllerLevel?.deprecated === true || methodLevel?.deprecated === true;
|
|
659
|
+
}
|
|
660
|
+
getOperationMetadata(controller, handlerName) {
|
|
661
|
+
return getMethodMetadata(API_OPERATION_METADATA, controller, handlerName);
|
|
662
|
+
}
|
|
663
|
+
getResponseMetadata(controller, handlerName) {
|
|
664
|
+
return getMethodMetadata(API_RESPONSE_METADATA, controller, handlerName) || [];
|
|
665
|
+
}
|
|
666
|
+
getBodyMetadata(controller, handlerName) {
|
|
667
|
+
return getMethodMetadata(API_BODY_METADATA, controller, handlerName);
|
|
668
|
+
}
|
|
669
|
+
getSwaggerParamMetadata(controller, handlerName) {
|
|
670
|
+
return getMethodMetadata(API_PARAM_METADATA, controller, handlerName) || [];
|
|
671
|
+
}
|
|
672
|
+
getQueryMetadata(controller, handlerName) {
|
|
673
|
+
return getMethodMetadata(API_QUERY_METADATA, controller, handlerName) || [];
|
|
674
|
+
}
|
|
675
|
+
getHeaderMetadata(controller, handlerName) {
|
|
676
|
+
return getMethodMetadata(API_HEADER_METADATA, controller, handlerName) || [];
|
|
677
|
+
}
|
|
678
|
+
getSecurityMetadata(controller, handlerName) {
|
|
679
|
+
const controllerLevel = getClassMetadata(API_SECURITY_METADATA, controller);
|
|
680
|
+
const methodLevel = getMethodMetadata(API_SECURITY_METADATA, controller, handlerName);
|
|
681
|
+
const result = [];
|
|
682
|
+
if (controllerLevel && typeof controllerLevel === "object" && "name" in controllerLevel) {
|
|
683
|
+
result.push(controllerLevel);
|
|
684
|
+
} else if (Array.isArray(controllerLevel)) {
|
|
685
|
+
result.push(...controllerLevel);
|
|
686
|
+
}
|
|
687
|
+
if (methodLevel && typeof methodLevel === "object" && "name" in methodLevel) {
|
|
688
|
+
result.push(methodLevel);
|
|
689
|
+
} else if (Array.isArray(methodLevel)) {
|
|
690
|
+
result.push(...methodLevel);
|
|
691
|
+
}
|
|
692
|
+
return result;
|
|
693
|
+
}
|
|
694
|
+
getMethodTags(controller, handlerName) {
|
|
695
|
+
const operation = this.getOperationMetadata(controller, handlerName);
|
|
696
|
+
return operation?.tags;
|
|
697
|
+
}
|
|
698
|
+
getHttpStatusCode(controller, handlerName) {
|
|
699
|
+
return getHttpCode(controller, handlerName);
|
|
700
|
+
}
|
|
701
|
+
getCoreParams(controller, handlerName) {
|
|
702
|
+
return getCoreParamMetadata(controller, handlerName);
|
|
703
|
+
}
|
|
704
|
+
// ============================================================================
|
|
705
|
+
// Private: Path Utilities
|
|
706
|
+
// ============================================================================
|
|
707
|
+
normalizePath(prefix, path) {
|
|
708
|
+
let fullPath = "";
|
|
709
|
+
if (prefix) {
|
|
710
|
+
fullPath = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
711
|
+
}
|
|
712
|
+
if (path) {
|
|
713
|
+
const cleanPath = path.startsWith("/") ? path : `/${path}`;
|
|
714
|
+
fullPath = fullPath + cleanPath;
|
|
715
|
+
}
|
|
716
|
+
if (!fullPath) {
|
|
717
|
+
fullPath = "/";
|
|
718
|
+
}
|
|
719
|
+
fullPath = fullPath.replace(/:([^/]+)/g, "{$1}");
|
|
720
|
+
if (fullPath !== "/" && fullPath.endsWith("/")) {
|
|
721
|
+
fullPath = fullPath.slice(0, -1);
|
|
722
|
+
}
|
|
723
|
+
return fullPath;
|
|
724
|
+
}
|
|
725
|
+
// ============================================================================
|
|
726
|
+
// Private: Operation Builder
|
|
727
|
+
// ============================================================================
|
|
728
|
+
buildOperation(controller, route, controllerTags, controllerDeprecated) {
|
|
729
|
+
const handlerName = route.handlerName;
|
|
730
|
+
const operationMeta = this.getOperationMetadata(controller, handlerName);
|
|
731
|
+
const methodTags = this.getMethodTags(controller, handlerName);
|
|
732
|
+
const operation = {
|
|
733
|
+
responses: {}
|
|
734
|
+
};
|
|
735
|
+
const tags = methodTags || controllerTags;
|
|
736
|
+
if (tags.length > 0) {
|
|
737
|
+
operation.tags = tags;
|
|
738
|
+
}
|
|
739
|
+
if (operationMeta?.summary) {
|
|
740
|
+
operation.summary = operationMeta.summary;
|
|
741
|
+
}
|
|
742
|
+
if (operationMeta?.description) {
|
|
743
|
+
operation.description = operationMeta.description;
|
|
744
|
+
}
|
|
745
|
+
if (operationMeta?.operationId) {
|
|
746
|
+
operation.operationId = operationMeta.operationId;
|
|
747
|
+
}
|
|
748
|
+
if (controllerDeprecated || operationMeta?.deprecated || this.isEndpointDeprecated(controller, handlerName)) {
|
|
749
|
+
operation.deprecated = true;
|
|
750
|
+
}
|
|
751
|
+
const parameters = this.buildParameters(controller, handlerName, route.path);
|
|
752
|
+
if (parameters.length > 0) {
|
|
753
|
+
operation.parameters = parameters;
|
|
754
|
+
}
|
|
755
|
+
if ([
|
|
756
|
+
"POST",
|
|
757
|
+
"PUT",
|
|
758
|
+
"PATCH"
|
|
759
|
+
].includes(route.method)) {
|
|
760
|
+
const requestBody = this.buildRequestBody(controller, handlerName);
|
|
761
|
+
if (requestBody) {
|
|
762
|
+
operation.requestBody = requestBody;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
operation.responses = this.buildResponses(controller, handlerName, route.statusCode);
|
|
766
|
+
const security = this.getSecurityMetadata(controller, handlerName);
|
|
767
|
+
if (security.length > 0) {
|
|
768
|
+
operation.security = security.map((s) => ({
|
|
769
|
+
[s.name]: s.scopes || []
|
|
770
|
+
}));
|
|
771
|
+
}
|
|
772
|
+
return operation;
|
|
773
|
+
}
|
|
774
|
+
buildParameters(controller, handlerName, routePath) {
|
|
775
|
+
const parameters = [];
|
|
776
|
+
const pathParams = this.extractPathParams(routePath);
|
|
777
|
+
const paramDecorators = this.getSwaggerParamMetadata(controller, handlerName);
|
|
778
|
+
const queryDecorators = this.getQueryMetadata(controller, handlerName);
|
|
779
|
+
const headerDecorators = this.getHeaderMetadata(controller, handlerName);
|
|
780
|
+
const coreParams = this.getCoreParams(controller, handlerName);
|
|
781
|
+
const usedPathParams = /* @__PURE__ */ new Set();
|
|
782
|
+
for (const param of paramDecorators) {
|
|
783
|
+
usedPathParams.add(param.name);
|
|
784
|
+
const baseSchema = toOpenApiSchema(param.schema);
|
|
785
|
+
const fallbackSchema = {
|
|
786
|
+
type: param.type || "string"
|
|
787
|
+
};
|
|
788
|
+
if (param.format) {
|
|
789
|
+
fallbackSchema.format = param.format;
|
|
790
|
+
}
|
|
791
|
+
parameters.push({
|
|
792
|
+
name: param.name,
|
|
793
|
+
in: "path",
|
|
794
|
+
required: true,
|
|
795
|
+
deprecated: param.deprecated,
|
|
796
|
+
description: param.description,
|
|
797
|
+
schema: baseSchema || fallbackSchema,
|
|
798
|
+
example: param.example
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
for (const paramName of pathParams) {
|
|
802
|
+
if (!usedPathParams.has(paramName)) {
|
|
803
|
+
const coreParam = coreParams.find((p) => p.type === ParamType.PARAM && p.key === paramName);
|
|
804
|
+
const schema = coreParam?.zodSchema ? zodToOpenApi(coreParam.zodSchema) : {
|
|
805
|
+
type: "string"
|
|
806
|
+
};
|
|
807
|
+
parameters.push({
|
|
808
|
+
name: paramName,
|
|
809
|
+
in: "path",
|
|
810
|
+
required: true,
|
|
811
|
+
schema
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
for (const query of queryDecorators) {
|
|
816
|
+
const baseSchema = toOpenApiSchema(query.schema);
|
|
817
|
+
const fallbackSchema = {
|
|
818
|
+
type: query.type || "string"
|
|
819
|
+
};
|
|
820
|
+
if (query.format) {
|
|
821
|
+
fallbackSchema.format = query.format;
|
|
822
|
+
}
|
|
823
|
+
parameters.push({
|
|
824
|
+
name: query.name,
|
|
825
|
+
in: "query",
|
|
826
|
+
required: query.required,
|
|
827
|
+
deprecated: query.deprecated,
|
|
828
|
+
description: query.description,
|
|
829
|
+
schema: baseSchema || fallbackSchema,
|
|
830
|
+
example: query.example
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
for (const header of headerDecorators) {
|
|
834
|
+
parameters.push({
|
|
835
|
+
name: header.name,
|
|
836
|
+
in: "header",
|
|
837
|
+
required: header.required,
|
|
838
|
+
deprecated: header.deprecated,
|
|
839
|
+
description: header.description,
|
|
840
|
+
schema: toOpenApiSchema(header.schema) || {
|
|
841
|
+
type: header.type || "string"
|
|
842
|
+
},
|
|
843
|
+
example: header.example
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
return parameters;
|
|
847
|
+
}
|
|
848
|
+
extractPathParams(path) {
|
|
849
|
+
const params = [];
|
|
850
|
+
const regex = /:([^/]+)|{([^}]+)}/g;
|
|
851
|
+
let match;
|
|
852
|
+
while ((match = regex.exec(path)) !== null) {
|
|
853
|
+
const paramName = match[1] ?? match[2];
|
|
854
|
+
if (paramName) {
|
|
855
|
+
params.push(paramName);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return params;
|
|
859
|
+
}
|
|
860
|
+
buildRequestBody(controller, handlerName) {
|
|
861
|
+
const bodyMeta = this.getBodyMetadata(controller, handlerName);
|
|
862
|
+
const coreParams = this.getCoreParams(controller, handlerName);
|
|
863
|
+
if (bodyMeta) {
|
|
864
|
+
const schema = toOpenApiSchema(bodyMeta.schema);
|
|
865
|
+
return {
|
|
866
|
+
description: bodyMeta.description,
|
|
867
|
+
required: bodyMeta.required ?? true,
|
|
868
|
+
content: {
|
|
869
|
+
[bodyMeta.type || "application/json"]: {
|
|
870
|
+
schema: bodyMeta.isArray && schema ? {
|
|
871
|
+
type: "array",
|
|
872
|
+
items: schema
|
|
873
|
+
} : schema,
|
|
874
|
+
example: bodyMeta.example
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
const bodyParam = coreParams.find((p) => p.type === ParamType.BODY);
|
|
880
|
+
if (bodyParam?.zodSchema) {
|
|
881
|
+
return {
|
|
882
|
+
required: true,
|
|
883
|
+
content: {
|
|
884
|
+
"application/json": {
|
|
885
|
+
schema: zodToOpenApi(bodyParam.zodSchema)
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
return void 0;
|
|
891
|
+
}
|
|
892
|
+
buildResponses(controller, handlerName, defaultStatusCode) {
|
|
893
|
+
const responses = {};
|
|
894
|
+
const responseMeta = this.getResponseMetadata(controller, handlerName);
|
|
895
|
+
const httpCode = this.getHttpStatusCode(controller, handlerName);
|
|
896
|
+
if (responseMeta.length > 0) {
|
|
897
|
+
for (const response of responseMeta) {
|
|
898
|
+
const statusCode = response.status.toString();
|
|
899
|
+
const schema = toOpenApiSchema(response.schema);
|
|
900
|
+
responses[statusCode] = {
|
|
901
|
+
description: response.description || this.getDefaultStatusDescription(response.status)
|
|
902
|
+
};
|
|
903
|
+
if (schema || response.example) {
|
|
904
|
+
responses[statusCode].content = {
|
|
905
|
+
[response.type || "application/json"]: {
|
|
906
|
+
schema: response.isArray && schema ? {
|
|
907
|
+
type: "array",
|
|
908
|
+
items: schema
|
|
909
|
+
} : schema,
|
|
910
|
+
example: response.example
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
} else {
|
|
916
|
+
const status = (httpCode || defaultStatusCode || 200).toString();
|
|
917
|
+
responses[status] = {
|
|
918
|
+
description: this.getDefaultStatusDescription(Number(status))
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
return responses;
|
|
922
|
+
}
|
|
923
|
+
getDefaultStatusDescription(status) {
|
|
924
|
+
const descriptions = {
|
|
925
|
+
200: "Successful response",
|
|
926
|
+
201: "Resource created successfully",
|
|
927
|
+
204: "No content",
|
|
928
|
+
400: "Bad request",
|
|
929
|
+
401: "Unauthorized",
|
|
930
|
+
403: "Forbidden",
|
|
931
|
+
404: "Not found",
|
|
932
|
+
409: "Conflict",
|
|
933
|
+
422: "Unprocessable entity",
|
|
934
|
+
500: "Internal server error"
|
|
935
|
+
};
|
|
936
|
+
return descriptions[status] || "Response";
|
|
937
|
+
}
|
|
938
|
+
buildSecuritySchemes() {
|
|
939
|
+
const schemes = {};
|
|
940
|
+
for (const [name, options] of this.globalSecuritySchemes) {
|
|
941
|
+
schemes[name] = {
|
|
942
|
+
type: options.type,
|
|
943
|
+
description: options.description
|
|
944
|
+
};
|
|
945
|
+
if (options.type === "apiKey") {
|
|
946
|
+
schemes[name].name = options.name;
|
|
947
|
+
schemes[name].in = options.in;
|
|
948
|
+
} else if (options.type === "http") {
|
|
949
|
+
schemes[name].scheme = options.scheme;
|
|
950
|
+
if (options.bearerFormat) {
|
|
951
|
+
schemes[name].bearerFormat = options.bearerFormat;
|
|
952
|
+
}
|
|
953
|
+
} else if (options.type === "oauth2" && options.flows) {
|
|
954
|
+
schemes[name].flows = options.flows;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return schemes;
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
// src/plugin/swagger.plugin.ts
|
|
962
|
+
import fp from "fastify-plugin";
|
|
963
|
+
import fastifySwagger from "@fastify/swagger";
|
|
964
|
+
import fastifySwaggerUI from "@fastify/swagger-ui";
|
|
965
|
+
import { registry } from "@riktajs/core";
|
|
966
|
+
var DEFAULT_OPTIONS = {
|
|
967
|
+
jsonPath: "/docs/json",
|
|
968
|
+
uiPath: "/docs",
|
|
969
|
+
exposeUI: true,
|
|
970
|
+
exposeSpec: true
|
|
971
|
+
};
|
|
972
|
+
async function swaggerPluginImpl(fastify, options) {
|
|
973
|
+
const mergedOptions = {
|
|
974
|
+
...DEFAULT_OPTIONS,
|
|
975
|
+
...options
|
|
976
|
+
};
|
|
977
|
+
const { jsonPath, uiPath, exposeUI, exposeSpec, controllers, config, info, transform } = mergedOptions;
|
|
978
|
+
const apiInfo = info || config?.info || {
|
|
979
|
+
title: "API Documentation",
|
|
980
|
+
version: "1.0.0"
|
|
981
|
+
};
|
|
982
|
+
const generator = new OpenApiGenerator({
|
|
983
|
+
...config,
|
|
984
|
+
info: apiInfo
|
|
985
|
+
});
|
|
986
|
+
const controllersToDocument = controllers || registry.getControllers();
|
|
987
|
+
for (const controller of controllersToDocument) {
|
|
988
|
+
generator.addController(controller);
|
|
989
|
+
}
|
|
990
|
+
if (config?.securitySchemes) {
|
|
991
|
+
for (const [name, scheme] of Object.entries(config.securitySchemes)) {
|
|
992
|
+
generator.addSecurityScheme(name, scheme);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
let spec = generator.generate();
|
|
996
|
+
if (transform) {
|
|
997
|
+
spec = await transform(spec);
|
|
998
|
+
}
|
|
999
|
+
await fastify.register(fastifySwagger, {
|
|
1000
|
+
mode: "static",
|
|
1001
|
+
specification: {
|
|
1002
|
+
document: spec
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
if (exposeUI) {
|
|
1006
|
+
const uiOptions = {
|
|
1007
|
+
routePrefix: uiPath,
|
|
1008
|
+
uiConfig: {
|
|
1009
|
+
docExpansion: "list",
|
|
1010
|
+
deepLinking: true,
|
|
1011
|
+
displayRequestDuration: true,
|
|
1012
|
+
filter: true,
|
|
1013
|
+
syntaxHighlight: {
|
|
1014
|
+
activate: true,
|
|
1015
|
+
theme: mergedOptions.theme === "dark" ? "monokai" : "agate"
|
|
1016
|
+
}
|
|
1017
|
+
},
|
|
1018
|
+
staticCSP: true,
|
|
1019
|
+
transformStaticCSP: /* @__PURE__ */ __name((header) => header, "transformStaticCSP")
|
|
1020
|
+
};
|
|
1021
|
+
if (mergedOptions.logo) {
|
|
1022
|
+
uiOptions.logo = {
|
|
1023
|
+
type: "image/png",
|
|
1024
|
+
content: mergedOptions.logo.url,
|
|
1025
|
+
href: mergedOptions.logo.url
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
await fastify.register(fastifySwaggerUI, uiOptions);
|
|
1029
|
+
}
|
|
1030
|
+
const defaultSwaggerUIJsonPath = `${uiPath}/json`;
|
|
1031
|
+
const shouldRegisterCustomJsonRoute = exposeSpec && (!exposeUI || jsonPath !== defaultSwaggerUIJsonPath && jsonPath !== "/docs/json");
|
|
1032
|
+
if (shouldRegisterCustomJsonRoute) {
|
|
1033
|
+
fastify.get(jsonPath, {
|
|
1034
|
+
schema: {
|
|
1035
|
+
hide: true
|
|
1036
|
+
}
|
|
1037
|
+
}, async () => {
|
|
1038
|
+
return spec;
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
fastify.decorate("openApiSpec", spec);
|
|
1042
|
+
}
|
|
1043
|
+
__name(swaggerPluginImpl, "swaggerPluginImpl");
|
|
1044
|
+
var swaggerPlugin = fp(swaggerPluginImpl, {
|
|
1045
|
+
fastify: ">=4.0.0",
|
|
1046
|
+
name: "@riktajs/swagger",
|
|
1047
|
+
dependencies: []
|
|
1048
|
+
});
|
|
1049
|
+
async function registerSwagger(app, options = {}) {
|
|
1050
|
+
await app.register(swaggerPlugin, options);
|
|
1051
|
+
}
|
|
1052
|
+
__name(registerSwagger, "registerSwagger");
|
|
1053
|
+
function createSwaggerConfig(options = {}) {
|
|
1054
|
+
const mergedOptions = {
|
|
1055
|
+
...DEFAULT_OPTIONS,
|
|
1056
|
+
...options
|
|
1057
|
+
};
|
|
1058
|
+
const { uiPath, controllers, config, info } = mergedOptions;
|
|
1059
|
+
const apiInfo = info || config?.info || {
|
|
1060
|
+
title: "API Documentation",
|
|
1061
|
+
version: "1.0.0"
|
|
1062
|
+
};
|
|
1063
|
+
const generator = new OpenApiGenerator({
|
|
1064
|
+
...config,
|
|
1065
|
+
info: apiInfo
|
|
1066
|
+
});
|
|
1067
|
+
const controllersToDocument = controllers || registry.getControllers();
|
|
1068
|
+
for (const controller of controllersToDocument) {
|
|
1069
|
+
generator.addController(controller);
|
|
1070
|
+
}
|
|
1071
|
+
if (config?.securitySchemes) {
|
|
1072
|
+
for (const [name, scheme] of Object.entries(config.securitySchemes)) {
|
|
1073
|
+
generator.addSecurityScheme(name, scheme);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
const specification = generator.generate();
|
|
1077
|
+
return {
|
|
1078
|
+
swaggerOptions: {
|
|
1079
|
+
mode: "static",
|
|
1080
|
+
specification: {
|
|
1081
|
+
document: specification
|
|
1082
|
+
}
|
|
1083
|
+
},
|
|
1084
|
+
swaggerUIOptions: {
|
|
1085
|
+
routePrefix: uiPath,
|
|
1086
|
+
uiConfig: {
|
|
1087
|
+
docExpansion: "list",
|
|
1088
|
+
deepLinking: true,
|
|
1089
|
+
displayRequestDuration: true,
|
|
1090
|
+
filter: true
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
specification
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
__name(createSwaggerConfig, "createSwaggerConfig");
|
|
1097
|
+
export {
|
|
1098
|
+
API_BODY_METADATA,
|
|
1099
|
+
API_DEPRECATED_METADATA,
|
|
1100
|
+
API_EXCLUDE_METADATA,
|
|
1101
|
+
API_HEADER_METADATA,
|
|
1102
|
+
API_OPERATION_METADATA,
|
|
1103
|
+
API_PARAM_METADATA,
|
|
1104
|
+
API_PROPERTY_METADATA,
|
|
1105
|
+
API_QUERY_METADATA,
|
|
1106
|
+
API_RESPONSE_METADATA,
|
|
1107
|
+
API_SECURITY_METADATA,
|
|
1108
|
+
API_TAGS_METADATA,
|
|
1109
|
+
ApiAcceptedResponse,
|
|
1110
|
+
ApiBadRequestResponse,
|
|
1111
|
+
ApiBasicAuth,
|
|
1112
|
+
ApiBearerAuth,
|
|
1113
|
+
ApiBody,
|
|
1114
|
+
ApiConflictResponse,
|
|
1115
|
+
ApiCookieAuth,
|
|
1116
|
+
ApiCreatedResponse,
|
|
1117
|
+
ApiDeprecated,
|
|
1118
|
+
ApiExcludeController,
|
|
1119
|
+
ApiExcludeEndpoint,
|
|
1120
|
+
ApiForbiddenResponse,
|
|
1121
|
+
ApiHeader,
|
|
1122
|
+
ApiHideProperty,
|
|
1123
|
+
ApiInternalServerErrorResponse,
|
|
1124
|
+
ApiNoContentResponse,
|
|
1125
|
+
ApiNotFoundResponse,
|
|
1126
|
+
ApiOAuth2,
|
|
1127
|
+
ApiOkResponse,
|
|
1128
|
+
ApiOperation,
|
|
1129
|
+
ApiParam,
|
|
1130
|
+
ApiProperty,
|
|
1131
|
+
ApiPropertyOptional,
|
|
1132
|
+
ApiQuery,
|
|
1133
|
+
ApiResponse,
|
|
1134
|
+
ApiSecurity,
|
|
1135
|
+
ApiTags,
|
|
1136
|
+
ApiUnauthorizedResponse,
|
|
1137
|
+
ApiUnprocessableEntityResponse,
|
|
1138
|
+
CONTROLLER_METADATA,
|
|
1139
|
+
GUARDS_METADATA,
|
|
1140
|
+
HTTP_CODE_METADATA,
|
|
1141
|
+
OpenApiGenerator,
|
|
1142
|
+
PARAM_METADATA,
|
|
1143
|
+
ROUTES_METADATA,
|
|
1144
|
+
ZOD_SCHEMA_METADATA,
|
|
1145
|
+
createSwaggerConfig,
|
|
1146
|
+
getApiBody,
|
|
1147
|
+
getApiDeprecated,
|
|
1148
|
+
getApiHeaders,
|
|
1149
|
+
getApiOperation,
|
|
1150
|
+
getApiParams,
|
|
1151
|
+
getApiProperties,
|
|
1152
|
+
getApiQueries,
|
|
1153
|
+
getApiResponses,
|
|
1154
|
+
getApiSecurity,
|
|
1155
|
+
getApiTags,
|
|
1156
|
+
isApiExcluded,
|
|
1157
|
+
isZodSchema,
|
|
1158
|
+
registerSwagger,
|
|
1159
|
+
swaggerPlugin,
|
|
1160
|
+
toOpenApiSchema,
|
|
1161
|
+
zodToOpenApi
|
|
1162
|
+
};
|
|
1163
|
+
//# sourceMappingURL=index.js.map
|