@lucaapp/service-utils 5.26.0 → 5.27.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/lib/api/api.d.ts +1 -0
- package/dist/lib/api/api.js +12 -6
- package/dist/lib/api/index.d.ts +1 -0
- package/dist/lib/api/openapi.d.ts +1 -1
- package/dist/lib/api/openapi.js +25 -2
- package/dist/lib/api/security.d.ts +3 -0
- package/dist/lib/api/security.js +15 -0
- package/dist/lib/api/types/middleware.d.ts +2 -0
- package/package.json +2 -2
package/dist/lib/api/api.d.ts
CHANGED
package/dist/lib/api/api.js
CHANGED
|
@@ -10,6 +10,7 @@ const swagger_ui_express_1 = __importDefault(require("swagger-ui-express"));
|
|
|
10
10
|
const zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
|
|
11
11
|
const endpoint_1 = require("./endpoint");
|
|
12
12
|
const openapi_1 = require("./openapi");
|
|
13
|
+
const security_1 = require("./security");
|
|
13
14
|
const body_parser_1 = __importDefault(require("body-parser"));
|
|
14
15
|
const rawBodySaver = function (req, res, buf, encoding) {
|
|
15
16
|
if (buf && buf.length) {
|
|
@@ -22,6 +23,7 @@ class Api {
|
|
|
22
23
|
this.router = options.router || (0, express_1.Router)();
|
|
23
24
|
this.registry = options.registry || new zod_to_openapi_1.OpenAPIRegistry();
|
|
24
25
|
this.prefixPath = options.prefixPath || '';
|
|
26
|
+
this.rootPrefixPath = this.prefixPath;
|
|
25
27
|
this.openApiVersion = options.openApiVersion || '3.0.0';
|
|
26
28
|
this.apiVersion = options.apiVersion || '1.0.0';
|
|
27
29
|
this.apiTitle = options.apiTitle || 'API';
|
|
@@ -31,33 +33,35 @@ class Api {
|
|
|
31
33
|
this.router.use(body_parser_1.default.json({ verify: rawBodySaver, limit: '2mb' }));
|
|
32
34
|
}
|
|
33
35
|
child(options) {
|
|
34
|
-
|
|
36
|
+
const child = new Api({
|
|
35
37
|
prefixPath: this.prefixPath + (options.prefixPath || ''),
|
|
36
38
|
debug: this.debug,
|
|
37
39
|
tags: [...this.tags, ...(options.tags || [])],
|
|
38
40
|
registry: this.registry,
|
|
39
41
|
router: this.router,
|
|
40
42
|
});
|
|
43
|
+
child.rootPrefixPath = this.rootPrefixPath;
|
|
44
|
+
return child;
|
|
41
45
|
}
|
|
42
46
|
get(path, summary, options, handler) {
|
|
43
47
|
(0, endpoint_1.mountEndpoint)(this.router, 'get', path, options, handler, this.debug);
|
|
44
|
-
(0, openapi_1.registerEndpoint)(this.registry, 'get', this.prefixPath, path, summary, options, this.tags, this.debug);
|
|
48
|
+
(0, openapi_1.registerEndpoint)(this.registry, 'get', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug);
|
|
45
49
|
}
|
|
46
50
|
post(path, summary, options, handler) {
|
|
47
51
|
(0, endpoint_1.mountEndpoint)(this.router, 'post', path, options, handler, this.debug);
|
|
48
|
-
(0, openapi_1.registerEndpoint)(this.registry, 'post', this.prefixPath, path, summary, options, this.tags, this.debug);
|
|
52
|
+
(0, openapi_1.registerEndpoint)(this.registry, 'post', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug);
|
|
49
53
|
}
|
|
50
54
|
patch(path, summary, options, handler) {
|
|
51
55
|
(0, endpoint_1.mountEndpoint)(this.router, 'patch', path, options, handler, this.debug);
|
|
52
|
-
(0, openapi_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, path, summary, options, this.tags, this.debug);
|
|
56
|
+
(0, openapi_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug);
|
|
53
57
|
}
|
|
54
58
|
put(path, summary, options, handler) {
|
|
55
59
|
(0, endpoint_1.mountEndpoint)(this.router, 'put', path, options, handler, this.debug);
|
|
56
|
-
(0, openapi_1.registerEndpoint)(this.registry, 'put', this.prefixPath, path, summary, options, this.tags, this.debug);
|
|
60
|
+
(0, openapi_1.registerEndpoint)(this.registry, 'put', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug);
|
|
57
61
|
}
|
|
58
62
|
delete(path, summary, options, handler) {
|
|
59
63
|
(0, endpoint_1.mountEndpoint)(this.router, 'delete', path, options, handler, this.debug);
|
|
60
|
-
(0, openapi_1.registerEndpoint)(this.registry, 'delete', this.prefixPath, path, summary, options, this.tags, this.debug);
|
|
64
|
+
(0, openapi_1.registerEndpoint)(this.registry, 'delete', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug);
|
|
61
65
|
}
|
|
62
66
|
generateOpenAPISpec() {
|
|
63
67
|
let generator;
|
|
@@ -74,9 +78,11 @@ class Api {
|
|
|
74
78
|
title: this.apiTitle,
|
|
75
79
|
description: this.apiDescription,
|
|
76
80
|
},
|
|
81
|
+
servers: [{ url: '/' }],
|
|
77
82
|
});
|
|
78
83
|
(0, openapi_1.forcePathParamsRequired)(spec);
|
|
79
84
|
(0, openapi_1.hoistCombinatorRequiredFields)(spec);
|
|
85
|
+
spec.components = { ...spec.components, securitySchemes: security_1.SECURITY_SCHEMES };
|
|
80
86
|
return spec;
|
|
81
87
|
}
|
|
82
88
|
mountSwaggerMiddlewares() {
|
package/dist/lib/api/index.d.ts
CHANGED
|
@@ -25,5 +25,5 @@ export declare const hoistCombinatorRequiredFields: (spec: {
|
|
|
25
25
|
schemas?: Record<string, unknown>;
|
|
26
26
|
};
|
|
27
27
|
}) => void;
|
|
28
|
-
export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>, tags: string[], debug: boolean) => void;
|
|
28
|
+
export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, rootPrefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>, tags: string[], debug: boolean) => void;
|
|
29
29
|
export {};
|
package/dist/lib/api/openapi.js
CHANGED
|
@@ -4,6 +4,21 @@ exports.registerEndpoint = exports.hoistCombinatorRequiredFields = exports.force
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const http_1 = require("./types/http");
|
|
6
6
|
const mapExpressParamsToOpenAPIParams = (path) => path.replaceAll(/\:([^\:\/]+)/g, '{$1}');
|
|
7
|
+
const deriveOperationId = (registry, method, path) => {
|
|
8
|
+
const operationId = method +
|
|
9
|
+
path
|
|
10
|
+
.replaceAll(':', 'by-')
|
|
11
|
+
.split(/[^A-Za-z0-9]+/)
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
14
|
+
.join('');
|
|
15
|
+
const isTaken = registry.definitions.some(definition => definition.type === 'route' &&
|
|
16
|
+
definition.route.operationId === operationId);
|
|
17
|
+
if (isTaken) {
|
|
18
|
+
throw new Error(`Duplicate operationId ${operationId} for ${method.toUpperCase()} ${path}, set options.operationId`);
|
|
19
|
+
}
|
|
20
|
+
return operationId;
|
|
21
|
+
};
|
|
7
22
|
const buildResponseConfig = (responseOptions) => {
|
|
8
23
|
const responses = {};
|
|
9
24
|
responseOptions.forEach(response => {
|
|
@@ -210,7 +225,7 @@ const hoistCombinatorRequiredFields = (spec) => {
|
|
|
210
225
|
visit(schemas);
|
|
211
226
|
};
|
|
212
227
|
exports.hoistCombinatorRequiredFields = hoistCombinatorRequiredFields;
|
|
213
|
-
const registerEndpoint = (registry, method, prefixPath, path, summary,
|
|
228
|
+
const registerEndpoint = (registry, method, prefixPath, rootPrefixPath, path, summary,
|
|
214
229
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
215
230
|
options, tags, debug) => {
|
|
216
231
|
let bodySchema = options.schemas?.body || undefined;
|
|
@@ -218,6 +233,7 @@ options, tags, debug) => {
|
|
|
218
233
|
let querySchema = options.schemas?.query || undefined;
|
|
219
234
|
let headersSchema = options.schemas?.headers || undefined;
|
|
220
235
|
let responseSchemas = options.responses;
|
|
236
|
+
const securitySchemes = new Set();
|
|
221
237
|
if (options.errors) {
|
|
222
238
|
for (const errorType of Object.keys(options.errors)) {
|
|
223
239
|
const statusCode = options.errors[errorType];
|
|
@@ -278,6 +294,9 @@ options, tags, debug) => {
|
|
|
278
294
|
});
|
|
279
295
|
}
|
|
280
296
|
}
|
|
297
|
+
for (const scheme of middleware.options.security || []) {
|
|
298
|
+
securitySchemes.add(scheme);
|
|
299
|
+
}
|
|
281
300
|
}
|
|
282
301
|
// Add ZodError response
|
|
283
302
|
responseSchemas.push({
|
|
@@ -334,7 +353,11 @@ options, tags, debug) => {
|
|
|
334
353
|
headers: headersSchema ? [headersSchema] : [],
|
|
335
354
|
},
|
|
336
355
|
responses: responseMap,
|
|
337
|
-
|
|
356
|
+
operationId: options.operationId ||
|
|
357
|
+
deriveOperationId(registry, method, prefixPath.slice(rootPrefixPath.length) + path),
|
|
358
|
+
...(securitySchemes.size > 0 && {
|
|
359
|
+
security: [...securitySchemes].map(scheme => ({ [scheme]: [] })),
|
|
360
|
+
}),
|
|
338
361
|
});
|
|
339
362
|
};
|
|
340
363
|
exports.registerEndpoint = registerEndpoint;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SECURITY_SCHEMES = void 0;
|
|
4
|
+
const X_AUTH_HEADER = {
|
|
5
|
+
type: 'apiKey',
|
|
6
|
+
in: 'header',
|
|
7
|
+
name: 'X-Auth',
|
|
8
|
+
};
|
|
9
|
+
exports.SECURITY_SCHEMES = {
|
|
10
|
+
jwt_operator: X_AUTH_HEADER,
|
|
11
|
+
jwt_support: X_AUTH_HEADER,
|
|
12
|
+
jwt_operator_device: X_AUTH_HEADER,
|
|
13
|
+
jwt_consumer: X_AUTH_HEADER,
|
|
14
|
+
api_key: { type: 'apiKey', in: 'header', name: 'X-Api-Key' },
|
|
15
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { SecurityScheme } from '../security';
|
|
2
3
|
import { ArrayToUnion, ExtractZodOutput, ZodSchemaOuput } from './utils';
|
|
3
4
|
export type EndpointResponseSchema = {
|
|
4
5
|
status: number;
|
|
@@ -45,6 +46,7 @@ export type MiddlewareOptions<TResponseSchemas extends ReadonlyArray<EndpointRes
|
|
|
45
46
|
returnRawBody?: boolean;
|
|
46
47
|
};
|
|
47
48
|
errors?: Record<string, number>;
|
|
49
|
+
security?: ReadonlyArray<SecurityScheme>;
|
|
48
50
|
};
|
|
49
51
|
export type Middleware<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema> = {
|
|
50
52
|
options: MiddlewareOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucaapp/service-utils",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.27.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"tar": "7.5.21",
|
|
89
89
|
"body-parser": "1.20.6",
|
|
90
90
|
"lodash": "^4.18.1",
|
|
91
|
-
"qs": "6.
|
|
91
|
+
"qs": "6.16.0",
|
|
92
92
|
"dottie": "2.0.7",
|
|
93
93
|
"fast-xml-parser": "^5.7.1",
|
|
94
94
|
"yaml": "^2.8.3",
|