@grandlinex/swagger-mate 1.2.2 → 1.3.2
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/cjs/Swagger/Client/ClientUtil.d.ts +18 -4
- package/dist/cjs/Swagger/Client/ClientUtil.js +51 -8
- package/dist/cjs/Swagger/Client/InterfaceTemplate.js +1 -1
- package/dist/cjs/Swagger/Client/SwaggerClient.js +5 -5
- package/dist/cjs/Swagger/Meta/SwaggerTypes.d.ts +1 -0
- package/dist/cjs/Swagger/Path/SPathUtil.d.ts +173 -2
- package/dist/cjs/Swagger/Path/SPathUtil.js +261 -5
- package/dist/cjs/Swagger/SwaggerUtil.d.ts +18 -2
- package/dist/cjs/Swagger/SwaggerUtil.js +32 -5
- package/dist/cjs/Swagger/annotation/index.d.ts +8 -3
- package/dist/cjs/Swagger/debug/BaseCon.d.ts +115 -11
- package/dist/cjs/Swagger/debug/BaseCon.js +142 -38
- package/dist/cjs/cli.js +5 -1
- package/dist/mjs/Swagger/Client/ClientUtil.d.ts +18 -4
- package/dist/mjs/Swagger/Client/ClientUtil.js +50 -8
- package/dist/mjs/Swagger/Client/InterfaceTemplate.js +2 -2
- package/dist/mjs/Swagger/Client/SwaggerClient.js +5 -5
- package/dist/mjs/Swagger/Meta/SwaggerTypes.d.ts +1 -0
- package/dist/mjs/Swagger/Path/SPathUtil.d.ts +173 -2
- package/dist/mjs/Swagger/Path/SPathUtil.js +261 -5
- package/dist/mjs/Swagger/SwaggerUtil.d.ts +18 -2
- package/dist/mjs/Swagger/SwaggerUtil.js +33 -6
- package/dist/mjs/Swagger/annotation/index.d.ts +8 -3
- package/dist/mjs/Swagger/debug/BaseCon.d.ts +115 -11
- package/dist/mjs/Swagger/debug/BaseCon.js +142 -38
- package/dist/mjs/cli.js +5 -1
- package/package.json +10 -8
- package/res/html/rapi-doc/index.html +28 -0
- package/res/html/rapi-doc/rapidoc-min.js +3915 -0
- package/res/html/{index.html → swagger-ui/index.html} +11 -3
- package/res/html/swagger-ui/swagger-ui-bundle.js +2 -0
- package/res/html/swagger-ui/swagger-ui-standalone-preset.js +2 -0
- package/res/html/swagger-ui/swagger-ui.css +3 -0
- package/res/templates/class/BaseCon.ts +160 -61
- package/res/html/swagger-ui-bundle.js +0 -2
- package/res/html/swagger-ui-standalone-preset.js +0 -2
- package/res/html/swagger-ui.css +0 -3
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { getEntityMeta, XUtil, getColumnMeta, } from '@grandlinex/core';
|
|
2
2
|
import map from './SUtilMap.js';
|
|
3
|
+
import { isSwaggerRef, } from '../Meta/SwaggerTypes.js';
|
|
3
4
|
function resolveDBType(dType) {
|
|
4
5
|
switch (dType) {
|
|
5
6
|
case 'int':
|
|
7
|
+
case 'long':
|
|
6
8
|
return 'integer';
|
|
7
9
|
case 'double':
|
|
8
10
|
case 'float':
|
|
@@ -24,6 +26,11 @@ function resolveDBType(dType) {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
export default class SPathUtil {
|
|
29
|
+
/**
|
|
30
|
+
* Generates a default response mapping for the specified HTTP status types.
|
|
31
|
+
*
|
|
32
|
+
* @param {HttpStatusTypes[]} types - The HTTP status types for which default responses should be created.
|
|
33
|
+
* @return {SwaggerRPathConfResponse} An object mapping each provided status type to its default response definition. */
|
|
27
34
|
static defaultResponse(...types) {
|
|
28
35
|
const res = {};
|
|
29
36
|
types.forEach((el) => {
|
|
@@ -31,6 +38,12 @@ export default class SPathUtil {
|
|
|
31
38
|
});
|
|
32
39
|
return res;
|
|
33
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a request body definition for JSON content type using the provided schema.
|
|
43
|
+
*
|
|
44
|
+
* @param {SSchemaEl} schema - The JSON schema used for validating the request body.
|
|
45
|
+
* @return {SwaggerRPathReqBody} A Swagger path request body object specifying application/json content type with the provided schema.
|
|
46
|
+
*/
|
|
34
47
|
static jsonBody(schema) {
|
|
35
48
|
return {
|
|
36
49
|
content: {
|
|
@@ -40,6 +53,13 @@ export default class SPathUtil {
|
|
|
40
53
|
},
|
|
41
54
|
};
|
|
42
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds a Swagger request body for `multipart/form-data` requests.
|
|
58
|
+
*
|
|
59
|
+
* @param {SSchemaEl} [schema] Optional schema describing the form data.
|
|
60
|
+
* If omitted, a default schema with a single binary `file` field is provided.
|
|
61
|
+
* @return {SwaggerRPathReqBody} Swagger request body definition with
|
|
62
|
+
* `multipart/form-data` content and the supplied or default schema. */
|
|
43
63
|
static formBody(schema) {
|
|
44
64
|
return {
|
|
45
65
|
content: {
|
|
@@ -58,6 +78,14 @@ export default class SPathUtil {
|
|
|
58
78
|
},
|
|
59
79
|
};
|
|
60
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Generates a Swagger content definition for the provided entity.
|
|
83
|
+
*
|
|
84
|
+
* @param {T} entity - The entity instance to derive the Swagger schema from.
|
|
85
|
+
* @param {boolean} [list] - When true, the schema will be wrapped in an array type, representing a list of entities.
|
|
86
|
+
*
|
|
87
|
+
* @returns {SwaggerContent|undefined} The Swagger content object for the entity, or `undefined` if the entity does not have a schema.
|
|
88
|
+
*/
|
|
61
89
|
static entityContent(entity, list) {
|
|
62
90
|
const schema = this.schemaFromEntity(entity);
|
|
63
91
|
if (!schema) {
|
|
@@ -79,6 +107,13 @@ export default class SPathUtil {
|
|
|
79
107
|
},
|
|
80
108
|
};
|
|
81
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* @template T extends CoreEntity
|
|
112
|
+
* @param {T} entity - The entity instance for which to build the response configuration.
|
|
113
|
+
* @param {boolean} [list] - Indicates whether the response should represent a list of entities.
|
|
114
|
+
* @param {boolean} [create] - Indicates whether the response corresponds to a creation operation (status code 201); otherwise 200.
|
|
115
|
+
* @returns {SwaggerRPathConfResponse} The Swagger response configuration object containing the appropriate status code and content.
|
|
116
|
+
*/
|
|
82
117
|
static entityResponse(entity, list, create) {
|
|
83
118
|
const code = create ? '201' : '200';
|
|
84
119
|
const an = {};
|
|
@@ -88,9 +123,58 @@ export default class SPathUtil {
|
|
|
88
123
|
};
|
|
89
124
|
return an;
|
|
90
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Builds a JSON schema reference path for the given component name.
|
|
128
|
+
*
|
|
129
|
+
* @param {string} inp - The name of the schema component.
|
|
130
|
+
* @return {string} The JSON reference path formatted as `#/components/schemas/<inp>`.
|
|
131
|
+
*/
|
|
91
132
|
static schemaPath(inp) {
|
|
92
133
|
return `#/components/schemas/${inp}`;
|
|
93
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Creates a Swagger request body definition that references a schema.
|
|
137
|
+
*
|
|
138
|
+
* @param {string | CoreEntity} $ref
|
|
139
|
+
* Either the string reference to a schema or a `CoreEntity` instance whose
|
|
140
|
+
* class name will be used to build the reference path.
|
|
141
|
+
* @param {boolean} list
|
|
142
|
+
* If true, the referenced schema is wrapped in an array; otherwise the
|
|
143
|
+
* schema is used directly.
|
|
144
|
+
* @returns {SwaggerRPathReqBody}
|
|
145
|
+
* The request body object containing the appropriate content and schema
|
|
146
|
+
* configuration.
|
|
147
|
+
*/
|
|
148
|
+
static refRequest($ref, list) {
|
|
149
|
+
const t = typeof $ref === 'string'
|
|
150
|
+
? { $ref }
|
|
151
|
+
: {
|
|
152
|
+
$ref: this.schemaPath(XUtil.getEntityNames($ref).className),
|
|
153
|
+
};
|
|
154
|
+
if (list) {
|
|
155
|
+
return {
|
|
156
|
+
content: {
|
|
157
|
+
'application/json': {
|
|
158
|
+
schema: {
|
|
159
|
+
type: 'array',
|
|
160
|
+
items: t,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
content: {
|
|
168
|
+
'application/json': {
|
|
169
|
+
schema: t,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Creates a Swagger response configuration for a given HTTP status code.
|
|
176
|
+
*
|
|
177
|
+
* @param {HttpStatusTypes} code - The primary HTTP status code for */
|
|
94
178
|
static refResponse(code, $ref, list, ...addCodes) {
|
|
95
179
|
const an = {
|
|
96
180
|
...this.defaultResponse(...addCodes),
|
|
@@ -125,6 +209,15 @@ export default class SPathUtil {
|
|
|
125
209
|
}
|
|
126
210
|
return an;
|
|
127
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Builds a Swagger response configuration object for a given HTTP status code and schema.
|
|
214
|
+
*
|
|
215
|
+
* @param {HttpStatusTypes} code - The primary HTTP status code for the response.
|
|
216
|
+
* @param {SSchemaEl} schema - The JSON schema definition for the response body.
|
|
217
|
+
* @param {boolean} list - If true, the schema is wrapped in an array for list responses.
|
|
218
|
+
* @param {...HttpStatusTypes} addCodes - Additional HTTP status codes for default responses.
|
|
219
|
+
* @return {SwaggerRPathConfResponse} The constructed response configuration object.
|
|
220
|
+
*/
|
|
128
221
|
static jsonResponse(code, schema, list, ...addCodes) {
|
|
129
222
|
const an = {
|
|
130
223
|
...this.defaultResponse(...addCodes),
|
|
@@ -154,6 +247,23 @@ export default class SPathUtil {
|
|
|
154
247
|
}
|
|
155
248
|
return an;
|
|
156
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Generates a JSON schema representation from a CoreEntity instance.
|
|
252
|
+
*
|
|
253
|
+
* This method inspects the entity's metadata to construct a schema object
|
|
254
|
+
* describing the entity's shape. The resulting schema contains:
|
|
255
|
+
* - `type`: always `"object"`.
|
|
256
|
+
* - `description`: a string indicating the entity name.
|
|
257
|
+
* - `required`: an array of property names that are defined on the entity.
|
|
258
|
+
* - `properties`: an object mapping each property name to an object that
|
|
259
|
+
* includes the resolved database type and its nullability.
|
|
260
|
+
*
|
|
261
|
+
* If no metadata is found for the provided entity, the method returns `undefined`.
|
|
262
|
+
*
|
|
263
|
+
* @param {T} entity - The entity instance for which to create a schema.
|
|
264
|
+
* @returns {SSchemaEl | undefined} The generated schema object, or `undefined`
|
|
265
|
+
* if the entity's metadata could not be retrieved.
|
|
266
|
+
*/
|
|
157
267
|
static schemaFromEntity(entity) {
|
|
158
268
|
const schema = {
|
|
159
269
|
type: 'object',
|
|
@@ -169,16 +279,21 @@ export default class SPathUtil {
|
|
|
169
279
|
keys.forEach((k) => {
|
|
170
280
|
const cMeta = getColumnMeta(entity, k);
|
|
171
281
|
if (cMeta && schema.properties) {
|
|
172
|
-
|
|
173
|
-
schema.required?.push(k);
|
|
174
|
-
}
|
|
282
|
+
schema.required.push(k);
|
|
175
283
|
schema.properties[k] = {
|
|
176
284
|
type: resolveDBType(cMeta.dataType),
|
|
285
|
+
nullable: cMeta.canBeNull,
|
|
177
286
|
};
|
|
178
287
|
}
|
|
179
288
|
});
|
|
180
289
|
return schema;
|
|
181
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* Generates a content schema object for the given entity. The schema contains a description derived from the entity metadata and a JSON content schema based on the entity's structure.
|
|
293
|
+
*
|
|
294
|
+
* @param {T} entity - The entity instance for which to generate the content schema. The generic type `T` must extend {@link CoreEntity}.
|
|
295
|
+
* @returns {{ description: string; content: { 'application/json': { schema: SSchemaEl } }; } | undefined} An object containing the content schema, or `undefined` if no metadata is available for the entity.
|
|
296
|
+
*/
|
|
182
297
|
static contentSchemaFromEntity(entity) {
|
|
183
298
|
const meta = getEntityMeta(entity);
|
|
184
299
|
if (!meta) {
|
|
@@ -194,8 +309,10 @@ export default class SPathUtil {
|
|
|
194
309
|
};
|
|
195
310
|
}
|
|
196
311
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
312
|
+
* Generates a mapping from entity names to their corresponding schema objects.
|
|
313
|
+
*
|
|
314
|
+
* @param {CoreEntity[]} e The entities for which schema entries should be generated.
|
|
315
|
+
* @return {SKey<SSchemaEl>} An object whose keys are entity names and values are the schemas derived from those entities.
|
|
199
316
|
*/
|
|
200
317
|
static schemaEntryGen(...e) {
|
|
201
318
|
const out = {};
|
|
@@ -207,6 +324,14 @@ export default class SPathUtil {
|
|
|
207
324
|
});
|
|
208
325
|
return out;
|
|
209
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Builds a JSON schema representation for an entity view that includes both the
|
|
329
|
+
* entity data and its related entity map.
|
|
330
|
+
*
|
|
331
|
+
* @param entity The primary entity used to construct the `dat` portion of the schema.
|
|
332
|
+
* @param entityMap The related entity map used to construct the `join_map` portion of the schema.
|
|
333
|
+
* @returns A {@link SSchemaEl} object schema with properties `i`, `dat`, and `join_map`.
|
|
334
|
+
*/
|
|
210
335
|
static schemaFromEntityView(entity, entityMap) {
|
|
211
336
|
return {
|
|
212
337
|
type: 'object',
|
|
@@ -219,4 +344,135 @@ export default class SPathUtil {
|
|
|
219
344
|
},
|
|
220
345
|
};
|
|
221
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Extends an entity schema object by merging additional schema options.
|
|
349
|
+
*
|
|
350
|
+
* @param {CoreEntity} entity
|
|
351
|
+
* The entity for which the schema should be extended.
|
|
352
|
+
*
|
|
353
|
+
* @param {...Object} options
|
|
354
|
+
* One or more objects defining schema extensions. Each object may contain:
|
|
355
|
+
* - `key` (string): The property key to add or extend.
|
|
356
|
+
* - `list` (boolean, optional): Indicates whether the property is a list.
|
|
357
|
+
* - `entity` (CoreEntity, optional): The entity type for the property.
|
|
358
|
+
* - `schema` (SSchemaEl, optional): A custom schema definition for the property.
|
|
359
|
+
* - `required` (boolean, optional): Whether the property is required.
|
|
360
|
+
*
|
|
361
|
+
* @return {SSchemaEl}
|
|
362
|
+
* The resulting schema element. If a single property is returned by
|
|
363
|
+
* `extendEntitySchema`, its schema is returned directly; otherwise an
|
|
364
|
+
* object schema with a type of `'object'` is returned.
|
|
365
|
+
*/
|
|
366
|
+
static extendEntitySchemaObject(entity, ...options) {
|
|
367
|
+
const schema = this.extendEntitySchema(entity, ...options);
|
|
368
|
+
const ent = Object.entries(schema);
|
|
369
|
+
if (ent.length === 1) {
|
|
370
|
+
return ent[0][1];
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
type: 'object',
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Extends the schema of a given {@link CoreEntity} with additional properties.
|
|
378
|
+
*
|
|
379
|
+
* @param {CoreEntity} entity
|
|
380
|
+
* The entity whose schema will be extended.
|
|
381
|
+
*
|
|
382
|
+
* @param {...{
|
|
383
|
+
* key: string,
|
|
384
|
+
* list?: boolean,
|
|
385
|
+
* entity?: CoreEntity,
|
|
386
|
+
* schema?: SSchemaEl,
|
|
387
|
+
* required?: boolean
|
|
388
|
+
* }} options
|
|
389
|
+
* One or more option objects specifying the extensions to apply. Each option
|
|
390
|
+
* may provide either a direct schema (`schema`) or an entity reference
|
|
391
|
+
* (`entity`). The `list` flag indicates whether the property should be
|
|
392
|
+
* represented as an array of the provided schema. The `required` flag
|
|
393
|
+
* adds the property to the schema’s required list.
|
|
394
|
+
*
|
|
395
|
+
* @returns {SKey<SSchemaEl>}
|
|
396
|
+
* An object containing the updated schema for the entity, keyed by the
|
|
397
|
+
* entity’s name. If the entity metadata cannot be found, an empty
|
|
398
|
+
* object is returned.
|
|
399
|
+
*/
|
|
400
|
+
static extendEntitySchema(entity, ...options) {
|
|
401
|
+
const meta = getEntityMeta(entity);
|
|
402
|
+
if (meta) {
|
|
403
|
+
const schema = SPathUtil.schemaEntryGen(entity)[meta.name];
|
|
404
|
+
if (schema && !isSwaggerRef(schema) && schema.properties) {
|
|
405
|
+
for (const option of options) {
|
|
406
|
+
if (option.schema) {
|
|
407
|
+
if (option.list) {
|
|
408
|
+
schema.properties[option.key] = {
|
|
409
|
+
type: 'array',
|
|
410
|
+
items: option.schema,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
schema.properties[option.key] = option.schema;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else if (option.entity) {
|
|
418
|
+
const eMeta = getEntityMeta(option.entity);
|
|
419
|
+
if (eMeta) {
|
|
420
|
+
const scheme = SPathUtil.schemaEntryGen(option.entity)[eMeta.name];
|
|
421
|
+
if (option.list) {
|
|
422
|
+
schema.properties[option.key] = {
|
|
423
|
+
type: 'array',
|
|
424
|
+
items: scheme,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
schema.properties[option.key] = scheme;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (option.required) {
|
|
433
|
+
schema.required = [...(schema.required || []), option.key];
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
[meta.name]: schema,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
return {};
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Reduces the entity schema to a single schema element or a generic object.
|
|
445
|
+
*
|
|
446
|
+
* @param entity The entity whose schema should be reduced.
|
|
447
|
+
* @param keys Optional list of keys to include in the reduced schema. If omitted, all keys are considered.
|
|
448
|
+
* @return Returns the schema element of the sole key if only one key is present; otherwise, returns a generic object schema with type `'object'`. */
|
|
449
|
+
static reduceEntitySchemaObject(entity, ...keys) {
|
|
450
|
+
const schema = this.reduceEntitySchema(entity, ...keys);
|
|
451
|
+
const ent = Object.entries(schema);
|
|
452
|
+
if (ent.length === 1) {
|
|
453
|
+
return ent[0][1];
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
type: 'object',
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Creates a reduced version of an entity's schema by excluding specified properties.
|
|
461
|
+
*
|
|
462
|
+
* @param {CoreEntity} entity - The entity whose schema is to be processed.
|
|
463
|
+
* @param {...string} keys - Property names to remove from the schema's `properties` and `required` lists.
|
|
464
|
+
*
|
|
465
|
+
* @returns */
|
|
466
|
+
static reduceEntitySchema(entity, ...keys) {
|
|
467
|
+
const meta = getEntityMeta(entity);
|
|
468
|
+
if (meta) {
|
|
469
|
+
const schema = SPathUtil.schemaEntryGen(entity)[meta.name];
|
|
470
|
+
if (schema && !isSwaggerRef(schema) && schema.properties) {
|
|
471
|
+
schema.properties = Object.fromEntries(Object.entries(schema.properties).filter(([e]) => !keys.includes(e)));
|
|
472
|
+
schema.required = (schema.required || []).filter((e) => !keys.includes(e));
|
|
473
|
+
}
|
|
474
|
+
return { [meta.name]: schema };
|
|
475
|
+
}
|
|
476
|
+
return {};
|
|
477
|
+
}
|
|
222
478
|
}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
|
-
import { ObjectLike } from '@grandlinex/core';
|
|
1
|
+
import { CoreLogChannel, ObjectLike } from '@grandlinex/core';
|
|
2
2
|
import { Server } from 'net';
|
|
3
3
|
import { MergeInputType, SwaggerConfig, SwaggerRPath } from './Meta/SwaggerTypes.js';
|
|
4
4
|
import { RouteData } from './annotation/index.js';
|
|
5
5
|
export default class SwaggerUtil {
|
|
6
|
+
static logger: CoreLogChannel | null;
|
|
7
|
+
static getLogger(): CoreLogChannel;
|
|
6
8
|
static writeMeta(conf: SwaggerConfig, kind: 'JSON' | 'YAML', path?: string): void;
|
|
7
9
|
static readMeta(path: string): any;
|
|
8
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Serves a meta page for Swagger UI or rapi-doc.
|
|
12
|
+
*
|
|
13
|
+
* @param {SwaggerConfig} conf The swagger configuration to expose via `/spec`.
|
|
14
|
+
* @param {Object} [option] Options for serving the meta page.
|
|
15
|
+
* @param {'swagger-ui'|'rapi-doc'} [option.type='swagger-ui'] The type of UI to serve.
|
|
16
|
+
* @param {number} [option.port] The port to listen on. Defaults to 9000.
|
|
17
|
+
* @param {string} [option.auth] Optional authentication key appended to the URL.
|
|
18
|
+
* @returns {Promise<Server|null>} A promise that resolves with the created server instance or null.
|
|
19
|
+
*/
|
|
20
|
+
static serveMeta(conf: SwaggerConfig, option?: {
|
|
21
|
+
type?: 'swagger-ui' | 'rapi-doc';
|
|
22
|
+
port?: number;
|
|
23
|
+
auth?: string;
|
|
24
|
+
}): Promise<Server | null>;
|
|
9
25
|
static metaExtractor(root: ObjectLike, npmPackageVersion: boolean, ...path: ObjectLike[]): SwaggerConfig | undefined;
|
|
10
26
|
static routeToSwaggerPath(route: RouteData): SwaggerRPath;
|
|
11
27
|
static merge(root: SwaggerConfig, data: MergeInputType[]): SwaggerConfig;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Path from 'path';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import jsyaml from 'js-yaml';
|
|
4
|
-
import { CMap, instanceOfEntity } from '@grandlinex/core';
|
|
4
|
+
import { CMap, CoreLogChannel, DefaultLogger, instanceOfEntity, } from '@grandlinex/core';
|
|
5
5
|
import express from 'express';
|
|
6
6
|
import * as process from 'process';
|
|
7
7
|
import { getSComponent, getSPath, getSwaggerMeta } from './Meta/Swagger.js';
|
|
@@ -9,6 +9,13 @@ import PathHelp, { getBaseFolder } from '../PathHelp.js';
|
|
|
9
9
|
import { getRouteMeta } from './annotation/index.js';
|
|
10
10
|
import { SPathUtil } from '../index.js';
|
|
11
11
|
export default class SwaggerUtil {
|
|
12
|
+
static getLogger() {
|
|
13
|
+
if (!this.logger) {
|
|
14
|
+
const logger = new DefaultLogger();
|
|
15
|
+
this.logger = new CoreLogChannel('SwaggerUtil', logger);
|
|
16
|
+
}
|
|
17
|
+
return this.logger;
|
|
18
|
+
}
|
|
12
19
|
static writeMeta(conf, kind, path) {
|
|
13
20
|
if (kind === 'JSON') {
|
|
14
21
|
const p = Path.join(path || process.cwd(), 'openapi.json');
|
|
@@ -25,11 +32,25 @@ export default class SwaggerUtil {
|
|
|
25
32
|
return JSON.parse(file);
|
|
26
33
|
}
|
|
27
34
|
catch (e) {
|
|
35
|
+
this.getLogger().error(e);
|
|
28
36
|
return null;
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Serves a meta page for Swagger UI or rapi-doc.
|
|
41
|
+
*
|
|
42
|
+
* @param {SwaggerConfig} conf The swagger configuration to expose via `/spec`.
|
|
43
|
+
* @param {Object} [option] Options for serving the meta page.
|
|
44
|
+
* @param {'swagger-ui'|'rapi-doc'} [option.type='swagger-ui'] The type of UI to serve.
|
|
45
|
+
* @param {number} [option.port] The port to listen on. Defaults to 9000.
|
|
46
|
+
* @param {string} [option.auth] Optional authentication key appended to the URL.
|
|
47
|
+
* @returns {Promise<Server|null>} A promise that resolves with the created server instance or null.
|
|
48
|
+
*/
|
|
49
|
+
static async serveMeta(conf, option) {
|
|
50
|
+
const type = option?.type ?? 'swagger-ui';
|
|
51
|
+
const port = option?.port || 9000;
|
|
52
|
+
const auth = option?.auth;
|
|
53
|
+
const resFiles = PathHelp(getBaseFolder(), '..', 'res', 'html', type);
|
|
33
54
|
const key = auth ? `?auth=${auth}` : '';
|
|
34
55
|
const app = express();
|
|
35
56
|
app.use('/', express.static(resFiles));
|
|
@@ -37,8 +58,8 @@ export default class SwaggerUtil {
|
|
|
37
58
|
res.status(200).send(conf);
|
|
38
59
|
});
|
|
39
60
|
return new Promise((resolve) => {
|
|
40
|
-
const s = app.listen(port
|
|
41
|
-
|
|
61
|
+
const s = app.listen(port, () => {
|
|
62
|
+
this.getLogger().log(`${type} listen on http://localhost:${port}${key}#`);
|
|
42
63
|
resolve(s);
|
|
43
64
|
});
|
|
44
65
|
});
|
|
@@ -83,7 +104,13 @@ export default class SwaggerUtil {
|
|
|
83
104
|
// Handle requestBody
|
|
84
105
|
if (!conf.requestBody) {
|
|
85
106
|
if (route.meta.requestSchema) {
|
|
86
|
-
|
|
107
|
+
if (typeof route.meta.requestSchema === 'string' ||
|
|
108
|
+
instanceOfEntity(route.meta.requestSchema)) {
|
|
109
|
+
conf.requestBody = SPathUtil.refRequest(route.meta.requestSchema, route.meta.responseType === 'LIST');
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
conf.requestBody = SPathUtil.jsonBody(route.meta.requestSchema);
|
|
113
|
+
}
|
|
87
114
|
}
|
|
88
115
|
}
|
|
89
116
|
// Handle responses
|
|
@@ -8,13 +8,18 @@ export declare enum ActionMode {
|
|
|
8
8
|
'DMZ_WITH_USER' = 2
|
|
9
9
|
}
|
|
10
10
|
export type ActionTypes = 'POST' | 'GET' | 'USE' | 'PATCH' | 'DELETE';
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* LIST - Response is an array of items
|
|
13
|
+
* SINGLE - Response is a single item (default)
|
|
14
|
+
*/
|
|
15
|
+
export type ResponseRequestTypes = 'LIST' | 'SINGLE';
|
|
12
16
|
export type RouteMeta = {
|
|
13
17
|
pathOverride?: string;
|
|
14
18
|
mode?: ActionMode;
|
|
15
|
-
requestSchema?: SSchemaEl;
|
|
19
|
+
requestSchema?: SSchemaEl | CoreEntity | string;
|
|
16
20
|
responseSchema?: SSchemaEl | CoreEntity | string;
|
|
17
|
-
|
|
21
|
+
requestType?: ResponseRequestTypes;
|
|
22
|
+
responseType?: ResponseRequestTypes;
|
|
18
23
|
responseCodes?: HttpStatusTypes[];
|
|
19
24
|
} & SwaggerRPathConf;
|
|
20
25
|
export type RouteData = {
|
|
@@ -38,13 +38,20 @@ export interface ConHandle {
|
|
|
38
38
|
patch<T, J>(url: string, body?: J, config?: ConHandleConfig): Promise<ConHandleResponse<T>>;
|
|
39
39
|
delete<T>(url: string, config?: ConHandleConfig): Promise<ConHandleResponse<T>>;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* BaseCon provides a minimal client for interacting with an HTTP backend.
|
|
43
|
+
* It manages connection state, authentication tokens, and reconnection
|
|
44
|
+
* logic while delegating actual HTTP requests to a supplied {@link ConHandle}.
|
|
45
|
+
*
|
|
46
|
+
* @class
|
|
47
|
+
*/
|
|
41
48
|
export default class BaseCon {
|
|
42
|
-
api
|
|
43
|
-
permanentHeader
|
|
44
|
-
authorization
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
private api;
|
|
50
|
+
private permanentHeader;
|
|
51
|
+
private authorization;
|
|
52
|
+
private noAuth;
|
|
53
|
+
private disconnected;
|
|
54
|
+
private readonly logger;
|
|
48
55
|
con: ConHandle;
|
|
49
56
|
reconnect: () => Promise<boolean>;
|
|
50
57
|
onReconnect: (con: BaseCon) => Promise<boolean>;
|
|
@@ -53,16 +60,113 @@ export default class BaseCon {
|
|
|
53
60
|
endpoint: string;
|
|
54
61
|
logger?: (arg: any) => void;
|
|
55
62
|
});
|
|
63
|
+
/**
|
|
64
|
+
* Retrieves the API endpoint.
|
|
65
|
+
*
|
|
66
|
+
* @return {string} The API endpoint string.
|
|
67
|
+
*/
|
|
68
|
+
getApiEndpoint(): string;
|
|
69
|
+
/**
|
|
70
|
+
* Sets the API endpoint URL used by the client.
|
|
71
|
+
*
|
|
72
|
+
* @param {string} endpoint - The full URL of the API endpoint.
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
75
|
+
setApiEndpoint(endpoint: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Indicates whether the instance is considered connected.
|
|
78
|
+
*
|
|
79
|
+
* The instance is regarded as connected when it either does not require authentication
|
|
80
|
+
* (`noAuth` is true) or it has an authorization token set (`authorization` is not null),
|
|
81
|
+
* and it is not currently marked as disconnected.
|
|
82
|
+
*
|
|
83
|
+
* @return {boolean} `true` if the instance is connected, `false` otherwise.
|
|
84
|
+
*/
|
|
56
85
|
isConnected(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Returns the current authorization token.
|
|
88
|
+
*
|
|
89
|
+
* @return {string} The authorization token or an empty string if none is set.
|
|
90
|
+
*/
|
|
57
91
|
token(): string;
|
|
58
|
-
p
|
|
92
|
+
private p;
|
|
93
|
+
/**
|
|
94
|
+
* Sends a ping request to the API to verify connectivity and version availability.
|
|
95
|
+
*
|
|
96
|
+
* @return {boolean} `true` if the API responded with a 200 status code and a valid version object; `false` otherwise.
|
|
97
|
+
*/
|
|
59
98
|
ping(): Promise<boolean>;
|
|
60
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Validates the current authentication token by performing a ping and a test request
|
|
101
|
+
* to the backend. The method first ensures connectivity via {@link ping}. If the ping
|
|
102
|
+
* succeeds, it attempts to retrieve a token from the `/test/auth` endpoint using the
|
|
103
|
+
* current token in the `Authorization` header. The operation is considered successful
|
|
104
|
+
* if the response status code is 200 or 201.
|
|
105
|
+
*
|
|
106
|
+
* If any step fails, an error is logged and the method returns {@code false}. On
|
|
107
|
+
* success, it returns {@code true}.
|
|
108
|
+
*
|
|
109
|
+
* @return {Promise<boolean>} A promise that resolves to {@code true} if the token
|
|
110
|
+
* test succeeds, otherwise {@code false}.
|
|
111
|
+
*/
|
|
61
112
|
testToken(): Promise<boolean>;
|
|
62
|
-
connect(email: string, pw: string): Promise<boolean>;
|
|
63
113
|
/**
|
|
64
|
-
*
|
|
114
|
+
* Attempts to establish a connection to the backend without authentication.
|
|
115
|
+
*
|
|
116
|
+
* This method sends a ping request. If the ping succeeds, it clears any
|
|
117
|
+
* existing authorization data, marks the instance as connected,
|
|
118
|
+
* enables the no‑authentication mode, and returns `true`. If the ping
|
|
119
|
+
* fails, it logs a warning, clears authorization, marks the instance
|
|
120
|
+
* as disconnected, and returns `false`.
|
|
121
|
+
*
|
|
122
|
+
* @return {Promise<boolean>} `true` when a connection is successfully
|
|
123
|
+
* established without authentication, otherwise `false`.
|
|
124
|
+
*/
|
|
125
|
+
connectNoAuth(): Promise<boolean>;
|
|
126
|
+
/**
|
|
127
|
+
* Forces a connection using the provided bearer token.
|
|
128
|
+
*
|
|
129
|
+
* @param {string} token The token to be used for authentication.
|
|
130
|
+
* @returns {void}
|
|
131
|
+
*/
|
|
132
|
+
forceConnectWithToken(token: string): void;
|
|
133
|
+
/**
|
|
134
|
+
* Establishes a connection to the backend using the supplied credentials.
|
|
135
|
+
* Performs a health‑check ping first; if successful, it requests an authentication
|
|
136
|
+
* token from the `/token` endpoint. When the token is obtained, the method
|
|
137
|
+
* updates internal state (authorization header, connection flags) and, unless
|
|
138
|
+
* a dry run is requested, sets up a reconnection routine. Any errors are
|
|
139
|
+
* logged and the method resolves to `false`.
|
|
140
|
+
*
|
|
141
|
+
* @param {string} email - The user's email address for authentication.
|
|
142
|
+
* @param {string} pw - The password (or token) for the specified user.
|
|
143
|
+
* @param {boolean} [dry=false] - If `true`, the method performs a dry run
|
|
144
|
+
* without persisting credentials or configuring reconnection logic.
|
|
145
|
+
*
|
|
146
|
+
* @returns Promise<boolean> `true` if the connection was successfully
|
|
147
|
+
* established, otherwise `false`.
|
|
148
|
+
*/
|
|
149
|
+
connect(email: string, pw: string, dry?: boolean): Promise<boolean>;
|
|
150
|
+
/**
|
|
151
|
+
* Performs an HTTP request using the client’s internal connection.
|
|
152
|
+
*
|
|
153
|
+
* The method verifies that the client is connected before attempting a request.
|
|
154
|
+
* It automatically injects the authorization token, permanent headers, and any
|
|
155
|
+
* headers supplied in `config`. If the request body is a `FormData` instance
|
|
156
|
+
* (or provides a `getHeaders` method), the appropriate form headers are added.
|
|
157
|
+
*
|
|
158
|
+
* Response handling:
|
|
159
|
+
* - `200` or `201`: returns `success: true` with the received data.
|
|
160
|
+
* - `498`: attempts to reconnect and retries the request once.
|
|
161
|
+
* - `401`: logs an authentication error, marks the client as disconnected.
|
|
162
|
+
* - `403` and other status codes: return `success: false` with the status code.
|
|
163
|
+
*
|
|
164
|
+
* @param {'POST'|'GET'|'PATCH'|'DELETE'} type The HTTP method to use.
|
|
165
|
+
* @param {string} path The endpoint path relative to the base URL.
|
|
166
|
+
* @param {J} [body] Optional request payload. May be `FormData` or a plain object.
|
|
167
|
+
* @param {ConHandleConfig} [config] Optional Axios-like configuration for the request.
|
|
168
|
+
* @returns {Promise<HandleRes<T>>} A promise that resolves to a `HandleRes` object
|
|
169
|
+
* containing the response data, status code, any error information, and headers.
|
|
65
170
|
*/
|
|
66
|
-
fakeEnableClient(): void;
|
|
67
171
|
handle<T, J>(type: 'POST' | 'GET' | 'PATCH' | 'DELETE', path: string, body?: J, config?: ConHandleConfig): Promise<HandleRes<T>>;
|
|
68
172
|
}
|