@forklaunch/core 0.14.8 → 0.14.11-beta.1
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/http/index.d.mts +126 -75
- package/lib/http/index.d.ts +126 -75
- package/lib/http/index.js +161 -93
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +119 -49
- package/lib/http/index.mjs.map +1 -1
- package/package.json +9 -9
package/lib/http/index.js
CHANGED
@@ -102,7 +102,7 @@ function cors(corsOptions) {
|
|
102
102
|
}
|
103
103
|
|
104
104
|
// src/http/router/expressLikeRouter.ts
|
105
|
-
var
|
105
|
+
var import_common9 = require("@forklaunch/common");
|
106
106
|
|
107
107
|
// src/http/guards/hasVersionedSchema.ts
|
108
108
|
function hasVersionedSchema(contractDetails) {
|
@@ -157,12 +157,14 @@ function isTypedHandler(maybeTypedHandler) {
|
|
157
157
|
}
|
158
158
|
|
159
159
|
// src/http/middleware/request/auth.middleware.ts
|
160
|
-
var
|
160
|
+
var import_common3 = require("@forklaunch/common");
|
161
|
+
var import_validator = require("@forklaunch/validator");
|
161
162
|
|
162
163
|
// src/http/discriminateAuthMethod.ts
|
163
164
|
var import_jose = require("jose");
|
164
165
|
|
165
166
|
// src/http/createHmacToken.ts
|
167
|
+
var import_common2 = require("@forklaunch/common");
|
166
168
|
var import_crypto = require("crypto");
|
167
169
|
function createHmacToken({
|
168
170
|
method,
|
@@ -173,11 +175,14 @@ function createHmacToken({
|
|
173
175
|
secretKey
|
174
176
|
}) {
|
175
177
|
const hmac = (0, import_crypto.createHmac)("sha256", secretKey);
|
176
|
-
|
178
|
+
const bodyString = body ? `${(0, import_common2.safeStringify)(body)}
|
179
|
+
` : void 0;
|
180
|
+
hmac.update(
|
181
|
+
`${method}
|
177
182
|
${path}
|
178
|
-
${
|
179
|
-
${
|
180
|
-
|
183
|
+
${bodyString}${timestamp.toISOString()}
|
184
|
+
${nonce}`
|
185
|
+
);
|
181
186
|
return hmac.digest("base64");
|
182
187
|
}
|
183
188
|
|
@@ -197,6 +202,12 @@ function isJwtAuthMethod(maybeJwtAuthMethod) {
|
|
197
202
|
}
|
198
203
|
|
199
204
|
// src/http/discriminateAuthMethod.ts
|
205
|
+
var DEFAULT_TTL = 60 * 1e3 * 5;
|
206
|
+
var memoizedJwks = {
|
207
|
+
value: null,
|
208
|
+
lastUpdated: null,
|
209
|
+
ttl: DEFAULT_TTL
|
210
|
+
};
|
200
211
|
async function discriminateAuthMethod(auth) {
|
201
212
|
let authMethod;
|
202
213
|
if (isBasicAuthMethod(auth)) {
|
@@ -221,8 +232,17 @@ async function discriminateAuthMethod(auth) {
|
|
221
232
|
} else {
|
222
233
|
let jwks;
|
223
234
|
if ("jwksPublicKeyUrl" in jwt) {
|
224
|
-
|
225
|
-
|
235
|
+
if (memoizedJwks.value && memoizedJwks.lastUpdated && Date.now() - memoizedJwks.lastUpdated.getTime() < memoizedJwks.ttl) {
|
236
|
+
jwks = memoizedJwks.value;
|
237
|
+
} else {
|
238
|
+
const jwksResponse = await fetch(jwt.jwksPublicKeyUrl);
|
239
|
+
jwks = (await jwksResponse.json()).keys;
|
240
|
+
memoizedJwks.value = jwks;
|
241
|
+
memoizedJwks.lastUpdated = /* @__PURE__ */ new Date();
|
242
|
+
memoizedJwks.ttl = parseInt(
|
243
|
+
jwksResponse.headers.get("cache-control")?.split("=")[1] ?? `${DEFAULT_TTL / 1e3}`
|
244
|
+
) * 1e3;
|
245
|
+
}
|
226
246
|
} else if ("jwksPublicKey" in jwt) {
|
227
247
|
jwks = [jwt.jwksPublicKey];
|
228
248
|
}
|
@@ -232,6 +252,9 @@ async function discriminateAuthMethod(auth) {
|
|
232
252
|
const { payload } = await (0, import_jose.jwtVerify)(token, key);
|
233
253
|
return payload;
|
234
254
|
} catch {
|
255
|
+
memoizedJwks.value = null;
|
256
|
+
memoizedJwks.lastUpdated = null;
|
257
|
+
memoizedJwks.ttl = DEFAULT_TTL;
|
235
258
|
continue;
|
236
259
|
}
|
237
260
|
}
|
@@ -249,7 +272,15 @@ async function discriminateAuthMethod(auth) {
|
|
249
272
|
type: "hmac",
|
250
273
|
auth: {
|
251
274
|
secretKeys: auth.hmac.secretKeys,
|
252
|
-
verificationFunction: async (
|
275
|
+
verificationFunction: async ({
|
276
|
+
method,
|
277
|
+
path,
|
278
|
+
body,
|
279
|
+
timestamp,
|
280
|
+
nonce,
|
281
|
+
signature,
|
282
|
+
secretKey
|
283
|
+
}) => {
|
253
284
|
return createHmacToken({
|
254
285
|
method,
|
255
286
|
path,
|
@@ -327,7 +358,7 @@ function parseHmacTokenPart(part, expectedKey) {
|
|
327
358
|
if (key !== expectedKey || rest.length === 0) return void 0;
|
328
359
|
return rest.join("=");
|
329
360
|
}
|
330
|
-
async function checkAuthorizationToken(
|
361
|
+
async function checkAuthorizationToken(req, authorizationMethod, authorizationToken, globalOptions) {
|
331
362
|
if (authorizationMethod == null) {
|
332
363
|
return void 0;
|
333
364
|
}
|
@@ -342,7 +373,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
342
373
|
if (!tokenParts.length || !tokenPrefix) {
|
343
374
|
return invalidAuthorizationTokenFormat;
|
344
375
|
}
|
345
|
-
let
|
376
|
+
let sessionPayload;
|
346
377
|
const { type, auth } = await discriminateAuthMethod(
|
347
378
|
collapsedAuthorizationMethod
|
348
379
|
);
|
@@ -362,19 +393,19 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
362
393
|
if (!parsedKeyId || !parsedTimestamp || !parsedNonce || !parsedSignature) {
|
363
394
|
return invalidAuthorizationTokenFormat;
|
364
395
|
}
|
365
|
-
const verificationResult = await auth.verificationFunction(
|
366
|
-
req?.method ?? "",
|
367
|
-
req?.path ?? "",
|
368
|
-
|
369
|
-
parsedTimestamp,
|
370
|
-
parsedNonce,
|
371
|
-
parsedSignature,
|
372
|
-
collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
|
373
|
-
);
|
396
|
+
const verificationResult = await auth.verificationFunction({
|
397
|
+
method: req?.method ?? "",
|
398
|
+
path: req?.path ?? "",
|
399
|
+
body: req?.body,
|
400
|
+
timestamp: new Date(parsedTimestamp),
|
401
|
+
nonce: parsedNonce,
|
402
|
+
signature: parsedSignature,
|
403
|
+
secretKey: collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
|
404
|
+
});
|
374
405
|
if (!verificationResult) {
|
375
406
|
return invalidAuthorizationSignature;
|
376
407
|
}
|
377
|
-
|
408
|
+
sessionPayload = null;
|
378
409
|
break;
|
379
410
|
}
|
380
411
|
case "jwt": {
|
@@ -387,7 +418,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
387
418
|
if (!decodedJwt) {
|
388
419
|
return invalidAuthorizationToken;
|
389
420
|
}
|
390
|
-
|
421
|
+
sessionPayload = decodedJwt;
|
391
422
|
} catch (error) {
|
392
423
|
req?.openTelemetryCollector.error(error);
|
393
424
|
return invalidAuthorizationToken;
|
@@ -400,7 +431,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
400
431
|
return invalidAuthorizationTokenFormat;
|
401
432
|
}
|
402
433
|
if (auth.decodeResource) {
|
403
|
-
|
434
|
+
sessionPayload = await auth.decodeResource(token);
|
404
435
|
} else {
|
405
436
|
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
406
437
|
if (!username || !password) {
|
@@ -409,26 +440,39 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
409
440
|
if (!auth.login(username, password)) {
|
410
441
|
return invalidAuthorizationLogin;
|
411
442
|
}
|
412
|
-
|
443
|
+
sessionPayload = {
|
413
444
|
sub: username
|
414
445
|
};
|
415
446
|
}
|
416
447
|
break;
|
417
448
|
}
|
418
449
|
default:
|
419
|
-
(0,
|
450
|
+
(0, import_common3.isNever)(type);
|
420
451
|
return [401, "Invalid Authorization method."];
|
421
452
|
}
|
422
|
-
if (isHmacMethod(collapsedAuthorizationMethod) &&
|
453
|
+
if (isHmacMethod(collapsedAuthorizationMethod) && sessionPayload == null) {
|
423
454
|
return;
|
424
455
|
}
|
425
|
-
if (
|
456
|
+
if (sessionPayload == null) {
|
426
457
|
return invalidAuthorizationToken;
|
427
458
|
}
|
459
|
+
req.session = sessionPayload;
|
460
|
+
if (collapsedAuthorizationMethod.sessionSchema) {
|
461
|
+
const parsedSession = req.schemaValidator.parse(
|
462
|
+
collapsedAuthorizationMethod.sessionSchema,
|
463
|
+
sessionPayload
|
464
|
+
);
|
465
|
+
if (!parsedSession.ok) {
|
466
|
+
return [
|
467
|
+
400,
|
468
|
+
`Invalid session: ${(0, import_validator.prettyPrintParseErrors)(parsedSession.errors, "Session")}`
|
469
|
+
];
|
470
|
+
}
|
471
|
+
}
|
428
472
|
if (hasScopeChecks(collapsedAuthorizationMethod)) {
|
429
473
|
if (collapsedAuthorizationMethod.surfaceScopes) {
|
430
474
|
const resourceScopes = await collapsedAuthorizationMethod.surfaceScopes(
|
431
|
-
|
475
|
+
sessionPayload,
|
432
476
|
req
|
433
477
|
);
|
434
478
|
if (collapsedAuthorizationMethod.scopeHeirarchy) {
|
@@ -447,7 +491,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
447
491
|
return [500, "No permission surfacing function provided."];
|
448
492
|
}
|
449
493
|
const resourcePermissions = await collapsedAuthorizationMethod.surfacePermissions(
|
450
|
-
|
494
|
+
sessionPayload,
|
451
495
|
req
|
452
496
|
);
|
453
497
|
if ("allowedPermissions" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedPermissions) {
|
@@ -469,7 +513,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
469
513
|
return [500, "No role surfacing function provided."];
|
470
514
|
}
|
471
515
|
const resourceRoles = await collapsedAuthorizationMethod.surfaceRoles(
|
472
|
-
|
516
|
+
sessionPayload,
|
473
517
|
req
|
474
518
|
);
|
475
519
|
if ("allowedRoles" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedRoles) {
|
@@ -489,10 +533,10 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
489
533
|
async function parseRequestAuth(req, res, next) {
|
490
534
|
const auth = req.contractDetails.auth;
|
491
535
|
const [error, message] = await checkAuthorizationToken(
|
536
|
+
req,
|
492
537
|
auth,
|
493
|
-
req._globalOptions?.()?.auth,
|
494
538
|
req.headers[auth?.headerName ?? "Authorization"] || req.headers[auth?.headerName ?? "authorization"],
|
495
|
-
req
|
539
|
+
req._globalOptions?.()?.auth
|
496
540
|
) ?? [];
|
497
541
|
if (error != null) {
|
498
542
|
res.type("text/plain");
|
@@ -503,7 +547,7 @@ async function parseRequestAuth(req, res, next) {
|
|
503
547
|
}
|
504
548
|
|
505
549
|
// src/http/middleware/request/createContext.middleware.ts
|
506
|
-
var
|
550
|
+
var import_common4 = require("@forklaunch/common");
|
507
551
|
var import_api = require("@opentelemetry/api");
|
508
552
|
var import_uuid = require("uuid");
|
509
553
|
|
@@ -530,7 +574,7 @@ function createContext(schemaValidator) {
|
|
530
574
|
req.context.span?.setAttribute(ATTR_CORRELATION_ID, correlationId);
|
531
575
|
req.context.span?.setAttribute(
|
532
576
|
import_semantic_conventions.ATTR_SERVICE_NAME,
|
533
|
-
(0,
|
577
|
+
(0, import_common4.getEnvVar)("OTEL_SERVICE_NAME")
|
534
578
|
);
|
535
579
|
}
|
536
580
|
next?.();
|
@@ -538,10 +582,10 @@ function createContext(schemaValidator) {
|
|
538
582
|
}
|
539
583
|
|
540
584
|
// src/http/middleware/request/enrichDetails.middleware.ts
|
541
|
-
var
|
585
|
+
var import_common7 = require("@forklaunch/common");
|
542
586
|
|
543
587
|
// src/http/telemetry/openTelemetryCollector.ts
|
544
|
-
var
|
588
|
+
var import_common6 = require("@forklaunch/common");
|
545
589
|
var import_opentelemetry_instrumentation_hyper_express = require("@forklaunch/opentelemetry-instrumentation-hyper-express");
|
546
590
|
var import_api3 = require("@opentelemetry/api");
|
547
591
|
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
@@ -562,7 +606,7 @@ function isForklaunchRequest(request) {
|
|
562
606
|
}
|
563
607
|
|
564
608
|
// src/http/telemetry/pinoLogger.ts
|
565
|
-
var
|
609
|
+
var import_common5 = require("@forklaunch/common");
|
566
610
|
var import_api2 = require("@opentelemetry/api");
|
567
611
|
var import_api_logs = require("@opentelemetry/api-logs");
|
568
612
|
var import_pino = __toESM(require("pino"));
|
@@ -594,7 +638,7 @@ function mapSeverity(level) {
|
|
594
638
|
case "fatal":
|
595
639
|
return 21;
|
596
640
|
default:
|
597
|
-
(0,
|
641
|
+
(0, import_common5.isNever)(level);
|
598
642
|
return 0;
|
599
643
|
}
|
600
644
|
}
|
@@ -787,24 +831,24 @@ var OpenTelemetryCollector = class {
|
|
787
831
|
return this.metrics[metricId];
|
788
832
|
}
|
789
833
|
};
|
790
|
-
import_dotenv.default.config({ path: (0,
|
834
|
+
import_dotenv.default.config({ path: (0, import_common6.getEnvVar)("DOTENV_FILE_PATH") });
|
791
835
|
new import_sdk_node.NodeSDK({
|
792
836
|
resource: (0, import_resources.resourceFromAttributes)({
|
793
|
-
[import_semantic_conventions2.ATTR_SERVICE_NAME]: (0,
|
837
|
+
[import_semantic_conventions2.ATTR_SERVICE_NAME]: (0, import_common6.getEnvVar)("OTEL_SERVICE_NAME")
|
794
838
|
}),
|
795
839
|
traceExporter: new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
796
|
-
url: `${(0,
|
840
|
+
url: `${(0, import_common6.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
|
797
841
|
}),
|
798
842
|
metricReader: new import_sdk_metrics.PeriodicExportingMetricReader({
|
799
843
|
exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
800
|
-
url: `${(0,
|
844
|
+
url: `${(0, import_common6.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
|
801
845
|
}),
|
802
846
|
exportIntervalMillis: 5e3
|
803
847
|
}),
|
804
848
|
logRecordProcessors: [
|
805
849
|
new import_sdk_logs.BatchLogRecordProcessor(
|
806
850
|
new import_exporter_logs_otlp_http.OTLPLogExporter({
|
807
|
-
url: `${(0,
|
851
|
+
url: `${(0, import_common6.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
|
808
852
|
})
|
809
853
|
)
|
810
854
|
],
|
@@ -813,7 +857,7 @@ new import_sdk_node.NodeSDK({
|
|
813
857
|
applyCustomAttributesOnSpan: (span, request) => {
|
814
858
|
span.setAttribute(
|
815
859
|
import_semantic_conventions2.ATTR_SERVICE_NAME,
|
816
|
-
(0,
|
860
|
+
(0, import_common6.getEnvVar)("OTEL_SERVICE_NAME") ?? "unknown"
|
817
861
|
);
|
818
862
|
if (isForklaunchRequest(request)) {
|
819
863
|
span.setAttribute(ATTR_API_NAME, request.contractDetails?.name);
|
@@ -825,10 +869,10 @@ new import_sdk_node.NodeSDK({
|
|
825
869
|
new import_opentelemetry_instrumentation_hyper_express.HyperExpressInstrumentation()
|
826
870
|
]
|
827
871
|
}).start();
|
828
|
-
var httpRequestsTotalCounter = import_api3.metrics.getMeter((0,
|
872
|
+
var httpRequestsTotalCounter = import_api3.metrics.getMeter((0, import_common6.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
829
873
|
description: "Number of HTTP requests"
|
830
874
|
});
|
831
|
-
var httpServerDurationHistogram = import_api3.metrics.getMeter((0,
|
875
|
+
var httpServerDurationHistogram = import_api3.metrics.getMeter((0, import_common6.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createHistogram("http_server_duration", {
|
832
876
|
description: "Duration of HTTP server requests",
|
833
877
|
unit: "s"
|
834
878
|
});
|
@@ -848,7 +892,7 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
848
892
|
const [seconds, nanoseconds] = process.hrtime(startTime);
|
849
893
|
const durationMs = seconds + nanoseconds / 1e9;
|
850
894
|
httpServerDurationHistogram.record(durationMs, {
|
851
|
-
[import_semantic_conventions.ATTR_SERVICE_NAME]: (0,
|
895
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: (0, import_common7.getEnvVar)("OTEL_SERVICE_NAME") || "unknown",
|
852
896
|
[ATTR_API_NAME]: req.contractDetails?.name || "unknown",
|
853
897
|
[import_semantic_conventions.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
854
898
|
[import_semantic_conventions.ATTR_HTTP_ROUTE]: req.originalPath || "unknown",
|
@@ -860,8 +904,8 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
860
904
|
}
|
861
905
|
|
862
906
|
// src/http/middleware/request/parse.middleware.ts
|
863
|
-
var
|
864
|
-
var
|
907
|
+
var import_common8 = require("@forklaunch/common");
|
908
|
+
var import_validator2 = require("@forklaunch/validator");
|
865
909
|
|
866
910
|
// src/http/guards/hasSend.ts
|
867
911
|
function hasSend(res) {
|
@@ -888,7 +932,7 @@ function parse(req, res, next) {
|
|
888
932
|
let parsedRequest;
|
889
933
|
let collectedParseErrors;
|
890
934
|
if (req.contractDetails.versions) {
|
891
|
-
if ((0,
|
935
|
+
if ((0, import_common8.isRecord)(req.requestSchema)) {
|
892
936
|
let runningParseErrors = "";
|
893
937
|
matchedVersions = [];
|
894
938
|
Object.entries(req.requestSchema).forEach(([version, schema]) => {
|
@@ -899,7 +943,7 @@ function parse(req, res, next) {
|
|
899
943
|
req.version = version;
|
900
944
|
res.version = req.version;
|
901
945
|
} else {
|
902
|
-
runningParseErrors += (0,
|
946
|
+
runningParseErrors += (0, import_validator2.prettyPrintParseErrors)(
|
903
947
|
parsingResult.errors,
|
904
948
|
`Version ${version} request`
|
905
949
|
);
|
@@ -957,7 +1001,7 @@ function parse(req, res, next) {
|
|
957
1001
|
res.status(400);
|
958
1002
|
if (hasSend(res)) {
|
959
1003
|
res.send(
|
960
|
-
`${collectedParseErrors ?? (0,
|
1004
|
+
`${collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")}
|
961
1005
|
|
962
1006
|
Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
963
1007
|
);
|
@@ -967,7 +1011,7 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
967
1011
|
return;
|
968
1012
|
case "warning":
|
969
1013
|
req.openTelemetryCollector.warn(
|
970
|
-
collectedParseErrors ?? (0,
|
1014
|
+
collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")
|
971
1015
|
);
|
972
1016
|
break;
|
973
1017
|
case "none":
|
@@ -1280,13 +1324,13 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1280
1324
|
versionedContractDetails,
|
1281
1325
|
contractDetails.params
|
1282
1326
|
);
|
1283
|
-
if ((0,
|
1327
|
+
if ((0, import_common9.isRecord)(requestSchema)) {
|
1284
1328
|
requestSchema = {
|
1285
1329
|
...requestSchema,
|
1286
1330
|
[version]: versionedRequestSchema
|
1287
1331
|
};
|
1288
1332
|
}
|
1289
|
-
if ((0,
|
1333
|
+
if ((0, import_common9.isRecord)(responseSchemas)) {
|
1290
1334
|
responseSchemas = {
|
1291
1335
|
...responseSchemas,
|
1292
1336
|
[version]: versionedResponseSchemas
|
@@ -1475,8 +1519,8 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1475
1519
|
...resolvedMiddlewares,
|
1476
1520
|
this.#parseAndRunControllerHandler(controllerHandler)
|
1477
1521
|
);
|
1478
|
-
(0,
|
1479
|
-
...this._fetchMap[(0,
|
1522
|
+
(0, import_common9.toRecord)(this._fetchMap)[(0, import_common9.sanitizePathSlashes)(`${this.basePath}${path}`)] = {
|
1523
|
+
...this._fetchMap[(0, import_common9.sanitizePathSlashes)(`${this.basePath}${path}`)] ?? {},
|
1480
1524
|
[method.toUpperCase()]: contractDetails.versions ? Object.fromEntries(
|
1481
1525
|
Object.keys(contractDetails.versions).map((version) => [
|
1482
1526
|
version,
|
@@ -1484,7 +1528,7 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1484
1528
|
])
|
1485
1529
|
) : this.#localParamRequest(handlers, controllerHandler)
|
1486
1530
|
};
|
1487
|
-
(0,
|
1531
|
+
(0, import_common9.toRecord)(this.sdk)[(0, import_common9.toPrettyCamelCase)(contractDetails.name)] = contractDetails.versions ? Object.fromEntries(
|
1488
1532
|
Object.keys(contractDetails.versions).map((version) => [
|
1489
1533
|
version,
|
1490
1534
|
(req) => this.#localParamRequest(
|
@@ -1583,10 +1627,10 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1583
1627
|
}
|
1584
1628
|
addRouterToSdk(router) {
|
1585
1629
|
Object.entries(router._fetchMap).map(
|
1586
|
-
([key, value]) => (0,
|
1630
|
+
([key, value]) => (0, import_common9.toRecord)(this._fetchMap)[(0, import_common9.sanitizePathSlashes)(`${this.basePath}${key}`)] = value
|
1587
1631
|
);
|
1588
|
-
const existingSdk = this.sdk[router.sdkName ?? (0,
|
1589
|
-
(0,
|
1632
|
+
const existingSdk = this.sdk[router.sdkName ?? (0, import_common9.toPrettyCamelCase)(router.basePath)];
|
1633
|
+
(0, import_common9.toRecord)(this.sdk)[router.sdkName ?? (0, import_common9.toPrettyCamelCase)(router.basePath)] = {
|
1590
1634
|
...typeof existingSdk === "object" ? existingSdk : {},
|
1591
1635
|
...router.sdk
|
1592
1636
|
};
|
@@ -2985,7 +3029,7 @@ var getCodeForStatus = (status) => {
|
|
2985
3029
|
var httpStatusCodes_default = HTTPStatuses;
|
2986
3030
|
|
2987
3031
|
// src/http/mcpGenerator/mcpGenerator.ts
|
2988
|
-
var
|
3032
|
+
var import_common10 = require("@forklaunch/common");
|
2989
3033
|
var import_fastmcp_fork = require("@forklaunch/fastmcp-fork");
|
2990
3034
|
var import_zod = require("@forklaunch/validator/zod");
|
2991
3035
|
|
@@ -3122,7 +3166,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3122
3166
|
if (discriminatedBody) {
|
3123
3167
|
switch (discriminatedBody.parserType) {
|
3124
3168
|
case "json": {
|
3125
|
-
parsedBody = (0,
|
3169
|
+
parsedBody = (0, import_common10.safeStringify)(body);
|
3126
3170
|
break;
|
3127
3171
|
}
|
3128
3172
|
case "text": {
|
@@ -3135,7 +3179,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3135
3179
|
}
|
3136
3180
|
case "multipart": {
|
3137
3181
|
const formData = new FormData();
|
3138
|
-
if ((0,
|
3182
|
+
if ((0, import_common10.isRecord)(body)) {
|
3139
3183
|
for (const key in body) {
|
3140
3184
|
if (typeof body[key] === "string" || body[key] instanceof Blob) {
|
3141
3185
|
formData.append(key, body[key]);
|
@@ -3150,11 +3194,11 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3150
3194
|
break;
|
3151
3195
|
}
|
3152
3196
|
case "urlEncoded": {
|
3153
|
-
if ((0,
|
3197
|
+
if ((0, import_common10.isRecord)(body)) {
|
3154
3198
|
parsedBody = new URLSearchParams(
|
3155
3199
|
Object.entries(body).map(([key, value]) => [
|
3156
3200
|
key,
|
3157
|
-
(0,
|
3201
|
+
(0, import_common10.safeStringify)(value)
|
3158
3202
|
])
|
3159
3203
|
);
|
3160
3204
|
} else {
|
@@ -3163,8 +3207,8 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3163
3207
|
break;
|
3164
3208
|
}
|
3165
3209
|
default: {
|
3166
|
-
(0,
|
3167
|
-
parsedBody = (0,
|
3210
|
+
(0, import_common10.isNever)(discriminatedBody.parserType);
|
3211
|
+
parsedBody = (0, import_common10.safeStringify)(body);
|
3168
3212
|
break;
|
3169
3213
|
}
|
3170
3214
|
}
|
@@ -3173,7 +3217,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3173
3217
|
const queryString = new URLSearchParams(
|
3174
3218
|
Object.entries(query).map(([key, value]) => [
|
3175
3219
|
key,
|
3176
|
-
(0,
|
3220
|
+
(0, import_common10.safeStringify)(value)
|
3177
3221
|
])
|
3178
3222
|
).toString();
|
3179
3223
|
url += queryString ? `?${queryString}` : "";
|
@@ -3206,7 +3250,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3206
3250
|
content: [
|
3207
3251
|
{
|
3208
3252
|
type: "text",
|
3209
|
-
text: (0,
|
3253
|
+
text: (0, import_common10.safeStringify)(await response.json())
|
3210
3254
|
}
|
3211
3255
|
]
|
3212
3256
|
};
|
@@ -3251,7 +3295,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3251
3295
|
}
|
3252
3296
|
|
3253
3297
|
// src/http/middleware/response/parse.middleware.ts
|
3254
|
-
var
|
3298
|
+
var import_validator3 = require("@forklaunch/validator");
|
3255
3299
|
|
3256
3300
|
// src/http/guards/isResponseCompiledSchema.ts
|
3257
3301
|
function isResponseCompiledSchema(schema) {
|
@@ -3312,13 +3356,13 @@ function parse2(req, res, next) {
|
|
3312
3356
|
);
|
3313
3357
|
const parseErrors = [];
|
3314
3358
|
if (!parsedHeaders.ok) {
|
3315
|
-
const headerErrors = (0,
|
3359
|
+
const headerErrors = (0, import_validator3.prettyPrintParseErrors)(parsedHeaders.errors, "Header");
|
3316
3360
|
if (headerErrors) {
|
3317
3361
|
parseErrors.push(headerErrors);
|
3318
3362
|
}
|
3319
3363
|
}
|
3320
3364
|
if (!parsedResponse.ok) {
|
3321
|
-
const responseErrors = (0,
|
3365
|
+
const responseErrors = (0, import_validator3.prettyPrintParseErrors)(
|
3322
3366
|
parsedResponse.errors,
|
3323
3367
|
"Response"
|
3324
3368
|
);
|
@@ -3360,18 +3404,18 @@ ${parseErrors.join("\n\n")}`
|
|
3360
3404
|
}
|
3361
3405
|
|
3362
3406
|
// src/http/middleware/response/enrichExpressLikeSend.middleware.ts
|
3363
|
-
var
|
3407
|
+
var import_common12 = require("@forklaunch/common");
|
3364
3408
|
var import_stream = require("stream");
|
3365
3409
|
|
3366
3410
|
// src/http/telemetry/recordMetric.ts
|
3367
|
-
var
|
3411
|
+
var import_common11 = require("@forklaunch/common");
|
3368
3412
|
var import_semantic_conventions3 = require("@opentelemetry/semantic-conventions");
|
3369
3413
|
function recordMetric(req, res) {
|
3370
3414
|
if (res.metricRecorded) {
|
3371
3415
|
return;
|
3372
3416
|
}
|
3373
3417
|
httpRequestsTotalCounter.add(1, {
|
3374
|
-
[import_semantic_conventions3.ATTR_SERVICE_NAME]: (0,
|
3418
|
+
[import_semantic_conventions3.ATTR_SERVICE_NAME]: (0, import_common11.getEnvVar)("OTEL_SERVICE_NAME"),
|
3375
3419
|
[ATTR_API_NAME]: req.contractDetails?.name,
|
3376
3420
|
[import_semantic_conventions3.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
3377
3421
|
[import_semantic_conventions3.ATTR_HTTP_ROUTE]: req.originalPath,
|
@@ -3420,8 +3464,8 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
3420
3464
|
`attachment; filename="${data.name}"`
|
3421
3465
|
);
|
3422
3466
|
}
|
3423
|
-
if ((0,
|
3424
|
-
import_stream.Readable.from((0,
|
3467
|
+
if ((0, import_common12.isNodeJsWriteableStream)(res)) {
|
3468
|
+
import_stream.Readable.from((0, import_common12.readableStreamToAsyncIterable)(data.stream())).pipe(
|
3425
3469
|
res
|
3426
3470
|
);
|
3427
3471
|
} else {
|
@@ -3430,7 +3474,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
3430
3474
|
originalSend.call(instance, "Not a NodeJS WritableStream");
|
3431
3475
|
errorSent = true;
|
3432
3476
|
}
|
3433
|
-
} else if ((0,
|
3477
|
+
} else if ((0, import_common12.isAsyncGenerator)(data)) {
|
3434
3478
|
let firstPass = true;
|
3435
3479
|
const transformer = new import_stream.Transform({
|
3436
3480
|
objectMode: true,
|
@@ -3458,7 +3502,7 @@ ${res.locals.errorMessage}`;
|
|
3458
3502
|
if (!errorSent) {
|
3459
3503
|
let data2 = "";
|
3460
3504
|
for (const [key, value] of Object.entries(chunk)) {
|
3461
|
-
data2 += `${key}: ${typeof value === "string" ? value : (0,
|
3505
|
+
data2 += `${key}: ${typeof value === "string" ? value : (0, import_common12.safeStringify)(value)}
|
3462
3506
|
`;
|
3463
3507
|
}
|
3464
3508
|
data2 += "\n";
|
@@ -3466,7 +3510,7 @@ ${res.locals.errorMessage}`;
|
|
3466
3510
|
}
|
3467
3511
|
}
|
3468
3512
|
});
|
3469
|
-
if ((0,
|
3513
|
+
if ((0, import_common12.isNodeJsWriteableStream)(res)) {
|
3470
3514
|
import_stream.Readable.from(data).pipe(transformer).pipe(res);
|
3471
3515
|
} else {
|
3472
3516
|
res.type("text/plain");
|
@@ -3477,7 +3521,7 @@ ${res.locals.errorMessage}`;
|
|
3477
3521
|
} else {
|
3478
3522
|
const parserType = responseBodies?.[Number(res.statusCode)]?.parserType;
|
3479
3523
|
res.bodyData = data;
|
3480
|
-
if ((0,
|
3524
|
+
if ((0, import_common12.isRecord)(data)) {
|
3481
3525
|
switch (parserType) {
|
3482
3526
|
case "json":
|
3483
3527
|
res.bodyData = "json" in data ? data.json : data;
|
@@ -3498,7 +3542,7 @@ ${res.locals.errorMessage}`;
|
|
3498
3542
|
res.bodyData = data;
|
3499
3543
|
break;
|
3500
3544
|
default:
|
3501
|
-
(0,
|
3545
|
+
(0, import_common12.isNever)(parserType);
|
3502
3546
|
res.bodyData = data;
|
3503
3547
|
break;
|
3504
3548
|
}
|
@@ -3534,7 +3578,7 @@ ${res.locals.errorMessage}`;
|
|
3534
3578
|
}
|
3535
3579
|
|
3536
3580
|
// src/http/openApiV3Generator/openApiV3Generator.ts
|
3537
|
-
var
|
3581
|
+
var import_common13 = require("@forklaunch/common");
|
3538
3582
|
var OPENAPI_DEFAULT_VERSION = Symbol("default");
|
3539
3583
|
function toUpperCase(str) {
|
3540
3584
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
@@ -3757,7 +3801,7 @@ function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, a
|
|
3757
3801
|
].forEach(({ fullPath, router }) => {
|
3758
3802
|
const controllerName = transformBasePath(fullPath);
|
3759
3803
|
router.routes.forEach((route) => {
|
3760
|
-
const openApiPath = (0,
|
3804
|
+
const openApiPath = (0, import_common13.openApiCompliantPath)(
|
3761
3805
|
`${fullPath}${route.path === "/" ? "" : route.path}`
|
3762
3806
|
);
|
3763
3807
|
const { name, summary, params, versions, auth, options: options2 } = route.contractDetails;
|
@@ -3862,7 +3906,7 @@ function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, a
|
|
3862
3906
|
}
|
3863
3907
|
|
3864
3908
|
// src/http/sdk/sdkClient.ts
|
3865
|
-
var
|
3909
|
+
var import_common14 = require("@forklaunch/common");
|
3866
3910
|
|
3867
3911
|
// src/http/guards/isSdkRouter.ts
|
3868
3912
|
function isSdkRouter(value) {
|
@@ -3874,12 +3918,12 @@ function mapToSdk(schemaValidator, routerMap, runningPath = void 0) {
|
|
3874
3918
|
const routerUniquenessCache = /* @__PURE__ */ new Set();
|
3875
3919
|
return Object.fromEntries(
|
3876
3920
|
Object.entries(routerMap).map(([key, value]) => {
|
3877
|
-
if (routerUniquenessCache.has((0,
|
3921
|
+
if (routerUniquenessCache.has((0, import_common14.hashString)((0, import_common14.safeStringify)(value)))) {
|
3878
3922
|
throw new Error(
|
3879
3923
|
`SdkClient: Cannot use the same router pointer twice. Please clone the duplicate router with .clone() or only use the router once.`
|
3880
3924
|
);
|
3881
3925
|
}
|
3882
|
-
routerUniquenessCache.add((0,
|
3926
|
+
routerUniquenessCache.add((0, import_common14.hashString)((0, import_common14.safeStringify)(value)));
|
3883
3927
|
const currentPath = runningPath ? [runningPath, key].join(".") : key;
|
3884
3928
|
if (isSdkRouter(value)) {
|
3885
3929
|
Object.entries(value.sdkPaths).forEach(([routePath, sdkKey]) => {
|
@@ -3928,19 +3972,43 @@ function mapToFetch(schemaValidator, routerMap) {
|
|
3928
3972
|
return ((path, ...reqInit) => {
|
3929
3973
|
const method = reqInit[0]?.method;
|
3930
3974
|
const version = reqInit[0] != null && "version" in reqInit[0] ? reqInit[0].version : void 0;
|
3931
|
-
return (version ? (0,
|
3975
|
+
return (version ? (0, import_common14.toRecord)((0, import_common14.toRecord)(flattenedFetchMap[path])[method ?? "GET"])[version] : (0, import_common14.toRecord)(flattenedFetchMap[path])[method ?? "GET"])(path, reqInit[0]);
|
3932
3976
|
});
|
3933
3977
|
}
|
3934
|
-
function sdkClient(schemaValidator, routerMap) {
|
3935
|
-
|
3978
|
+
function sdkClient(schemaValidator, routerMap, options2) {
|
3979
|
+
if (options2?.lazyEvaluation) {
|
3980
|
+
let _sdk;
|
3981
|
+
let _fetch;
|
3982
|
+
const lazyClient = {
|
3983
|
+
_finalizedSdk: true,
|
3984
|
+
get sdk() {
|
3985
|
+
if (!_sdk) {
|
3986
|
+
_sdk = mapToSdk(schemaValidator, routerMap);
|
3987
|
+
}
|
3988
|
+
return _sdk;
|
3989
|
+
},
|
3990
|
+
get fetch() {
|
3991
|
+
if (!_fetch) {
|
3992
|
+
_fetch = mapToFetch(schemaValidator, routerMap);
|
3993
|
+
}
|
3994
|
+
return _fetch;
|
3995
|
+
}
|
3996
|
+
};
|
3997
|
+
return lazyClient;
|
3998
|
+
}
|
3999
|
+
const client = {
|
3936
4000
|
_finalizedSdk: true,
|
3937
4001
|
sdk: mapToSdk(schemaValidator, routerMap),
|
3938
4002
|
fetch: mapToFetch(schemaValidator, routerMap)
|
3939
4003
|
};
|
4004
|
+
if (options2?.optimizePerformance) {
|
4005
|
+
return client;
|
4006
|
+
}
|
4007
|
+
return client;
|
3940
4008
|
}
|
3941
4009
|
|
3942
4010
|
// src/http/sdk/sdkRouter.ts
|
3943
|
-
var
|
4011
|
+
var import_common15 = require("@forklaunch/common");
|
3944
4012
|
function sdkRouter(schemaValidator, controller, router) {
|
3945
4013
|
const controllerSdkPaths = [];
|
3946
4014
|
const mappedSdk = Object.fromEntries(
|
@@ -3950,7 +4018,7 @@ function sdkRouter(schemaValidator, controller, router) {
|
|
3950
4018
|
router.sdkPaths[sdkPath] = key;
|
3951
4019
|
return [
|
3952
4020
|
key,
|
3953
|
-
router.sdk[(0,
|
4021
|
+
router.sdk[(0, import_common15.toPrettyCamelCase)(value.contractDetails.name)]
|
3954
4022
|
];
|
3955
4023
|
})
|
3956
4024
|
);
|