@forklaunch/core 0.7.3 → 0.8.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/lib/__test__/index.d.mts +7 -1
- package/lib/__test__/index.d.ts +7 -1
- package/lib/__test__/index.js +3 -5
- package/lib/__test__/index.js.map +1 -1
- package/lib/__test__/index.mjs +4 -6
- package/lib/__test__/index.mjs.map +1 -1
- package/lib/src/cache/index.js +30 -20
- package/lib/src/cache/index.js.map +1 -1
- package/lib/src/cache/index.mjs +37 -20
- package/lib/src/cache/index.mjs.map +1 -1
- package/lib/src/http/index.d.mts +201 -43
- package/lib/src/http/index.d.ts +201 -43
- package/lib/src/http/index.js +321 -37
- package/lib/src/http/index.js.map +1 -1
- package/lib/src/http/index.mjs +326 -37
- package/lib/src/http/index.mjs.map +1 -1
- package/lib/src/services/index.js +7 -1
- package/lib/src/services/index.js.map +1 -1
- package/lib/src/services/index.mjs +7 -1
- package/lib/src/services/index.mjs.map +1 -1
- package/package.json +31 -31
package/lib/src/http/index.mjs
CHANGED
@@ -210,6 +210,7 @@ async function parseRequestAuth(req, res, next) {
|
|
210
210
|
req
|
211
211
|
) ?? [];
|
212
212
|
if (error != null) {
|
213
|
+
res.type("text/plain");
|
213
214
|
res.status(error).send(message);
|
214
215
|
next?.(new Error(message));
|
215
216
|
}
|
@@ -484,7 +485,7 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
484
485
|
[ATTR_API_NAME]: req.contractDetails?.name || "unknown",
|
485
486
|
[ATTR_HTTP_REQUEST_METHOD]: req.method,
|
486
487
|
[ATTR_HTTP_ROUTE]: req.originalPath || "unknown",
|
487
|
-
[ATTR_HTTP_RESPONSE_STATUS_CODE]: res.statusCode
|
488
|
+
[ATTR_HTTP_RESPONSE_STATUS_CODE]: Number(res.statusCode)
|
488
489
|
});
|
489
490
|
});
|
490
491
|
next?.();
|
@@ -501,9 +502,9 @@ function hasSend(res) {
|
|
501
502
|
return typeof res === "object" && res !== null && "send" in res;
|
502
503
|
}
|
503
504
|
|
504
|
-
// src/http/guards/
|
505
|
-
function
|
506
|
-
return maybeResponseShape != null && "body" in maybeResponseShape
|
505
|
+
// src/http/guards/isRequestShape.ts
|
506
|
+
function isRequestShape(maybeResponseShape) {
|
507
|
+
return maybeResponseShape != null && ("body" in maybeResponseShape || "query" in maybeResponseShape || "params" in maybeResponseShape || "headers" in maybeResponseShape);
|
507
508
|
}
|
508
509
|
|
509
510
|
// src/http/middleware/request/parse.middleware.ts
|
@@ -518,7 +519,7 @@ function parse(req, res, next) {
|
|
518
519
|
req.requestSchema,
|
519
520
|
request
|
520
521
|
);
|
521
|
-
if (parsedRequest.ok &&
|
522
|
+
if (parsedRequest.ok && isRequestShape(parsedRequest.value)) {
|
522
523
|
req.body = parsedRequest.value.body;
|
523
524
|
req.params = parsedRequest.value.params;
|
524
525
|
Object.defineProperty(req, "query", {
|
@@ -527,7 +528,7 @@ function parse(req, res, next) {
|
|
527
528
|
enumerable: true,
|
528
529
|
configurable: false
|
529
530
|
});
|
530
|
-
req.headers = parsedRequest.value.headers;
|
531
|
+
req.headers = parsedRequest.value.headers ?? {};
|
531
532
|
}
|
532
533
|
if (!parsedRequest.ok) {
|
533
534
|
switch (req.contractDetails.options?.requestValidation) {
|
@@ -560,11 +561,132 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
560
561
|
next?.();
|
561
562
|
}
|
562
563
|
|
564
|
+
// src/http/router/discriminateBody.ts
|
565
|
+
function discriminateBody(schemaValidator, body) {
|
566
|
+
if (body == null) {
|
567
|
+
return void 0;
|
568
|
+
}
|
569
|
+
const maybeTypedBody = body;
|
570
|
+
if ("text" in maybeTypedBody && maybeTypedBody.text != null) {
|
571
|
+
return {
|
572
|
+
contentType: maybeTypedBody.contentType ?? "text/plain",
|
573
|
+
parserType: "text",
|
574
|
+
schema: maybeTypedBody.text
|
575
|
+
};
|
576
|
+
} else if ("json" in maybeTypedBody && maybeTypedBody.json != null) {
|
577
|
+
return {
|
578
|
+
contentType: maybeTypedBody.contentType ?? "application/json",
|
579
|
+
parserType: "json",
|
580
|
+
schema: maybeTypedBody.json
|
581
|
+
};
|
582
|
+
} else if ("file" in maybeTypedBody && maybeTypedBody.file != null) {
|
583
|
+
return {
|
584
|
+
contentType: maybeTypedBody.contentType ?? "application/octet-stream",
|
585
|
+
parserType: "file",
|
586
|
+
schema: maybeTypedBody.file
|
587
|
+
};
|
588
|
+
} else if ("multipartForm" in maybeTypedBody && maybeTypedBody.multipartForm != null) {
|
589
|
+
return {
|
590
|
+
contentType: maybeTypedBody.contentType ?? "multipart/form-data",
|
591
|
+
parserType: "multipart",
|
592
|
+
schema: maybeTypedBody.multipartForm
|
593
|
+
};
|
594
|
+
} else if ("urlEncodedForm" in maybeTypedBody && maybeTypedBody.urlEncodedForm != null) {
|
595
|
+
return {
|
596
|
+
contentType: maybeTypedBody.contentType ?? "application/x-www-form-urlencoded",
|
597
|
+
parserType: "urlEncoded",
|
598
|
+
schema: maybeTypedBody.urlEncodedForm
|
599
|
+
};
|
600
|
+
} else if ("schema" in maybeTypedBody && maybeTypedBody.schema != null) {
|
601
|
+
return {
|
602
|
+
contentType: maybeTypedBody.contentType ?? "application/json",
|
603
|
+
parserType: "text",
|
604
|
+
schema: maybeTypedBody.schema
|
605
|
+
};
|
606
|
+
} else if (schemaValidator.isInstanceOf(
|
607
|
+
maybeTypedBody,
|
608
|
+
schemaValidator.string
|
609
|
+
)) {
|
610
|
+
return {
|
611
|
+
contentType: "text/plain",
|
612
|
+
parserType: "text",
|
613
|
+
schema: maybeTypedBody
|
614
|
+
};
|
615
|
+
} else {
|
616
|
+
return {
|
617
|
+
contentType: "application/json",
|
618
|
+
parserType: "json",
|
619
|
+
schema: maybeTypedBody
|
620
|
+
};
|
621
|
+
}
|
622
|
+
}
|
623
|
+
function discriminateResponseBodies(schemaValidator, responses) {
|
624
|
+
const discriminatedResponses = {};
|
625
|
+
for (const [statusCode, response] of Object.entries(responses)) {
|
626
|
+
if (response != null && typeof response === "object") {
|
627
|
+
if ("json" in response && response.json != null) {
|
628
|
+
discriminatedResponses[Number(statusCode)] = {
|
629
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/json") ?? "application/json",
|
630
|
+
parserType: "json",
|
631
|
+
schema: response.json
|
632
|
+
};
|
633
|
+
} else if ("schema" in response && response.schema != null) {
|
634
|
+
discriminatedResponses[Number(statusCode)] = {
|
635
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/json") ?? "application/json",
|
636
|
+
parserType: "text",
|
637
|
+
schema: response.schema
|
638
|
+
};
|
639
|
+
} else if ("text" in response && response.text != null) {
|
640
|
+
discriminatedResponses[Number(statusCode)] = {
|
641
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "text/plain") ?? "text/plain",
|
642
|
+
parserType: "text",
|
643
|
+
schema: response.text
|
644
|
+
};
|
645
|
+
} else if ("file" in response && response.file != null) {
|
646
|
+
discriminatedResponses[Number(statusCode)] = {
|
647
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/octet-stream") ?? "application/octet-stream",
|
648
|
+
parserType: "file",
|
649
|
+
schema: response.file
|
650
|
+
};
|
651
|
+
} else if ("event" in response && response.event != null) {
|
652
|
+
discriminatedResponses[Number(statusCode)] = {
|
653
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "text/event-stream") ?? "text/event-stream",
|
654
|
+
parserType: "serverSentEvent",
|
655
|
+
schema: response.event
|
656
|
+
};
|
657
|
+
} else if (schemaValidator.isInstanceOf(
|
658
|
+
response,
|
659
|
+
schemaValidator.string
|
660
|
+
)) {
|
661
|
+
discriminatedResponses[Number(statusCode)] = {
|
662
|
+
contentType: "text/plain",
|
663
|
+
parserType: "text",
|
664
|
+
schema: response
|
665
|
+
};
|
666
|
+
} else {
|
667
|
+
discriminatedResponses[Number(statusCode)] = {
|
668
|
+
contentType: "application/json",
|
669
|
+
parserType: "json",
|
670
|
+
schema: response
|
671
|
+
};
|
672
|
+
}
|
673
|
+
} else {
|
674
|
+
discriminatedResponses[Number(statusCode)] = {
|
675
|
+
contentType: "application/json",
|
676
|
+
parserType: "json",
|
677
|
+
schema: response
|
678
|
+
};
|
679
|
+
}
|
680
|
+
}
|
681
|
+
return discriminatedResponses;
|
682
|
+
}
|
683
|
+
|
563
684
|
// src/http/router/expressLikeRouter.ts
|
564
685
|
var ForklaunchExpressLikeRouter = class {
|
565
|
-
constructor(basePath, schemaValidator, internal, openTelemetryCollector) {
|
686
|
+
constructor(basePath, schemaValidator, internal, postEnrichMiddleware, openTelemetryCollector) {
|
566
687
|
this.schemaValidator = schemaValidator;
|
567
688
|
this.internal = internal;
|
689
|
+
this.postEnrichMiddleware = postEnrichMiddleware;
|
568
690
|
this.openTelemetryCollector = openTelemetryCollector;
|
569
691
|
this.basePath = basePath;
|
570
692
|
}
|
@@ -587,6 +709,7 @@ var ForklaunchExpressLikeRouter = class {
|
|
587
709
|
responseSchemas,
|
588
710
|
this.openTelemetryCollector
|
589
711
|
),
|
712
|
+
...this.postEnrichMiddleware,
|
590
713
|
parse,
|
591
714
|
parseRequestAuth
|
592
715
|
];
|
@@ -642,12 +765,16 @@ var ForklaunchExpressLikeRouter = class {
|
|
642
765
|
}
|
643
766
|
#compile(contractDetails) {
|
644
767
|
const schemaValidator = this.schemaValidator;
|
768
|
+
let body = null;
|
769
|
+
if (isHttpContractDetails(contractDetails)) {
|
770
|
+
body = discriminateBody(this.schemaValidator, contractDetails.body);
|
771
|
+
}
|
645
772
|
const requestSchema = schemaValidator.compile(
|
646
773
|
schemaValidator.schemify({
|
647
774
|
...contractDetails.params ? { params: contractDetails.params } : {},
|
648
775
|
...contractDetails.requestHeaders ? { headers: contractDetails.requestHeaders } : {},
|
649
776
|
...contractDetails.query ? { query: contractDetails.query } : {},
|
650
|
-
...
|
777
|
+
...body != null ? { body: body.schema } : {}
|
651
778
|
})
|
652
779
|
);
|
653
780
|
const responseEntries = {
|
@@ -656,9 +783,16 @@ var ForklaunchExpressLikeRouter = class {
|
|
656
783
|
403: schemaValidator.string,
|
657
784
|
404: schemaValidator.string,
|
658
785
|
500: schemaValidator.string,
|
659
|
-
...isPathParamHttpContractDetails(contractDetails) || isHttpContractDetails(contractDetails) ?
|
660
|
-
|
661
|
-
|
786
|
+
...isPathParamHttpContractDetails(contractDetails) || isHttpContractDetails(contractDetails) ? Object.fromEntries(
|
787
|
+
Object.entries(
|
788
|
+
discriminateResponseBodies(
|
789
|
+
this.schemaValidator,
|
790
|
+
contractDetails.responses
|
791
|
+
)
|
792
|
+
).map(([key, value]) => {
|
793
|
+
return [key, value.schema];
|
794
|
+
})
|
795
|
+
) : {}
|
662
796
|
};
|
663
797
|
const responseSchemas = {
|
664
798
|
responses: {},
|
@@ -694,7 +828,7 @@ var ForklaunchExpressLikeRouter = class {
|
|
694
828
|
params: request?.params ?? {},
|
695
829
|
query: request?.query ?? {},
|
696
830
|
headers: request?.headers ?? {},
|
697
|
-
body: request?.body ?? {},
|
831
|
+
body: discriminateBody(this.schemaValidator, request?.body)?.schema ?? {},
|
698
832
|
path: route
|
699
833
|
};
|
700
834
|
const res = {
|
@@ -713,6 +847,9 @@ var ForklaunchExpressLikeRouter = class {
|
|
713
847
|
},
|
714
848
|
setHeader: (key, value) => {
|
715
849
|
responseHeaders[key] = value;
|
850
|
+
},
|
851
|
+
sseEmiter: (generator) => {
|
852
|
+
responseMessage = generator;
|
716
853
|
}
|
717
854
|
};
|
718
855
|
let cursor = handlers.shift();
|
@@ -738,7 +875,7 @@ var ForklaunchExpressLikeRouter = class {
|
|
738
875
|
}
|
739
876
|
});
|
740
877
|
return {
|
741
|
-
code: statusCode,
|
878
|
+
code: Number(statusCode),
|
742
879
|
response: responseMessage,
|
743
880
|
headers: responseHeaders
|
744
881
|
};
|
@@ -1146,10 +1283,17 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
|
|
1146
1283
|
*
|
1147
1284
|
* @param {SV} schemaValidator - The schema validator.
|
1148
1285
|
*/
|
1149
|
-
constructor(schemaValidator, internal, openTelemetryCollector) {
|
1150
|
-
super(
|
1286
|
+
constructor(schemaValidator, internal, postEnrichMiddleware, openTelemetryCollector) {
|
1287
|
+
super(
|
1288
|
+
"/",
|
1289
|
+
schemaValidator,
|
1290
|
+
internal,
|
1291
|
+
postEnrichMiddleware,
|
1292
|
+
openTelemetryCollector
|
1293
|
+
);
|
1151
1294
|
this.schemaValidator = schemaValidator;
|
1152
1295
|
this.internal = internal;
|
1296
|
+
this.postEnrichMiddleware = postEnrichMiddleware;
|
1153
1297
|
this.openTelemetryCollector = openTelemetryCollector;
|
1154
1298
|
this.internal.use(createContext(this.schemaValidator));
|
1155
1299
|
this.internal.use(cors);
|
@@ -2222,8 +2366,9 @@ import {
|
|
2222
2366
|
} from "@forklaunch/validator";
|
2223
2367
|
function parse2(req, res, next) {
|
2224
2368
|
const { headers, responses } = res.responseSchemas;
|
2369
|
+
const statusCode = Number(res.statusCode);
|
2225
2370
|
const parsedResponse = req.schemaValidator.parse(
|
2226
|
-
responses?.[
|
2371
|
+
responses?.[statusCode],
|
2227
2372
|
res.bodyData
|
2228
2373
|
);
|
2229
2374
|
const parsedHeaders = req.schemaValidator.parse(
|
@@ -2251,7 +2396,7 @@ function parse2(req, res, next) {
|
|
2251
2396
|
default:
|
2252
2397
|
case "error":
|
2253
2398
|
res.type("text/plain");
|
2254
|
-
res.status(
|
2399
|
+
res.status(500);
|
2255
2400
|
if (hasSend(res)) {
|
2256
2401
|
res.send(
|
2257
2402
|
`Invalid response:
|
@@ -2278,6 +2423,17 @@ ${parseErrors.join("\n\n")}`
|
|
2278
2423
|
next?.();
|
2279
2424
|
}
|
2280
2425
|
|
2426
|
+
// src/http/middleware/response/enrichExpressLikeSend.middleware.ts
|
2427
|
+
import {
|
2428
|
+
isAsyncGenerator,
|
2429
|
+
isNever as isNever3,
|
2430
|
+
isNodeJsWriteableStream,
|
2431
|
+
isRecord,
|
2432
|
+
readableStreamToAsyncIterable,
|
2433
|
+
safeStringify as safeStringify2
|
2434
|
+
} from "@forklaunch/common";
|
2435
|
+
import { Readable, Transform } from "stream";
|
2436
|
+
|
2281
2437
|
// src/http/telemetry/recordMetric.ts
|
2282
2438
|
import {
|
2283
2439
|
ATTR_HTTP_REQUEST_METHOD as ATTR_HTTP_REQUEST_METHOD3,
|
@@ -2303,21 +2459,121 @@ function recordMetric(req, res) {
|
|
2303
2459
|
[ATTR_CORRELATION_ID]: req.context.correlationId,
|
2304
2460
|
[ATTR_HTTP_REQUEST_METHOD3]: req.method,
|
2305
2461
|
[ATTR_HTTP_ROUTE3]: req.originalPath,
|
2306
|
-
[ATTR_HTTP_RESPONSE_STATUS_CODE3]: res.statusCode || 0
|
2462
|
+
[ATTR_HTTP_RESPONSE_STATUS_CODE3]: Number(res.statusCode) || 0
|
2307
2463
|
});
|
2308
2464
|
res.metricRecorded = true;
|
2309
2465
|
}
|
2310
2466
|
|
2311
2467
|
// src/http/middleware/response/enrichExpressLikeSend.middleware.ts
|
2312
|
-
function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnrich) {
|
2313
|
-
let
|
2314
|
-
if (
|
2315
|
-
|
2316
|
-
|
2468
|
+
function enrichExpressLikeSend(instance, req, res, originalOperation, originalSend, data, shouldEnrich) {
|
2469
|
+
let errorSent = false;
|
2470
|
+
if (data == null) {
|
2471
|
+
originalSend.call(instance, data);
|
2472
|
+
return;
|
2473
|
+
}
|
2474
|
+
if (res.statusCode === 404) {
|
2475
|
+
res.type("text/plain");
|
2476
|
+
res.status(404);
|
2477
|
+
logger("error").error("Not Found");
|
2478
|
+
originalSend.call(instance, "Not Found");
|
2479
|
+
errorSent = true;
|
2480
|
+
}
|
2481
|
+
const responseBodies = discriminateResponseBodies(
|
2482
|
+
req.schemaValidator,
|
2483
|
+
req.contractDetails.responses
|
2484
|
+
);
|
2485
|
+
if (responseBodies != null && responseBodies[Number(res.statusCode)] != null) {
|
2486
|
+
res.type(responseBodies[Number(res.statusCode)].contentType);
|
2487
|
+
}
|
2488
|
+
if (data instanceof File || data instanceof Blob) {
|
2489
|
+
if (data instanceof File) {
|
2490
|
+
res.setHeader(
|
2491
|
+
"Content-Disposition",
|
2492
|
+
`attachment; filename="${data.name}"`
|
2493
|
+
);
|
2494
|
+
}
|
2495
|
+
if (isNodeJsWriteableStream(res)) {
|
2496
|
+
Readable.from(readableStreamToAsyncIterable(data.stream())).pipe(
|
2497
|
+
res
|
2498
|
+
);
|
2499
|
+
} else {
|
2500
|
+
res.type("text/plain");
|
2501
|
+
res.status(500);
|
2502
|
+
originalSend.call(instance, "Not a NodeJS WritableStream");
|
2503
|
+
errorSent = true;
|
2504
|
+
}
|
2505
|
+
} else if (isAsyncGenerator(data)) {
|
2506
|
+
let firstPass = true;
|
2507
|
+
const transformer = new Transform({
|
2508
|
+
objectMode: true,
|
2509
|
+
transform(chunk, _encoding, callback) {
|
2510
|
+
if (firstPass) {
|
2511
|
+
res.bodyData = chunk;
|
2512
|
+
parse2(req, res, (err) => {
|
2513
|
+
if (err) {
|
2514
|
+
let errorString = err.message;
|
2515
|
+
if (res.locals.errorMessage) {
|
2516
|
+
errorString += `
|
2517
|
+
------------------
|
2518
|
+
${res.locals.errorMessage}`;
|
2519
|
+
}
|
2520
|
+
logger("error").error(errorString);
|
2521
|
+
res.type("text/plain");
|
2522
|
+
res.status(500);
|
2523
|
+
originalSend.call(instance, errorString);
|
2524
|
+
errorSent = true;
|
2525
|
+
callback(new Error(errorString));
|
2526
|
+
}
|
2527
|
+
});
|
2528
|
+
firstPass = false;
|
2529
|
+
}
|
2530
|
+
if (!errorSent) {
|
2531
|
+
let data2 = "";
|
2532
|
+
for (const [key, value] of Object.entries(chunk)) {
|
2533
|
+
data2 += `${key}: ${typeof value === "string" ? value : safeStringify2(value)}
|
2534
|
+
`;
|
2535
|
+
}
|
2536
|
+
data2 += "\n";
|
2537
|
+
callback(null, data2);
|
2538
|
+
}
|
2539
|
+
}
|
2540
|
+
});
|
2541
|
+
if (isNodeJsWriteableStream(res)) {
|
2542
|
+
Readable.from(data).pipe(transformer).pipe(res);
|
2543
|
+
} else {
|
2317
2544
|
res.type("text/plain");
|
2318
|
-
res.status(
|
2319
|
-
|
2320
|
-
|
2545
|
+
res.status(500);
|
2546
|
+
originalSend.call(instance, "Not a NodeJS WritableStream");
|
2547
|
+
errorSent = true;
|
2548
|
+
}
|
2549
|
+
} else {
|
2550
|
+
const parserType = responseBodies?.[Number(res.statusCode)]?.parserType;
|
2551
|
+
res.bodyData = data;
|
2552
|
+
if (isRecord(data)) {
|
2553
|
+
switch (parserType) {
|
2554
|
+
case "json":
|
2555
|
+
res.bodyData = "json" in data ? data.json : data;
|
2556
|
+
break;
|
2557
|
+
case "text":
|
2558
|
+
res.bodyData = "text" in data ? data.text : data;
|
2559
|
+
break;
|
2560
|
+
case "file":
|
2561
|
+
res.bodyData = "file" in data ? data.file : data;
|
2562
|
+
break;
|
2563
|
+
case "serverSentEvent":
|
2564
|
+
res.bodyData = "event" in data ? data.event : data;
|
2565
|
+
break;
|
2566
|
+
case "multipart":
|
2567
|
+
res.bodyData = "multipart" in data ? data.multipart : data;
|
2568
|
+
break;
|
2569
|
+
case void 0:
|
2570
|
+
res.bodyData = data;
|
2571
|
+
break;
|
2572
|
+
default:
|
2573
|
+
isNever3(parserType);
|
2574
|
+
res.bodyData = data;
|
2575
|
+
break;
|
2576
|
+
}
|
2321
2577
|
}
|
2322
2578
|
parse2(req, res, (err) => {
|
2323
2579
|
if (err) {
|
@@ -2331,12 +2587,21 @@ ${res.locals.errorMessage}`;
|
|
2331
2587
|
res.type("text/plain");
|
2332
2588
|
res.status(500);
|
2333
2589
|
originalSend.call(instance, errorString);
|
2334
|
-
|
2590
|
+
errorSent = true;
|
2335
2591
|
}
|
2336
2592
|
});
|
2593
|
+
if (!errorSent) {
|
2594
|
+
if (typeof data === "string") {
|
2595
|
+
res.type("text/plain");
|
2596
|
+
originalSend.call(instance, data);
|
2597
|
+
} else if (!(data instanceof File)) {
|
2598
|
+
res.sent = true;
|
2599
|
+
originalOperation.call(instance, data);
|
2600
|
+
}
|
2601
|
+
}
|
2337
2602
|
}
|
2338
|
-
if (
|
2339
|
-
|
2603
|
+
if (shouldEnrich) {
|
2604
|
+
recordMetric(req, res);
|
2340
2605
|
}
|
2341
2606
|
}
|
2342
2607
|
|
@@ -2375,10 +2640,14 @@ function generateOpenApiDocument(port, tags, paths) {
|
|
2375
2640
|
paths
|
2376
2641
|
};
|
2377
2642
|
}
|
2378
|
-
function contentResolver(schemaValidator, body) {
|
2643
|
+
function contentResolver(schemaValidator, body, contentType) {
|
2379
2644
|
const bodySpec = schemaValidator.openapi(body);
|
2380
|
-
return
|
2381
|
-
|
2645
|
+
return contentType != null ? {
|
2646
|
+
[contentType]: {
|
2647
|
+
schema: bodySpec
|
2648
|
+
}
|
2649
|
+
} : body === schemaValidator.string ? {
|
2650
|
+
"text/plain": {
|
2382
2651
|
schema: bodySpec
|
2383
2652
|
}
|
2384
2653
|
} : {
|
@@ -2403,15 +2672,29 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
|
|
2403
2672
|
}
|
2404
2673
|
const { name, summary, query, requestHeaders } = route.contractDetails;
|
2405
2674
|
const responses = {};
|
2406
|
-
|
2675
|
+
const discriminatedResponseBodiesResult = discriminateResponseBodies(
|
2676
|
+
schemaValidator,
|
2677
|
+
route.contractDetails.responses
|
2678
|
+
);
|
2679
|
+
for (const key in discriminatedResponseBodiesResult) {
|
2407
2680
|
responses[key] = {
|
2408
2681
|
description: httpStatusCodes_default[key],
|
2409
2682
|
content: contentResolver(
|
2410
2683
|
schemaValidator,
|
2411
|
-
|
2684
|
+
discriminatedResponseBodiesResult[key].schema,
|
2685
|
+
discriminatedResponseBodiesResult[key].contentType
|
2412
2686
|
)
|
2413
2687
|
};
|
2414
2688
|
}
|
2689
|
+
const commonErrors = [400, 404, 500];
|
2690
|
+
for (const error of commonErrors) {
|
2691
|
+
if (!(error in responses)) {
|
2692
|
+
responses[error] = {
|
2693
|
+
description: httpStatusCodes_default[error],
|
2694
|
+
content: contentResolver(schemaValidator, schemaValidator.string)
|
2695
|
+
};
|
2696
|
+
}
|
2697
|
+
}
|
2415
2698
|
const pathItemObject = {
|
2416
2699
|
tags: [controllerName],
|
2417
2700
|
summary: `${name}: ${summary}`,
|
@@ -2429,11 +2712,15 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
|
|
2429
2712
|
});
|
2430
2713
|
}
|
2431
2714
|
}
|
2432
|
-
const
|
2433
|
-
if (
|
2715
|
+
const discriminatedBodyResult = "body" in route.contractDetails ? discriminateBody(schemaValidator, route.contractDetails.body) : null;
|
2716
|
+
if (discriminatedBodyResult) {
|
2434
2717
|
pathItemObject.requestBody = {
|
2435
2718
|
required: true,
|
2436
|
-
content: contentResolver(
|
2719
|
+
content: contentResolver(
|
2720
|
+
schemaValidator,
|
2721
|
+
discriminatedBodyResult.schema,
|
2722
|
+
discriminatedBodyResult.contentType
|
2723
|
+
)
|
2437
2724
|
};
|
2438
2725
|
}
|
2439
2726
|
if (requestHeaders) {
|
@@ -2515,6 +2802,8 @@ export {
|
|
2515
2802
|
HTTPStatuses,
|
2516
2803
|
OpenTelemetryCollector,
|
2517
2804
|
delete_,
|
2805
|
+
discriminateBody,
|
2806
|
+
discriminateResponseBodies,
|
2518
2807
|
enrichExpressLikeSend,
|
2519
2808
|
evaluateTelemetryOptions,
|
2520
2809
|
generateSwaggerDocument,
|