@forklaunch/core 0.10.4 → 0.11.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 +118 -121
- package/lib/http/index.d.ts +118 -121
- package/lib/http/index.js +180 -99
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +141 -61
- package/lib/http/index.mjs.map +1 -1
- package/package.json +19 -19
package/lib/http/index.js
CHANGED
@@ -70,6 +70,7 @@ __export(http_exports, {
|
|
70
70
|
put: () => put,
|
71
71
|
recordMetric: () => recordMetric,
|
72
72
|
trace: () => trace3,
|
73
|
+
typedAuthHandler: () => typedAuthHandler,
|
73
74
|
typedHandler: () => typedHandler
|
74
75
|
});
|
75
76
|
module.exports = __toCommonJS(http_exports);
|
@@ -92,7 +93,7 @@ function cors(corsOptions) {
|
|
92
93
|
}
|
93
94
|
|
94
95
|
// src/http/router/expressLikeRouter.ts
|
95
|
-
var
|
96
|
+
var import_common6 = require("@forklaunch/common");
|
96
97
|
|
97
98
|
// src/http/guards/isForklaunchRouter.ts
|
98
99
|
function isForklaunchRouter(maybeForklaunchRouter) {
|
@@ -138,7 +139,47 @@ function isTypedHandler(maybeTypedHandler) {
|
|
138
139
|
}
|
139
140
|
|
140
141
|
// src/http/middleware/request/auth.middleware.ts
|
142
|
+
var import_common2 = require("@forklaunch/common");
|
141
143
|
var import_jose = require("jose");
|
144
|
+
|
145
|
+
// src/http/discriminateAuthMethod.ts
|
146
|
+
function discriminateAuthMethod(auth) {
|
147
|
+
if ("basic" in auth) {
|
148
|
+
return {
|
149
|
+
type: "basic",
|
150
|
+
auth: {
|
151
|
+
decodeResource: auth.decodeResource,
|
152
|
+
login: auth.basic.login
|
153
|
+
}
|
154
|
+
};
|
155
|
+
} else if ("jwt" in auth) {
|
156
|
+
return {
|
157
|
+
type: "jwt",
|
158
|
+
auth: {
|
159
|
+
decodeResource: auth.decodeResource
|
160
|
+
}
|
161
|
+
};
|
162
|
+
} else {
|
163
|
+
return {
|
164
|
+
type: "jwt",
|
165
|
+
auth: {
|
166
|
+
decodeResource: auth.decodeResource
|
167
|
+
}
|
168
|
+
};
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
// src/http/guards/hasPermissionChecks.ts
|
173
|
+
function hasPermissionChecks(maybePermissionedAuth) {
|
174
|
+
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && "mapPermissions" in maybePermissionedAuth && ("allowedPermissions" in maybePermissionedAuth || "forbiddenPermissions" in maybePermissionedAuth);
|
175
|
+
}
|
176
|
+
|
177
|
+
// src/http/guards/hasRoleChecks.ts
|
178
|
+
function hasRoleChecks(maybeRoledAuth) {
|
179
|
+
return typeof maybeRoledAuth === "object" && maybeRoledAuth !== null && "mapRoles" in maybeRoledAuth && ("allowedRoles" in maybeRoledAuth || "forbiddenRoles" in maybeRoledAuth);
|
180
|
+
}
|
181
|
+
|
182
|
+
// src/http/middleware/request/auth.middleware.ts
|
142
183
|
var invalidAuthorizationTokenFormat = [
|
143
184
|
401,
|
144
185
|
"Invalid Authorization token format."
|
@@ -169,51 +210,52 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
169
210
|
}
|
170
211
|
const [tokenPrefix, token] = authorizationToken.split(" ");
|
171
212
|
let resourceId;
|
172
|
-
|
213
|
+
const { type, auth } = discriminateAuthMethod(authorizationMethod);
|
214
|
+
switch (type) {
|
173
215
|
case "jwt": {
|
174
|
-
if (tokenPrefix !== "Bearer") {
|
216
|
+
if (tokenPrefix !== (authorizationMethod.tokenPrefix ?? "Bearer")) {
|
175
217
|
return invalidAuthorizationTokenFormat;
|
176
218
|
}
|
177
219
|
try {
|
178
|
-
const decodedJwt = await (0, import_jose.jwtVerify)(
|
220
|
+
const decodedJwt = await auth?.decodeResource?.(token) ?? (await (0, import_jose.jwtVerify)(
|
179
221
|
token,
|
180
|
-
new TextEncoder().encode(
|
181
|
-
|
182
|
-
|
183
|
-
)
|
184
|
-
);
|
185
|
-
if (!decodedJwt.payload.sub) {
|
222
|
+
new TextEncoder().encode(process.env.JWT_SECRET)
|
223
|
+
)).payload;
|
224
|
+
if (!decodedJwt) {
|
186
225
|
return invalidAuthorizationSubject;
|
187
226
|
}
|
188
|
-
resourceId = decodedJwt
|
227
|
+
resourceId = decodedJwt;
|
189
228
|
} catch (error) {
|
190
|
-
req
|
229
|
+
req?.openTelemetryCollector.error(error);
|
191
230
|
return invalidAuthorizationToken;
|
192
231
|
}
|
193
232
|
break;
|
194
233
|
}
|
195
234
|
case "basic": {
|
196
|
-
if (
|
197
|
-
return invalidAuthorizationTokenFormat;
|
198
|
-
}
|
199
|
-
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
200
|
-
if (!username || !password) {
|
235
|
+
if (tokenPrefix !== (authorizationMethod.tokenPrefix ?? "Basic")) {
|
201
236
|
return invalidAuthorizationTokenFormat;
|
202
237
|
}
|
203
|
-
if (
|
204
|
-
|
238
|
+
if (auth.decodeResource) {
|
239
|
+
resourceId = await auth.decodeResource(token);
|
240
|
+
} else {
|
241
|
+
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
242
|
+
if (!username || !password) {
|
243
|
+
return invalidAuthorizationTokenFormat;
|
244
|
+
}
|
245
|
+
if (!auth.login(username, password)) {
|
246
|
+
return invalidAuthorizationLogin;
|
247
|
+
}
|
248
|
+
resourceId = {
|
249
|
+
sub: username
|
250
|
+
};
|
205
251
|
}
|
206
|
-
resourceId = username;
|
207
252
|
break;
|
208
253
|
}
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
}
|
213
|
-
resourceId = authorizationMethod.decodeResource(token);
|
214
|
-
break;
|
254
|
+
default:
|
255
|
+
(0, import_common2.isNever)(type);
|
256
|
+
return [401, "Invalid Authorization method."];
|
215
257
|
}
|
216
|
-
if (authorizationMethod
|
258
|
+
if (hasPermissionChecks(authorizationMethod)) {
|
217
259
|
if (!authorizationMethod.mapPermissions) {
|
218
260
|
return [500, "No permission mapping function provided."];
|
219
261
|
}
|
@@ -221,49 +263,49 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
221
263
|
resourceId,
|
222
264
|
req
|
223
265
|
);
|
224
|
-
if (authorizationMethod.allowedPermissions) {
|
266
|
+
if ("allowedPermissions" in authorizationMethod && authorizationMethod.allowedPermissions) {
|
225
267
|
if (resourcePermissions.intersection(authorizationMethod.allowedPermissions).size === 0) {
|
226
268
|
return invalidAuthorizationTokenPermissions;
|
227
269
|
}
|
228
270
|
}
|
229
|
-
if (authorizationMethod.forbiddenPermissions) {
|
271
|
+
if ("forbiddenPermissions" in authorizationMethod && authorizationMethod.forbiddenPermissions) {
|
230
272
|
if (resourcePermissions.intersection(
|
231
273
|
authorizationMethod.forbiddenPermissions
|
232
274
|
).size !== 0) {
|
233
275
|
return invalidAuthorizationTokenPermissions;
|
234
276
|
}
|
235
277
|
}
|
236
|
-
}
|
237
|
-
if (authorizationMethod.allowedRoles || authorizationMethod.forbiddenRoles) {
|
278
|
+
} else if (hasRoleChecks(authorizationMethod)) {
|
238
279
|
if (!authorizationMethod.mapRoles) {
|
239
280
|
return [500, "No role mapping function provided."];
|
240
281
|
}
|
241
282
|
const resourceRoles = await authorizationMethod.mapRoles(resourceId, req);
|
242
|
-
if (authorizationMethod.allowedRoles) {
|
283
|
+
if ("allowedRoles" in authorizationMethod && authorizationMethod.allowedRoles) {
|
243
284
|
if (resourceRoles.intersection(authorizationMethod.allowedRoles).size === 0) {
|
244
285
|
return invalidAuthorizationTokenRoles;
|
245
286
|
}
|
246
287
|
}
|
247
|
-
if (authorizationMethod.forbiddenRoles) {
|
288
|
+
if ("forbiddenRoles" in authorizationMethod && authorizationMethod.forbiddenRoles) {
|
248
289
|
if (resourceRoles.intersection(authorizationMethod.forbiddenRoles).size !== 0) {
|
249
290
|
return invalidAuthorizationTokenRoles;
|
250
291
|
}
|
251
292
|
}
|
293
|
+
} else {
|
294
|
+
return [401, "Invalid Authorization method."];
|
252
295
|
}
|
253
|
-
return [401, "Invalid Authorization method."];
|
254
296
|
}
|
255
297
|
async function parseRequestAuth(req, res, next) {
|
256
298
|
const auth = req.contractDetails.auth;
|
257
299
|
if (auth) {
|
258
300
|
const [error, message] = await checkAuthorizationToken(
|
259
301
|
auth,
|
260
|
-
req.headers[
|
302
|
+
req.headers[auth.headerName ?? "Authorization"] || req.headers[auth.headerName ?? "authorization"],
|
261
303
|
req
|
262
304
|
) ?? [];
|
263
305
|
if (error != null) {
|
264
306
|
res.type("text/plain");
|
265
307
|
res.status(error).send(message);
|
266
|
-
|
308
|
+
return;
|
267
309
|
}
|
268
310
|
}
|
269
311
|
next?.();
|
@@ -300,10 +342,10 @@ function createContext(schemaValidator) {
|
|
300
342
|
}
|
301
343
|
|
302
344
|
// src/http/middleware/request/enrichDetails.middleware.ts
|
303
|
-
var
|
345
|
+
var import_common5 = require("@forklaunch/common");
|
304
346
|
|
305
347
|
// src/http/telemetry/openTelemetryCollector.ts
|
306
|
-
var
|
348
|
+
var import_common4 = require("@forklaunch/common");
|
307
349
|
var import_opentelemetry_instrumentation_hyper_express = require("@forklaunch/opentelemetry-instrumentation-hyper-express");
|
308
350
|
var import_api3 = require("@opentelemetry/api");
|
309
351
|
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
@@ -325,7 +367,7 @@ function isForklaunchRequest(request) {
|
|
325
367
|
}
|
326
368
|
|
327
369
|
// src/http/telemetry/pinoLogger.ts
|
328
|
-
var
|
370
|
+
var import_common3 = require("@forklaunch/common");
|
329
371
|
var import_api2 = require("@opentelemetry/api");
|
330
372
|
var import_api_logs = require("@opentelemetry/api-logs");
|
331
373
|
var import_pino = __toESM(require("pino"));
|
@@ -357,7 +399,7 @@ function mapSeverity(level) {
|
|
357
399
|
case "fatal":
|
358
400
|
return 21;
|
359
401
|
default:
|
360
|
-
(0,
|
402
|
+
(0, import_common3.isNever)(level);
|
361
403
|
return 0;
|
362
404
|
}
|
363
405
|
}
|
@@ -391,7 +433,7 @@ var PinoLogger = class _PinoLogger {
|
|
391
433
|
return false;
|
392
434
|
}
|
393
435
|
return true;
|
394
|
-
}).map(
|
436
|
+
}).map(import_common3.safeStringify);
|
395
437
|
const activeSpan = import_api2.trace.getActiveSpan();
|
396
438
|
if (activeSpan) {
|
397
439
|
const activeSpanContext = activeSpan.spanContext();
|
@@ -497,24 +539,24 @@ var OpenTelemetryCollector = class {
|
|
497
539
|
return this.metrics[metricId];
|
498
540
|
}
|
499
541
|
};
|
500
|
-
import_dotenv.default.config({ path: (0,
|
542
|
+
import_dotenv.default.config({ path: (0, import_common4.getEnvVar)("DOTENV_FILE_PATH") });
|
501
543
|
new import_sdk_node.NodeSDK({
|
502
544
|
resource: (0, import_resources.resourceFromAttributes)({
|
503
|
-
[import_semantic_conventions2.ATTR_SERVICE_NAME]: (0,
|
545
|
+
[import_semantic_conventions2.ATTR_SERVICE_NAME]: (0, import_common4.getEnvVar)("OTEL_SERVICE_NAME")
|
504
546
|
}),
|
505
547
|
traceExporter: new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
506
|
-
url: `${(0,
|
548
|
+
url: `${(0, import_common4.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
|
507
549
|
}),
|
508
550
|
metricReader: new import_sdk_metrics.PeriodicExportingMetricReader({
|
509
551
|
exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
510
|
-
url: `${(0,
|
552
|
+
url: `${(0, import_common4.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
|
511
553
|
}),
|
512
554
|
exportIntervalMillis: 5e3
|
513
555
|
}),
|
514
556
|
logRecordProcessors: [
|
515
557
|
new import_sdk_logs.BatchLogRecordProcessor(
|
516
558
|
new import_exporter_logs_otlp_http.OTLPLogExporter({
|
517
|
-
url: `${(0,
|
559
|
+
url: `${(0, import_common4.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
|
518
560
|
})
|
519
561
|
)
|
520
562
|
],
|
@@ -523,7 +565,7 @@ new import_sdk_node.NodeSDK({
|
|
523
565
|
applyCustomAttributesOnSpan: (span, request) => {
|
524
566
|
span.setAttribute(
|
525
567
|
"service.name",
|
526
|
-
(0,
|
568
|
+
(0, import_common4.getEnvVar)("OTEL_SERVICE_NAME") ?? "unknown"
|
527
569
|
);
|
528
570
|
if (isForklaunchRequest(request)) {
|
529
571
|
span.setAttribute("api.name", request.contractDetails?.name);
|
@@ -534,10 +576,10 @@ new import_sdk_node.NodeSDK({
|
|
534
576
|
new import_opentelemetry_instrumentation_hyper_express.HyperExpressInstrumentation()
|
535
577
|
]
|
536
578
|
}).start();
|
537
|
-
var httpRequestsTotalCounter = import_api3.metrics.getMeter((0,
|
579
|
+
var httpRequestsTotalCounter = import_api3.metrics.getMeter((0, import_common4.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
538
580
|
description: "Number of HTTP requests"
|
539
581
|
});
|
540
|
-
var httpServerDurationHistogram = import_api3.metrics.getMeter((0,
|
582
|
+
var httpServerDurationHistogram = import_api3.metrics.getMeter((0, import_common4.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createHistogram("http_server_duration", {
|
541
583
|
description: "Duration of HTTP server requests",
|
542
584
|
unit: "s"
|
543
585
|
});
|
@@ -556,7 +598,7 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
556
598
|
const [seconds, nanoseconds] = process.hrtime(startTime);
|
557
599
|
const durationMs = seconds + nanoseconds / 1e9;
|
558
600
|
httpServerDurationHistogram.record(durationMs, {
|
559
|
-
[import_semantic_conventions.ATTR_SERVICE_NAME]: (0,
|
601
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: (0, import_common5.getEnvVar)("OTEL_SERVICE_NAME") || "unknown",
|
560
602
|
[ATTR_API_NAME]: req.contractDetails?.name || "unknown",
|
561
603
|
[import_semantic_conventions.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
562
604
|
[import_semantic_conventions.ATTR_HTTP_ROUTE]: req.originalPath || "unknown",
|
@@ -601,7 +643,18 @@ function parse(req, res, next) {
|
|
601
643
|
enumerable: true,
|
602
644
|
configurable: false
|
603
645
|
});
|
604
|
-
|
646
|
+
const parsedHeaders = parsedRequest.value.headers ?? {};
|
647
|
+
req.headers = Object.keys(req.headers).reduce(
|
648
|
+
(acc, key) => {
|
649
|
+
if (parsedHeaders?.[key]) {
|
650
|
+
acc[key] = parsedHeaders[key];
|
651
|
+
} else {
|
652
|
+
acc[key] = req.headers[key];
|
653
|
+
}
|
654
|
+
return acc;
|
655
|
+
},
|
656
|
+
{}
|
657
|
+
);
|
605
658
|
}
|
606
659
|
if (!parsedRequest.ok) {
|
607
660
|
switch (req.contractDetails.options?.requestValidation) {
|
@@ -1052,8 +1105,8 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1052
1105
|
handlers,
|
1053
1106
|
controllerHandler
|
1054
1107
|
);
|
1055
|
-
(0,
|
1056
|
-
(0,
|
1108
|
+
(0, import_common6.toRecord)(this.fetchMap)[(0, import_common6.sanitizePathSlashes)(`${this.basePath}${path}`)] = localParamRequest;
|
1109
|
+
(0, import_common6.toRecord)(this.sdk)[(0, import_common6.toPrettyCamelCase)(contractDetails.name ?? this.basePath)] = (req) => localParamRequest(`${this.basePath}${path}`, req);
|
1057
1110
|
return this;
|
1058
1111
|
}
|
1059
1112
|
}
|
@@ -1140,10 +1193,10 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1140
1193
|
}
|
1141
1194
|
addRouterToSdk(router) {
|
1142
1195
|
Object.entries(router.fetchMap).map(
|
1143
|
-
([key, value]) => (0,
|
1196
|
+
([key, value]) => (0, import_common6.toRecord)(this.fetchMap)[(0, import_common6.sanitizePathSlashes)(`${this.basePath}${key}`)] = value
|
1144
1197
|
);
|
1145
|
-
const existingSdk = this.sdk[router.sdkName ?? (0,
|
1146
|
-
(0,
|
1198
|
+
const existingSdk = this.sdk[router.sdkName ?? (0, import_common6.toPrettyCamelCase)(router.basePath)];
|
1199
|
+
(0, import_common6.toRecord)(this.sdk)[router.sdkName ?? (0, import_common6.toPrettyCamelCase)(router.basePath)] = {
|
1147
1200
|
...typeof existingSdk === "object" ? existingSdk : {},
|
1148
1201
|
...router.sdk
|
1149
1202
|
};
|
@@ -1518,6 +1571,11 @@ var trace3 = (_schemaValidator, path, contractDetails, ...handlers) => {
|
|
1518
1571
|
return typedHandler(_schemaValidator, path, "trace", contractDetails, ...handlers);
|
1519
1572
|
};
|
1520
1573
|
|
1574
|
+
// src/http/handlers/typedAuthHandler.ts
|
1575
|
+
function typedAuthHandler(_schemaValidator, _contractDetails, authHandler) {
|
1576
|
+
return authHandler;
|
1577
|
+
}
|
1578
|
+
|
1521
1579
|
// src/http/httpStatusCodes.ts
|
1522
1580
|
var HTTPStatuses = {
|
1523
1581
|
/**
|
@@ -2502,19 +2560,19 @@ var getCodeForStatus = (status) => {
|
|
2502
2560
|
var httpStatusCodes_default = HTTPStatuses;
|
2503
2561
|
|
2504
2562
|
// src/http/mcpGenerator/mcpGenerator.ts
|
2505
|
-
var
|
2563
|
+
var import_common8 = require("@forklaunch/common");
|
2506
2564
|
var import_zod = require("@forklaunch/validator/zod");
|
2507
2565
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
2508
2566
|
|
2509
2567
|
// src/http/router/unpackRouters.ts
|
2510
|
-
var
|
2568
|
+
var import_common7 = require("@forklaunch/common");
|
2511
2569
|
function unpackRouters(routers, recursiveBasePath = [], recursiveSdkPath = []) {
|
2512
2570
|
return routers.reduce((acc, router) => {
|
2513
2571
|
acc.push({
|
2514
2572
|
fullPath: [...recursiveBasePath, router.basePath].join(""),
|
2515
2573
|
sdkPath: [
|
2516
2574
|
...recursiveSdkPath,
|
2517
|
-
(0,
|
2575
|
+
(0, import_common7.toPrettyCamelCase)(router.sdkName ?? router.basePath)
|
2518
2576
|
].join("."),
|
2519
2577
|
router
|
2520
2578
|
});
|
@@ -2524,7 +2582,7 @@ function unpackRouters(routers, recursiveBasePath = [], recursiveSdkPath = []) {
|
|
2524
2582
|
[...recursiveBasePath, router.basePath],
|
2525
2583
|
[
|
2526
2584
|
...recursiveSdkPath,
|
2527
|
-
(0,
|
2585
|
+
(0, import_common7.toPrettyCamelCase)(router.sdkName ?? router.basePath)
|
2528
2586
|
]
|
2529
2587
|
)
|
2530
2588
|
);
|
@@ -2560,14 +2618,15 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2560
2618
|
...route.contractDetails.params ? { params: schemaValidator.schemify(route.contractDetails.params) } : {},
|
2561
2619
|
...route.contractDetails.query ? { query: schemaValidator.schemify(route.contractDetails.query) } : {},
|
2562
2620
|
...route.contractDetails.requestHeaders ? {
|
2563
|
-
headers: schemaValidator.schemify(
|
2564
|
-
route.contractDetails.requestHeaders
|
2565
|
-
|
2621
|
+
headers: schemaValidator.schemify({
|
2622
|
+
...route.contractDetails.requestHeaders,
|
2623
|
+
...route.contractDetails.auth ? {
|
2624
|
+
[route.contractDetails.auth.headerName ?? "authorization"]: import_zod.string.startsWith(
|
2625
|
+
route.contractDetails.auth.tokenPrefix ?? ("basic" in route.contractDetails.auth ? "Basic " : "Bearer ")
|
2626
|
+
)
|
2627
|
+
} : {}
|
2628
|
+
})
|
2566
2629
|
} : {}
|
2567
|
-
// TODO: support auth
|
2568
|
-
// ...(route.contractDetails.auth
|
2569
|
-
// ? { auth: route.contractDetails.auth }
|
2570
|
-
// : {})
|
2571
2630
|
};
|
2572
2631
|
mcpServer.tool(
|
2573
2632
|
route.contractDetails.name,
|
@@ -2588,7 +2647,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2588
2647
|
if (discriminatedBody) {
|
2589
2648
|
switch (discriminatedBody.parserType) {
|
2590
2649
|
case "json": {
|
2591
|
-
parsedBody = (0,
|
2650
|
+
parsedBody = (0, import_common8.safeStringify)(body);
|
2592
2651
|
break;
|
2593
2652
|
}
|
2594
2653
|
case "text": {
|
@@ -2601,7 +2660,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2601
2660
|
}
|
2602
2661
|
case "multipart": {
|
2603
2662
|
const formData = new FormData();
|
2604
|
-
if ((0,
|
2663
|
+
if ((0, import_common8.isRecord)(body)) {
|
2605
2664
|
for (const key in body) {
|
2606
2665
|
if (typeof body[key] === "string" || body[key] instanceof Blob) {
|
2607
2666
|
formData.append(key, body[key]);
|
@@ -2616,11 +2675,11 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2616
2675
|
break;
|
2617
2676
|
}
|
2618
2677
|
case "urlEncoded": {
|
2619
|
-
if ((0,
|
2678
|
+
if ((0, import_common8.isRecord)(body)) {
|
2620
2679
|
parsedBody = new URLSearchParams(
|
2621
2680
|
Object.entries(body).map(([key, value]) => [
|
2622
2681
|
key,
|
2623
|
-
(0,
|
2682
|
+
(0, import_common8.safeStringify)(value)
|
2624
2683
|
])
|
2625
2684
|
);
|
2626
2685
|
} else {
|
@@ -2629,8 +2688,8 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2629
2688
|
break;
|
2630
2689
|
}
|
2631
2690
|
default: {
|
2632
|
-
(0,
|
2633
|
-
parsedBody = (0,
|
2691
|
+
(0, import_common8.isNever)(discriminatedBody.parserType);
|
2692
|
+
parsedBody = (0, import_common8.safeStringify)(body);
|
2634
2693
|
break;
|
2635
2694
|
}
|
2636
2695
|
}
|
@@ -2639,7 +2698,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2639
2698
|
const queryString = new URLSearchParams(
|
2640
2699
|
Object.entries(query).map(([key, value]) => [
|
2641
2700
|
key,
|
2642
|
-
(0,
|
2701
|
+
(0, import_common8.safeStringify)(value)
|
2643
2702
|
])
|
2644
2703
|
).toString();
|
2645
2704
|
url += queryString ? `?${queryString}` : "";
|
@@ -2669,7 +2728,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, route
|
|
2669
2728
|
content: [
|
2670
2729
|
{
|
2671
2730
|
type: "text",
|
2672
|
-
text: (0,
|
2731
|
+
text: (0, import_common8.safeStringify)(await response.json())
|
2673
2732
|
}
|
2674
2733
|
]
|
2675
2734
|
};
|
@@ -2775,18 +2834,18 @@ ${parseErrors.join("\n\n")}`
|
|
2775
2834
|
}
|
2776
2835
|
|
2777
2836
|
// src/http/middleware/response/enrichExpressLikeSend.middleware.ts
|
2778
|
-
var
|
2837
|
+
var import_common10 = require("@forklaunch/common");
|
2779
2838
|
var import_stream = require("stream");
|
2780
2839
|
|
2781
2840
|
// src/http/telemetry/recordMetric.ts
|
2782
|
-
var
|
2841
|
+
var import_common9 = require("@forklaunch/common");
|
2783
2842
|
var import_semantic_conventions3 = require("@opentelemetry/semantic-conventions");
|
2784
2843
|
function recordMetric(req, res) {
|
2785
2844
|
if (res.metricRecorded) {
|
2786
2845
|
return;
|
2787
2846
|
}
|
2788
2847
|
httpRequestsTotalCounter.add(1, {
|
2789
|
-
[import_semantic_conventions3.ATTR_SERVICE_NAME]: (0,
|
2848
|
+
[import_semantic_conventions3.ATTR_SERVICE_NAME]: (0, import_common9.getEnvVar)("OTEL_SERVICE_NAME"),
|
2790
2849
|
[ATTR_API_NAME]: req.contractDetails?.name,
|
2791
2850
|
[ATTR_CORRELATION_ID]: req.context.correlationId,
|
2792
2851
|
[import_semantic_conventions3.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
@@ -2824,8 +2883,8 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
2824
2883
|
`attachment; filename="${data.name}"`
|
2825
2884
|
);
|
2826
2885
|
}
|
2827
|
-
if ((0,
|
2828
|
-
import_stream.Readable.from((0,
|
2886
|
+
if ((0, import_common10.isNodeJsWriteableStream)(res)) {
|
2887
|
+
import_stream.Readable.from((0, import_common10.readableStreamToAsyncIterable)(data.stream())).pipe(
|
2829
2888
|
res
|
2830
2889
|
);
|
2831
2890
|
} else {
|
@@ -2834,7 +2893,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
2834
2893
|
originalSend.call(instance, "Not a NodeJS WritableStream");
|
2835
2894
|
errorSent = true;
|
2836
2895
|
}
|
2837
|
-
} else if ((0,
|
2896
|
+
} else if ((0, import_common10.isAsyncGenerator)(data)) {
|
2838
2897
|
let firstPass = true;
|
2839
2898
|
const transformer = new import_stream.Transform({
|
2840
2899
|
objectMode: true,
|
@@ -2862,7 +2921,7 @@ ${res.locals.errorMessage}`;
|
|
2862
2921
|
if (!errorSent) {
|
2863
2922
|
let data2 = "";
|
2864
2923
|
for (const [key, value] of Object.entries(chunk)) {
|
2865
|
-
data2 += `${key}: ${typeof value === "string" ? value : (0,
|
2924
|
+
data2 += `${key}: ${typeof value === "string" ? value : (0, import_common10.safeStringify)(value)}
|
2866
2925
|
`;
|
2867
2926
|
}
|
2868
2927
|
data2 += "\n";
|
@@ -2870,7 +2929,7 @@ ${res.locals.errorMessage}`;
|
|
2870
2929
|
}
|
2871
2930
|
}
|
2872
2931
|
});
|
2873
|
-
if ((0,
|
2932
|
+
if ((0, import_common10.isNodeJsWriteableStream)(res)) {
|
2874
2933
|
import_stream.Readable.from(data).pipe(transformer).pipe(res);
|
2875
2934
|
} else {
|
2876
2935
|
res.type("text/plain");
|
@@ -2881,7 +2940,7 @@ ${res.locals.errorMessage}`;
|
|
2881
2940
|
} else {
|
2882
2941
|
const parserType = responseBodies?.[Number(res.statusCode)]?.parserType;
|
2883
2942
|
res.bodyData = data;
|
2884
|
-
if ((0,
|
2943
|
+
if ((0, import_common10.isRecord)(data)) {
|
2885
2944
|
switch (parserType) {
|
2886
2945
|
case "json":
|
2887
2946
|
res.bodyData = "json" in data ? data.json : data;
|
@@ -2902,7 +2961,7 @@ ${res.locals.errorMessage}`;
|
|
2902
2961
|
res.bodyData = data;
|
2903
2962
|
break;
|
2904
2963
|
default:
|
2905
|
-
(0,
|
2964
|
+
(0, import_common10.isNever)(parserType);
|
2906
2965
|
res.bodyData = data;
|
2907
2966
|
break;
|
2908
2967
|
}
|
@@ -2938,7 +2997,7 @@ ${res.locals.errorMessage}`;
|
|
2938
2997
|
}
|
2939
2998
|
|
2940
2999
|
// src/http/openApiV3Generator/openApiV3Generator.ts
|
2941
|
-
var
|
3000
|
+
var import_common11 = require("@forklaunch/common");
|
2942
3001
|
function toUpperCase(str) {
|
2943
3002
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
2944
3003
|
}
|
@@ -2948,7 +3007,7 @@ function transformBasePath(basePath) {
|
|
2948
3007
|
}
|
2949
3008
|
return `/${basePath}`;
|
2950
3009
|
}
|
2951
|
-
function generateOpenApiDocument(protocol, host, port, tags, paths, otherServers) {
|
3010
|
+
function generateOpenApiDocument(protocol, host, port, tags, paths, securitySchemes, otherServers) {
|
2952
3011
|
return {
|
2953
3012
|
openapi: "3.1.0",
|
2954
3013
|
info: {
|
@@ -2956,13 +3015,7 @@ function generateOpenApiDocument(protocol, host, port, tags, paths, otherServers
|
|
2956
3015
|
version: process.env.VERSION || "1.0.0"
|
2957
3016
|
},
|
2958
3017
|
components: {
|
2959
|
-
securitySchemes
|
2960
|
-
bearer: {
|
2961
|
-
type: "http",
|
2962
|
-
scheme: "bearer",
|
2963
|
-
bearerFormat: "JWT"
|
2964
|
-
}
|
2965
|
-
}
|
3018
|
+
securitySchemes
|
2966
3019
|
},
|
2967
3020
|
tags,
|
2968
3021
|
servers: [
|
@@ -2994,6 +3047,7 @@ function contentResolver(schemaValidator, body, contentType) {
|
|
2994
3047
|
function generateSwaggerDocument(schemaValidator, protocol, host, port, routers, otherServers) {
|
2995
3048
|
const tags = [];
|
2996
3049
|
const paths = {};
|
3050
|
+
const securitySchemes = {};
|
2997
3051
|
unpackRouters(routers).forEach(({ fullPath, router, sdkPath }) => {
|
2998
3052
|
const controllerName = transformBasePath(fullPath);
|
2999
3053
|
tags.push({
|
@@ -3001,7 +3055,7 @@ function generateSwaggerDocument(schemaValidator, protocol, host, port, routers,
|
|
3001
3055
|
description: `${toUpperCase(controllerName)} Operations`
|
3002
3056
|
});
|
3003
3057
|
router.routes.forEach((route) => {
|
3004
|
-
const openApiPath = (0,
|
3058
|
+
const openApiPath = (0, import_common11.openApiCompliantPath)(
|
3005
3059
|
`${fullPath}${route.path === "/" ? "" : route.path}`
|
3006
3060
|
);
|
3007
3061
|
if (!paths[openApiPath]) {
|
@@ -3037,7 +3091,7 @@ function generateSwaggerDocument(schemaValidator, protocol, host, port, routers,
|
|
3037
3091
|
summary: `${name}: ${summary}`,
|
3038
3092
|
parameters: [],
|
3039
3093
|
responses,
|
3040
|
-
operationId: `${sdkPath}.${(0,
|
3094
|
+
operationId: `${sdkPath}.${(0, import_common11.toPrettyCamelCase)(name)}`
|
3041
3095
|
};
|
3042
3096
|
if (route.contractDetails.params) {
|
3043
3097
|
for (const key in route.contractDetails.params) {
|
@@ -3090,14 +3144,39 @@ function generateSwaggerDocument(schemaValidator, protocol, host, port, routers,
|
|
3090
3144
|
description: httpStatusCodes_default[403],
|
3091
3145
|
content: contentResolver(schemaValidator, schemaValidator.string)
|
3092
3146
|
};
|
3093
|
-
if (route.contractDetails.auth
|
3147
|
+
if ("basic" in route.contractDetails.auth) {
|
3148
|
+
operationObject.security = [
|
3149
|
+
{
|
3150
|
+
basic: Array.from(
|
3151
|
+
"allowedPermissions" in route.contractDetails.auth ? route.contractDetails.auth.allowedPermissions?.values() || [] : []
|
3152
|
+
)
|
3153
|
+
}
|
3154
|
+
];
|
3155
|
+
securitySchemes["basic"] = {
|
3156
|
+
type: "http",
|
3157
|
+
scheme: "basic"
|
3158
|
+
};
|
3159
|
+
} else if (route.contractDetails.auth) {
|
3094
3160
|
operationObject.security = [
|
3095
3161
|
{
|
3096
|
-
bearer: Array.from(
|
3097
|
-
route.contractDetails.auth.allowedPermissions?.values() || []
|
3162
|
+
[route.contractDetails.auth.headerName !== "Authorization" ? "bearer" : "apiKey"]: Array.from(
|
3163
|
+
"allowedPermissions" in route.contractDetails.auth ? route.contractDetails.auth.allowedPermissions?.values() || [] : []
|
3098
3164
|
)
|
3099
3165
|
}
|
3100
3166
|
];
|
3167
|
+
if (route.contractDetails.auth.headerName && route.contractDetails.auth.headerName !== "Authorization") {
|
3168
|
+
securitySchemes[route.contractDetails.auth.headerName] = {
|
3169
|
+
type: "apiKey",
|
3170
|
+
in: "header",
|
3171
|
+
name: route.contractDetails.auth.headerName
|
3172
|
+
};
|
3173
|
+
} else {
|
3174
|
+
securitySchemes["Authorization"] = {
|
3175
|
+
type: "http",
|
3176
|
+
scheme: "bearer",
|
3177
|
+
bearerFormat: "JWT"
|
3178
|
+
};
|
3179
|
+
}
|
3101
3180
|
}
|
3102
3181
|
}
|
3103
3182
|
if (route.method !== "middleware") {
|
@@ -3111,6 +3190,7 @@ function generateSwaggerDocument(schemaValidator, protocol, host, port, routers,
|
|
3111
3190
|
port,
|
3112
3191
|
tags,
|
3113
3192
|
paths,
|
3193
|
+
securitySchemes,
|
3114
3194
|
otherServers
|
3115
3195
|
);
|
3116
3196
|
}
|
@@ -3177,6 +3257,7 @@ function metricsDefinitions(metrics2) {
|
|
3177
3257
|
put,
|
3178
3258
|
recordMetric,
|
3179
3259
|
trace,
|
3260
|
+
typedAuthHandler,
|
3180
3261
|
typedHandler
|
3181
3262
|
});
|
3182
3263
|
//# sourceMappingURL=index.js.map
|