vls-openapi-generator 1.3.4 → 1.5.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/generate-openapi.js +4 -2
- package/dist/index.js +4 -15
- package/dist/lambda-type.d.ts +9 -0
- package/dist/openapi-type.d.ts +20 -22
- package/dist/postman-service.d.ts +41 -4
- package/dist/postman-service.js +46 -7
- package/dist/upload-openapi.js +63 -5
- package/package.json +4 -2
- package/src/generate-openapi.ts +9 -4
- package/src/index.ts +4 -16
- package/src/lambda-type.ts +10 -0
- package/src/openapi-type.ts +33 -30
- package/src/postman-service.ts +75 -8
- package/src/upload-openapi.ts +91 -5
package/dist/generate-openapi.js
CHANGED
|
@@ -46,13 +46,13 @@ const HANDLERS_DIR = path.join(process.cwd(), 'dist', 'src', 'handlers');
|
|
|
46
46
|
const SCHEMAS_DIR = path.join(process.cwd(), 'dist', 'src', 'schemas');
|
|
47
47
|
const OUTPUT_FILE = path.join(process.cwd(), 'openapi.json');
|
|
48
48
|
const generateOpenAPI = async () => {
|
|
49
|
+
console.info('Generating Open API documentation...');
|
|
49
50
|
const args = process.argv;
|
|
50
51
|
const params = {};
|
|
51
52
|
for (let i = 2; i < args.length; i += 2) {
|
|
52
53
|
const key = args[i].replace('--', '');
|
|
53
54
|
params[key] = args[i + 1];
|
|
54
55
|
}
|
|
55
|
-
console.info('Generating Open API documentation...');
|
|
56
56
|
await (0, util_1.promisify)(child_process_1.exec)('rm -rf ./dist');
|
|
57
57
|
await (0, util_1.promisify)(child_process_1.exec)('npx tsc');
|
|
58
58
|
const handlerFiles = await fs_1.promises.readdir(HANDLERS_DIR);
|
|
@@ -61,6 +61,7 @@ const generateOpenAPI = async () => {
|
|
|
61
61
|
for (const handler of handlerFiles) {
|
|
62
62
|
const fileName = path.parse(handler).name;
|
|
63
63
|
const { bodySchema, queryParametersSchema, eventResponseParametersSchema, eventResponseModulesSchema, OPENAPI_CONFIG: openAPIConfig } = (await Promise.resolve(`${path.join(SCHEMAS_DIR, fileName + '.js')}`).then(s => __importStar(require(s))).catch(() => ({})));
|
|
64
|
+
const { LAMBDA_CONFIG } = (await Promise.resolve(`${path.join(HANDLERS_DIR, `${fileName}.js`)}`).then(s => __importStar(require(s))));
|
|
64
65
|
const bodyComponent = (0, zod_openapi_1.generateSchema)(bodySchema ?? zod_1.z.never(), undefined, '3.0');
|
|
65
66
|
const queryParametersComponent = (0, zod_openapi_1.generateSchema)(queryParametersSchema ?? zod_1.z.never(), undefined, '3.0');
|
|
66
67
|
const eventResponseComponent = (0, zod_openapi_1.generateSchema)(zod_1.z.object({
|
|
@@ -91,7 +92,7 @@ const generateOpenAPI = async () => {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
existingOpenAPIFile.paths['/' + fileName] = {
|
|
94
|
-
post: {
|
|
95
|
+
[LAMBDA_CONFIG?.method?.toLowerCase() ?? 'post']: {
|
|
95
96
|
tags: openAPIConfig.tags,
|
|
96
97
|
parameters: queryParametersSchema ? queryParameters : undefined,
|
|
97
98
|
requestBody: bodySchema
|
|
@@ -118,5 +119,6 @@ const generateOpenAPI = async () => {
|
|
|
118
119
|
};
|
|
119
120
|
}
|
|
120
121
|
await fs_1.promises.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
|
|
122
|
+
console.info('Open API documentation generated successfully');
|
|
121
123
|
};
|
|
122
124
|
exports.generateOpenAPI = generateOpenAPI;
|
package/dist/index.js
CHANGED
|
@@ -16,28 +16,17 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const generate_openapi_1 = require("./generate-openapi");
|
|
19
|
-
|
|
19
|
+
const upload_openapi_js_1 = require("./upload-openapi.js");
|
|
20
20
|
__exportStar(require("./lambda-type"), exports);
|
|
21
21
|
(async () => {
|
|
22
22
|
try {
|
|
23
23
|
await (0, generate_openapi_1.generateOpenAPI)();
|
|
24
|
-
|
|
24
|
+
if (process.argv.includes('--upload')) {
|
|
25
|
+
await (0, upload_openapi_js_1.uploadOpenAPI)();
|
|
26
|
+
}
|
|
25
27
|
}
|
|
26
28
|
catch (error) {
|
|
27
29
|
console.error(error);
|
|
28
30
|
process.exit(1);
|
|
29
31
|
}
|
|
30
|
-
// if (process.argv.includes('--upload')) {
|
|
31
|
-
// console.info('Uploading Open API documentation to Postman...');
|
|
32
|
-
//
|
|
33
|
-
// try {
|
|
34
|
-
// await uploadOpenAPI();
|
|
35
|
-
//
|
|
36
|
-
// console.info('Open API documentation uploaded successfully');
|
|
37
|
-
// } catch (error) {
|
|
38
|
-
// console.error(error);
|
|
39
|
-
//
|
|
40
|
-
// process.exit(1);
|
|
41
|
-
// }
|
|
42
|
-
// }
|
|
43
32
|
})().catch(console.error);
|
package/dist/lambda-type.d.ts
CHANGED
package/dist/openapi-type.d.ts
CHANGED
|
@@ -12,32 +12,30 @@ export type OpenAPI = {
|
|
|
12
12
|
}, {
|
|
13
13
|
url: string;
|
|
14
14
|
}];
|
|
15
|
-
paths: Record<string, {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
paths: Record<string, Partial<Record<'get' | 'post', {
|
|
16
|
+
parameters: {
|
|
17
|
+
name: string;
|
|
18
|
+
in: 'query';
|
|
19
|
+
schema: ReturnType<typeof generateSchema>;
|
|
20
|
+
}[] | undefined;
|
|
21
|
+
requestBody: {
|
|
22
|
+
required: true;
|
|
23
|
+
content: {
|
|
24
|
+
'application/json': {
|
|
25
|
+
schema: ReturnType<typeof generateSchema>;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
} | undefined;
|
|
29
|
+
responses: {
|
|
30
|
+
200: {
|
|
31
|
+
description: string;
|
|
24
32
|
content: {
|
|
25
33
|
'application/json': {
|
|
26
34
|
schema: ReturnType<typeof generateSchema>;
|
|
27
35
|
};
|
|
28
|
-
};
|
|
29
|
-
} | undefined;
|
|
30
|
-
responses: {
|
|
31
|
-
200: {
|
|
32
|
-
description: string;
|
|
33
|
-
content: {
|
|
34
|
-
'application/json': {
|
|
35
|
-
schema: ReturnType<typeof generateSchema>;
|
|
36
|
-
};
|
|
37
|
-
} | undefined;
|
|
38
|
-
};
|
|
36
|
+
} | undefined;
|
|
39
37
|
};
|
|
40
|
-
tags: string[];
|
|
41
38
|
};
|
|
42
|
-
|
|
39
|
+
tags: string[];
|
|
40
|
+
}>>>;
|
|
43
41
|
};
|
|
@@ -1,13 +1,50 @@
|
|
|
1
|
-
import { OpenAPI } from './openapi-type';
|
|
2
1
|
export declare class PostmanService {
|
|
3
2
|
private client;
|
|
4
|
-
|
|
3
|
+
private workspaceID;
|
|
4
|
+
constructor(apiKey: string, workspaceID: string);
|
|
5
5
|
getCollections: () => Promise<{
|
|
6
6
|
collections: {
|
|
7
7
|
id: string;
|
|
8
8
|
name: string;
|
|
9
9
|
}[];
|
|
10
10
|
}>;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
getCollection: (id: string) => Promise<{
|
|
12
|
+
collection: {
|
|
13
|
+
info: {
|
|
14
|
+
_postman_id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
item: {
|
|
18
|
+
id: string;
|
|
19
|
+
name: "development" | "production";
|
|
20
|
+
item: object[];
|
|
21
|
+
}[];
|
|
22
|
+
variable: {
|
|
23
|
+
key: string;
|
|
24
|
+
value: string;
|
|
25
|
+
}[];
|
|
26
|
+
};
|
|
27
|
+
}>;
|
|
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>>;
|
|
32
|
+
updateVariablesCollection: (collectionID: string, variables: {
|
|
33
|
+
key: string;
|
|
34
|
+
value: string;
|
|
35
|
+
}[]) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
36
|
+
getAllEnvironments: () => Promise<{
|
|
37
|
+
environments: {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
}[];
|
|
41
|
+
}>;
|
|
42
|
+
createEnvironment: (name: string, values: {
|
|
43
|
+
key: string;
|
|
44
|
+
value: string;
|
|
45
|
+
}[]) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
46
|
+
updateEnvironment: (id: string, name: string, values: {
|
|
47
|
+
key: string;
|
|
48
|
+
value: string;
|
|
49
|
+
}[]) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
13
50
|
}
|
package/dist/postman-service.js
CHANGED
|
@@ -6,19 +6,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PostmanService = void 0;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
class PostmanService {
|
|
9
|
-
constructor(apiKey) {
|
|
9
|
+
constructor(apiKey, workspaceID) {
|
|
10
10
|
this.getCollections = async () => {
|
|
11
11
|
return (await this.client.get('/collections')).data;
|
|
12
12
|
};
|
|
13
|
-
this.
|
|
14
|
-
return await this.client.
|
|
13
|
+
this.getCollection = async (id) => {
|
|
14
|
+
return (await this.client.get(`/collections/${id}?workspace=${this.workspaceID}`)).data;
|
|
15
15
|
};
|
|
16
|
-
this.createCollection = async (
|
|
17
|
-
return await this.client.post(
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
this.createCollection = async (partnerName) => {
|
|
17
|
+
return (await this.client.post(`/collections?workspace=${this.workspaceID}`, {
|
|
18
|
+
collection: {
|
|
19
|
+
info: {
|
|
20
|
+
name: partnerName,
|
|
21
|
+
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
|
22
|
+
},
|
|
23
|
+
item: []
|
|
24
|
+
}
|
|
25
|
+
})).data.collection.id;
|
|
26
|
+
};
|
|
27
|
+
this.deleteFolder = async (collectionID, folderID) => {
|
|
28
|
+
return await this.client.delete(`/collections/${collectionID}/folders/${folderID}`);
|
|
29
|
+
};
|
|
30
|
+
this.createFolder = async (collectionID, folderName) => {
|
|
31
|
+
return await this.client.post(`/collections/${collectionID}/folders`, {
|
|
32
|
+
name: folderName
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
this.updateCollection = async (collectionID, collection) => {
|
|
36
|
+
return await this.client.put(`/collections/${collectionID}`, collection);
|
|
37
|
+
};
|
|
38
|
+
this.updateVariablesCollection = async (collectionID, variables) => {
|
|
39
|
+
return await this.client.patch(`/collections/${collectionID}`, { collection: { variable: variables } });
|
|
40
|
+
};
|
|
41
|
+
this.getAllEnvironments = async () => {
|
|
42
|
+
return (await this.client.get(`/environments?workspace=${this.workspaceID}`)).data;
|
|
43
|
+
};
|
|
44
|
+
this.createEnvironment = async (name, values) => {
|
|
45
|
+
return await this.client.post(`/environments?workspace=${this.workspaceID}`, {
|
|
46
|
+
environment: {
|
|
47
|
+
name,
|
|
48
|
+
values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
this.updateEnvironment = async (id, name, values) => {
|
|
53
|
+
return await this.client.put(`/environments/${id}?workspace=${this.workspaceID}`, {
|
|
54
|
+
environment: {
|
|
55
|
+
name,
|
|
56
|
+
values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
|
|
57
|
+
}
|
|
20
58
|
});
|
|
21
59
|
};
|
|
60
|
+
this.workspaceID = workspaceID;
|
|
22
61
|
this.client = axios_1.default.create({
|
|
23
62
|
baseURL: 'https://api.getpostman.com',
|
|
24
63
|
headers: {
|
package/dist/upload-openapi.js
CHANGED
|
@@ -36,15 +36,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.uploadOpenAPI = void 0;
|
|
37
37
|
const fs_1 = require("fs");
|
|
38
38
|
require("module-alias/register.js");
|
|
39
|
+
const openapi_to_postmanv2_1 = require("openapi-to-postmanv2");
|
|
39
40
|
const path = __importStar(require("path"));
|
|
41
|
+
const util_1 = require("util");
|
|
40
42
|
const postman_service_1 = require("./postman-service");
|
|
41
43
|
const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
|
|
42
44
|
const uploadOpenAPI = async () => {
|
|
45
|
+
console.info('Uploading Open API documentation to Postman...');
|
|
43
46
|
const args = process.argv;
|
|
44
47
|
const params = {};
|
|
45
48
|
for (let i = 2; i < args.length;) {
|
|
46
49
|
const key = args[i].replace('--', '');
|
|
47
50
|
params[key] = args[i + 1];
|
|
51
|
+
if (!params[key]) {
|
|
52
|
+
i++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
48
55
|
if (params[key].startsWith('--')) {
|
|
49
56
|
i++;
|
|
50
57
|
delete params[key];
|
|
@@ -61,12 +68,63 @@ const uploadOpenAPI = async () => {
|
|
|
61
68
|
if (!params['stack-name']) {
|
|
62
69
|
throw new Error('Stack name is missing.');
|
|
63
70
|
}
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
const splitStackName = stackName.split('-');
|
|
72
|
+
const environment = splitStackName.pop();
|
|
73
|
+
const partnerName = splitStackName.join('-');
|
|
74
|
+
if (environment !== 'development' && environment !== 'production') {
|
|
75
|
+
throw new Error('Stack name should end with development or production. Example: example-development');
|
|
76
|
+
}
|
|
77
|
+
const postmanService = new postman_service_1.PostmanService(postmanToken, '489fad1b-5992-4ffe-8427-1f82f3ca0661');
|
|
78
|
+
const { collections } = await postmanService.getCollections();
|
|
79
|
+
let collectionID = '';
|
|
80
|
+
const stackCollection = collections.find((x) => x.name === partnerName);
|
|
81
|
+
if (!stackCollection) {
|
|
82
|
+
collectionID = await postmanService.createCollection(partnerName);
|
|
68
83
|
}
|
|
84
|
+
else {
|
|
85
|
+
collectionID = stackCollection.id;
|
|
86
|
+
}
|
|
87
|
+
const { collection: { item } } = await postmanService.getCollection(collectionID);
|
|
88
|
+
const folder = item.find((x) => x.name === environment);
|
|
89
|
+
if (folder) {
|
|
90
|
+
await postmanService.deleteFolder(collectionID, folder.id);
|
|
91
|
+
}
|
|
92
|
+
await postmanService.createFolder(collectionID, environment);
|
|
93
|
+
const collection = await postmanService.getCollection(collectionID);
|
|
69
94
|
const existingOpenAPIFile = JSON.parse(await fs_1.promises.readFile(OPENAPI_FILE, 'utf-8'));
|
|
70
|
-
|
|
95
|
+
const convertPromise = (0, util_1.promisify)(openapi_to_postmanv2_1.convert);
|
|
96
|
+
const converted = await convertPromise({
|
|
97
|
+
data: JSON.stringify(existingOpenAPIFile),
|
|
98
|
+
type: 'json'
|
|
99
|
+
}, {
|
|
100
|
+
folderStrategy: 'Tags'
|
|
101
|
+
});
|
|
102
|
+
if (!converted.result) {
|
|
103
|
+
throw new Error('Failed to convert Open API to Postman collection');
|
|
104
|
+
}
|
|
105
|
+
const convertedData = converted.output[0].data;
|
|
106
|
+
for (const item of collection.collection.item) {
|
|
107
|
+
if (item.name === environment) {
|
|
108
|
+
item.item = convertedData.item ?? [];
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
await postmanService.updateCollection(collectionID, collection);
|
|
113
|
+
const baseUrl = existingOpenAPIFile.servers.find((x) => x.url.includes(environment))?.url;
|
|
114
|
+
if (!baseUrl) {
|
|
115
|
+
console.warn(`Base URL was not found with the given environment. Environment will not be updated. Given environment: ${environment}`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const environments = (await postmanService.getAllEnvironments()).environments;
|
|
119
|
+
const stackEnvironment = environments.find((x) => x.name === stackName);
|
|
120
|
+
if (!stackEnvironment) {
|
|
121
|
+
await postmanService.createEnvironment(stackName, [{ key: 'baseUrl', value: baseUrl }]);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
await postmanService.updateEnvironment(stackEnvironment.id, stackEnvironment.name, [
|
|
125
|
+
{ key: 'baseUrl', value: baseUrl }
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
console.info('Open API documentation uploaded successfully');
|
|
71
129
|
};
|
|
72
130
|
exports.uploadOpenAPI = uploadOpenAPI;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vls-openapi-generator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@anatine/zod-openapi": "^2.2.7",
|
|
19
19
|
"axios": "^1.7.9",
|
|
20
|
-
"module-alias": "^2.2.3"
|
|
20
|
+
"module-alias": "^2.2.3",
|
|
21
|
+
"openapi-to-postmanv2": "^4.25.0"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@commitlint/config-conventional": "^19.5.0",
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
"@semantic-release/git": "^10.0.1",
|
|
26
27
|
"@semantic-release/npm": "^12.0.1",
|
|
27
28
|
"@types/node": "^20.14.8",
|
|
29
|
+
"@types/openapi-to-postmanv2": "^3.2.4",
|
|
28
30
|
"commitlint": "^19.5.0",
|
|
29
31
|
"eslint": "^9.12.0",
|
|
30
32
|
"husky": "^9.1.6",
|
package/src/generate-openapi.ts
CHANGED
|
@@ -5,7 +5,7 @@ import 'module-alias/register.js';
|
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import { OpenAPIConfig } from './lambda-type';
|
|
8
|
+
import { LambdaConfig, OpenAPIConfig } from './lambda-type';
|
|
9
9
|
import { OpenAPI } from './openapi-type';
|
|
10
10
|
|
|
11
11
|
const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
|
|
@@ -14,6 +14,8 @@ const SCHEMAS_DIR = path.join(process.cwd(), 'dist', 'src', 'schemas');
|
|
|
14
14
|
const OUTPUT_FILE = path.join(process.cwd(), 'openapi.json');
|
|
15
15
|
|
|
16
16
|
export const generateOpenAPI = async (): Promise<void> => {
|
|
17
|
+
console.info('Generating Open API documentation...');
|
|
18
|
+
|
|
17
19
|
const args = process.argv;
|
|
18
20
|
const params: Record<string, string> = {};
|
|
19
21
|
|
|
@@ -22,8 +24,6 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
22
24
|
params[key] = args[i + 1];
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
console.info('Generating Open API documentation...');
|
|
26
|
-
|
|
27
27
|
await promisify(exec)('rm -rf ./dist');
|
|
28
28
|
await promisify(exec)('npx tsc');
|
|
29
29
|
|
|
@@ -49,6 +49,10 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
49
49
|
OPENAPI_CONFIG: OpenAPIConfig;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
const { LAMBDA_CONFIG } = (await import(path.join(HANDLERS_DIR, `${fileName}.js`))) as {
|
|
53
|
+
LAMBDA_CONFIG?: LambdaConfig;
|
|
54
|
+
};
|
|
55
|
+
|
|
52
56
|
const bodyComponent = generateSchema(bodySchema ?? z.never(), undefined, '3.0');
|
|
53
57
|
const queryParametersComponent = generateSchema(queryParametersSchema ?? z.never(), undefined, '3.0');
|
|
54
58
|
const eventResponseComponent = generateSchema(
|
|
@@ -88,7 +92,7 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
existingOpenAPIFile.paths['/' + fileName] = {
|
|
91
|
-
post: {
|
|
95
|
+
[LAMBDA_CONFIG?.method?.toLowerCase() ?? 'post']: {
|
|
92
96
|
tags: openAPIConfig.tags,
|
|
93
97
|
parameters: queryParametersSchema ? queryParameters : undefined,
|
|
94
98
|
requestBody: bodySchema
|
|
@@ -116,4 +120,5 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
await fs.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
|
|
123
|
+
console.info('Open API documentation generated successfully');
|
|
119
124
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { generateOpenAPI } from './generate-openapi';
|
|
4
|
-
|
|
4
|
+
import { uploadOpenAPI } from './upload-openapi.js';
|
|
5
5
|
|
|
6
6
|
export * from './lambda-type';
|
|
7
7
|
|
|
@@ -9,24 +9,12 @@ export * from './lambda-type';
|
|
|
9
9
|
try {
|
|
10
10
|
await generateOpenAPI();
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
if (process.argv.includes('--upload')) {
|
|
13
|
+
await uploadOpenAPI();
|
|
14
|
+
}
|
|
13
15
|
} catch (error) {
|
|
14
16
|
console.error(error);
|
|
15
17
|
|
|
16
18
|
process.exit(1);
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
// if (process.argv.includes('--upload')) {
|
|
20
|
-
// console.info('Uploading Open API documentation to Postman...');
|
|
21
|
-
//
|
|
22
|
-
// try {
|
|
23
|
-
// await uploadOpenAPI();
|
|
24
|
-
//
|
|
25
|
-
// console.info('Open API documentation uploaded successfully');
|
|
26
|
-
// } catch (error) {
|
|
27
|
-
// console.error(error);
|
|
28
|
-
//
|
|
29
|
-
// process.exit(1);
|
|
30
|
-
// }
|
|
31
|
-
// }
|
|
32
20
|
})().catch(console.error);
|
package/src/lambda-type.ts
CHANGED
package/src/openapi-type.ts
CHANGED
|
@@ -6,39 +6,42 @@ export type OpenAPI = {
|
|
|
6
6
|
servers: [{ url: string }, { url: string }, { url: string }];
|
|
7
7
|
paths: Record<
|
|
8
8
|
string,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
| undefined;
|
|
28
|
-
responses: {
|
|
29
|
-
200: {
|
|
30
|
-
description: string;
|
|
31
|
-
content:
|
|
32
|
-
| {
|
|
9
|
+
Partial<
|
|
10
|
+
Record<
|
|
11
|
+
'get' | 'post',
|
|
12
|
+
{
|
|
13
|
+
parameters:
|
|
14
|
+
| {
|
|
15
|
+
name: string;
|
|
16
|
+
in: 'query';
|
|
17
|
+
schema: ReturnType<typeof generateSchema>;
|
|
18
|
+
}[]
|
|
19
|
+
| undefined;
|
|
20
|
+
requestBody:
|
|
21
|
+
| {
|
|
22
|
+
required: true;
|
|
23
|
+
content: {
|
|
33
24
|
'application/json': {
|
|
34
25
|
schema: ReturnType<typeof generateSchema>;
|
|
35
26
|
};
|
|
36
|
-
}
|
|
37
|
-
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
| undefined;
|
|
30
|
+
responses: {
|
|
31
|
+
200: {
|
|
32
|
+
description: string;
|
|
33
|
+
content:
|
|
34
|
+
| {
|
|
35
|
+
'application/json': {
|
|
36
|
+
schema: ReturnType<typeof generateSchema>;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
| undefined;
|
|
40
|
+
};
|
|
38
41
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
tags: string[];
|
|
43
|
+
}
|
|
44
|
+
>
|
|
45
|
+
>
|
|
43
46
|
>;
|
|
44
47
|
};
|
package/src/postman-service.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import axios, { Axios } from 'axios';
|
|
2
|
-
import { OpenAPI } from './openapi-type';
|
|
3
2
|
|
|
4
3
|
export class PostmanService {
|
|
5
4
|
private client: Axios;
|
|
5
|
+
private workspaceID: string;
|
|
6
6
|
|
|
7
|
-
constructor(apiKey: string) {
|
|
7
|
+
constructor(apiKey: string, workspaceID: string) {
|
|
8
|
+
this.workspaceID = workspaceID;
|
|
8
9
|
this.client = axios.create({
|
|
9
10
|
baseURL: 'https://api.getpostman.com',
|
|
10
11
|
headers: {
|
|
@@ -25,14 +26,80 @@ export class PostmanService {
|
|
|
25
26
|
).data;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
public
|
|
29
|
-
return
|
|
29
|
+
public getCollection = async (id: string) => {
|
|
30
|
+
return (
|
|
31
|
+
await this.client.get<{
|
|
32
|
+
collection: {
|
|
33
|
+
info: {
|
|
34
|
+
_postman_id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
item: { id: string; name: 'development' | 'production'; item: object[] }[];
|
|
38
|
+
variable: { key: string; value: string }[];
|
|
39
|
+
};
|
|
40
|
+
}>(`/collections/${id}?workspace=${this.workspaceID}`)
|
|
41
|
+
).data;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
public createCollection = async (partnerName: string) => {
|
|
45
|
+
return (
|
|
46
|
+
await this.client.post<{
|
|
47
|
+
collection: {
|
|
48
|
+
id: string;
|
|
49
|
+
};
|
|
50
|
+
}>(`/collections?workspace=${this.workspaceID}`, {
|
|
51
|
+
collection: {
|
|
52
|
+
info: {
|
|
53
|
+
name: partnerName,
|
|
54
|
+
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
|
55
|
+
},
|
|
56
|
+
item: []
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
).data.collection.id;
|
|
30
60
|
};
|
|
31
61
|
|
|
32
|
-
public
|
|
33
|
-
return await this.client.
|
|
34
|
-
|
|
35
|
-
|
|
62
|
+
public deleteFolder = async (collectionID: string, folderID: string) => {
|
|
63
|
+
return await this.client.delete(`/collections/${collectionID}/folders/${folderID}`);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
public createFolder = async (collectionID: string, folderName: string) => {
|
|
67
|
+
return await this.client.post(`/collections/${collectionID}/folders`, {
|
|
68
|
+
name: folderName
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
public updateCollection = async (collectionID: string, collection: object) => {
|
|
73
|
+
return await this.client.put(`/collections/${collectionID}`, collection);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
public updateVariablesCollection = async (collectionID: string, variables: { key: string; value: string }[]) => {
|
|
77
|
+
return await this.client.patch(`/collections/${collectionID}`, { collection: { variable: variables } });
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
public getAllEnvironments = async () => {
|
|
81
|
+
return (
|
|
82
|
+
await this.client.get<{ environments: { id: string; name: string }[] }>(
|
|
83
|
+
`/environments?workspace=${this.workspaceID}`
|
|
84
|
+
)
|
|
85
|
+
).data;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
public createEnvironment = async (name: string, values: { key: string; value: string }[]) => {
|
|
89
|
+
return await this.client.post(`/environments?workspace=${this.workspaceID}`, {
|
|
90
|
+
environment: {
|
|
91
|
+
name,
|
|
92
|
+
values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
public updateEnvironment = async (id: string, name: string, values: { key: string; value: string }[]) => {
|
|
98
|
+
return await this.client.put(`/environments/${id}?workspace=${this.workspaceID}`, {
|
|
99
|
+
environment: {
|
|
100
|
+
name,
|
|
101
|
+
values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
|
|
102
|
+
}
|
|
36
103
|
});
|
|
37
104
|
};
|
|
38
105
|
}
|
package/src/upload-openapi.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import 'module-alias/register.js';
|
|
3
|
+
import { convert } from 'openapi-to-postmanv2';
|
|
3
4
|
import * as path from 'path';
|
|
5
|
+
import { promisify } from 'util';
|
|
4
6
|
import { OpenAPI } from './openapi-type';
|
|
5
7
|
import { PostmanService } from './postman-service';
|
|
6
8
|
|
|
7
9
|
const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
|
|
8
10
|
|
|
9
11
|
export const uploadOpenAPI = async (): Promise<void> => {
|
|
12
|
+
console.info('Uploading Open API documentation to Postman...');
|
|
13
|
+
|
|
10
14
|
const args = process.argv;
|
|
11
15
|
const params: Record<string, string> = {};
|
|
12
16
|
|
|
@@ -14,6 +18,11 @@ export const uploadOpenAPI = async (): Promise<void> => {
|
|
|
14
18
|
const key = args[i].replace('--', '');
|
|
15
19
|
params[key] = args[i + 1];
|
|
16
20
|
|
|
21
|
+
if (!params[key]) {
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
if (params[key].startsWith('--')) {
|
|
18
27
|
i++;
|
|
19
28
|
delete params[key];
|
|
@@ -33,15 +42,92 @@ export const uploadOpenAPI = async (): Promise<void> => {
|
|
|
33
42
|
throw new Error('Stack name is missing.');
|
|
34
43
|
}
|
|
35
44
|
|
|
36
|
-
const
|
|
45
|
+
const splitStackName = stackName.split('-');
|
|
46
|
+
const environment = splitStackName.pop();
|
|
47
|
+
const partnerName = splitStackName.join('-');
|
|
48
|
+
|
|
49
|
+
if (environment !== 'development' && environment !== 'production') {
|
|
50
|
+
throw new Error('Stack name should end with development or production. Example: example-development');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const postmanService = new PostmanService(postmanToken, '489fad1b-5992-4ffe-8427-1f82f3ca0661');
|
|
54
|
+
|
|
55
|
+
const { collections } = await postmanService.getCollections();
|
|
56
|
+
|
|
57
|
+
let collectionID = '';
|
|
37
58
|
|
|
38
|
-
const stackCollection =
|
|
59
|
+
const stackCollection = collections.find((x) => x.name === partnerName);
|
|
39
60
|
|
|
40
|
-
if (stackCollection) {
|
|
41
|
-
await postmanService.
|
|
61
|
+
if (!stackCollection) {
|
|
62
|
+
collectionID = await postmanService.createCollection(partnerName);
|
|
63
|
+
} else {
|
|
64
|
+
collectionID = stackCollection.id;
|
|
42
65
|
}
|
|
43
66
|
|
|
67
|
+
const {
|
|
68
|
+
collection: { item }
|
|
69
|
+
} = await postmanService.getCollection(collectionID);
|
|
70
|
+
|
|
71
|
+
const folder = item.find((x) => x.name === environment);
|
|
72
|
+
|
|
73
|
+
if (folder) {
|
|
74
|
+
await postmanService.deleteFolder(collectionID, folder.id);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await postmanService.createFolder(collectionID, environment);
|
|
78
|
+
|
|
79
|
+
const collection = await postmanService.getCollection(collectionID);
|
|
80
|
+
|
|
44
81
|
const existingOpenAPIFile = JSON.parse(await fs.readFile(OPENAPI_FILE, 'utf-8')) as OpenAPI;
|
|
45
82
|
|
|
46
|
-
|
|
83
|
+
const convertPromise = promisify(convert);
|
|
84
|
+
|
|
85
|
+
const converted = await convertPromise(
|
|
86
|
+
{
|
|
87
|
+
data: JSON.stringify(existingOpenAPIFile),
|
|
88
|
+
type: 'json'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
folderStrategy: 'Tags'
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (!converted.result) {
|
|
96
|
+
throw new Error('Failed to convert Open API to Postman collection');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const convertedData = converted.output[0].data;
|
|
100
|
+
|
|
101
|
+
for (const item of collection.collection.item) {
|
|
102
|
+
if (item.name === environment) {
|
|
103
|
+
item.item = convertedData.item ?? [];
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await postmanService.updateCollection(collectionID, collection);
|
|
109
|
+
|
|
110
|
+
const baseUrl = existingOpenAPIFile.servers.find((x) => x.url.includes(environment))?.url;
|
|
111
|
+
|
|
112
|
+
if (!baseUrl) {
|
|
113
|
+
console.warn(
|
|
114
|
+
`Base URL was not found with the given environment. Environment will not be updated. Given environment: ${environment}`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const environments = (await postmanService.getAllEnvironments()).environments;
|
|
121
|
+
|
|
122
|
+
const stackEnvironment = environments.find((x) => x.name === stackName);
|
|
123
|
+
|
|
124
|
+
if (!stackEnvironment) {
|
|
125
|
+
await postmanService.createEnvironment(stackName, [{ key: 'baseUrl', value: baseUrl }]);
|
|
126
|
+
} else {
|
|
127
|
+
await postmanService.updateEnvironment(stackEnvironment.id, stackEnvironment.name, [
|
|
128
|
+
{ key: 'baseUrl', value: baseUrl }
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.info('Open API documentation uploaded successfully');
|
|
47
133
|
};
|