openapi-jsonrpc-jsdoc 1.4.2 → 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/README.md +52 -96
- package/index.mjs +85 -52
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -17,15 +17,19 @@ npm i openapi-jsonrpc-jsdoc
|
|
|
17
17
|
* @description Название API
|
|
18
18
|
* @param {object} parameters - params
|
|
19
19
|
* @param {string} parameters.id - id
|
|
20
|
+
* @param {string} [parameters.test] - test
|
|
21
|
+
* @param {string[]} parameters.array - array
|
|
22
|
+
* @param {1|2} parameters.num - enum
|
|
23
|
+
* @tags api
|
|
20
24
|
* @example
|
|
21
25
|
* {
|
|
22
|
-
* "
|
|
23
|
-
* "type": "Note"
|
|
26
|
+
* "id": "https://www.w3.org/ns/activitystreams"
|
|
24
27
|
* }
|
|
25
28
|
*/
|
|
26
29
|
module.exports = (parameters) => {
|
|
27
|
-
|
|
28
|
-
}
|
|
30
|
+
return parameters.id;
|
|
31
|
+
};
|
|
32
|
+
|
|
29
33
|
```
|
|
30
34
|
|
|
31
35
|
### Generate OpenAPI JSON
|
|
@@ -39,6 +43,9 @@ openapiJSONRpcJSDoc({
|
|
|
39
43
|
url: '0.0.0.0:8080',
|
|
40
44
|
},
|
|
41
45
|
],
|
|
46
|
+
info: {
|
|
47
|
+
title: 'Test API',
|
|
48
|
+
},
|
|
42
49
|
packageUrl: './package.json',
|
|
43
50
|
files: './api/*.js',
|
|
44
51
|
}).then(data => {
|
|
@@ -51,22 +58,16 @@ openapiJSONRpcJSDoc({
|
|
|
51
58
|
|
|
52
59
|
```json
|
|
53
60
|
{
|
|
54
|
-
"
|
|
55
|
-
"openapi": "3.0.0",
|
|
56
|
-
"x-api-id": "json-rpc-example",
|
|
57
|
-
"x-headers": [],
|
|
58
|
-
"x-explorer-enabled": true,
|
|
59
|
-
"x-proxy-enabled": true,
|
|
61
|
+
"openapi": "3.1.0",
|
|
60
62
|
"x-samples-enabled": true,
|
|
61
63
|
"x-samples-languages": [
|
|
62
|
-
"curl",
|
|
63
64
|
"node",
|
|
64
65
|
"javascript"
|
|
65
66
|
],
|
|
66
67
|
"info": {
|
|
67
|
-
"version": "1.
|
|
68
|
-
"title": "
|
|
69
|
-
"description": "OpenAPI
|
|
68
|
+
"version": "1.4.3",
|
|
69
|
+
"title": "Test API",
|
|
70
|
+
"description": "Transform JSDoc-annotated JSON-RPC 2.0 methods into OpenAPI specifications."
|
|
70
71
|
},
|
|
71
72
|
"servers": [
|
|
72
73
|
{
|
|
@@ -81,7 +82,7 @@ openapiJSONRpcJSDoc({
|
|
|
81
82
|
"summary": "/v1",
|
|
82
83
|
"description": "Название API",
|
|
83
84
|
"tags": [
|
|
84
|
-
"
|
|
85
|
+
"api"
|
|
85
86
|
],
|
|
86
87
|
"parameters": [],
|
|
87
88
|
"responses": {
|
|
@@ -107,32 +108,31 @@ openapiJSONRpcJSDoc({
|
|
|
107
108
|
}
|
|
108
109
|
},
|
|
109
110
|
"requestBody": {
|
|
111
|
+
"required": true,
|
|
110
112
|
"content": {
|
|
111
113
|
"application/json": {
|
|
112
114
|
"schema": {
|
|
113
115
|
"type": "object",
|
|
114
116
|
"required": [
|
|
115
117
|
"method",
|
|
116
|
-
"
|
|
117
|
-
"jsonrpc",
|
|
118
|
-
"params"
|
|
118
|
+
"jsonrpc"
|
|
119
119
|
],
|
|
120
120
|
"properties": {
|
|
121
121
|
"method": {
|
|
122
122
|
"type": "string",
|
|
123
|
-
"default": "v1",
|
|
124
123
|
"description": "API method v1"
|
|
125
124
|
},
|
|
126
125
|
"id": {
|
|
127
|
-
"type":
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
"type": [
|
|
127
|
+
"string",
|
|
128
|
+
"integer"
|
|
129
|
+
],
|
|
130
130
|
"description": "Request ID"
|
|
131
131
|
},
|
|
132
132
|
"jsonrpc": {
|
|
133
133
|
"type": "string",
|
|
134
134
|
"default": "2.0",
|
|
135
|
-
"description": "JSON-RPC
|
|
135
|
+
"description": "JSON-RPC 2.0 protocol"
|
|
136
136
|
},
|
|
137
137
|
"params": {
|
|
138
138
|
"title": "Parameters",
|
|
@@ -142,15 +142,33 @@ openapiJSONRpcJSDoc({
|
|
|
142
142
|
"type": "Note"
|
|
143
143
|
},
|
|
144
144
|
"required": [
|
|
145
|
-
"method",
|
|
146
145
|
"id",
|
|
147
|
-
"
|
|
148
|
-
"
|
|
146
|
+
"array",
|
|
147
|
+
"num"
|
|
149
148
|
],
|
|
150
149
|
"properties": {
|
|
151
150
|
"id": {
|
|
152
151
|
"type": "string",
|
|
153
152
|
"description": "id"
|
|
153
|
+
},
|
|
154
|
+
"test": {
|
|
155
|
+
"type": "string",
|
|
156
|
+
"description": "test"
|
|
157
|
+
},
|
|
158
|
+
"array": {
|
|
159
|
+
"type": "array",
|
|
160
|
+
"description": "array",
|
|
161
|
+
"items": {
|
|
162
|
+
"type": "string"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"num": {
|
|
166
|
+
"enum": [
|
|
167
|
+
1,
|
|
168
|
+
2
|
|
169
|
+
],
|
|
170
|
+
"type": "integer",
|
|
171
|
+
"description": "enum"
|
|
154
172
|
}
|
|
155
173
|
}
|
|
156
174
|
}
|
|
@@ -160,83 +178,18 @@ openapiJSONRpcJSDoc({
|
|
|
160
178
|
}
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
|
-
},
|
|
164
|
-
"/api/v2": {
|
|
165
|
-
"post": {
|
|
166
|
-
"operationId": "v2.js",
|
|
167
|
-
"deprecated": true,
|
|
168
|
-
"summary": "/v2",
|
|
169
|
-
"description": "Название API 2",
|
|
170
|
-
"tags": [
|
|
171
|
-
"JSONRPC"
|
|
172
|
-
],
|
|
173
|
-
"parameters": [],
|
|
174
|
-
"responses": {
|
|
175
|
-
"200": {
|
|
176
|
-
"description": "OK",
|
|
177
|
-
"content": {
|
|
178
|
-
"application/json": {
|
|
179
|
-
"schema": {
|
|
180
|
-
"type": "object"
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
"default": {
|
|
186
|
-
"description": "unexpected error",
|
|
187
|
-
"content": {
|
|
188
|
-
"application/json": {
|
|
189
|
-
"schema": {
|
|
190
|
-
"$ref": "#/components/schemas/Error"
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
|
-
"requestBody": {
|
|
197
|
-
"content": {
|
|
198
|
-
"application/json": {
|
|
199
|
-
"schema": {
|
|
200
|
-
"type": "object",
|
|
201
|
-
"required": [
|
|
202
|
-
"method",
|
|
203
|
-
"id",
|
|
204
|
-
"jsonrpc"
|
|
205
|
-
],
|
|
206
|
-
"properties": {
|
|
207
|
-
"method": {
|
|
208
|
-
"type": "string",
|
|
209
|
-
"default": "v2",
|
|
210
|
-
"description": "API method v2"
|
|
211
|
-
},
|
|
212
|
-
"id": {
|
|
213
|
-
"type": "integer",
|
|
214
|
-
"default": 1,
|
|
215
|
-
"format": "int32",
|
|
216
|
-
"description": "Request ID"
|
|
217
|
-
},
|
|
218
|
-
"jsonrpc": {
|
|
219
|
-
"type": "string",
|
|
220
|
-
"default": "2.0",
|
|
221
|
-
"description": "JSON-RPC Version (2.0)"
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
181
|
}
|
|
230
182
|
},
|
|
231
183
|
"components": {
|
|
232
184
|
"securitySchemes": {
|
|
233
185
|
"BasicAuth": {
|
|
234
186
|
"type": "http",
|
|
235
|
-
"scheme": "
|
|
187
|
+
"scheme": "basic"
|
|
236
188
|
}
|
|
237
189
|
},
|
|
238
190
|
"schemas": {
|
|
239
191
|
"Error": {
|
|
192
|
+
"type": "object",
|
|
240
193
|
"required": [
|
|
241
194
|
"error",
|
|
242
195
|
"id",
|
|
@@ -244,14 +197,17 @@ openapiJSONRpcJSDoc({
|
|
|
244
197
|
],
|
|
245
198
|
"properties": {
|
|
246
199
|
"id": {
|
|
247
|
-
"type":
|
|
248
|
-
|
|
200
|
+
"type": [
|
|
201
|
+
"string",
|
|
202
|
+
"integer"
|
|
203
|
+
]
|
|
249
204
|
},
|
|
250
205
|
"error": {
|
|
251
206
|
"type": "object"
|
|
252
207
|
},
|
|
253
208
|
"jsonrpc": {
|
|
254
|
-
"type": "string"
|
|
209
|
+
"type": "string",
|
|
210
|
+
"default": "2.0"
|
|
255
211
|
}
|
|
256
212
|
}
|
|
257
213
|
}
|
package/index.mjs
CHANGED
|
@@ -8,24 +8,36 @@ function extractName(name) {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function extractTypeName(names = []) {
|
|
12
|
+
let typeName;
|
|
13
|
+
if (names.length === 0) {
|
|
14
|
+
typeName = 'null';
|
|
15
|
+
} else if (names.length === 1) {
|
|
16
|
+
[typeName] = names;
|
|
17
|
+
} else {
|
|
18
|
+
typeName = 'enum';
|
|
19
|
+
}
|
|
20
|
+
return typeName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isBigInt64(n) {
|
|
24
|
+
try {
|
|
25
|
+
const b = BigInt(n);
|
|
26
|
+
return b >= -9223372036854775808n && b <= 9223372036854775807n;
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
11
32
|
function resolveSchemaFromTypeNames(names) {
|
|
12
33
|
let type;
|
|
13
34
|
let format;
|
|
14
35
|
let items;
|
|
15
|
-
let oneOf;
|
|
16
36
|
let nullable;
|
|
17
37
|
let constant;
|
|
18
38
|
let enumData;
|
|
19
39
|
|
|
20
|
-
|
|
21
|
-
type = 'null';
|
|
22
|
-
} else if (names.length === 1) {
|
|
23
|
-
[type] = names;
|
|
24
|
-
} else {
|
|
25
|
-
type = 'enum';
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
switch (type) {
|
|
40
|
+
switch (extractTypeName(names)) {
|
|
29
41
|
case 'Array.<string>': {
|
|
30
42
|
type = 'array';
|
|
31
43
|
items = {type: 'string'};
|
|
@@ -67,23 +79,32 @@ function resolveSchemaFromTypeNames(names) {
|
|
|
67
79
|
nullable = true;
|
|
68
80
|
enumData = enumData.filter(n => n !== 'null');
|
|
69
81
|
}
|
|
70
|
-
|
|
82
|
+
enumData = enumData.map((n) => {
|
|
71
83
|
if (!Number.isNaN(Number(n))) {
|
|
72
84
|
return Number(n);
|
|
85
|
+
} else if (isBigInt64(n)) {
|
|
86
|
+
return n;
|
|
73
87
|
}
|
|
74
|
-
return n;
|
|
88
|
+
return String(n);
|
|
75
89
|
});
|
|
76
90
|
|
|
77
|
-
if (enumData.every(n => Number.
|
|
91
|
+
if (enumData.every(n => Number.isSafeInteger(n))) {
|
|
78
92
|
type = 'integer';
|
|
93
|
+
} else if (enumData.every(n => Number.isInteger(n))) {
|
|
94
|
+
type = 'number';
|
|
95
|
+
format = 'float';
|
|
96
|
+
} else if (enumData.every(n => typeof n === 'number' && n === Math.fround(n))) {
|
|
97
|
+
type = 'number';
|
|
98
|
+
format = 'double';
|
|
99
|
+
} else if (enumData.every(n => isBigInt64(n))) {
|
|
100
|
+
type = 'integer';
|
|
101
|
+
format = 'int64';
|
|
79
102
|
} else if (enumData.every(n => !Number.isNaN(Number(n)))) {
|
|
80
103
|
type = 'number';
|
|
81
104
|
} else if (enumData.every(n => n?.toLowerCase() === 'boolean')) {
|
|
82
105
|
type = 'boolean';
|
|
83
106
|
} else if (enumData.every(n => n?.toLowerCase() === 'number')) {
|
|
84
107
|
type = 'number';
|
|
85
|
-
} else if (enumData.every(n => n?.toLowerCase() === 'string')) {
|
|
86
|
-
type = 'string';
|
|
87
108
|
} else if (enumData.every(n => n?.toLowerCase() === 'date')) {
|
|
88
109
|
type = 'string';
|
|
89
110
|
format = 'date-time';
|
|
@@ -96,18 +117,22 @@ function resolveSchemaFromTypeNames(names) {
|
|
|
96
117
|
} else if (enumData.every(n => n?.toLowerCase() === 'false')) {
|
|
97
118
|
type = 'boolean';
|
|
98
119
|
constant = false;
|
|
99
|
-
} else {
|
|
120
|
+
} else if (enumData.every(n => typeof n === 'string')) {
|
|
100
121
|
type = 'string';
|
|
122
|
+
} else if (enumData.length === 1) {
|
|
123
|
+
type = enumData[0];
|
|
124
|
+
constant = true;
|
|
125
|
+
} else {
|
|
126
|
+
type = undefined;
|
|
101
127
|
}
|
|
102
128
|
|
|
103
|
-
if (enumData?.length === 1
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
[format] = enumData;
|
|
107
|
-
}
|
|
108
|
-
oneOf = undefined;
|
|
109
|
-
enumData = undefined;
|
|
129
|
+
if (enumData?.length === 1) {
|
|
130
|
+
if (!format) {
|
|
131
|
+
[format] = enumData;
|
|
110
132
|
}
|
|
133
|
+
enumData = undefined;
|
|
134
|
+
} else if (nullable) {
|
|
135
|
+
enumData.push(null);
|
|
111
136
|
}
|
|
112
137
|
break;
|
|
113
138
|
}
|
|
@@ -119,7 +144,6 @@ function resolveSchemaFromTypeNames(names) {
|
|
|
119
144
|
return {
|
|
120
145
|
type,
|
|
121
146
|
format,
|
|
122
|
-
oneOf,
|
|
123
147
|
nullable,
|
|
124
148
|
items,
|
|
125
149
|
constant,
|
|
@@ -127,31 +151,42 @@ function resolveSchemaFromTypeNames(names) {
|
|
|
127
151
|
};
|
|
128
152
|
}
|
|
129
153
|
|
|
130
|
-
export default async function openapiJsonrpcJsdoc({
|
|
154
|
+
export default async function openapiJsonrpcJsdoc({
|
|
155
|
+
openapi = '3.1.0',
|
|
156
|
+
encoding = 'utf8',
|
|
157
|
+
access = 'public',
|
|
158
|
+
files,
|
|
159
|
+
info = {},
|
|
160
|
+
securitySchemes = {},
|
|
161
|
+
packageUrl,
|
|
162
|
+
servers,
|
|
163
|
+
api = '/',
|
|
164
|
+
samples = ['node', 'javascript'],
|
|
165
|
+
...xHeaders
|
|
166
|
+
}) {
|
|
131
167
|
const allData = await jsdoc.explain({
|
|
132
168
|
files: Array.isArray(files) ? files : [files],
|
|
133
|
-
|
|
134
|
-
access
|
|
135
|
-
encoding
|
|
169
|
+
packageJson: packageUrl,
|
|
170
|
+
access,
|
|
171
|
+
encoding,
|
|
136
172
|
undocumented: false,
|
|
137
173
|
allowUnknownTags: true,
|
|
138
174
|
dictionaries: ['jsdoc'],
|
|
175
|
+
cache: true,
|
|
176
|
+
samples,
|
|
139
177
|
});
|
|
140
178
|
const package_ = allData.find(item => item.kind === 'package');
|
|
141
179
|
const documents = allData.filter(item => item.kind !== 'package');
|
|
142
180
|
const temporaryDocument = {
|
|
143
|
-
'
|
|
144
|
-
'
|
|
145
|
-
'x-
|
|
146
|
-
|
|
147
|
-
'x-explorer-enabled': true,
|
|
148
|
-
'x-proxy-enabled': true,
|
|
149
|
-
'x-samples-enabled': true,
|
|
150
|
-
'x-samples-languages': ['node', 'javascript'],
|
|
181
|
+
'openapi': openapi,
|
|
182
|
+
'x-samples-enabled': samples.length > 0,
|
|
183
|
+
'x-samples-languages': samples,
|
|
184
|
+
...xHeaders,
|
|
151
185
|
'info': {
|
|
152
186
|
version: package_.version,
|
|
153
187
|
title: package_.name,
|
|
154
188
|
description: package_.description,
|
|
189
|
+
...info,
|
|
155
190
|
},
|
|
156
191
|
'servers': servers,
|
|
157
192
|
'paths': {},
|
|
@@ -159,6 +194,7 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
159
194
|
securitySchemes,
|
|
160
195
|
schemas: {
|
|
161
196
|
Error: {
|
|
197
|
+
type: 'object',
|
|
162
198
|
required: [
|
|
163
199
|
'error',
|
|
164
200
|
'id',
|
|
@@ -166,26 +202,25 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
166
202
|
],
|
|
167
203
|
properties: {
|
|
168
204
|
id: {
|
|
169
|
-
type: 'integer',
|
|
170
|
-
format: 'int32',
|
|
205
|
+
type: ['string', 'integer'],
|
|
171
206
|
},
|
|
172
207
|
error: {
|
|
173
208
|
type: 'object',
|
|
174
209
|
},
|
|
175
210
|
jsonrpc: {
|
|
176
211
|
type: 'string',
|
|
212
|
+
default: '2.0',
|
|
177
213
|
},
|
|
178
214
|
},
|
|
179
215
|
},
|
|
180
216
|
}
|
|
181
217
|
},
|
|
182
|
-
'security': [
|
|
183
|
-
{
|
|
184
|
-
BasicAuth: [],
|
|
185
|
-
},
|
|
186
|
-
],
|
|
218
|
+
'security': Object.keys(securitySchemes).map(val => ({ [val]: [] })),
|
|
187
219
|
'tags': [],
|
|
188
220
|
};
|
|
221
|
+
if (!temporaryDocument.info.title) {
|
|
222
|
+
throw new Error('Info title is required');
|
|
223
|
+
}
|
|
189
224
|
const requiredSchema = ['method', 'jsonrpc'];
|
|
190
225
|
prepare: for (const module of documents) {
|
|
191
226
|
let isJsonRpc = false;
|
|
@@ -237,6 +272,7 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
237
272
|
}
|
|
238
273
|
},
|
|
239
274
|
requestBody: {
|
|
275
|
+
required: true,
|
|
240
276
|
content: {
|
|
241
277
|
'application/json': {
|
|
242
278
|
schema: {
|
|
@@ -245,13 +281,10 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
245
281
|
properties: {
|
|
246
282
|
method: {
|
|
247
283
|
type: 'string',
|
|
248
|
-
default: apiName,
|
|
249
284
|
description: `API method ${apiName}`,
|
|
250
285
|
},
|
|
251
286
|
id: {
|
|
252
|
-
type: 'integer',
|
|
253
|
-
default: 1,
|
|
254
|
-
format: 'int32',
|
|
287
|
+
type: ['string', 'integer'],
|
|
255
288
|
description: 'Request ID',
|
|
256
289
|
},
|
|
257
290
|
jsonrpc: {
|
|
@@ -285,9 +318,10 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
285
318
|
return accumulator;
|
|
286
319
|
}
|
|
287
320
|
|
|
288
|
-
const description = parameter.description;
|
|
289
321
|
const name = extractName(parameter.name);
|
|
290
322
|
accumulator.properties[name] = accumulator.properties[name] ?? {};
|
|
323
|
+
const description = parameter.description;
|
|
324
|
+
const defaultValue = parameter.defaultvalue;
|
|
291
325
|
|
|
292
326
|
const {
|
|
293
327
|
items,
|
|
@@ -295,7 +329,6 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
295
329
|
enumData,
|
|
296
330
|
type,
|
|
297
331
|
format,
|
|
298
|
-
oneOf,
|
|
299
332
|
nullable,
|
|
300
333
|
} = resolveSchemaFromTypeNames(parameter.type.names)
|
|
301
334
|
if (!parameter.optional) {
|
|
@@ -304,6 +337,9 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
304
337
|
if (nullable) {
|
|
305
338
|
accumulator.properties[name].nullable = nullable;
|
|
306
339
|
}
|
|
340
|
+
if (defaultValue) {
|
|
341
|
+
accumulator.properties[name].default = defaultValue;
|
|
342
|
+
}
|
|
307
343
|
if (constant) {
|
|
308
344
|
accumulator.properties[name].const = constant;
|
|
309
345
|
}
|
|
@@ -313,9 +349,6 @@ export default async function openapiJsonrpcJsdoc({ files, securitySchemes = {},
|
|
|
313
349
|
if (enumData) {
|
|
314
350
|
accumulator.properties[name].enum = enumData;
|
|
315
351
|
}
|
|
316
|
-
if (oneOf) {
|
|
317
|
-
accumulator.properties[name].oneOf = oneOf;
|
|
318
|
-
}
|
|
319
352
|
if (type) {
|
|
320
353
|
accumulator.properties[name].type = type;
|
|
321
354
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-jsonrpc-jsdoc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Transform JSDoc-annotated JSON-RPC 2.0 methods into OpenAPI specifications.",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"ava": "~6.4.1",
|
|
36
|
-
"express": "~5.2.1"
|
|
37
|
-
"express-openapi-validator": "~5.6.2"
|
|
36
|
+
"express": "~5.2.1"
|
|
38
37
|
},
|
|
39
38
|
"engines": {
|
|
40
39
|
"node": ">= 22"
|