@globalart/nestjs-swagger 1.3.0 → 1.4.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 CHANGED
@@ -1,7 +1,6 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _nestjs_common = require("@nestjs/common");
3
3
  let _nestjs_swagger = require("@nestjs/swagger");
4
-
5
4
  //#region src/constants.ts
6
5
  const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
7
6
  const ERROR_DESCRIPTIONS = {
@@ -15,22 +14,19 @@ const ERROR_DESCRIPTIONS = {
15
14
  INTERNAL_SERVER_ERROR: "Internal server error",
16
15
  SERVICE_UNAVAILABLE: "Service temporarily unavailable"
17
16
  };
18
-
19
17
  //#endregion
20
- //#region \0@oxc-project+runtime@0.112.0/helpers/decorateMetadata.js
18
+ //#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
21
19
  function __decorateMetadata(k, v) {
22
20
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
23
21
  }
24
-
25
22
  //#endregion
26
- //#region \0@oxc-project+runtime@0.112.0/helpers/decorate.js
23
+ //#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
27
24
  function __decorate(decorators, target, key, desc) {
28
25
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29
26
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
30
27
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
31
28
  return c > 3 && r && Object.defineProperty(target, key, r), r;
32
29
  }
33
-
34
30
  //#endregion
35
31
  //#region src/dtos/index.ts
36
32
  var PaginatedResponseDto = class {
@@ -42,7 +38,6 @@ var PaginatedResponseDto = class {
42
38
  __decorate([(0, _nestjs_swagger.ApiProperty)(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "totalCount", void 0);
43
39
  __decorate([(0, _nestjs_swagger.ApiProperty)(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "offset", void 0);
44
40
  __decorate([(0, _nestjs_swagger.ApiProperty)(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "limit", void 0);
45
-
46
41
  //#endregion
47
42
  //#region src/decorators/index.ts
48
43
  const SwaggerDocumentation = (data) => {
@@ -79,9 +74,100 @@ const SwaggerDocumentation = (data) => {
79
74
  else decorators.push((0, _nestjs_swagger.ApiOkResponse)({ description: API_RESPONSE_DESCRIPTION }));
80
75
  return (0, _nestjs_common.applyDecorators)(...decorators);
81
76
  };
82
-
77
+ //#endregion
78
+ //#region src/swagger.service.ts
79
+ var OpenApiDocsBuilder = class {
80
+ constructor(doc, metaTags) {
81
+ this.doc = doc;
82
+ this.metaTags = metaTags;
83
+ }
84
+ stripMetaTags() {
85
+ return this.mapOperations((op) => ({
86
+ ...op,
87
+ tags: this.removeMeta(op.tags)
88
+ }));
89
+ }
90
+ filterByTag(tag) {
91
+ const filteredPaths = {};
92
+ for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
93
+ const filteredMethods = {};
94
+ for (const [method, operation] of Object.entries(methods)) {
95
+ const op = operation;
96
+ if (op.tags?.includes(tag)) filteredMethods[method] = {
97
+ ...op,
98
+ tags: this.removeMeta(op.tags)
99
+ };
100
+ }
101
+ if (Object.keys(filteredMethods).length > 0) filteredPaths[path] = filteredMethods;
102
+ }
103
+ return {
104
+ ...this.doc,
105
+ paths: filteredPaths
106
+ };
107
+ }
108
+ mapOperations(fn) {
109
+ const paths = {};
110
+ for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
111
+ const mapped = {};
112
+ for (const [method, operation] of Object.entries(methods)) mapped[method] = fn(operation);
113
+ paths[path] = mapped;
114
+ }
115
+ return {
116
+ ...this.doc,
117
+ paths
118
+ };
119
+ }
120
+ removeMeta(tags) {
121
+ return (tags ?? []).filter((t) => !this.metaTags.includes(t));
122
+ }
123
+ };
124
+ let SwaggerService = class SwaggerService {
125
+ app = null;
126
+ documents = {};
127
+ versions = [];
128
+ metaTags = [
129
+ "protected",
130
+ "private",
131
+ "support"
132
+ ];
133
+ setApp(app) {
134
+ this.app = app;
135
+ }
136
+ setVersions(versions) {
137
+ this.versions = versions;
138
+ }
139
+ setMetaTags(tags) {
140
+ this.metaTags = tags;
141
+ }
142
+ getDocument(key, serverUrl) {
143
+ const doc = this.documents[key];
144
+ if (!doc) return void 0;
145
+ if (!serverUrl) return doc;
146
+ return {
147
+ ...doc,
148
+ servers: [{ url: serverUrl }]
149
+ };
150
+ }
151
+ init() {
152
+ if (!this.app) throw new Error("App not found");
153
+ for (const version of this.versions) {
154
+ const { config, filterTag } = version;
155
+ const builder = new OpenApiDocsBuilder(_nestjs_swagger.SwaggerModule.createDocument(this.app, config), this.metaTags);
156
+ const document = filterTag ? builder.filterByTag(filterTag) : builder.stripMetaTags();
157
+ this.documents[version.name] = document;
158
+ }
159
+ }
160
+ };
161
+ SwaggerService = __decorate([(0, _nestjs_common.Injectable)()], SwaggerService);
83
162
  //#endregion
84
163
  exports.API_RESPONSE_DESCRIPTION = API_RESPONSE_DESCRIPTION;
85
164
  exports.ERROR_DESCRIPTIONS = ERROR_DESCRIPTIONS;
86
165
  exports.SwaggerDocumentation = SwaggerDocumentation;
166
+ Object.defineProperty(exports, "SwaggerService", {
167
+ enumerable: true,
168
+ get: function() {
169
+ return SwaggerService;
170
+ }
171
+ });
172
+
87
173
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n"],"mappings":";;;;;AAAA,MAAa,2BACX;AAEF,MAAa,qBAAqB;CAChC,aAAa;CACb,cAAc;CACd,WAAW;CACX,WAAW;CACX,UAAU;CACV,sBAAsB;CACtB,qBAAqB;CACrB,uBAAuB;CACvB,qBAAqB;CACtB;;;;;;;;;;;;;;;;;;;ACXD,IAAa,uBAAb,MAAqC;CACnC;CAEA,AACA;CAEA,AACA;CAEA,AACA;;8CAPc;8CAGA;8CAGA;;;;ACWhB,MAAa,wBAAwB,SAAsC;CACzE,MAAM,cAAc,KAAK;CAEzB,MAAM,aAAa,mCACJ;EACX;EACA,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,YAAY,KAAK;EAClB,CAAC,CACH;AAED,KAAI,KAAK,oBACP,YAAW,gDACa,EACpB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,kDACe,EACtB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,+CACY,EACnB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,8CACW,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,8CACW,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,yDACsB,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,qDACkB,EACzB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,yDACsB,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,wDACqB,EAC5B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,eAAe,KAAK,YAC3B,YAAW,wCACK;EACZ,QAAQ,EACN,OAAO,CACL,EAAE,yCAAoB,qBAAqB,EAAE,EAC7C,EACE,YAAY,EACV,MAAM;GACJ,MAAM;GACN,OAAO,EACL,yCAAoB,KAAK,YAAY,EACtC;GACF,EACF,EACF,CACF,EACF;EACD,aAAa;EACd,CAAC,sCACa,KAAK,aAAa,qBAAqB,CACvD;UACQ,KAAK,YACd,YAAW,wCACK;EACZ,QAAQ,KAAK,UACT;GACE,MAAM;GACN,OAAO,EAAE,yCAAoB,KAAK,YAAY,EAAE;GACjD,GACD,EAAE,yCAAoB,KAAK,YAAY,EAAE;EAC7C,aAAa;EACd,CAAC,sCACa,KAAK,YAAY,CACjC;KAED,YAAW,wCACK,EACZ,aAAa,0BACd,CAAC,CACH;AAGH,4CAAuB,GAAG,WAAW"}
1
+ {"version":3,"file":"index.cjs","names":["SwaggerModule"],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts","../src/swagger.service.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n","import { INestApplication, Injectable } from '@nestjs/common';\nimport { OpenAPIObject, SwaggerModule } from '@nestjs/swagger';\n\ntype Paths = OpenAPIObject['paths'];\n\nclass OpenApiDocsBuilder {\n constructor(\n private readonly doc: OpenAPIObject,\n private readonly metaTags: string[],\n ) {}\n\n stripMetaTags(): OpenAPIObject {\n return this.mapOperations((op) => ({ ...op, tags: this.removeMeta(op.tags) }));\n }\n\n filterByTag(tag: string): OpenAPIObject {\n const filteredPaths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const filteredMethods: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n const op = operation as { tags?: string[] };\n if (op.tags?.includes(tag)) {\n filteredMethods[method] = { ...op, tags: this.removeMeta(op.tags) };\n }\n }\n if (Object.keys(filteredMethods).length > 0) {\n filteredPaths[path] = filteredMethods as Paths[string];\n }\n }\n return { ...this.doc, paths: filteredPaths };\n }\n\n private mapOperations(fn: (op: { tags?: string[] }) => unknown): OpenAPIObject {\n const paths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const mapped: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n mapped[method] = fn(operation as { tags?: string[] });\n }\n paths[path] = mapped as Paths[string];\n }\n return { ...this.doc, paths };\n }\n\n private removeMeta(tags?: string[]): string[] {\n return (tags ?? []).filter((t) => !this.metaTags.includes(t));\n }\n}\n\ninterface Version {\n name: string;\n url: string;\n config: Omit<OpenAPIObject, 'paths'>;\n filterTag?: string;\n}\n\n@Injectable()\nexport class SwaggerService {\n private app: INestApplication | null = null;\n private documents: Record<string, OpenAPIObject> = {};\n private versions: Version[] = [];\n private metaTags: string[] = ['protected', 'private', 'support'];\n\n setApp(app: any) {\n this.app = app;\n }\n\n setVersions(versions: Version[]) {\n this.versions = versions;\n }\n\n setMetaTags(tags: string[]) {\n this.metaTags = tags;\n }\n\n getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined {\n const doc = this.documents[key];\n if (!doc) return undefined;\n if (!serverUrl) return doc;\n return { ...doc, servers: [{ url: serverUrl }] };\n }\n\n init() {\n if (!this.app) {\n throw new Error('App not found');\n }\n\n for (const version of this.versions) {\n const { config, filterTag } = version;\n const tempDoc = SwaggerModule.createDocument(this.app, config);\n const builder = new OpenApiDocsBuilder(tempDoc, this.metaTags);\n\n const document = filterTag\n ? builder.filterByTag(filterTag)\n : builder.stripMetaTags();\n\n this.documents[version.name] = document;\n }\n }\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { OpenAPIObject } from "@nestjs/swagger";
2
+
1
3
  //#region src/constants.d.ts
2
4
  declare const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
3
5
  declare const ERROR_DESCRIPTIONS: {
@@ -37,5 +39,24 @@ interface SwaggerDocumentationOptions extends SwaggerDocumentationErrorStatus {
37
39
  //#region src/decorators/index.d.ts
38
40
  declare const SwaggerDocumentation: (data: SwaggerDocumentationOptions) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
39
41
  //#endregion
40
- export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerDocumentationErrorStatus, SwaggerDocumentationOptions };
42
+ //#region src/swagger.service.d.ts
43
+ interface Version {
44
+ name: string;
45
+ url: string;
46
+ config: Omit<OpenAPIObject, 'paths'>;
47
+ filterTag?: string;
48
+ }
49
+ declare class SwaggerService {
50
+ private app;
51
+ private documents;
52
+ private versions;
53
+ private metaTags;
54
+ setApp(app: any): void;
55
+ setVersions(versions: Version[]): void;
56
+ setMetaTags(tags: string[]): void;
57
+ getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined;
58
+ init(): void;
59
+ }
60
+ //#endregion
61
+ export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerDocumentationErrorStatus, SwaggerDocumentationOptions, SwaggerService };
41
62
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import { OpenAPIObject } from "@nestjs/swagger";
2
+
1
3
  //#region src/constants.d.ts
2
4
  declare const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
3
5
  declare const ERROR_DESCRIPTIONS: {
@@ -37,5 +39,24 @@ interface SwaggerDocumentationOptions extends SwaggerDocumentationErrorStatus {
37
39
  //#region src/decorators/index.d.ts
38
40
  declare const SwaggerDocumentation: (data: SwaggerDocumentationOptions) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
39
41
  //#endregion
40
- export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerDocumentationErrorStatus, SwaggerDocumentationOptions };
42
+ //#region src/swagger.service.d.ts
43
+ interface Version {
44
+ name: string;
45
+ url: string;
46
+ config: Omit<OpenAPIObject, 'paths'>;
47
+ filterTag?: string;
48
+ }
49
+ declare class SwaggerService {
50
+ private app;
51
+ private documents;
52
+ private versions;
53
+ private metaTags;
54
+ setApp(app: any): void;
55
+ setVersions(versions: Version[]): void;
56
+ setMetaTags(tags: string[]): void;
57
+ getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined;
58
+ init(): void;
59
+ }
60
+ //#endregion
61
+ export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerDocumentationErrorStatus, SwaggerDocumentationOptions, SwaggerService };
41
62
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import { applyDecorators } from "@nestjs/common";
2
- import { ApiBadRequestResponse, ApiConflictResponse, ApiExtraModels, ApiForbiddenResponse, ApiInternalServerErrorResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiProperty, ApiServiceUnavailableResponse, ApiTooManyRequestsResponse, ApiUnauthorizedResponse, ApiUnprocessableEntityResponse, getSchemaPath } from "@nestjs/swagger";
3
-
1
+ import { Injectable, applyDecorators } from "@nestjs/common";
2
+ import { ApiBadRequestResponse, ApiConflictResponse, ApiExtraModels, ApiForbiddenResponse, ApiInternalServerErrorResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiProperty, ApiServiceUnavailableResponse, ApiTooManyRequestsResponse, ApiUnauthorizedResponse, ApiUnprocessableEntityResponse, SwaggerModule, getSchemaPath } from "@nestjs/swagger";
4
3
  //#region src/constants.ts
5
4
  const API_RESPONSE_DESCRIPTION = "If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text";
6
5
  const ERROR_DESCRIPTIONS = {
@@ -14,22 +13,19 @@ const ERROR_DESCRIPTIONS = {
14
13
  INTERNAL_SERVER_ERROR: "Internal server error",
15
14
  SERVICE_UNAVAILABLE: "Service temporarily unavailable"
16
15
  };
17
-
18
16
  //#endregion
19
- //#region \0@oxc-project+runtime@0.112.0/helpers/decorateMetadata.js
17
+ //#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
20
18
  function __decorateMetadata(k, v) {
21
19
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
20
  }
23
-
24
21
  //#endregion
25
- //#region \0@oxc-project+runtime@0.112.0/helpers/decorate.js
22
+ //#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
26
23
  function __decorate(decorators, target, key, desc) {
27
24
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
28
25
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
29
26
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
30
27
  return c > 3 && r && Object.defineProperty(target, key, r), r;
31
28
  }
32
-
33
29
  //#endregion
34
30
  //#region src/dtos/index.ts
35
31
  var PaginatedResponseDto = class {
@@ -41,7 +37,6 @@ var PaginatedResponseDto = class {
41
37
  __decorate([ApiProperty(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "totalCount", void 0);
42
38
  __decorate([ApiProperty(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "offset", void 0);
43
39
  __decorate([ApiProperty(), __decorateMetadata("design:type", Number)], PaginatedResponseDto.prototype, "limit", void 0);
44
-
45
40
  //#endregion
46
41
  //#region src/decorators/index.ts
47
42
  const SwaggerDocumentation = (data) => {
@@ -78,7 +73,92 @@ const SwaggerDocumentation = (data) => {
78
73
  else decorators.push(ApiOkResponse({ description: API_RESPONSE_DESCRIPTION }));
79
74
  return applyDecorators(...decorators);
80
75
  };
81
-
82
76
  //#endregion
83
- export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation };
77
+ //#region src/swagger.service.ts
78
+ var OpenApiDocsBuilder = class {
79
+ constructor(doc, metaTags) {
80
+ this.doc = doc;
81
+ this.metaTags = metaTags;
82
+ }
83
+ stripMetaTags() {
84
+ return this.mapOperations((op) => ({
85
+ ...op,
86
+ tags: this.removeMeta(op.tags)
87
+ }));
88
+ }
89
+ filterByTag(tag) {
90
+ const filteredPaths = {};
91
+ for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
92
+ const filteredMethods = {};
93
+ for (const [method, operation] of Object.entries(methods)) {
94
+ const op = operation;
95
+ if (op.tags?.includes(tag)) filteredMethods[method] = {
96
+ ...op,
97
+ tags: this.removeMeta(op.tags)
98
+ };
99
+ }
100
+ if (Object.keys(filteredMethods).length > 0) filteredPaths[path] = filteredMethods;
101
+ }
102
+ return {
103
+ ...this.doc,
104
+ paths: filteredPaths
105
+ };
106
+ }
107
+ mapOperations(fn) {
108
+ const paths = {};
109
+ for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {
110
+ const mapped = {};
111
+ for (const [method, operation] of Object.entries(methods)) mapped[method] = fn(operation);
112
+ paths[path] = mapped;
113
+ }
114
+ return {
115
+ ...this.doc,
116
+ paths
117
+ };
118
+ }
119
+ removeMeta(tags) {
120
+ return (tags ?? []).filter((t) => !this.metaTags.includes(t));
121
+ }
122
+ };
123
+ let SwaggerService = class SwaggerService {
124
+ app = null;
125
+ documents = {};
126
+ versions = [];
127
+ metaTags = [
128
+ "protected",
129
+ "private",
130
+ "support"
131
+ ];
132
+ setApp(app) {
133
+ this.app = app;
134
+ }
135
+ setVersions(versions) {
136
+ this.versions = versions;
137
+ }
138
+ setMetaTags(tags) {
139
+ this.metaTags = tags;
140
+ }
141
+ getDocument(key, serverUrl) {
142
+ const doc = this.documents[key];
143
+ if (!doc) return void 0;
144
+ if (!serverUrl) return doc;
145
+ return {
146
+ ...doc,
147
+ servers: [{ url: serverUrl }]
148
+ };
149
+ }
150
+ init() {
151
+ if (!this.app) throw new Error("App not found");
152
+ for (const version of this.versions) {
153
+ const { config, filterTag } = version;
154
+ const builder = new OpenApiDocsBuilder(SwaggerModule.createDocument(this.app, config), this.metaTags);
155
+ const document = filterTag ? builder.filterByTag(filterTag) : builder.stripMetaTags();
156
+ this.documents[version.name] = document;
157
+ }
158
+ }
159
+ };
160
+ SwaggerService = __decorate([Injectable()], SwaggerService);
161
+ //#endregion
162
+ export { API_RESPONSE_DESCRIPTION, ERROR_DESCRIPTIONS, SwaggerDocumentation, SwaggerService };
163
+
84
164
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n"],"mappings":";;;;AAAA,MAAa,2BACX;AAEF,MAAa,qBAAqB;CAChC,aAAa;CACb,cAAc;CACd,WAAW;CACX,WAAW;CACX,UAAU;CACV,sBAAsB;CACtB,qBAAqB;CACrB,uBAAuB;CACvB,qBAAqB;CACtB;;;;;;;;;;;;;;;;;;;ACXD,IAAa,uBAAb,MAAqC;CACnC;CAEA,AACA;CAEA,AACA;CAEA,AACA;;YAPC,aAAa;YAGb,aAAa;YAGb,aAAa;;;;ACWhB,MAAa,wBAAwB,SAAsC;CACzE,MAAM,cAAc,KAAK;CAEzB,MAAM,aAAa,CACjB,aAAa;EACX;EACA,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,YAAY,KAAK;EAClB,CAAC,CACH;AAED,KAAI,KAAK,oBACP,YAAW,KACT,sBAAsB,EACpB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,wBAAwB,EACtB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,qBAAqB,EACnB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,oBAAoB,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,oBAAoB,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,+BAA+B,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,2BAA2B,EACzB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,+BAA+B,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,8BAA8B,EAC5B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,eAAe,KAAK,YAC3B,YAAW,KACT,cAAc;EACZ,QAAQ,EACN,OAAO,CACL,EAAE,MAAM,cAAc,qBAAqB,EAAE,EAC7C,EACE,YAAY,EACV,MAAM;GACJ,MAAM;GACN,OAAO,EACL,MAAM,cAAc,KAAK,YAAY,EACtC;GACF,EACF,EACF,CACF,EACF;EACD,aAAa;EACd,CAAC,EACF,eAAe,KAAK,aAAa,qBAAqB,CACvD;UACQ,KAAK,YACd,YAAW,KACT,cAAc;EACZ,QAAQ,KAAK,UACT;GACE,MAAM;GACN,OAAO,EAAE,MAAM,cAAc,KAAK,YAAY,EAAE;GACjD,GACD,EAAE,MAAM,cAAc,KAAK,YAAY,EAAE;EAC7C,aAAa;EACd,CAAC,EACF,eAAe,KAAK,YAAY,CACjC;KAED,YAAW,KACT,cAAc,EACZ,aAAa,0BACd,CAAC,CACH;AAGH,QAAO,gBAAgB,GAAG,WAAW"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/constants.ts","../src/dtos/index.ts","../src/decorators/index.ts","../src/swagger.service.ts"],"sourcesContent":["export const API_RESPONSE_DESCRIPTION =\n \"If the server is available, it always responds with code 200 or 201. Error code 400 and higher will replace the ok field: it equals false and the error text in the error field. If the input data does not pass validation, the error field contains an object with invalid fields and error text\";\n\nexport const ERROR_DESCRIPTIONS = {\n BAD_REQUEST: \"Invalid request data or parameters\",\n UNAUTHORIZED: \"Authentication required\",\n FORBIDDEN: \"Access denied\",\n NOT_FOUND: \"Resource not found\",\n CONFLICT: \"Resource already exists or conflict detected\",\n UNPROCESSABLE_ENTITY: \"Validation error\",\n RATE_LIMIT_EXCEEDED: \"Rate limit exceeded. Too many requests\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n SERVICE_UNAVAILABLE: \"Service temporarily unavailable\",\n};\n","import { ApiProperty } from \"@nestjs/swagger\";\n\nexport class PaginatedResponseDto<T> {\n data!: T[];\n\n @ApiProperty()\n totalCount!: number;\n\n @ApiProperty()\n offset!: number;\n\n @ApiProperty()\n limit!: number;\n}\n","import { applyDecorators } from \"@nestjs/common\";\nimport {\n ApiBadRequestResponse,\n ApiConflictResponse,\n ApiExtraModels,\n ApiForbiddenResponse,\n ApiInternalServerErrorResponse,\n ApiNotFoundResponse,\n ApiOkResponse,\n ApiOperation,\n ApiServiceUnavailableResponse,\n ApiTooManyRequestsResponse,\n ApiUnauthorizedResponse,\n ApiUnprocessableEntityResponse,\n getSchemaPath,\n} from \"@nestjs/swagger\";\nimport { API_RESPONSE_DESCRIPTION } from \"../constants\";\nimport { PaginatedResponseDto } from \"../dtos\";\nimport { SwaggerDocumentationOptions } from \"../interfaces\";\nimport { createHash } from \"crypto\";\n\n// SwaggerDocumentation is a decorator function to generate Swagger documentation for endpoints based on the provided options.\nexport const SwaggerDocumentation = (data: SwaggerDocumentationOptions) => {\n const operationId = data.operationId;\n\n const decorators = [\n ApiOperation({\n operationId,\n description: data.endpointDescription,\n summary: data.endpointSummary,\n deprecated: data.deprecated,\n }),\n ];\n\n if (data.error400Description) {\n decorators.push(\n ApiBadRequestResponse({\n description: data.error400Description,\n })\n );\n }\n\n if (data.error401Description) {\n decorators.push(\n ApiUnauthorizedResponse({\n description: data.error401Description,\n })\n );\n }\n\n if (data.error403Description) {\n decorators.push(\n ApiForbiddenResponse({\n description: data.error403Description,\n })\n );\n }\n\n if (data.error404Description) {\n decorators.push(\n ApiNotFoundResponse({\n description: data.error404Description,\n })\n );\n }\n\n if (data.error409Description) {\n decorators.push(\n ApiConflictResponse({\n description: data.error409Description,\n })\n );\n }\n\n if (data.error422Description) {\n decorators.push(\n ApiUnprocessableEntityResponse({\n description: data.error422Description,\n })\n );\n }\n\n if (data.error429Description) {\n decorators.push(\n ApiTooManyRequestsResponse({\n description: data.error429Description,\n })\n );\n }\n\n if (data.error500Description) {\n decorators.push(\n ApiInternalServerErrorResponse({\n description: data.error500Description,\n })\n );\n }\n\n if (data.error503Description) {\n decorators.push(\n ApiServiceUnavailableResponse({\n description: data.error503Description,\n })\n );\n }\n\n if (data.isPaginated && data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: {\n allOf: [\n { $ref: getSchemaPath(PaginatedResponseDto) },\n {\n properties: {\n data: {\n type: \"array\",\n items: {\n $ref: getSchemaPath(data.responseDto),\n },\n },\n },\n },\n ],\n },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto, PaginatedResponseDto)\n );\n } else if (data.responseDto) {\n decorators.push(\n ApiOkResponse({\n schema: data.isArray\n ? {\n type: \"array\",\n items: { $ref: getSchemaPath(data.responseDto) },\n }\n : { $ref: getSchemaPath(data.responseDto) },\n description: API_RESPONSE_DESCRIPTION,\n }),\n ApiExtraModels(data.responseDto)\n );\n } else {\n decorators.push(\n ApiOkResponse({\n description: API_RESPONSE_DESCRIPTION,\n })\n );\n }\n\n return applyDecorators(...decorators);\n};\n","import { INestApplication, Injectable } from '@nestjs/common';\nimport { OpenAPIObject, SwaggerModule } from '@nestjs/swagger';\n\ntype Paths = OpenAPIObject['paths'];\n\nclass OpenApiDocsBuilder {\n constructor(\n private readonly doc: OpenAPIObject,\n private readonly metaTags: string[],\n ) {}\n\n stripMetaTags(): OpenAPIObject {\n return this.mapOperations((op) => ({ ...op, tags: this.removeMeta(op.tags) }));\n }\n\n filterByTag(tag: string): OpenAPIObject {\n const filteredPaths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const filteredMethods: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n const op = operation as { tags?: string[] };\n if (op.tags?.includes(tag)) {\n filteredMethods[method] = { ...op, tags: this.removeMeta(op.tags) };\n }\n }\n if (Object.keys(filteredMethods).length > 0) {\n filteredPaths[path] = filteredMethods as Paths[string];\n }\n }\n return { ...this.doc, paths: filteredPaths };\n }\n\n private mapOperations(fn: (op: { tags?: string[] }) => unknown): OpenAPIObject {\n const paths: Paths = {};\n for (const [path, methods] of Object.entries(this.doc.paths ?? {})) {\n const mapped: Record<string, unknown> = {};\n for (const [method, operation] of Object.entries(methods as Record<string, unknown>)) {\n mapped[method] = fn(operation as { tags?: string[] });\n }\n paths[path] = mapped as Paths[string];\n }\n return { ...this.doc, paths };\n }\n\n private removeMeta(tags?: string[]): string[] {\n return (tags ?? []).filter((t) => !this.metaTags.includes(t));\n }\n}\n\ninterface Version {\n name: string;\n url: string;\n config: Omit<OpenAPIObject, 'paths'>;\n filterTag?: string;\n}\n\n@Injectable()\nexport class SwaggerService {\n private app: INestApplication | null = null;\n private documents: Record<string, OpenAPIObject> = {};\n private versions: Version[] = [];\n private metaTags: string[] = ['protected', 'private', 'support'];\n\n setApp(app: any) {\n this.app = app;\n }\n\n setVersions(versions: Version[]) {\n this.versions = versions;\n }\n\n setMetaTags(tags: string[]) {\n this.metaTags = tags;\n }\n\n getDocument(key: string, serverUrl?: string): OpenAPIObject | undefined {\n const doc = this.documents[key];\n if (!doc) return undefined;\n if (!serverUrl) return doc;\n return { ...doc, servers: [{ url: serverUrl }] };\n }\n\n init() {\n if (!this.app) {\n throw new Error('App not found');\n }\n\n for (const version of this.versions) {\n const { config, filterTag } = version;\n const tempDoc = SwaggerModule.createDocument(this.app, config);\n const builder = new OpenApiDocsBuilder(tempDoc, this.metaTags);\n\n const document = filterTag\n ? builder.filterByTag(filterTag)\n : builder.stripMetaTags();\n\n this.documents[version.name] = document;\n }\n }\n}\n"],"mappings":";;;AAAA,MAAa,2BACX;AAEF,MAAa,qBAAqB;CAChC,aAAa;CACb,cAAc;CACd,WAAW;CACX,WAAW;CACX,UAAU;CACV,sBAAsB;CACtB,qBAAqB;CACrB,uBAAuB;CACvB,qBAAqB;CACtB;;;;;;;;;;;;;;;;ACXD,IAAa,uBAAb,MAAqC;CACnC;CAEA;CAGA;CAGA;;YANC,aAAa,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,qBAAA,WAAA,cAAA,KAAA,EAAA;YAGb,aAAa,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,qBAAA,WAAA,UAAA,KAAA,EAAA;YAGb,aAAa,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,qBAAA,WAAA,SAAA,KAAA,EAAA;;;ACWhB,MAAa,wBAAwB,SAAsC;CACzE,MAAM,cAAc,KAAK;CAEzB,MAAM,aAAa,CACjB,aAAa;EACX;EACA,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,YAAY,KAAK;EAClB,CAAC,CACH;AAED,KAAI,KAAK,oBACP,YAAW,KACT,sBAAsB,EACpB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,wBAAwB,EACtB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,qBAAqB,EACnB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,oBAAoB,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,oBAAoB,EAClB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,+BAA+B,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,2BAA2B,EACzB,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,+BAA+B,EAC7B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,oBACP,YAAW,KACT,8BAA8B,EAC5B,aAAa,KAAK,qBACnB,CAAC,CACH;AAGH,KAAI,KAAK,eAAe,KAAK,YAC3B,YAAW,KACT,cAAc;EACZ,QAAQ,EACN,OAAO,CACL,EAAE,MAAM,cAAc,qBAAqB,EAAE,EAC7C,EACE,YAAY,EACV,MAAM;GACJ,MAAM;GACN,OAAO,EACL,MAAM,cAAc,KAAK,YAAY,EACtC;GACF,EACF,EACF,CACF,EACF;EACD,aAAa;EACd,CAAC,EACF,eAAe,KAAK,aAAa,qBAAqB,CACvD;UACQ,KAAK,YACd,YAAW,KACT,cAAc;EACZ,QAAQ,KAAK,UACT;GACE,MAAM;GACN,OAAO,EAAE,MAAM,cAAc,KAAK,YAAY,EAAE;GACjD,GACD,EAAE,MAAM,cAAc,KAAK,YAAY,EAAE;EAC7C,aAAa;EACd,CAAC,EACF,eAAe,KAAK,YAAY,CACjC;KAED,YAAW,KACT,cAAc,EACZ,aAAa,0BACd,CAAC,CACH;AAGH,QAAO,gBAAgB,GAAG,WAAW;;;;AChJvC,IAAM,qBAAN,MAAyB;CACvB,YACE,KACA,UACA;AAFiB,OAAA,MAAA;AACA,OAAA,WAAA;;CAGnB,gBAA+B;AAC7B,SAAO,KAAK,eAAe,QAAQ;GAAE,GAAG;GAAI,MAAM,KAAK,WAAW,GAAG,KAAK;GAAE,EAAE;;CAGhF,YAAY,KAA4B;EACtC,MAAM,gBAAuB,EAAE;AAC/B,OAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,KAAK,IAAI,SAAS,EAAE,CAAC,EAAE;GAClE,MAAM,kBAA2C,EAAE;AACnD,QAAK,MAAM,CAAC,QAAQ,cAAc,OAAO,QAAQ,QAAmC,EAAE;IACpF,MAAM,KAAK;AACX,QAAI,GAAG,MAAM,SAAS,IAAI,CACxB,iBAAgB,UAAU;KAAE,GAAG;KAAI,MAAM,KAAK,WAAW,GAAG,KAAK;KAAE;;AAGvE,OAAI,OAAO,KAAK,gBAAgB,CAAC,SAAS,EACxC,eAAc,QAAQ;;AAG1B,SAAO;GAAE,GAAG,KAAK;GAAK,OAAO;GAAe;;CAG9C,cAAsB,IAAyD;EAC7E,MAAM,QAAe,EAAE;AACvB,OAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,KAAK,IAAI,SAAS,EAAE,CAAC,EAAE;GAClE,MAAM,SAAkC,EAAE;AAC1C,QAAK,MAAM,CAAC,QAAQ,cAAc,OAAO,QAAQ,QAAmC,CAClF,QAAO,UAAU,GAAG,UAAiC;AAEvD,SAAM,QAAQ;;AAEhB,SAAO;GAAE,GAAG,KAAK;GAAK;GAAO;;CAG/B,WAAmB,MAA2B;AAC5C,UAAQ,QAAQ,EAAE,EAAE,QAAQ,MAAM,CAAC,KAAK,SAAS,SAAS,EAAE,CAAC;;;AAY1D,IAAA,iBAAA,MAAM,eAAe;CAC1B,MAAuC;CACvC,YAAmD,EAAE;CACrD,WAA8B,EAAE;CAChC,WAA6B;EAAC;EAAa;EAAW;EAAU;CAEhE,OAAO,KAAU;AACf,OAAK,MAAM;;CAGb,YAAY,UAAqB;AAC/B,OAAK,WAAW;;CAGlB,YAAY,MAAgB;AAC1B,OAAK,WAAW;;CAGlB,YAAY,KAAa,WAA+C;EACtE,MAAM,MAAM,KAAK,UAAU;AAC3B,MAAI,CAAC,IAAK,QAAO,KAAA;AACjB,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO;GAAE,GAAG;GAAK,SAAS,CAAC,EAAE,KAAK,WAAW,CAAC;GAAE;;CAGlD,OAAO;AACL,MAAI,CAAC,KAAK,IACR,OAAM,IAAI,MAAM,gBAAgB;AAGlC,OAAK,MAAM,WAAW,KAAK,UAAU;GACnC,MAAM,EAAE,QAAQ,cAAc;GAE9B,MAAM,UAAU,IAAI,mBADJ,cAAc,eAAe,KAAK,KAAK,OAAO,EACd,KAAK,SAAS;GAE9D,MAAM,WAAW,YACb,QAAQ,YAAY,UAAU,GAC9B,QAAQ,eAAe;AAE3B,QAAK,UAAU,QAAQ,QAAQ;;;;6BAxCpC,YAAY,CAAA,EAAA,eAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalart/nestjs-swagger",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "A simple documentation builder for NestJS Swagger Module",
5
5
  "author": {
6
6
  "name": "GlobalArt, Inc"
@@ -48,16 +48,18 @@
48
48
  "publish:npm": "release-it --config ../../.release-it.json"
49
49
  },
50
50
  "dependencies": {
51
- "@nestjs/common": "11.1.14",
52
- "@nestjs/core": "11.1.14",
53
- "@nestjs/swagger": "^11.2.6",
54
- "@nestjs/testing": "11.1.14",
55
- "@nestjs/typeorm": "^11.0.0",
56
51
  "mysql": "^2.18.1"
57
52
  },
53
+ "peerDependencies": {
54
+ "@nestjs/common": "^10.0.0 || ^11.0.0",
55
+ "@nestjs/core": "^10.0.0 || ^11.0.0",
56
+ "@nestjs/swagger": "^10.0.0 || ^11.0.0",
57
+ "@nestjs/testing": "^10.0.0 || ^11.0.0",
58
+ "@nestjs/typeorm": "^10.0.0 || ^11.0.0"
59
+ },
58
60
  "devDependencies": {
59
61
  "@types/jest": "^30.0.0",
60
- "@types/node": "25.3.0",
62
+ "@types/node": "25.5.0",
61
63
  "coveralls": "^3.1.1",
62
64
  "jest": "^30.2.0",
63
65
  "prettier": "3.8.1",
@@ -66,9 +68,9 @@
66
68
  "rxjs": "^7.8.2",
67
69
  "ts-jest": "29.4.6",
68
70
  "ts-node": "^10.9.2",
69
- "tsdown": "0.20.3",
71
+ "tsdown": "0.21.5",
70
72
  "typeorm": "0.3.28",
71
- "typescript": "^5.9.3"
73
+ "typescript": "^6.0.2"
72
74
  },
73
75
  "jest": {
74
76
  "coveragePathIgnorePatterns": [