vls-openapi-generator 1.15.0 → 2.0.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/.eslintcache CHANGED
@@ -1 +1 @@
1
- [{"/__w/vls-openapi-generator/vls-openapi-generator/.commitlintrc.js":"1","/__w/vls-openapi-generator/vls-openapi-generator/dist/generate-openapi.js":"2","/__w/vls-openapi-generator/vls-openapi-generator/dist/index.js":"3","/__w/vls-openapi-generator/vls-openapi-generator/dist/lambda-type.js":"4","/__w/vls-openapi-generator/vls-openapi-generator/dist/openapi-type.js":"5","/__w/vls-openapi-generator/vls-openapi-generator/dist/postman-service.js":"6","/__w/vls-openapi-generator/vls-openapi-generator/dist/upload-openapi.js":"7","/__w/vls-openapi-generator/vls-openapi-generator/eslint.config.mjs":"8","/__w/vls-openapi-generator/vls-openapi-generator/release.config.js":"9","/__w/vls-openapi-generator/vls-openapi-generator/src/generate-openapi.ts":"10","/__w/vls-openapi-generator/vls-openapi-generator/src/index.ts":"11","/__w/vls-openapi-generator/vls-openapi-generator/src/lambda-type.ts":"12","/__w/vls-openapi-generator/vls-openapi-generator/src/openapi-type.ts":"13","/__w/vls-openapi-generator/vls-openapi-generator/src/postman-service.ts":"14","/__w/vls-openapi-generator/vls-openapi-generator/src/upload-openapi.ts":"15"},{"size":103,"mtime":1764155630302,"results":"16","hashOfConfig":"17"},{"size":6644,"mtime":1764169300649,"results":"18","hashOfConfig":"17"},{"size":530,"mtime":1764169300693,"results":"19","hashOfConfig":"17"},{"size":77,"mtime":1764169300629,"results":"20","hashOfConfig":"17"},{"size":77,"mtime":1764169300637,"results":"21","hashOfConfig":"17"},{"size":3073,"mtime":1764169300665,"results":"22","hashOfConfig":"17"},{"size":5361,"mtime":1764169300693,"results":"23","hashOfConfig":"17"},{"size":1247,"mtime":1764155630302,"results":"24","hashOfConfig":"17"},{"size":401,"mtime":1764155630302,"results":"25","hashOfConfig":"17"},{"size":5552,"mtime":1764169293749,"results":"26","hashOfConfig":"27"},{"size":441,"mtime":1764155630302,"results":"28","hashOfConfig":"27"},{"size":243,"mtime":1764155630302,"results":"29","hashOfConfig":"27"},{"size":1634,"mtime":1764155630302,"results":"30","hashOfConfig":"27"},{"size":3666,"mtime":1764155630302,"results":"31","hashOfConfig":"27"},{"size":3960,"mtime":1764155630302,"results":"32","hashOfConfig":"27"},{"filePath":"33","messages":"34","suppressedMessages":"35","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"47mvrp",{"filePath":"36","messages":"37","suppressedMessages":"38","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"39","messages":"40","suppressedMessages":"41","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"42","messages":"43","suppressedMessages":"44","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"45","messages":"46","suppressedMessages":"47","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","suppressedMessages":"50","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"51","messages":"52","suppressedMessages":"53","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"54","messages":"55","suppressedMessages":"56","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"57","messages":"58","suppressedMessages":"59","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"60","messages":"61","suppressedMessages":"62","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1fhi8uz",{"filePath":"63","messages":"64","suppressedMessages":"65","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"66","messages":"67","suppressedMessages":"68","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"69","messages":"70","suppressedMessages":"71","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"72","messages":"73","suppressedMessages":"74","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"75","messages":"76","suppressedMessages":"77","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/__w/vls-openapi-generator/vls-openapi-generator/.commitlintrc.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/dist/generate-openapi.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/dist/index.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/dist/lambda-type.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/dist/openapi-type.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/dist/postman-service.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/dist/upload-openapi.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/eslint.config.mjs",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/release.config.js",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/src/generate-openapi.ts",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/src/index.ts",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/src/lambda-type.ts",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/src/openapi-type.ts",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/src/postman-service.ts",[],[],"/__w/vls-openapi-generator/vls-openapi-generator/src/upload-openapi.ts",[],[]]
1
+ [{"/__w/vls-packages/vls-packages/.commitlintrc.js":"1","/__w/vls-packages/vls-packages/dist/generate-openapi.js":"2","/__w/vls-packages/vls-packages/dist/index.js":"3","/__w/vls-packages/vls-packages/dist/lambda-type.js":"4","/__w/vls-packages/vls-packages/dist/openapi-type.js":"5","/__w/vls-packages/vls-packages/dist/postman-service.js":"6","/__w/vls-packages/vls-packages/dist/upload-openapi.js":"7","/__w/vls-packages/vls-packages/eslint.config.mjs":"8","/__w/vls-packages/vls-packages/release.config.js":"9","/__w/vls-packages/vls-packages/src/generate-openapi.ts":"10","/__w/vls-packages/vls-packages/src/index.ts":"11","/__w/vls-packages/vls-packages/src/lambda-type.ts":"12","/__w/vls-packages/vls-packages/src/openapi-type.ts":"13","/__w/vls-packages/vls-packages/src/postman-service.ts":"14","/__w/vls-packages/vls-packages/src/upload-openapi.ts":"15"},{"size":103,"mtime":1767342111724,"results":"16","hashOfConfig":"17"},{"size":9432,"mtime":1767342117884,"results":"18","hashOfConfig":"17"},{"size":530,"mtime":1767342117932,"results":"19","hashOfConfig":"17"},{"size":77,"mtime":1767342117844,"results":"20","hashOfConfig":"17"},{"size":77,"mtime":1767342117848,"results":"21","hashOfConfig":"17"},{"size":3073,"mtime":1767342117900,"results":"22","hashOfConfig":"17"},{"size":5361,"mtime":1767342117928,"results":"23","hashOfConfig":"17"},{"size":1247,"mtime":1767342111724,"results":"24","hashOfConfig":"17"},{"size":414,"mtime":1767342111728,"results":"25","hashOfConfig":"17"},{"size":9628,"mtime":1767342111728,"results":"26","hashOfConfig":"27"},{"size":441,"mtime":1767342111728,"results":"28","hashOfConfig":"27"},{"size":90,"mtime":1767342111728,"results":"29","hashOfConfig":"27"},{"size":1630,"mtime":1767342111728,"results":"30","hashOfConfig":"27"},{"size":3666,"mtime":1767342111728,"results":"31","hashOfConfig":"27"},{"size":3960,"mtime":1767342111728,"results":"32","hashOfConfig":"27"},{"filePath":"33","messages":"34","suppressedMessages":"35","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"47mvrp",{"filePath":"36","messages":"37","suppressedMessages":"38","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"39","messages":"40","suppressedMessages":"41","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"42","messages":"43","suppressedMessages":"44","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"45","messages":"46","suppressedMessages":"47","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","suppressedMessages":"50","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"51","messages":"52","suppressedMessages":"53","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"54","messages":"55","suppressedMessages":"56","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"57","messages":"58","suppressedMessages":"59","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"60","messages":"61","suppressedMessages":"62","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1js9mgi",{"filePath":"63","messages":"64","suppressedMessages":"65","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"66","messages":"67","suppressedMessages":"68","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"69","messages":"70","suppressedMessages":"71","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"72","messages":"73","suppressedMessages":"74","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"75","messages":"76","suppressedMessages":"77","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/__w/vls-packages/vls-packages/.commitlintrc.js",[],[],"/__w/vls-packages/vls-packages/dist/generate-openapi.js",[],[],"/__w/vls-packages/vls-packages/dist/index.js",[],[],"/__w/vls-packages/vls-packages/dist/lambda-type.js",[],[],"/__w/vls-packages/vls-packages/dist/openapi-type.js",[],[],"/__w/vls-packages/vls-packages/dist/postman-service.js",[],[],"/__w/vls-packages/vls-packages/dist/upload-openapi.js",[],[],"/__w/vls-packages/vls-packages/eslint.config.mjs",[],[],"/__w/vls-packages/vls-packages/release.config.js",[],[],"/__w/vls-packages/vls-packages/src/generate-openapi.ts",[],[],"/__w/vls-packages/vls-packages/src/index.ts",[],[],"/__w/vls-packages/vls-packages/src/lambda-type.ts",[],[],"/__w/vls-packages/vls-packages/src/openapi-type.ts",[],[],"/__w/vls-packages/vls-packages/src/postman-service.ts",[],[],"/__w/vls-packages/vls-packages/src/upload-openapi.ts",[],[]]
@@ -34,13 +34,14 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.generateOpenAPI = void 0;
37
- const zod_openapi_1 = require("@anatine/zod-openapi");
37
+ const zod_openapi_1 = require("zod-openapi");
38
38
  const node_child_process_1 = require("node:child_process");
39
39
  const node_fs_1 = require("node:fs");
40
40
  require("module-alias/register.js");
41
41
  const path = __importStar(require("node:path"));
42
42
  const node_util_1 = require("node:util");
43
43
  const zod_1 = require("zod");
44
+ const axios_1 = require("axios");
44
45
  const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
45
46
  const HANDLERS_DIR = path.join(process.cwd(), 'dist', 'src', 'handlers');
46
47
  const SCHEMAS_DIR = path.join(process.cwd(), 'dist', 'src', 'schemas');
@@ -64,7 +65,7 @@ const generateOpenAPI = async () => {
64
65
  if (fileName.match(/^([a-z]+-)+queue-(publisher|consumer)$/)) {
65
66
  continue;
66
67
  }
67
- const { bodySchema, queryParametersSchema, eventResponseParametersSchema, eventResponseModulesSchema, OPENAPI_CONFIG: openAPIConfig } = (await Promise.resolve(`${path.join(SCHEMAS_DIR, fileName + '.js')}`).then(s => __importStar(require(s))).catch((error) => {
68
+ const { requestSchema, successfulResponseSchema, errorResponseSchema, OPENAPI_CONFIG: openAPIConfig } = (await Promise.resolve(`${path.join(SCHEMAS_DIR, fileName + '.js')}`).then(s => __importStar(require(s))).catch((error) => {
68
69
  console.error(error);
69
70
  return {};
70
71
  }));
@@ -75,69 +76,142 @@ const generateOpenAPI = async () => {
75
76
  continue;
76
77
  }
77
78
  const { LAMBDA_CONFIG } = (await Promise.resolve(`${path.join(HANDLERS_DIR, `${fileName}.js`)}`).then(s => __importStar(require(s))));
78
- const bodyComponent = (0, zod_openapi_1.generateSchema)(bodySchema ?? zod_1.z.never(), undefined, '3.0');
79
- const queryParametersComponent = (0, zod_openapi_1.generateSchema)(queryParametersSchema ?? zod_1.z.never(), undefined, '3.0');
80
- const eventResponseComponent = generateEventResponseComponent(openAPIConfig.responseType, eventResponseParametersSchema, eventResponseModulesSchema);
81
- const queryParameters = [];
82
- if (queryParametersSchema) {
83
- for (const key in queryParametersComponent.properties) {
84
- const properties = queryParametersComponent?.properties;
85
- if (!properties?.[key]) {
86
- continue;
79
+ const responses = {};
80
+ for (const label in successfulResponseSchema) {
81
+ const response = successfulResponseSchema[label];
82
+ responses[`Success - ${axios_1.HttpStatusCode[response.status]} - ${label}`] = {
83
+ description: axios_1.HttpStatusCode[response.status].toString(),
84
+ content: {
85
+ 'application/json': {
86
+ schema: response.type === 'mindbehind'
87
+ ? (0, zod_openapi_1.createSchema)(zod_1.z.object({
88
+ content: zod_1.z.object({
89
+ params: response.parameters,
90
+ modules: response.modules,
91
+ fallback: zod_1.z.literal(false)
92
+ })
93
+ }), {
94
+ openapiVersion: '3.1.1',
95
+ io: 'output'
96
+ }).schema
97
+ : (0, zod_openapi_1.createSchema)(response.parameters, {
98
+ openapiVersion: '3.1.1',
99
+ io: 'output'
100
+ }).schema
101
+ }
87
102
  }
88
- queryParameters.push({
89
- name: key,
90
- in: 'query',
91
- schema: properties[key]
92
- });
93
- }
103
+ };
94
104
  }
95
- existingOpenAPIFile.paths['/' + fileName] = {
96
- [LAMBDA_CONFIG?.api?.method?.toLowerCase() ?? 'post']: {
97
- tags: openAPIConfig.tags,
98
- parameters: queryParametersSchema ? queryParameters : undefined,
99
- requestBody: bodySchema
100
- ? {
101
- required: true,
102
- content: {
103
- 'application/json': {
104
- schema: bodyComponent
105
- }
106
- }
105
+ for (const label in errorResponseSchema) {
106
+ const response = errorResponseSchema[label];
107
+ responses[`Error - ${axios_1.HttpStatusCode[response.status]} - ${label}`] = {
108
+ description: axios_1.HttpStatusCode[response.status].toString(),
109
+ content: {
110
+ 'application/json': {
111
+ schema: response.type === 'mindbehind'
112
+ ? (0, zod_openapi_1.createSchema)(zod_1.z.object({
113
+ content: zod_1.z.object({
114
+ params: response.parameters,
115
+ modules: response.modules,
116
+ fallback: zod_1.z.literal(false)
117
+ })
118
+ }), {
119
+ openapiVersion: '3.1.1',
120
+ io: 'output'
121
+ }).schema
122
+ : (0, zod_openapi_1.createSchema)(response.parameters, {
123
+ openapiVersion: '3.1.1',
124
+ io: 'output'
125
+ }).schema
107
126
  }
108
- : undefined,
109
- responses: {
110
- '200': {
111
- description: `Successful response.`,
112
- content: {
113
- 'application/json': {
114
- schema: eventResponseComponent
127
+ }
128
+ };
129
+ }
130
+ const parameters = [];
131
+ const bodySchemas = [];
132
+ const headersSchemas = [];
133
+ const queryParametersSchemas = [];
134
+ for (const label in requestSchema) {
135
+ const { body, headers, queryParameters } = requestSchema[label];
136
+ if (!(body instanceof zod_1.z.ZodNever)) {
137
+ bodySchemas.push(body.meta({
138
+ title: label
139
+ }));
140
+ }
141
+ if (!(headers instanceof zod_1.z.ZodNever)) {
142
+ headersSchemas.push(headers.meta({
143
+ title: label
144
+ }));
145
+ }
146
+ if (!(queryParameters instanceof zod_1.z.ZodNever)) {
147
+ queryParametersSchemas.push(queryParameters.meta({
148
+ title: label
149
+ }));
150
+ }
151
+ }
152
+ const bodyComponent = bodySchemas.length !== 0
153
+ ? (0, zod_openapi_1.createSchema)(zod_1.z.union(bodySchemas), {
154
+ openapiVersion: '3.1.1',
155
+ io: 'input'
156
+ })
157
+ : null;
158
+ const headersComponent = headersSchemas.length !== 0
159
+ ? (0, zod_openapi_1.createSchema)(zod_1.z.union(headersSchemas), {
160
+ openapiVersion: '3.1.1',
161
+ io: 'input'
162
+ })
163
+ : null;
164
+ const queryParametersComponent = queryParametersSchemas.length !== 0
165
+ ? (0, zod_openapi_1.createSchema)(zod_1.z.union(queryParametersSchemas), {
166
+ openapiVersion: '3.1.1',
167
+ io: 'input'
168
+ })
169
+ : null;
170
+ if (queryParametersComponent) {
171
+ explodeObject(queryParametersComponent.schema, parameters, 'query');
172
+ }
173
+ if (headersComponent) {
174
+ explodeObject(headersComponent.schema, parameters, 'header');
175
+ }
176
+ for (const method of LAMBDA_CONFIG?.api?.methods ?? ['POST']) {
177
+ existingOpenAPIFile.paths['/' + fileName] = {
178
+ [method.toLowerCase()]: {
179
+ tags: openAPIConfig.tags,
180
+ parameters: parameters,
181
+ requestBody: bodyComponent
182
+ ? {
183
+ content: {
184
+ 'application/json': {
185
+ schema: bodyComponent.schema
186
+ }
115
187
  }
116
188
  }
117
- }
189
+ : undefined,
190
+ responses
118
191
  }
119
- }
120
- };
192
+ };
193
+ }
121
194
  }
122
195
  await node_fs_1.promises.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
123
196
  console.info('Open API documentation generated successfully');
124
197
  };
125
198
  exports.generateOpenAPI = generateOpenAPI;
126
- function generateEventResponseComponent(responseType = 'mindbehind-chat-bot-response', eventResponseParametersSchema, eventResponseModulesSchema) {
127
- if (responseType === 'mindbehind-chat-bot-response') {
128
- return (0, zod_openapi_1.generateSchema)(zod_1.z.object({
129
- ...(eventResponseParametersSchema
130
- ? { params: eventResponseParametersSchema }
131
- : { params: zod_1.z.object({}) }),
132
- ...(eventResponseModulesSchema
133
- ? { modules: eventResponseModulesSchema }
134
- : {
135
- modules: (0, zod_openapi_1.extendApi)(zod_1.z.array(zod_1.z.unknown()), {
136
- example: []
137
- })
138
- }),
139
- fallback: zod_1.z.boolean().default(false)
140
- }), undefined, '3.0');
199
+ function explodeObject(schema, parameters, type, isRequiredIncluded = true) {
200
+ if (!('type' in schema) || schema.type !== 'object') {
201
+ parameters.push({
202
+ name: '-',
203
+ in: type,
204
+ schema: schema,
205
+ required: true
206
+ });
207
+ return;
208
+ }
209
+ for (const element in schema.properties) {
210
+ parameters.push({
211
+ name: element,
212
+ in: type,
213
+ schema: schema.properties[element],
214
+ required: isRequiredIncluded ? schema.required?.includes(element) ?? false : false
215
+ });
141
216
  }
142
- return (0, zod_openapi_1.generateSchema)(eventResponseParametersSchema ?? zod_1.z.object({}), undefined, '3.0');
143
217
  }
@@ -1,10 +1,4 @@
1
1
  export type OpenAPIConfig = {
2
2
  tags: string[];
3
3
  isDocumentationNeeded?: boolean;
4
- responseType?: 'mindbehind-chat-bot-response' | 'api-response';
5
- };
6
- export type LambdaConfig = {
7
- api?: {
8
- method?: 'GET' | 'POST';
9
- };
10
4
  };
@@ -1,6 +1,6 @@
1
- import { generateSchema } from '@anatine/zod-openapi';
1
+ import { createSchema } from 'zod-openapi';
2
2
  export type OpenAPI = {
3
- openapi: '3.0.0';
3
+ openapi: '3.1.1';
4
4
  info: {
5
5
  title: string;
6
6
  version: string;
@@ -16,26 +16,23 @@ export type OpenAPI = {
16
16
  parameters: {
17
17
  name: string;
18
18
  in: 'query';
19
- schema: ReturnType<typeof generateSchema>;
19
+ schema: ReturnType<typeof createSchema>['schema'];
20
20
  }[] | undefined;
21
21
  requestBody: {
22
22
  required: true;
23
23
  content: {
24
24
  'application/json': {
25
- schema: ReturnType<typeof generateSchema>;
25
+ schema: ReturnType<typeof createSchema>['schema'];
26
26
  };
27
27
  };
28
28
  } | undefined;
29
- responses: {
30
- 200: {
31
- description: string;
32
- content: {
33
- 'application/json': {
34
- schema: ReturnType<typeof generateSchema>;
35
- };
36
- } | undefined;
37
- };
38
- };
29
+ responses: Record<number, {
30
+ content: {
31
+ 'application/json': {
32
+ schema: ReturnType<typeof createSchema>['schema'];
33
+ };
34
+ } | undefined;
35
+ }>;
39
36
  tags: string[];
40
37
  }>>>;
41
38
  };
@@ -26,13 +26,13 @@ export declare class PostmanService {
26
26
  };
27
27
  }>;
28
28
  createCollection: (partnerName: string) => Promise<string>;
29
- deleteFolder: (collectionID: string, folderID: string) => Promise<import("axios").AxiosResponse<any, any, {}>>;
30
- createFolder: (collectionID: string, folderName: string) => Promise<import("axios").AxiosResponse<any, any, {}>>;
31
- updateCollection: (collectionID: string, collection: object) => Promise<import("axios").AxiosResponse<any, any, {}>>;
29
+ deleteFolder: (collectionID: string, folderID: string) => Promise<import("axios").AxiosResponse<any, any>>;
30
+ createFolder: (collectionID: string, folderName: string) => Promise<import("axios").AxiosResponse<any, any>>;
31
+ updateCollection: (collectionID: string, collection: object) => Promise<import("axios").AxiosResponse<any, any>>;
32
32
  updateVariablesCollection: (collectionID: string, variables: {
33
33
  key: string;
34
34
  value: string;
35
- }[]) => Promise<import("axios").AxiosResponse<any, any, {}>>;
35
+ }[]) => Promise<import("axios").AxiosResponse<any, any>>;
36
36
  getAllEnvironments: () => Promise<{
37
37
  environments: {
38
38
  id: string;
@@ -42,9 +42,9 @@ export declare class PostmanService {
42
42
  createEnvironment: (name: string, values: {
43
43
  key: string;
44
44
  value: string;
45
- }[]) => Promise<import("axios").AxiosResponse<any, any, {}>>;
45
+ }[]) => Promise<import("axios").AxiosResponse<any, any>>;
46
46
  updateEnvironment: (id: string, name: string, values: {
47
47
  key: string;
48
48
  value: string;
49
- }[]) => Promise<import("axios").AxiosResponse<any, any, {}>>;
49
+ }[]) => Promise<import("axios").AxiosResponse<any, any>>;
50
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vls-openapi-generator",
3
- "version": "1.15.0",
3
+ "version": "2.0.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -15,10 +15,10 @@
15
15
  "license": "ISC",
16
16
  "description": "VLS Open API Generator",
17
17
  "dependencies": {
18
- "@anatine/zod-openapi": "^2.2.7",
19
- "axios": "^1.12.0",
20
18
  "module-alias": "^2.2.3",
21
- "openapi-to-postmanv2": "^4.25.0"
19
+ "openapi-to-postmanv2": "^4.25.0",
20
+ "zod": "^4.2.1",
21
+ "zod-openapi": "^5.4.5"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@commitlint/config-conventional": "^19.5.0",
@@ -27,13 +27,15 @@
27
27
  "@semantic-release/npm": "^12.0.1",
28
28
  "@types/node": "^20.14.8",
29
29
  "@types/openapi-to-postmanv2": "^3.2.4",
30
+ "axios": "^1.8.3",
30
31
  "commitlint": "^19.5.0",
31
32
  "eslint": "^9.12.0",
32
33
  "husky": "^9.1.6",
33
34
  "prettier": "^2.7.1",
34
35
  "semantic-release": "^24.1.2",
35
36
  "typescript": "^5.6.3",
36
- "typescript-eslint": "^8.9.0"
37
+ "typescript-eslint": "^8.9.0",
38
+ "vls-sam-template-generator": "^2.22.0"
37
39
  },
38
40
  "bin": {
39
41
  "vls-openapi-generator": "dist/index.js"
package/release.config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
- branches: ['main'],
2
+ branches: ['openapi-generator'],
3
3
  plugins: [
4
4
  '@semantic-release/commit-analyzer',
5
5
  '@semantic-release/release-notes-generator',
@@ -1,12 +1,14 @@
1
- import { extendApi, generateSchema, OpenApiZodAny } from '@anatine/zod-openapi';
1
+ import { createSchema, ZodOpenApiSchemaObject } from 'zod-openapi';
2
2
  import { exec } from 'node:child_process';
3
3
  import { promises as fs } from 'node:fs';
4
4
  import 'module-alias/register.js';
5
5
  import * as path from 'node:path';
6
6
  import { promisify } from 'node:util';
7
7
  import { z } from 'zod';
8
- import { LambdaConfig, OpenAPIConfig } from './lambda-type';
8
+ import { OpenAPIConfig } from './lambda-type';
9
9
  import { OpenAPI } from './openapi-type';
10
+ import type { LambdaConfig } from 'vls-sam-template-generator';
11
+ import { HttpStatusCode } from 'axios';
10
12
 
11
13
  const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
12
14
  const HANDLERS_DIR = path.join(process.cwd(), 'dist', 'src', 'handlers');
@@ -43,20 +45,18 @@ export const generateOpenAPI = async (): Promise<void> => {
43
45
  }
44
46
 
45
47
  const {
46
- bodySchema,
47
- queryParametersSchema,
48
- eventResponseParametersSchema,
49
- eventResponseModulesSchema,
48
+ requestSchema,
49
+ successfulResponseSchema,
50
+ errorResponseSchema,
50
51
  OPENAPI_CONFIG: openAPIConfig
51
52
  } = (await import(path.join(SCHEMAS_DIR, fileName + '.js')).catch((error) => {
52
53
  console.error(error);
53
54
 
54
55
  return {};
55
56
  })) as {
56
- bodySchema?: OpenApiZodAny;
57
- eventResponseParametersSchema?: OpenApiZodAny;
58
- eventResponseModulesSchema?: OpenApiZodAny;
59
- queryParametersSchema?: OpenApiZodAny;
57
+ requestSchema: RequestSchema;
58
+ successfulResponseSchema?: ResponseSchema;
59
+ errorResponseSchema?: ResponseSchema;
60
60
  OPENAPI_CONFIG: OpenAPIConfig;
61
61
  };
62
62
 
@@ -72,58 +72,157 @@ export const generateOpenAPI = async (): Promise<void> => {
72
72
  LAMBDA_CONFIG?: LambdaConfig;
73
73
  };
74
74
 
75
- const bodyComponent = generateSchema(bodySchema ?? z.never(), undefined, '3.0');
76
- const queryParametersComponent = generateSchema(queryParametersSchema ?? z.never(), undefined, '3.0');
77
- const eventResponseComponent = generateEventResponseComponent(
78
- openAPIConfig.responseType,
79
- eventResponseParametersSchema,
80
- eventResponseModulesSchema
81
- );
75
+ const responses: Record<
76
+ string,
77
+ { description: string; content: { 'application/json': { schema: ZodOpenApiSchemaObject } } }
78
+ > = {};
82
79
 
83
- const queryParameters = [];
80
+ for (const label in successfulResponseSchema) {
81
+ const response = successfulResponseSchema[label];
84
82
 
85
- if (queryParametersSchema) {
86
- for (const key in queryParametersComponent.properties) {
87
- const properties = queryParametersComponent?.properties;
83
+ responses[`Success - ${HttpStatusCode[response.status]} - ${label}`] = {
84
+ description: HttpStatusCode[response.status].toString(),
85
+ content: {
86
+ 'application/json': {
87
+ schema:
88
+ response.type === 'mindbehind'
89
+ ? createSchema(
90
+ z.object({
91
+ content: z.object({
92
+ params: response.parameters,
93
+ modules: response.modules,
94
+ fallback: z.literal(false)
95
+ })
96
+ }),
97
+ {
98
+ openapiVersion: '3.1.1',
99
+ io: 'output'
100
+ }
101
+ ).schema
102
+ : createSchema(response.parameters, {
103
+ openapiVersion: '3.1.1',
104
+ io: 'output'
105
+ }).schema
106
+ }
107
+ }
108
+ };
109
+ }
110
+
111
+ for (const label in errorResponseSchema) {
112
+ const response = errorResponseSchema[label];
88
113
 
89
- if (!properties?.[key]) {
90
- continue;
114
+ responses[`Error - ${HttpStatusCode[response.status]} - ${label}`] = {
115
+ description: HttpStatusCode[response.status].toString(),
116
+ content: {
117
+ 'application/json': {
118
+ schema:
119
+ response.type === 'mindbehind'
120
+ ? createSchema(
121
+ z.object({
122
+ content: z.object({
123
+ params: response.parameters,
124
+ modules: response.modules,
125
+ fallback: z.literal(false)
126
+ })
127
+ }),
128
+ {
129
+ openapiVersion: '3.1.1',
130
+ io: 'output'
131
+ }
132
+ ).schema
133
+ : createSchema(response.parameters, {
134
+ openapiVersion: '3.1.1',
135
+ io: 'output'
136
+ }).schema
137
+ }
91
138
  }
139
+ };
140
+ }
141
+
142
+ const parameters: Parameter[] = [];
143
+
144
+ const bodySchemas = [];
145
+ const headersSchemas = [];
146
+ const queryParametersSchemas = [];
92
147
 
93
- queryParameters.push({
94
- name: key,
95
- in: 'query',
96
- schema: properties[key]
97
- } as const);
148
+ for (const label in requestSchema) {
149
+ const { body, headers, queryParameters } = requestSchema[label];
150
+
151
+ if (!(body instanceof z.ZodNever)) {
152
+ bodySchemas.push(
153
+ body.meta({
154
+ title: label
155
+ })
156
+ );
157
+ }
158
+
159
+ if (!(headers instanceof z.ZodNever)) {
160
+ headersSchemas.push(
161
+ headers.meta({
162
+ title: label
163
+ })
164
+ );
165
+ }
166
+
167
+ if (!(queryParameters instanceof z.ZodNever)) {
168
+ queryParametersSchemas.push(
169
+ queryParameters.meta({
170
+ title: label
171
+ })
172
+ );
98
173
  }
99
174
  }
100
175
 
101
- existingOpenAPIFile.paths['/' + fileName] = {
102
- [LAMBDA_CONFIG?.api?.method?.toLowerCase() ?? 'post']: {
103
- tags: openAPIConfig.tags,
104
- parameters: queryParametersSchema ? queryParameters : undefined,
105
- requestBody: bodySchema
106
- ? {
107
- required: true,
108
- content: {
109
- 'application/json': {
110
- schema: bodyComponent
176
+ const bodyComponent =
177
+ bodySchemas.length !== 0
178
+ ? createSchema(z.union(bodySchemas), {
179
+ openapiVersion: '3.1.1',
180
+ io: 'input'
181
+ })
182
+ : null;
183
+
184
+ const headersComponent =
185
+ headersSchemas.length !== 0
186
+ ? createSchema(z.union(headersSchemas), {
187
+ openapiVersion: '3.1.1',
188
+ io: 'input'
189
+ })
190
+ : null;
191
+
192
+ const queryParametersComponent =
193
+ queryParametersSchemas.length !== 0
194
+ ? createSchema(z.union(queryParametersSchemas), {
195
+ openapiVersion: '3.1.1',
196
+ io: 'input'
197
+ })
198
+ : null;
199
+
200
+ if (queryParametersComponent) {
201
+ explodeObject(queryParametersComponent.schema, parameters, 'query');
202
+ }
203
+
204
+ if (headersComponent) {
205
+ explodeObject(headersComponent.schema, parameters, 'header');
206
+ }
207
+
208
+ for (const method of LAMBDA_CONFIG?.api?.methods ?? ['POST']) {
209
+ existingOpenAPIFile.paths['/' + fileName] = {
210
+ [method.toLowerCase()]: {
211
+ tags: openAPIConfig.tags,
212
+ parameters: parameters,
213
+ requestBody: bodyComponent
214
+ ? {
215
+ content: {
216
+ 'application/json': {
217
+ schema: bodyComponent.schema
218
+ }
111
219
  }
112
220
  }
113
- }
114
- : undefined,
115
- responses: {
116
- '200': {
117
- description: `Successful response.`,
118
- content: {
119
- 'application/json': {
120
- schema: eventResponseComponent
121
- }
122
- }
123
- }
221
+ : undefined,
222
+ responses
124
223
  }
125
- }
126
- };
224
+ };
225
+ }
127
226
  }
128
227
 
129
228
  await fs.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
@@ -131,30 +230,60 @@ export const generateOpenAPI = async (): Promise<void> => {
131
230
  console.info('Open API documentation generated successfully');
132
231
  };
133
232
 
134
- function generateEventResponseComponent(
135
- responseType: OpenAPIConfig['responseType'] = 'mindbehind-chat-bot-response',
136
- eventResponseParametersSchema?: OpenApiZodAny,
137
- eventResponseModulesSchema?: OpenApiZodAny
233
+ function explodeObject(
234
+ schema: ZodOpenApiSchemaObject,
235
+ parameters: Parameter[],
236
+ type: 'header' | 'query',
237
+ isRequiredIncluded = true
138
238
  ) {
139
- if (responseType === 'mindbehind-chat-bot-response') {
140
- return generateSchema(
141
- z.object({
142
- ...(eventResponseParametersSchema
143
- ? { params: eventResponseParametersSchema }
144
- : { params: z.object({}) }),
145
- ...(eventResponseModulesSchema
146
- ? { modules: eventResponseModulesSchema }
147
- : {
148
- modules: extendApi(z.array(z.unknown()), {
149
- example: []
150
- })
151
- }),
152
- fallback: z.boolean().default(false)
153
- }),
154
- undefined,
155
- '3.0'
156
- );
239
+ if (!('type' in schema) || schema.type !== 'object') {
240
+ parameters.push({
241
+ name: '-',
242
+ in: type,
243
+ schema: schema,
244
+ required: true
245
+ } as const);
246
+
247
+ return;
157
248
  }
158
249
 
159
- return generateSchema(eventResponseParametersSchema ?? z.object({}), undefined, '3.0');
250
+ for (const element in schema.properties) {
251
+ parameters.push({
252
+ name: element,
253
+ in: type,
254
+ schema: schema.properties[element],
255
+ required: isRequiredIncluded ? schema.required?.includes(element) ?? false : false
256
+ } as const);
257
+ }
160
258
  }
259
+
260
+ type Parameter = {
261
+ name: string;
262
+ in: 'query' | 'header';
263
+ schema: unknown;
264
+ required: boolean;
265
+ };
266
+
267
+ type RequestSchema = Record<
268
+ string,
269
+ {
270
+ body: z.ZodType;
271
+ queryParameters: z.ZodObject | z.ZodNever;
272
+ headers: z.ZodObject | z.ZodNever;
273
+ }
274
+ >;
275
+
276
+ type ResponseSchema = Record<
277
+ string,
278
+ | {
279
+ type: 'mindbehind';
280
+ status: keyof typeof HttpStatusCode;
281
+ parameters: z.ZodType;
282
+ modules: z.ZodArray;
283
+ }
284
+ | {
285
+ type: 'api';
286
+ status: keyof typeof HttpStatusCode;
287
+ parameters: z.ZodType;
288
+ }
289
+ >;
@@ -1,11 +1,4 @@
1
1
  export type OpenAPIConfig = {
2
2
  tags: string[];
3
3
  isDocumentationNeeded?: boolean;
4
- responseType?: 'mindbehind-chat-bot-response' | 'api-response';
5
- };
6
-
7
- export type LambdaConfig = {
8
- api?: {
9
- method?: 'GET' | 'POST';
10
- };
11
4
  };
@@ -1,7 +1,7 @@
1
- import { generateSchema } from '@anatine/zod-openapi';
1
+ import { createSchema } from 'zod-openapi';
2
2
 
3
3
  export type OpenAPI = {
4
- openapi: '3.0.0';
4
+ openapi: '3.1.1';
5
5
  info: { title: string; version: string };
6
6
  servers: [{ url: string }, { url: string }, { url: string }];
7
7
  paths: Record<
@@ -14,7 +14,7 @@ export type OpenAPI = {
14
14
  | {
15
15
  name: string;
16
16
  in: 'query';
17
- schema: ReturnType<typeof generateSchema>;
17
+ schema: ReturnType<typeof createSchema>['schema'];
18
18
  }[]
19
19
  | undefined;
20
20
  requestBody:
@@ -22,23 +22,23 @@ export type OpenAPI = {
22
22
  required: true;
23
23
  content: {
24
24
  'application/json': {
25
- schema: ReturnType<typeof generateSchema>;
25
+ schema: ReturnType<typeof createSchema>['schema'];
26
26
  };
27
27
  };
28
28
  }
29
29
  | undefined;
30
- responses: {
31
- 200: {
32
- description: string;
30
+ responses: Record<
31
+ number,
32
+ {
33
33
  content:
34
34
  | {
35
35
  'application/json': {
36
- schema: ReturnType<typeof generateSchema>;
36
+ schema: ReturnType<typeof createSchema>['schema'];
37
37
  };
38
38
  }
39
39
  | undefined;
40
- };
41
- };
40
+ }
41
+ >;
42
42
  tags: string[];
43
43
  }
44
44
  >