@forklaunch/core 0.16.1 → 0.17.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/{apiDefinition.types-BYizofKE.d.mts → apiDefinition.types-XZ0lrfFc.d.mts} +10 -6
- package/lib/{apiDefinition.types-BYizofKE.d.ts → apiDefinition.types-XZ0lrfFc.d.ts} +10 -6
- package/lib/http/index.d.mts +113 -8
- package/lib/http/index.d.ts +113 -8
- package/lib/http/index.js +789 -649
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +760 -625
- package/lib/http/index.mjs.map +1 -1
- package/lib/mappers/index.d.mts +14 -4
- package/lib/mappers/index.d.ts +14 -4
- package/lib/mappers/index.js +20 -8
- package/lib/mappers/index.js.map +1 -1
- package/lib/mappers/index.mjs +20 -8
- package/lib/mappers/index.mjs.map +1 -1
- package/lib/persistence/index.d.mts +6 -3
- package/lib/persistence/index.d.ts +6 -3
- package/lib/persistence/index.js +11 -3
- package/lib/persistence/index.js.map +1 -1
- package/lib/persistence/index.mjs +11 -3
- package/lib/persistence/index.mjs.map +1 -1
- package/lib/ws/index.d.mts +2 -2
- package/lib/ws/index.d.ts +2 -2
- package/package.json +33 -33
package/lib/http/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var http_exports = {};
|
|
32
32
|
__export(http_exports, {
|
|
33
33
|
ATTR_API_NAME: () => ATTR_API_NAME,
|
|
34
|
+
ATTR_APPLICATION_ID: () => ATTR_APPLICATION_ID,
|
|
34
35
|
ATTR_CORRELATION_ID: () => ATTR_CORRELATION_ID,
|
|
35
36
|
ATTR_HTTP_REQUEST_METHOD: () => import_semantic_conventions.ATTR_HTTP_REQUEST_METHOD,
|
|
36
37
|
ATTR_HTTP_RESPONSE_STATUS_CODE: () => import_semantic_conventions.ATTR_HTTP_RESPONSE_STATUS_CODE,
|
|
@@ -42,6 +43,7 @@ __export(http_exports, {
|
|
|
42
43
|
OPENAPI_DEFAULT_VERSION: () => OPENAPI_DEFAULT_VERSION,
|
|
43
44
|
OpenTelemetryCollector: () => OpenTelemetryCollector,
|
|
44
45
|
PinoLogger: () => PinoLogger,
|
|
46
|
+
createContext: () => createContext,
|
|
45
47
|
createHmacToken: () => createHmacToken,
|
|
46
48
|
delete_: () => delete_,
|
|
47
49
|
discriminateAuthMethod: () => discriminateAuthMethod,
|
|
@@ -49,6 +51,8 @@ __export(http_exports, {
|
|
|
49
51
|
discriminateResponseBodies: () => discriminateResponseBodies,
|
|
50
52
|
enrichExpressLikeSend: () => enrichExpressLikeSend,
|
|
51
53
|
evaluateTelemetryOptions: () => evaluateTelemetryOptions,
|
|
54
|
+
extractRouteHandlers: () => extractRouteHandlers,
|
|
55
|
+
generateHmacAuthHeaders: () => generateHmacAuthHeaders,
|
|
52
56
|
generateMcpServer: () => generateMcpServer,
|
|
53
57
|
generateOpenApiSpecs: () => generateOpenApiSpecs,
|
|
54
58
|
get: () => get,
|
|
@@ -103,12 +107,7 @@ function cors(corsOptions) {
|
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
// src/http/router/expressLikeRouter.ts
|
|
106
|
-
var
|
|
107
|
-
|
|
108
|
-
// src/http/guards/hasVersionedSchema.ts
|
|
109
|
-
function hasVersionedSchema(contractDetails) {
|
|
110
|
-
return typeof contractDetails === "object" && contractDetails !== null && "versions" in contractDetails && contractDetails.versions !== null;
|
|
111
|
-
}
|
|
110
|
+
var import_common11 = require("@forklaunch/common");
|
|
112
111
|
|
|
113
112
|
// src/http/guards/isForklaunchRouter.ts
|
|
114
113
|
function isForklaunchRouter(maybeForklaunchRouter) {
|
|
@@ -138,6 +137,192 @@ function isForklaunchExpressLikeRouter(maybeForklaunchExpressLikeRouter) {
|
|
|
138
137
|
) && "basePath" in maybeForklaunchExpressLikeRouter && "internal" in maybeForklaunchExpressLikeRouter;
|
|
139
138
|
}
|
|
140
139
|
|
|
140
|
+
// src/http/guards/isSdkHandler.ts
|
|
141
|
+
function isSdkHandler(handler) {
|
|
142
|
+
return typeof handler === "object" && handler !== null && "_path" in handler && "_method" in handler && "contractDetails" in handler;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/http/guards/isTypedHandler.ts
|
|
146
|
+
function isTypedHandler(maybeTypedHandler) {
|
|
147
|
+
return maybeTypedHandler != null && typeof maybeTypedHandler === "object" && "_typedHandler" in maybeTypedHandler && maybeTypedHandler._typedHandler === true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/http/middleware/request/createContext.middleware.ts
|
|
151
|
+
var import_common2 = require("@forklaunch/common");
|
|
152
|
+
var import_api = require("@opentelemetry/api");
|
|
153
|
+
var import_uuid = require("uuid");
|
|
154
|
+
|
|
155
|
+
// src/http/telemetry/constants.ts
|
|
156
|
+
var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
157
|
+
var ATTR_API_NAME = "api.name";
|
|
158
|
+
var ATTR_CORRELATION_ID = "correlation.id";
|
|
159
|
+
var ATTR_APPLICATION_ID = "application_id";
|
|
160
|
+
|
|
161
|
+
// src/http/middleware/request/createContext.middleware.ts
|
|
162
|
+
function createContext(schemaValidator) {
|
|
163
|
+
return function setContext(req, res, next) {
|
|
164
|
+
req.schemaValidator = schemaValidator;
|
|
165
|
+
let correlationId = (0, import_uuid.v4)();
|
|
166
|
+
if (req.headers["x-correlation-id"]) {
|
|
167
|
+
correlationId = req.headers["x-correlation-id"];
|
|
168
|
+
}
|
|
169
|
+
res.setHeader("x-correlation-id", correlationId);
|
|
170
|
+
req.context = {
|
|
171
|
+
correlationId
|
|
172
|
+
};
|
|
173
|
+
const span = import_api.trace.getSpan(import_api.context.active());
|
|
174
|
+
if (span != null) {
|
|
175
|
+
req.context.span = span;
|
|
176
|
+
req.context.span?.setAttribute(ATTR_CORRELATION_ID, correlationId);
|
|
177
|
+
req.context.span?.setAttribute(
|
|
178
|
+
import_semantic_conventions.ATTR_SERVICE_NAME,
|
|
179
|
+
(0, import_common2.getEnvVar)("OTEL_SERVICE_NAME")
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
next?.();
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/http/router/discriminateBody.ts
|
|
187
|
+
function discriminateBody(schemaValidator, body) {
|
|
188
|
+
if (body == null) {
|
|
189
|
+
return void 0;
|
|
190
|
+
}
|
|
191
|
+
const maybeTypedBody = body;
|
|
192
|
+
if ("text" in maybeTypedBody && maybeTypedBody.text != null) {
|
|
193
|
+
return {
|
|
194
|
+
contentType: maybeTypedBody.contentType ?? "text/plain",
|
|
195
|
+
parserType: "text",
|
|
196
|
+
schema: maybeTypedBody.text
|
|
197
|
+
};
|
|
198
|
+
} else if ("json" in maybeTypedBody && maybeTypedBody.json != null) {
|
|
199
|
+
return {
|
|
200
|
+
contentType: maybeTypedBody.contentType ?? "application/json",
|
|
201
|
+
parserType: "json",
|
|
202
|
+
schema: maybeTypedBody.json
|
|
203
|
+
};
|
|
204
|
+
} else if ("file" in maybeTypedBody && maybeTypedBody.file != null) {
|
|
205
|
+
return {
|
|
206
|
+
contentType: maybeTypedBody.contentType ?? "application/octet-stream",
|
|
207
|
+
parserType: "file",
|
|
208
|
+
schema: maybeTypedBody.file
|
|
209
|
+
};
|
|
210
|
+
} else if ("multipartForm" in maybeTypedBody && maybeTypedBody.multipartForm != null) {
|
|
211
|
+
return {
|
|
212
|
+
contentType: maybeTypedBody.contentType ?? "multipart/form-data",
|
|
213
|
+
parserType: "multipart",
|
|
214
|
+
schema: maybeTypedBody.multipartForm
|
|
215
|
+
};
|
|
216
|
+
} else if ("urlEncodedForm" in maybeTypedBody && maybeTypedBody.urlEncodedForm != null) {
|
|
217
|
+
return {
|
|
218
|
+
contentType: maybeTypedBody.contentType ?? "application/x-www-form-urlencoded",
|
|
219
|
+
parserType: "urlEncoded",
|
|
220
|
+
schema: maybeTypedBody.urlEncodedForm
|
|
221
|
+
};
|
|
222
|
+
} else if ("schema" in maybeTypedBody && maybeTypedBody.schema != null) {
|
|
223
|
+
return {
|
|
224
|
+
contentType: maybeTypedBody.contentType ?? "application/json",
|
|
225
|
+
parserType: "text",
|
|
226
|
+
schema: maybeTypedBody.schema
|
|
227
|
+
};
|
|
228
|
+
} else if (schemaValidator.isInstanceOf(
|
|
229
|
+
maybeTypedBody,
|
|
230
|
+
schemaValidator.string
|
|
231
|
+
)) {
|
|
232
|
+
return {
|
|
233
|
+
contentType: "text/plain",
|
|
234
|
+
parserType: "text",
|
|
235
|
+
schema: maybeTypedBody
|
|
236
|
+
};
|
|
237
|
+
} else if (schemaValidator.openapi(maybeTypedBody).format === "binary") {
|
|
238
|
+
return {
|
|
239
|
+
contentType: "application/octet-stream",
|
|
240
|
+
parserType: "file",
|
|
241
|
+
schema: maybeTypedBody
|
|
242
|
+
};
|
|
243
|
+
} else {
|
|
244
|
+
return {
|
|
245
|
+
contentType: "application/json",
|
|
246
|
+
parserType: "json",
|
|
247
|
+
schema: maybeTypedBody
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function discriminateResponseBodies(schemaValidator, responses) {
|
|
252
|
+
const discriminatedResponses = {};
|
|
253
|
+
for (const [statusCode, response] of Object.entries(responses)) {
|
|
254
|
+
if (response != null && typeof response === "object") {
|
|
255
|
+
if ("json" in response && response.json != null) {
|
|
256
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
257
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/json") ?? "application/json",
|
|
258
|
+
parserType: "json",
|
|
259
|
+
schema: response.json
|
|
260
|
+
};
|
|
261
|
+
} else if ("schema" in response && response.schema != null) {
|
|
262
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
263
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/json") ?? "application/json",
|
|
264
|
+
parserType: "text",
|
|
265
|
+
schema: response.schema
|
|
266
|
+
};
|
|
267
|
+
} else if ("text" in response && response.text != null) {
|
|
268
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
269
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "text/plain") ?? "text/plain",
|
|
270
|
+
parserType: "text",
|
|
271
|
+
schema: response.text
|
|
272
|
+
};
|
|
273
|
+
} else if ("file" in response && response.file != null) {
|
|
274
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
275
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/octet-stream") ?? "application/octet-stream",
|
|
276
|
+
parserType: "file",
|
|
277
|
+
schema: response.file
|
|
278
|
+
};
|
|
279
|
+
} else if ("event" in response && response.event != null) {
|
|
280
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
281
|
+
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "text/event-stream") ?? "text/event-stream",
|
|
282
|
+
parserType: "serverSentEvent",
|
|
283
|
+
schema: response.event
|
|
284
|
+
};
|
|
285
|
+
} else if (schemaValidator.isInstanceOf(
|
|
286
|
+
response,
|
|
287
|
+
schemaValidator.string
|
|
288
|
+
)) {
|
|
289
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
290
|
+
contentType: "text/plain",
|
|
291
|
+
parserType: "text",
|
|
292
|
+
schema: response
|
|
293
|
+
};
|
|
294
|
+
} else if (schemaValidator.openapi(response).format === "binary") {
|
|
295
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
296
|
+
contentType: "application/octet-stream",
|
|
297
|
+
parserType: "file",
|
|
298
|
+
schema: response
|
|
299
|
+
};
|
|
300
|
+
} else {
|
|
301
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
302
|
+
contentType: "application/json",
|
|
303
|
+
parserType: "json",
|
|
304
|
+
schema: response
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
discriminatedResponses[Number(statusCode)] = {
|
|
309
|
+
contentType: "application/json",
|
|
310
|
+
parserType: "json",
|
|
311
|
+
schema: response
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return discriminatedResponses;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/http/router/routerSharedLogic.ts
|
|
319
|
+
var import_common10 = require("@forklaunch/common");
|
|
320
|
+
|
|
321
|
+
// src/http/guards/hasVersionedSchema.ts
|
|
322
|
+
function hasVersionedSchema(contractDetails) {
|
|
323
|
+
return typeof contractDetails === "object" && contractDetails !== null && "versions" in contractDetails && contractDetails.versions !== null;
|
|
324
|
+
}
|
|
325
|
+
|
|
141
326
|
// src/http/guards/isPathParamContractDetails.ts
|
|
142
327
|
function isPathParamHttpContractDetails(maybePathParamHttpContractDetails) {
|
|
143
328
|
return maybePathParamHttpContractDetails != null && typeof maybePathParamHttpContractDetails === "object" && "name" in maybePathParamHttpContractDetails && "summary" in maybePathParamHttpContractDetails && maybePathParamHttpContractDetails.name != null && maybePathParamHttpContractDetails.summary != null && ("responses" in maybePathParamHttpContractDetails && maybePathParamHttpContractDetails.responses != null || "versions" in maybePathParamHttpContractDetails && typeof maybePathParamHttpContractDetails.versions === "object" && maybePathParamHttpContractDetails.versions != null && Object.values(maybePathParamHttpContractDetails.versions).every(
|
|
@@ -152,25 +337,16 @@ function isHttpContractDetails(maybeContractDetails) {
|
|
|
152
337
|
));
|
|
153
338
|
}
|
|
154
339
|
|
|
155
|
-
// src/http/guards/isSdkHandler.ts
|
|
156
|
-
function isSdkHandler(handler) {
|
|
157
|
-
return typeof handler === "object" && handler !== null && "_path" in handler && "_method" in handler && "contractDetails" in handler;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// src/http/guards/isTypedHandler.ts
|
|
161
|
-
function isTypedHandler(maybeTypedHandler) {
|
|
162
|
-
return maybeTypedHandler != null && typeof maybeTypedHandler === "object" && "_typedHandler" in maybeTypedHandler && maybeTypedHandler._typedHandler === true;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
340
|
// src/http/middleware/request/auth.middleware.ts
|
|
166
|
-
var
|
|
341
|
+
var import_common6 = require("@forklaunch/common");
|
|
167
342
|
var import_validator = require("@forklaunch/validator");
|
|
168
343
|
|
|
169
344
|
// src/http/discriminateAuthMethod.ts
|
|
345
|
+
var import_common4 = require("@forklaunch/common");
|
|
170
346
|
var import_jose = require("jose");
|
|
171
347
|
|
|
172
348
|
// src/http/createHmacToken.ts
|
|
173
|
-
var
|
|
349
|
+
var import_common3 = require("@forklaunch/common");
|
|
174
350
|
var import_crypto = require("crypto");
|
|
175
351
|
function createHmacToken({
|
|
176
352
|
method,
|
|
@@ -181,7 +357,7 @@ function createHmacToken({
|
|
|
181
357
|
secretKey
|
|
182
358
|
}) {
|
|
183
359
|
const hmac = (0, import_crypto.createHmac)("sha256", secretKey);
|
|
184
|
-
const bodyString = body ? `${(0,
|
|
360
|
+
const bodyString = body ? `${(0, import_common3.safeStringify)(body)}
|
|
185
361
|
` : void 0;
|
|
186
362
|
hmac.update(
|
|
187
363
|
`${method}
|
|
@@ -228,7 +404,7 @@ async function getCachedJwks(jwksPublicKeyUrl) {
|
|
|
228
404
|
return jwks;
|
|
229
405
|
}
|
|
230
406
|
}
|
|
231
|
-
async function discriminateAuthMethod(auth) {
|
|
407
|
+
async function discriminateAuthMethod(auth, openTelemetryCollector) {
|
|
232
408
|
let authMethod;
|
|
233
409
|
if (isBasicAuthMethod(auth)) {
|
|
234
410
|
authMethod = {
|
|
@@ -291,37 +467,219 @@ async function discriminateAuthMethod(auth) {
|
|
|
291
467
|
signature,
|
|
292
468
|
secretKey
|
|
293
469
|
}) => {
|
|
294
|
-
|
|
470
|
+
const computedSignature = createHmacToken({
|
|
295
471
|
method,
|
|
296
472
|
path,
|
|
297
473
|
body,
|
|
298
474
|
timestamp,
|
|
299
475
|
nonce,
|
|
300
476
|
secretKey
|
|
301
|
-
})
|
|
477
|
+
});
|
|
478
|
+
const isValid = computedSignature === signature;
|
|
479
|
+
if (!isValid) {
|
|
480
|
+
const errorInfo = {
|
|
481
|
+
method,
|
|
482
|
+
path,
|
|
483
|
+
timestamp: timestamp.toISOString(),
|
|
484
|
+
nonce,
|
|
485
|
+
receivedSignature: signature,
|
|
486
|
+
computedSignature
|
|
487
|
+
};
|
|
488
|
+
openTelemetryCollector?.debug("[HMAC Verification Failed]", {
|
|
489
|
+
...errorInfo,
|
|
490
|
+
bodyType: body ? typeof body : "undefined",
|
|
491
|
+
body: body ? (0, import_common4.safeStringify)(body) : "undefined"
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return isValid;
|
|
302
495
|
}
|
|
303
496
|
}
|
|
304
497
|
};
|
|
305
498
|
}
|
|
306
|
-
if (authMethod == null) {
|
|
307
|
-
throw new Error("Invalid auth method");
|
|
499
|
+
if (authMethod == null) {
|
|
500
|
+
throw new Error("Invalid auth method");
|
|
501
|
+
}
|
|
502
|
+
return authMethod;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/http/guards/hasPermissionChecks.ts
|
|
506
|
+
function hasPermissionChecks(maybePermissionedAuth) {
|
|
507
|
+
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && ("allowedPermissions" in maybePermissionedAuth || "forbiddenPermissions" in maybePermissionedAuth);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/http/guards/hasRoleChecks.ts
|
|
511
|
+
function hasRoleChecks(maybeRoledAuth) {
|
|
512
|
+
return typeof maybeRoledAuth === "object" && maybeRoledAuth !== null && ("allowedRoles" in maybeRoledAuth || "forbiddenRoles" in maybeRoledAuth);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/http/guards/hasScopeChecks.ts
|
|
516
|
+
function hasScopeChecks(maybePermissionedAuth) {
|
|
517
|
+
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && "requiredScope" in maybePermissionedAuth && maybePermissionedAuth.requiredScope != null;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// src/http/telemetry/pinoLogger.ts
|
|
521
|
+
var import_common5 = require("@forklaunch/common");
|
|
522
|
+
var import_api2 = require("@opentelemetry/api");
|
|
523
|
+
var import_api_logs = require("@opentelemetry/api-logs");
|
|
524
|
+
var import_pino = __toESM(require("pino"));
|
|
525
|
+
|
|
526
|
+
// src/http/guards/isLoggerMeta.ts
|
|
527
|
+
function isLoggerMeta(arg) {
|
|
528
|
+
return typeof arg === "object" && arg !== null && "_meta" in arg;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/http/telemetry/pinoLogger.ts
|
|
532
|
+
function meta(meta2) {
|
|
533
|
+
return meta2;
|
|
534
|
+
}
|
|
535
|
+
function mapSeverity(level) {
|
|
536
|
+
switch (level) {
|
|
537
|
+
case "silent":
|
|
538
|
+
return 0;
|
|
539
|
+
case "trace":
|
|
540
|
+
return 1;
|
|
541
|
+
case "debug":
|
|
542
|
+
return 5;
|
|
543
|
+
case "info":
|
|
544
|
+
return 9;
|
|
545
|
+
case "warn":
|
|
546
|
+
return 13;
|
|
547
|
+
case "error":
|
|
548
|
+
return 17;
|
|
549
|
+
case "fatal":
|
|
550
|
+
return 21;
|
|
551
|
+
default:
|
|
552
|
+
(0, import_common5.isNever)(level);
|
|
553
|
+
return 0;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function normalizeLogArgs(args) {
|
|
557
|
+
let message = "";
|
|
558
|
+
const metaObjects = [];
|
|
559
|
+
for (const arg of args) {
|
|
560
|
+
if (typeof arg === "string" && message === "") {
|
|
561
|
+
message = arg;
|
|
562
|
+
} else if (arg instanceof Error) {
|
|
563
|
+
metaObjects.push({
|
|
564
|
+
err: {
|
|
565
|
+
message: arg.message,
|
|
566
|
+
name: arg.name,
|
|
567
|
+
stack: arg.stack,
|
|
568
|
+
...Object.keys(arg).length > 0 ? arg : {}
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
} else if (arg && typeof arg === "object" && !Array.isArray(arg)) {
|
|
572
|
+
metaObjects.push(arg);
|
|
573
|
+
} else {
|
|
574
|
+
message += ` ${String(arg)}`;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const metadata = Object.assign({}, ...metaObjects);
|
|
578
|
+
return [metadata, message.trim()];
|
|
579
|
+
}
|
|
580
|
+
function safePrettyFormat(level, args, timestamp) {
|
|
581
|
+
try {
|
|
582
|
+
const [metadata, message] = normalizeLogArgs(args);
|
|
583
|
+
const formattedTimestamp = timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
584
|
+
return `[${formattedTimestamp}] ${level.toUpperCase()}: ${message}${Object.keys(metadata).length > 0 ? `
|
|
585
|
+
${JSON.stringify(metadata, null, 2)}` : ""}`;
|
|
586
|
+
} catch (error) {
|
|
587
|
+
const fallbackMessage = args.map((arg) => {
|
|
588
|
+
try {
|
|
589
|
+
if (typeof arg === "string") return arg;
|
|
590
|
+
if (arg === null) return "null";
|
|
591
|
+
if (arg === void 0) return "undefined";
|
|
592
|
+
return JSON.stringify(arg);
|
|
593
|
+
} catch {
|
|
594
|
+
return "[Circular/Non-serializable Object]";
|
|
595
|
+
}
|
|
596
|
+
}).join(" ");
|
|
597
|
+
return `[${(/* @__PURE__ */ new Date()).toISOString()}] ${level.toUpperCase()}: ${fallbackMessage} [Pretty Print Error: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
var PinoLogger = class _PinoLogger {
|
|
601
|
+
pinoLogger;
|
|
602
|
+
meta;
|
|
603
|
+
constructor(level, meta2 = {}) {
|
|
604
|
+
this.pinoLogger = (0, import_pino.default)({
|
|
605
|
+
level: level || "info",
|
|
606
|
+
formatters: {
|
|
607
|
+
level(label) {
|
|
608
|
+
return { level: label };
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
timestamp: import_pino.default.stdTimeFunctions.isoTime,
|
|
612
|
+
transport: {
|
|
613
|
+
target: "pino-pretty",
|
|
614
|
+
options: {
|
|
615
|
+
colorize: true,
|
|
616
|
+
errorLikeObjectKeys: ["err", "error"],
|
|
617
|
+
ignore: "pid,hostname",
|
|
618
|
+
translateTime: "SYS:standard"
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
this.meta = meta2;
|
|
623
|
+
}
|
|
624
|
+
log(level, ...args) {
|
|
625
|
+
let meta2 = {};
|
|
626
|
+
const filteredArgs = args.filter((arg) => {
|
|
627
|
+
if (isLoggerMeta(arg)) {
|
|
628
|
+
Object.assign(meta2, arg);
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
return true;
|
|
632
|
+
});
|
|
633
|
+
const [errorMetadata] = normalizeLogArgs(filteredArgs);
|
|
634
|
+
Object.assign(meta2, errorMetadata);
|
|
635
|
+
const activeSpan = import_api2.trace.getActiveSpan();
|
|
636
|
+
if (activeSpan) {
|
|
637
|
+
const activeSpanContext = activeSpan.spanContext();
|
|
638
|
+
meta2.trace_id = activeSpanContext.traceId;
|
|
639
|
+
meta2.span_id = activeSpanContext.spanId;
|
|
640
|
+
meta2.trace_flags = activeSpanContext.traceFlags;
|
|
641
|
+
meta2 = {
|
|
642
|
+
// @ts-expect-error accessing private property
|
|
643
|
+
...activeSpan.attributes,
|
|
644
|
+
...meta2
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
meta2 = {
|
|
648
|
+
"api.name": "none",
|
|
649
|
+
"correlation.id": "none",
|
|
650
|
+
...meta2
|
|
651
|
+
};
|
|
652
|
+
this.pinoLogger[level](...normalizeLogArgs(filteredArgs));
|
|
653
|
+
const formattedBody = safePrettyFormat(level, filteredArgs);
|
|
654
|
+
try {
|
|
655
|
+
import_api_logs.logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
|
656
|
+
severityText: level,
|
|
657
|
+
severityNumber: mapSeverity(level),
|
|
658
|
+
body: formattedBody,
|
|
659
|
+
attributes: { ...this.meta, ...meta2 }
|
|
660
|
+
});
|
|
661
|
+
} catch (error) {
|
|
662
|
+
console.error("Failed to emit OpenTelemetry log:", error);
|
|
663
|
+
console.log(
|
|
664
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${level.toUpperCase()}:`,
|
|
665
|
+
...filteredArgs
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
error = (msg, ...args) => this.log("error", msg, ...args);
|
|
670
|
+
info = (msg, ...args) => this.log("info", msg, ...args);
|
|
671
|
+
debug = (msg, ...args) => this.log("debug", msg, ...args);
|
|
672
|
+
warn = (msg, ...args) => this.log("warn", msg, ...args);
|
|
673
|
+
trace = (msg, ...args) => this.log("trace", msg, ...args);
|
|
674
|
+
child(meta2 = {}) {
|
|
675
|
+
return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta2 });
|
|
676
|
+
}
|
|
677
|
+
getBaseLogger() {
|
|
678
|
+
return this.pinoLogger;
|
|
308
679
|
}
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// src/http/guards/hasPermissionChecks.ts
|
|
313
|
-
function hasPermissionChecks(maybePermissionedAuth) {
|
|
314
|
-
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && ("allowedPermissions" in maybePermissionedAuth || "forbiddenPermissions" in maybePermissionedAuth);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// src/http/guards/hasRoleChecks.ts
|
|
318
|
-
function hasRoleChecks(maybeRoledAuth) {
|
|
319
|
-
return typeof maybeRoledAuth === "object" && maybeRoledAuth !== null && ("allowedRoles" in maybeRoledAuth || "forbiddenRoles" in maybeRoledAuth);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// src/http/guards/hasScopeChecks.ts
|
|
323
|
-
function hasScopeChecks(maybePermissionedAuth) {
|
|
324
|
-
return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && "requiredScope" in maybePermissionedAuth && maybePermissionedAuth.requiredScope != null;
|
|
680
|
+
};
|
|
681
|
+
function logger(level, meta2 = {}) {
|
|
682
|
+
return new PinoLogger(level, meta2);
|
|
325
683
|
}
|
|
326
684
|
|
|
327
685
|
// src/http/middleware/request/auth.middleware.ts
|
|
@@ -385,7 +743,8 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
385
743
|
}
|
|
386
744
|
let sessionPayload;
|
|
387
745
|
const { type, auth } = await discriminateAuthMethod(
|
|
388
|
-
collapsedAuthorizationMethod
|
|
746
|
+
collapsedAuthorizationMethod,
|
|
747
|
+
req.openTelemetryCollector
|
|
389
748
|
);
|
|
390
749
|
switch (type) {
|
|
391
750
|
case "hmac": {
|
|
@@ -406,7 +765,7 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
406
765
|
const verificationResult = await auth.verificationFunction({
|
|
407
766
|
method: req?.method ?? "",
|
|
408
767
|
path: req?.path ?? "",
|
|
409
|
-
body: req?.body,
|
|
768
|
+
body: req?._rawBody ?? req?.body,
|
|
410
769
|
timestamp: new Date(parsedTimestamp),
|
|
411
770
|
nonce: parsedNonce,
|
|
412
771
|
signature: parsedSignature,
|
|
@@ -430,7 +789,15 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
430
789
|
}
|
|
431
790
|
sessionPayload = decodedJwt;
|
|
432
791
|
} catch (error) {
|
|
433
|
-
req?.openTelemetryCollector
|
|
792
|
+
req?.openTelemetryCollector?.error(
|
|
793
|
+
"JWT Verification Failed",
|
|
794
|
+
meta({
|
|
795
|
+
error,
|
|
796
|
+
method: req.method,
|
|
797
|
+
path: req.path,
|
|
798
|
+
token
|
|
799
|
+
})
|
|
800
|
+
);
|
|
434
801
|
return invalidAuthorizationToken;
|
|
435
802
|
}
|
|
436
803
|
break;
|
|
@@ -457,7 +824,7 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
457
824
|
break;
|
|
458
825
|
}
|
|
459
826
|
default:
|
|
460
|
-
(0,
|
|
827
|
+
(0, import_common6.isNever)(type);
|
|
461
828
|
return [401, "Invalid Authorization method."];
|
|
462
829
|
}
|
|
463
830
|
if (isHmacMethod(collapsedAuthorizationMethod) && sessionPayload == null) {
|
|
@@ -542,14 +909,18 @@ async function checkAuthorizationToken(req, authorizationMethod, authorizationTo
|
|
|
542
909
|
}
|
|
543
910
|
async function parseRequestAuth(req, res, next) {
|
|
544
911
|
const auth = req.contractDetails.auth;
|
|
545
|
-
const [
|
|
546
|
-
|
|
547
|
-
auth,
|
|
548
|
-
req.headers[auth?.headerName ?? "Authorization"] || req.headers[auth?.headerName ?? "authorization"],
|
|
549
|
-
req._globalOptions?.()?.auth
|
|
550
|
-
) ?? [];
|
|
912
|
+
const token = req.headers[auth?.headerName ?? "Authorization"] || req.headers[auth?.headerName ?? "authorization"];
|
|
913
|
+
const [error, message] = await checkAuthorizationToken(req, auth, token, req._globalOptions?.()?.auth) ?? [];
|
|
551
914
|
if (error != null) {
|
|
552
|
-
req.openTelemetryCollector
|
|
915
|
+
req.openTelemetryCollector?.error(
|
|
916
|
+
message || "Authorization Failed",
|
|
917
|
+
meta({
|
|
918
|
+
statusCode: error,
|
|
919
|
+
method: req.method,
|
|
920
|
+
path: req.path,
|
|
921
|
+
token
|
|
922
|
+
})
|
|
923
|
+
);
|
|
553
924
|
res.type("text/plain");
|
|
554
925
|
res.status(error).send(message);
|
|
555
926
|
return;
|
|
@@ -557,46 +928,11 @@ async function parseRequestAuth(req, res, next) {
|
|
|
557
928
|
next?.();
|
|
558
929
|
}
|
|
559
930
|
|
|
560
|
-
// src/http/middleware/request/createContext.middleware.ts
|
|
561
|
-
var import_common4 = require("@forklaunch/common");
|
|
562
|
-
var import_api = require("@opentelemetry/api");
|
|
563
|
-
var import_uuid = require("uuid");
|
|
564
|
-
|
|
565
|
-
// src/http/telemetry/constants.ts
|
|
566
|
-
var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
567
|
-
var ATTR_API_NAME = "api.name";
|
|
568
|
-
var ATTR_CORRELATION_ID = "correlation.id";
|
|
569
|
-
|
|
570
|
-
// src/http/middleware/request/createContext.middleware.ts
|
|
571
|
-
function createContext(schemaValidator) {
|
|
572
|
-
return function setContext(req, res, next) {
|
|
573
|
-
req.schemaValidator = schemaValidator;
|
|
574
|
-
let correlationId = (0, import_uuid.v4)();
|
|
575
|
-
if (req.headers["x-correlation-id"]) {
|
|
576
|
-
correlationId = req.headers["x-correlation-id"];
|
|
577
|
-
}
|
|
578
|
-
res.setHeader("x-correlation-id", correlationId);
|
|
579
|
-
req.context = {
|
|
580
|
-
correlationId
|
|
581
|
-
};
|
|
582
|
-
const span = import_api.trace.getSpan(import_api.context.active());
|
|
583
|
-
if (span != null) {
|
|
584
|
-
req.context.span = span;
|
|
585
|
-
req.context.span?.setAttribute(ATTR_CORRELATION_ID, correlationId);
|
|
586
|
-
req.context.span?.setAttribute(
|
|
587
|
-
import_semantic_conventions.ATTR_SERVICE_NAME,
|
|
588
|
-
(0, import_common4.getEnvVar)("OTEL_SERVICE_NAME")
|
|
589
|
-
);
|
|
590
|
-
}
|
|
591
|
-
next?.();
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
|
|
595
931
|
// src/http/middleware/request/enrichDetails.middleware.ts
|
|
596
|
-
var
|
|
932
|
+
var import_common8 = require("@forklaunch/common");
|
|
597
933
|
|
|
598
934
|
// src/http/telemetry/openTelemetryCollector.ts
|
|
599
|
-
var
|
|
935
|
+
var import_common7 = require("@forklaunch/common");
|
|
600
936
|
var import_opentelemetry_instrumentation_hyper_express = require("@forklaunch/opentelemetry-instrumentation-hyper-express");
|
|
601
937
|
var import_api3 = require("@opentelemetry/api");
|
|
602
938
|
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
|
@@ -616,171 +952,6 @@ function isForklaunchRequest(request) {
|
|
|
616
952
|
return request != null && typeof request === "object" && "contractDetails" in request;
|
|
617
953
|
}
|
|
618
954
|
|
|
619
|
-
// src/http/telemetry/pinoLogger.ts
|
|
620
|
-
var import_common5 = require("@forklaunch/common");
|
|
621
|
-
var import_api2 = require("@opentelemetry/api");
|
|
622
|
-
var import_api_logs = require("@opentelemetry/api-logs");
|
|
623
|
-
var import_pino = __toESM(require("pino"));
|
|
624
|
-
|
|
625
|
-
// src/http/guards/isLoggerMeta.ts
|
|
626
|
-
function isLoggerMeta(arg) {
|
|
627
|
-
return typeof arg === "object" && arg !== null && "_meta" in arg;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// src/http/telemetry/pinoLogger.ts
|
|
631
|
-
function meta(meta2) {
|
|
632
|
-
return meta2;
|
|
633
|
-
}
|
|
634
|
-
function mapSeverity(level) {
|
|
635
|
-
switch (level) {
|
|
636
|
-
case "silent":
|
|
637
|
-
return 0;
|
|
638
|
-
case "trace":
|
|
639
|
-
return 1;
|
|
640
|
-
case "debug":
|
|
641
|
-
return 5;
|
|
642
|
-
case "info":
|
|
643
|
-
return 9;
|
|
644
|
-
case "warn":
|
|
645
|
-
return 13;
|
|
646
|
-
case "error":
|
|
647
|
-
return 17;
|
|
648
|
-
case "fatal":
|
|
649
|
-
return 21;
|
|
650
|
-
default:
|
|
651
|
-
(0, import_common5.isNever)(level);
|
|
652
|
-
return 0;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
function normalizeLogArgs(args) {
|
|
656
|
-
let message = "";
|
|
657
|
-
const metaObjects = [];
|
|
658
|
-
for (const arg of args) {
|
|
659
|
-
if (typeof arg === "string" && message === "") {
|
|
660
|
-
message = arg;
|
|
661
|
-
} else if (arg instanceof Error) {
|
|
662
|
-
metaObjects.push({
|
|
663
|
-
err: {
|
|
664
|
-
message: arg.message,
|
|
665
|
-
name: arg.name,
|
|
666
|
-
stack: arg.stack,
|
|
667
|
-
...Object.keys(arg).length > 0 ? arg : {}
|
|
668
|
-
}
|
|
669
|
-
});
|
|
670
|
-
} else if (arg && typeof arg === "object" && !Array.isArray(arg)) {
|
|
671
|
-
metaObjects.push(arg);
|
|
672
|
-
} else {
|
|
673
|
-
message += ` ${String(arg)}`;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
const metadata = Object.assign({}, ...metaObjects);
|
|
677
|
-
return [metadata, message.trim()];
|
|
678
|
-
}
|
|
679
|
-
function safePrettyFormat(level, args, timestamp) {
|
|
680
|
-
try {
|
|
681
|
-
const [metadata, message] = normalizeLogArgs(args);
|
|
682
|
-
const formattedTimestamp = timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
683
|
-
return `[${formattedTimestamp}] ${level.toUpperCase()}: ${message}${Object.keys(metadata).length > 0 ? `
|
|
684
|
-
${JSON.stringify(metadata, null, 2)}` : ""}`;
|
|
685
|
-
} catch (error) {
|
|
686
|
-
const fallbackMessage = args.map((arg) => {
|
|
687
|
-
try {
|
|
688
|
-
if (typeof arg === "string") return arg;
|
|
689
|
-
if (arg === null) return "null";
|
|
690
|
-
if (arg === void 0) return "undefined";
|
|
691
|
-
return JSON.stringify(arg);
|
|
692
|
-
} catch {
|
|
693
|
-
return "[Circular/Non-serializable Object]";
|
|
694
|
-
}
|
|
695
|
-
}).join(" ");
|
|
696
|
-
return `[${(/* @__PURE__ */ new Date()).toISOString()}] ${level.toUpperCase()}: ${fallbackMessage} [Pretty Print Error: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
var PinoLogger = class _PinoLogger {
|
|
700
|
-
pinoLogger;
|
|
701
|
-
meta;
|
|
702
|
-
constructor(level, meta2 = {}) {
|
|
703
|
-
this.pinoLogger = (0, import_pino.default)({
|
|
704
|
-
level: level || "info",
|
|
705
|
-
formatters: {
|
|
706
|
-
level(label) {
|
|
707
|
-
return { level: label };
|
|
708
|
-
}
|
|
709
|
-
},
|
|
710
|
-
timestamp: import_pino.default.stdTimeFunctions.isoTime,
|
|
711
|
-
transport: {
|
|
712
|
-
target: "pino-pretty",
|
|
713
|
-
options: {
|
|
714
|
-
colorize: true,
|
|
715
|
-
errorLikeObjectKeys: ["err", "error"],
|
|
716
|
-
ignore: "pid,hostname",
|
|
717
|
-
translateTime: "SYS:standard"
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
});
|
|
721
|
-
this.meta = meta2;
|
|
722
|
-
}
|
|
723
|
-
log(level, ...args) {
|
|
724
|
-
let meta2 = {};
|
|
725
|
-
const filteredArgs = args.filter((arg) => {
|
|
726
|
-
if (isLoggerMeta(arg)) {
|
|
727
|
-
Object.assign(meta2, arg);
|
|
728
|
-
return false;
|
|
729
|
-
}
|
|
730
|
-
return true;
|
|
731
|
-
});
|
|
732
|
-
const [errorMetadata] = normalizeLogArgs(filteredArgs);
|
|
733
|
-
Object.assign(meta2, errorMetadata);
|
|
734
|
-
const activeSpan = import_api2.trace.getActiveSpan();
|
|
735
|
-
if (activeSpan) {
|
|
736
|
-
const activeSpanContext = activeSpan.spanContext();
|
|
737
|
-
meta2.trace_id = activeSpanContext.traceId;
|
|
738
|
-
meta2.span_id = activeSpanContext.spanId;
|
|
739
|
-
meta2.trace_flags = activeSpanContext.traceFlags;
|
|
740
|
-
meta2 = {
|
|
741
|
-
// @ts-expect-error accessing private property
|
|
742
|
-
...activeSpan.attributes,
|
|
743
|
-
...meta2
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
meta2 = {
|
|
747
|
-
"api.name": "none",
|
|
748
|
-
"correlation.id": "none",
|
|
749
|
-
...meta2
|
|
750
|
-
};
|
|
751
|
-
this.pinoLogger[level](...normalizeLogArgs(filteredArgs));
|
|
752
|
-
const formattedBody = safePrettyFormat(level, filteredArgs);
|
|
753
|
-
try {
|
|
754
|
-
import_api_logs.logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
|
755
|
-
severityText: level,
|
|
756
|
-
severityNumber: mapSeverity(level),
|
|
757
|
-
body: formattedBody,
|
|
758
|
-
attributes: { ...this.meta, ...meta2 }
|
|
759
|
-
});
|
|
760
|
-
} catch (error) {
|
|
761
|
-
console.error("Failed to emit OpenTelemetry log:", error);
|
|
762
|
-
console.log(
|
|
763
|
-
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${level.toUpperCase()}:`,
|
|
764
|
-
...filteredArgs
|
|
765
|
-
);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
error = (msg, ...args) => this.log("error", msg, ...args);
|
|
769
|
-
info = (msg, ...args) => this.log("info", msg, ...args);
|
|
770
|
-
debug = (msg, ...args) => this.log("debug", msg, ...args);
|
|
771
|
-
warn = (msg, ...args) => this.log("warn", msg, ...args);
|
|
772
|
-
trace = (msg, ...args) => this.log("trace", msg, ...args);
|
|
773
|
-
child(meta2 = {}) {
|
|
774
|
-
return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta2 });
|
|
775
|
-
}
|
|
776
|
-
getBaseLogger() {
|
|
777
|
-
return this.pinoLogger;
|
|
778
|
-
}
|
|
779
|
-
};
|
|
780
|
-
function logger(level, meta2 = {}) {
|
|
781
|
-
return new PinoLogger(level, meta2);
|
|
782
|
-
}
|
|
783
|
-
|
|
784
955
|
// src/http/telemetry/openTelemetryCollector.ts
|
|
785
956
|
var OpenTelemetryCollector = class {
|
|
786
957
|
#logger;
|
|
@@ -845,24 +1016,40 @@ var OpenTelemetryCollector = class {
|
|
|
845
1016
|
return this.#metrics[metricId];
|
|
846
1017
|
}
|
|
847
1018
|
};
|
|
848
|
-
import_dotenv.default.config({ path: (0,
|
|
1019
|
+
import_dotenv.default.config({ path: (0, import_common7.getEnvVar)("DOTENV_FILE_PATH") });
|
|
1020
|
+
function parseOtelHeaders() {
|
|
1021
|
+
const headersEnv = (0, import_common7.getEnvVar)("OTEL_EXPORTER_OTLP_HEADERS");
|
|
1022
|
+
if (!headersEnv) return void 0;
|
|
1023
|
+
const headers = {};
|
|
1024
|
+
for (const pair of headersEnv.split(",")) {
|
|
1025
|
+
const [key, ...valueParts] = pair.split("=");
|
|
1026
|
+
if (key && valueParts.length > 0) {
|
|
1027
|
+
headers[key.trim()] = valueParts.join("=").trim();
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
1031
|
+
}
|
|
1032
|
+
var otelHeaders = parseOtelHeaders();
|
|
849
1033
|
new import_sdk_node.NodeSDK({
|
|
850
1034
|
resource: (0, import_resources.resourceFromAttributes)({
|
|
851
|
-
[import_semantic_conventions2.ATTR_SERVICE_NAME]: (0,
|
|
1035
|
+
[import_semantic_conventions2.ATTR_SERVICE_NAME]: (0, import_common7.getEnvVar)("OTEL_SERVICE_NAME")
|
|
852
1036
|
}),
|
|
853
1037
|
traceExporter: new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
854
|
-
url: `${(0,
|
|
1038
|
+
url: `${(0, import_common7.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`,
|
|
1039
|
+
headers: otelHeaders
|
|
855
1040
|
}),
|
|
856
1041
|
metricReader: new import_sdk_metrics.PeriodicExportingMetricReader({
|
|
857
1042
|
exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
|
858
|
-
url: `${(0,
|
|
1043
|
+
url: `${(0, import_common7.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`,
|
|
1044
|
+
headers: otelHeaders
|
|
859
1045
|
}),
|
|
860
1046
|
exportIntervalMillis: 5e3
|
|
861
1047
|
}),
|
|
862
1048
|
logRecordProcessors: [
|
|
863
1049
|
new import_sdk_logs.BatchLogRecordProcessor(
|
|
864
1050
|
new import_exporter_logs_otlp_http.OTLPLogExporter({
|
|
865
|
-
url: `${(0,
|
|
1051
|
+
url: `${(0, import_common7.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`,
|
|
1052
|
+
headers: otelHeaders
|
|
866
1053
|
})
|
|
867
1054
|
)
|
|
868
1055
|
],
|
|
@@ -871,7 +1058,7 @@ new import_sdk_node.NodeSDK({
|
|
|
871
1058
|
applyCustomAttributesOnSpan: (span, request) => {
|
|
872
1059
|
span.setAttribute(
|
|
873
1060
|
import_semantic_conventions2.ATTR_SERVICE_NAME,
|
|
874
|
-
(0,
|
|
1061
|
+
(0, import_common7.getEnvVar)("OTEL_SERVICE_NAME") ?? "unknown"
|
|
875
1062
|
);
|
|
876
1063
|
if (isForklaunchRequest(request)) {
|
|
877
1064
|
span.setAttribute(ATTR_API_NAME, request.contractDetails?.name);
|
|
@@ -883,10 +1070,10 @@ new import_sdk_node.NodeSDK({
|
|
|
883
1070
|
new import_opentelemetry_instrumentation_hyper_express.HyperExpressInstrumentation()
|
|
884
1071
|
]
|
|
885
1072
|
}).start();
|
|
886
|
-
var httpRequestsTotalCounter = import_api3.metrics.getMeter((0,
|
|
1073
|
+
var httpRequestsTotalCounter = import_api3.metrics.getMeter((0, import_common7.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
|
887
1074
|
description: "Number of HTTP requests"
|
|
888
1075
|
});
|
|
889
|
-
var httpServerDurationHistogram = import_api3.metrics.getMeter((0,
|
|
1076
|
+
var httpServerDurationHistogram = import_api3.metrics.getMeter((0, import_common7.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createHistogram("http_server_duration", {
|
|
890
1077
|
description: "Duration of HTTP server requests",
|
|
891
1078
|
unit: "s"
|
|
892
1079
|
});
|
|
@@ -899,14 +1086,15 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
|
899
1086
|
req.requestSchema = requestSchema;
|
|
900
1087
|
res.responseSchemas = responseSchemas;
|
|
901
1088
|
req.openTelemetryCollector = openTelemetryCollector;
|
|
902
|
-
req._globalOptions = globalOptions;
|
|
1089
|
+
req._globalOptions = globalOptions ?? (() => void 0);
|
|
903
1090
|
req.context?.span?.setAttribute(ATTR_API_NAME, req.contractDetails?.name);
|
|
904
1091
|
const startTime = process.hrtime();
|
|
905
1092
|
res.on("finish", () => {
|
|
906
1093
|
const [seconds, nanoseconds] = process.hrtime(startTime);
|
|
907
1094
|
const durationMs = seconds + nanoseconds / 1e9;
|
|
908
1095
|
httpServerDurationHistogram.record(durationMs, {
|
|
909
|
-
[import_semantic_conventions.ATTR_SERVICE_NAME]: (0,
|
|
1096
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: (0, import_common8.getEnvVar)("OTEL_SERVICE_NAME") || "unknown",
|
|
1097
|
+
[ATTR_APPLICATION_ID]: (0, import_common8.getEnvVar)("OTEL_APPLICATION_ID"),
|
|
910
1098
|
[ATTR_API_NAME]: req.contractDetails?.name || "unknown",
|
|
911
1099
|
[import_semantic_conventions.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
|
912
1100
|
[import_semantic_conventions.ATTR_HTTP_ROUTE]: req.originalPath || "unknown",
|
|
@@ -918,7 +1106,7 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
|
918
1106
|
}
|
|
919
1107
|
|
|
920
1108
|
// src/http/middleware/request/parse.middleware.ts
|
|
921
|
-
var
|
|
1109
|
+
var import_common9 = require("@forklaunch/common");
|
|
922
1110
|
var import_validator2 = require("@forklaunch/validator");
|
|
923
1111
|
|
|
924
1112
|
// src/http/guards/hasSend.ts
|
|
@@ -935,6 +1123,7 @@ function isRequestShape(maybeResponseShape) {
|
|
|
935
1123
|
function parse(req, res, next) {
|
|
936
1124
|
const globalOptions = req._globalOptions?.();
|
|
937
1125
|
const collapsedOptions = req.contractDetails.options?.requestValidation ?? (globalOptions?.validation === false ? "none" : globalOptions?.validation?.request);
|
|
1126
|
+
req._rawBody = req.body;
|
|
938
1127
|
const request = {
|
|
939
1128
|
params: req.params,
|
|
940
1129
|
query: req.query,
|
|
@@ -946,7 +1135,7 @@ function parse(req, res, next) {
|
|
|
946
1135
|
let parsedRequest;
|
|
947
1136
|
let collectedParseErrors;
|
|
948
1137
|
if (req.contractDetails.versions) {
|
|
949
|
-
if ((0,
|
|
1138
|
+
if ((0, import_common9.isRecord)(req.requestSchema)) {
|
|
950
1139
|
let runningParseErrors = "";
|
|
951
1140
|
matchedVersions = [];
|
|
952
1141
|
Object.entries(req.requestSchema).forEach(([version, schema]) => {
|
|
@@ -1024,7 +1213,7 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
|
1024
1213
|
}
|
|
1025
1214
|
return;
|
|
1026
1215
|
case "warning":
|
|
1027
|
-
req.openTelemetryCollector
|
|
1216
|
+
req.openTelemetryCollector?.warn(
|
|
1028
1217
|
collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")
|
|
1029
1218
|
);
|
|
1030
1219
|
break;
|
|
@@ -1032,143 +1221,221 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
|
1032
1221
|
break;
|
|
1033
1222
|
}
|
|
1034
1223
|
}
|
|
1035
|
-
req._parsedVersions = matchedVersions;
|
|
1036
|
-
next?.();
|
|
1224
|
+
req._parsedVersions = matchedVersions;
|
|
1225
|
+
next?.();
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// src/http/router/routerSharedLogic.ts
|
|
1229
|
+
function resolveContractDetailsAndHandlers(contractDetailsOrMiddlewareOrTypedHandler, middlewareOrMiddlewareAndTypedHandler) {
|
|
1230
|
+
let contractDetails;
|
|
1231
|
+
let handlers = [];
|
|
1232
|
+
if (isTypedHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
|
|
1233
|
+
contractDetails = contractDetailsOrMiddlewareOrTypedHandler.contractDetails;
|
|
1234
|
+
handlers = contractDetailsOrMiddlewareOrTypedHandler.handlers;
|
|
1235
|
+
} else {
|
|
1236
|
+
const maybeTypedHandler = middlewareOrMiddlewareAndTypedHandler[middlewareOrMiddlewareAndTypedHandler.length - 1];
|
|
1237
|
+
if (isTypedHandler(maybeTypedHandler)) {
|
|
1238
|
+
contractDetails = maybeTypedHandler.contractDetails;
|
|
1239
|
+
const typedHandlerHandlers = maybeTypedHandler.handlers;
|
|
1240
|
+
const finalHandlers = [];
|
|
1241
|
+
if (isExpressLikeSchemaHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
|
|
1242
|
+
finalHandlers.push(contractDetailsOrMiddlewareOrTypedHandler);
|
|
1243
|
+
}
|
|
1244
|
+
finalHandlers.push(...middlewareOrMiddlewareAndTypedHandler.slice(0, -1));
|
|
1245
|
+
finalHandlers.push(
|
|
1246
|
+
...typedHandlerHandlers
|
|
1247
|
+
);
|
|
1248
|
+
handlers = finalHandlers.filter(
|
|
1249
|
+
(handler) => isExpressLikeSchemaHandler(handler)
|
|
1250
|
+
);
|
|
1251
|
+
} else {
|
|
1252
|
+
if (isExpressLikeSchemaHandler(contractDetailsOrMiddlewareOrTypedHandler) || isTypedHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
|
|
1253
|
+
throw new Error("Contract details are not defined");
|
|
1254
|
+
}
|
|
1255
|
+
contractDetails = contractDetailsOrMiddlewareOrTypedHandler;
|
|
1256
|
+
handlers = middlewareOrMiddlewareAndTypedHandler.filter(
|
|
1257
|
+
(handler) => isExpressLikeSchemaHandler(handler)
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
return { contractDetails, handlers };
|
|
1262
|
+
}
|
|
1263
|
+
function validateContractDetails(contractDetails, schemaValidator) {
|
|
1264
|
+
if (!isHttpContractDetails(contractDetails) && !isPathParamHttpContractDetails(contractDetails)) {
|
|
1265
|
+
throw new Error("Contract details are malformed for route definition");
|
|
1266
|
+
}
|
|
1267
|
+
if (contractDetails.versions) {
|
|
1268
|
+
const parserTypes = Object.values(contractDetails.versions).map(
|
|
1269
|
+
(version) => discriminateBody(schemaValidator, version.body)?.parserType
|
|
1270
|
+
);
|
|
1271
|
+
const allParserTypesSame = parserTypes.length === 0 || parserTypes.every((pt) => pt === parserTypes[0]);
|
|
1272
|
+
if (!allParserTypesSame) {
|
|
1273
|
+
throw new Error(
|
|
1274
|
+
"All versioned contractDetails must have the same parsing type for body."
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1037
1278
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1279
|
+
function processContractDetailsIO(schemaValidator, contractDetailsIO, routeParams) {
|
|
1280
|
+
const responseSchemas = {
|
|
1281
|
+
400: schemaValidator.string,
|
|
1282
|
+
401: schemaValidator.string,
|
|
1283
|
+
403: schemaValidator.string,
|
|
1284
|
+
404: schemaValidator.string,
|
|
1285
|
+
500: schemaValidator.string,
|
|
1286
|
+
...Object.fromEntries(
|
|
1287
|
+
Object.entries(
|
|
1288
|
+
discriminateResponseBodies(schemaValidator, contractDetailsIO.responses)
|
|
1289
|
+
).map(([key, value]) => [Number(key), value.schema])
|
|
1290
|
+
)
|
|
1291
|
+
};
|
|
1292
|
+
return {
|
|
1293
|
+
requestSchema: schemaValidator.compile(
|
|
1294
|
+
schemaValidator.schemify({
|
|
1295
|
+
...routeParams != null ? { params: routeParams } : { params: schemaValidator.unknown },
|
|
1296
|
+
...contractDetailsIO.requestHeaders != null ? { headers: contractDetailsIO.requestHeaders } : { headers: schemaValidator.unknown },
|
|
1297
|
+
...contractDetailsIO.query != null ? { query: contractDetailsIO.query } : { query: schemaValidator.unknown },
|
|
1298
|
+
...contractDetailsIO.body != null ? {
|
|
1299
|
+
body: discriminateBody(schemaValidator, contractDetailsIO.body)?.schema
|
|
1300
|
+
} : { body: schemaValidator.unknown }
|
|
1301
|
+
})
|
|
1302
|
+
),
|
|
1303
|
+
responseSchemas: {
|
|
1304
|
+
...contractDetailsIO.responseHeaders != null ? {
|
|
1305
|
+
headers: schemaValidator.compile(
|
|
1306
|
+
schemaValidator.schemify(contractDetailsIO.responseHeaders)
|
|
1307
|
+
)
|
|
1308
|
+
} : { headers: schemaValidator.unknown },
|
|
1309
|
+
responses: Object.fromEntries(
|
|
1310
|
+
Object.entries(responseSchemas).map(([key, value]) => [
|
|
1311
|
+
key,
|
|
1312
|
+
schemaValidator.compile(schemaValidator.schemify(value))
|
|
1313
|
+
])
|
|
1314
|
+
)
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
function compileRouteSchemas(contractDetails, schemaValidator) {
|
|
1319
|
+
const validator = schemaValidator;
|
|
1320
|
+
let requestSchema;
|
|
1321
|
+
let responseSchemas;
|
|
1322
|
+
if (hasVersionedSchema(contractDetails)) {
|
|
1323
|
+
requestSchema = {};
|
|
1324
|
+
responseSchemas = {};
|
|
1325
|
+
Object.entries(contractDetails.versions ?? {}).forEach(
|
|
1326
|
+
([version, versionedContractDetails]) => {
|
|
1327
|
+
const {
|
|
1328
|
+
requestSchema: versionedRequestSchema,
|
|
1329
|
+
responseSchemas: versionedResponseSchemas
|
|
1330
|
+
} = processContractDetailsIO(
|
|
1331
|
+
validator,
|
|
1332
|
+
versionedContractDetails,
|
|
1333
|
+
contractDetails.params
|
|
1334
|
+
);
|
|
1335
|
+
if ((0, import_common10.isRecord)(requestSchema)) {
|
|
1336
|
+
requestSchema = {
|
|
1337
|
+
...requestSchema,
|
|
1338
|
+
[version]: versionedRequestSchema
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
if ((0, import_common10.isRecord)(responseSchemas)) {
|
|
1342
|
+
responseSchemas = {
|
|
1343
|
+
...responseSchemas,
|
|
1344
|
+
[version]: versionedResponseSchemas
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
);
|
|
1096
1349
|
} else {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1350
|
+
const {
|
|
1351
|
+
requestSchema: unversionedRequestSchema,
|
|
1352
|
+
responseSchemas: unversionedResponseSchemas
|
|
1353
|
+
} = processContractDetailsIO(
|
|
1354
|
+
validator,
|
|
1355
|
+
{
|
|
1356
|
+
..."params" in contractDetails && contractDetails.params != null ? { params: contractDetails.params } : { params: validator.unknown },
|
|
1357
|
+
..."requestHeaders" in contractDetails && contractDetails.requestHeaders != null ? { requestHeaders: contractDetails.requestHeaders } : {
|
|
1358
|
+
requestHeaders: validator.unknown
|
|
1359
|
+
},
|
|
1360
|
+
..."responseHeaders" in contractDetails && contractDetails.responseHeaders != null ? { responseHeaders: contractDetails.responseHeaders } : {
|
|
1361
|
+
responseHeaders: validator.unknown
|
|
1362
|
+
},
|
|
1363
|
+
..."query" in contractDetails && contractDetails.query != null ? { query: contractDetails.query } : {
|
|
1364
|
+
query: validator.unknown
|
|
1365
|
+
},
|
|
1366
|
+
..."body" in contractDetails && contractDetails.body != null ? { body: contractDetails.body } : {
|
|
1367
|
+
body: validator.unknown
|
|
1368
|
+
},
|
|
1369
|
+
responses: "responses" in contractDetails && contractDetails.responses != null ? contractDetails.responses : validator.unknown
|
|
1370
|
+
},
|
|
1371
|
+
contractDetails.params
|
|
1372
|
+
);
|
|
1373
|
+
requestSchema = unversionedRequestSchema;
|
|
1374
|
+
responseSchemas = unversionedResponseSchemas;
|
|
1102
1375
|
}
|
|
1376
|
+
return { requestSchema, responseSchemas };
|
|
1103
1377
|
}
|
|
1104
|
-
function
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
parserType: "json",
|
|
1112
|
-
schema: response.json
|
|
1113
|
-
};
|
|
1114
|
-
} else if ("schema" in response && response.schema != null) {
|
|
1115
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1116
|
-
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/json") ?? "application/json",
|
|
1117
|
-
parserType: "text",
|
|
1118
|
-
schema: response.schema
|
|
1119
|
-
};
|
|
1120
|
-
} else if ("text" in response && response.text != null) {
|
|
1121
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1122
|
-
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "text/plain") ?? "text/plain",
|
|
1123
|
-
parserType: "text",
|
|
1124
|
-
schema: response.text
|
|
1125
|
-
};
|
|
1126
|
-
} else if ("file" in response && response.file != null) {
|
|
1127
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1128
|
-
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "application/octet-stream") ?? "application/octet-stream",
|
|
1129
|
-
parserType: "file",
|
|
1130
|
-
schema: response.file
|
|
1131
|
-
};
|
|
1132
|
-
} else if ("event" in response && response.event != null) {
|
|
1133
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1134
|
-
contentType: ("contentType" in response && typeof response.contentType === "string" ? response.contentType : "text/event-stream") ?? "text/event-stream",
|
|
1135
|
-
parserType: "serverSentEvent",
|
|
1136
|
-
schema: response.event
|
|
1137
|
-
};
|
|
1138
|
-
} else if (schemaValidator.isInstanceOf(
|
|
1139
|
-
response,
|
|
1140
|
-
schemaValidator.string
|
|
1141
|
-
)) {
|
|
1142
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1143
|
-
contentType: "text/plain",
|
|
1144
|
-
parserType: "text",
|
|
1145
|
-
schema: response
|
|
1146
|
-
};
|
|
1147
|
-
} else if (schemaValidator.openapi(response).format === "binary") {
|
|
1148
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1149
|
-
contentType: "application/octet-stream",
|
|
1150
|
-
parserType: "file",
|
|
1151
|
-
schema: response
|
|
1152
|
-
};
|
|
1153
|
-
} else {
|
|
1154
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1155
|
-
contentType: "application/json",
|
|
1156
|
-
parserType: "json",
|
|
1157
|
-
schema: response
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
} else {
|
|
1161
|
-
discriminatedResponses[Number(statusCode)] = {
|
|
1162
|
-
contentType: "application/json",
|
|
1163
|
-
parserType: "json",
|
|
1164
|
-
schema: response
|
|
1165
|
-
};
|
|
1166
|
-
}
|
|
1378
|
+
function resolveRouteMiddlewares(params) {
|
|
1379
|
+
const handlersCopy = [...params.handlers];
|
|
1380
|
+
const controllerHandler = handlersCopy.pop();
|
|
1381
|
+
if (typeof controllerHandler !== "function") {
|
|
1382
|
+
throw new Error(
|
|
1383
|
+
`Last argument must be a handler, received: ${controllerHandler}`
|
|
1384
|
+
);
|
|
1167
1385
|
}
|
|
1168
|
-
|
|
1386
|
+
const middlewares = [
|
|
1387
|
+
...params.includeCreateContext !== false ? [createContext] : [],
|
|
1388
|
+
enrichDetails(
|
|
1389
|
+
`${params.basePath}${params.path}`,
|
|
1390
|
+
params.contractDetails,
|
|
1391
|
+
params.requestSchema,
|
|
1392
|
+
params.responseSchemas,
|
|
1393
|
+
params.openTelemetryCollector,
|
|
1394
|
+
() => params.routerOptions
|
|
1395
|
+
),
|
|
1396
|
+
...params.postEnrichMiddleware,
|
|
1397
|
+
parse,
|
|
1398
|
+
parseRequestAuth,
|
|
1399
|
+
...handlersCopy
|
|
1400
|
+
];
|
|
1401
|
+
return {
|
|
1402
|
+
middlewares,
|
|
1403
|
+
controllerHandler
|
|
1404
|
+
};
|
|
1169
1405
|
}
|
|
1170
1406
|
|
|
1171
1407
|
// src/http/router/expressLikeRouter.ts
|
|
1408
|
+
function extractRouteHandlers(params) {
|
|
1409
|
+
const schemaValidator = params.schemaValidator;
|
|
1410
|
+
const { contractDetails, handlers } = resolveContractDetailsAndHandlers(
|
|
1411
|
+
params.contractDetailsOrMiddlewareOrTypedHandler,
|
|
1412
|
+
params.middlewareOrMiddlewareAndTypedHandler
|
|
1413
|
+
);
|
|
1414
|
+
validateContractDetails(contractDetails, schemaValidator);
|
|
1415
|
+
const { requestSchema, responseSchemas } = compileRouteSchemas(
|
|
1416
|
+
contractDetails,
|
|
1417
|
+
schemaValidator
|
|
1418
|
+
);
|
|
1419
|
+
const { middlewares, controllerHandler } = resolveRouteMiddlewares({
|
|
1420
|
+
basePath: params.basePath,
|
|
1421
|
+
path: params.path,
|
|
1422
|
+
contractDetails,
|
|
1423
|
+
requestSchema,
|
|
1424
|
+
responseSchemas,
|
|
1425
|
+
openTelemetryCollector: params.openTelemetryCollector,
|
|
1426
|
+
routerOptions: params.routerOptions,
|
|
1427
|
+
postEnrichMiddleware: params.postEnrichMiddleware ?? [],
|
|
1428
|
+
handlers,
|
|
1429
|
+
includeCreateContext: false
|
|
1430
|
+
});
|
|
1431
|
+
return {
|
|
1432
|
+
middlewares: [
|
|
1433
|
+
createContext(schemaValidator),
|
|
1434
|
+
...middlewares
|
|
1435
|
+
],
|
|
1436
|
+
controllerHandler
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1172
1439
|
var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
1173
1440
|
constructor(basePath, schemaValidator, internal, postEnrichMiddleware, openTelemetryCollector, routerOptions) {
|
|
1174
1441
|
this.basePath = basePath;
|
|
@@ -1208,21 +1475,6 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
1208
1475
|
* @param {PathParamHttpContractDetails<SV> | HttpContractDetails<SV>} contractDetails - The contract details.
|
|
1209
1476
|
* @returns {MiddlewareHandler<SV>[]} - The resolved middlewares.
|
|
1210
1477
|
*/
|
|
1211
|
-
#resolveMiddlewares(path, contractDetails, requestSchema, responseSchemas) {
|
|
1212
|
-
return [
|
|
1213
|
-
enrichDetails(
|
|
1214
|
-
`${this.basePath}${path}`,
|
|
1215
|
-
contractDetails,
|
|
1216
|
-
requestSchema,
|
|
1217
|
-
responseSchemas,
|
|
1218
|
-
this.openTelemetryCollector,
|
|
1219
|
-
() => this.routerOptions
|
|
1220
|
-
),
|
|
1221
|
-
...this.postEnrichMiddleware,
|
|
1222
|
-
parse,
|
|
1223
|
-
parseRequestAuth
|
|
1224
|
-
];
|
|
1225
|
-
}
|
|
1226
1478
|
/**
|
|
1227
1479
|
* Parses and runs the controller handler with error handling.
|
|
1228
1480
|
*
|
|
@@ -1263,126 +1515,6 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
1263
1515
|
* @returns {MiddlewareHandler<SV, P, ResBodyMap, ReqBody, ReqQuery, LocalsObj>} - The extracted controller handler.
|
|
1264
1516
|
* @throws {Error} - Throws an error if the last argument is not a handler.
|
|
1265
1517
|
*/
|
|
1266
|
-
#extractControllerHandler(handlers) {
|
|
1267
|
-
const controllerHandler = handlers.pop();
|
|
1268
|
-
if (typeof controllerHandler !== "function") {
|
|
1269
|
-
throw new Error(
|
|
1270
|
-
`Last argument must be a handler, received: ${controllerHandler}`
|
|
1271
|
-
);
|
|
1272
|
-
}
|
|
1273
|
-
return controllerHandler;
|
|
1274
|
-
}
|
|
1275
|
-
#processContractDetailsIO(contractDetailsIO, params) {
|
|
1276
|
-
const schemaValidator = this.schemaValidator;
|
|
1277
|
-
const responseSchemas = {
|
|
1278
|
-
400: schemaValidator.string,
|
|
1279
|
-
401: schemaValidator.string,
|
|
1280
|
-
403: schemaValidator.string,
|
|
1281
|
-
404: schemaValidator.string,
|
|
1282
|
-
500: schemaValidator.string,
|
|
1283
|
-
...Object.fromEntries(
|
|
1284
|
-
Object.entries(
|
|
1285
|
-
discriminateResponseBodies(
|
|
1286
|
-
this.schemaValidator,
|
|
1287
|
-
contractDetailsIO.responses
|
|
1288
|
-
)
|
|
1289
|
-
).map(([key, value]) => {
|
|
1290
|
-
return [Number(key), value.schema];
|
|
1291
|
-
})
|
|
1292
|
-
)
|
|
1293
|
-
};
|
|
1294
|
-
return {
|
|
1295
|
-
requestSchema: schemaValidator.compile(
|
|
1296
|
-
schemaValidator.schemify({
|
|
1297
|
-
...params != null ? { params } : { params: schemaValidator.unknown },
|
|
1298
|
-
...contractDetailsIO.requestHeaders != null ? { headers: contractDetailsIO.requestHeaders } : { headers: schemaValidator.unknown },
|
|
1299
|
-
...contractDetailsIO.query != null ? { query: contractDetailsIO.query } : { query: schemaValidator.unknown },
|
|
1300
|
-
...contractDetailsIO.body != null ? {
|
|
1301
|
-
body: discriminateBody(
|
|
1302
|
-
this.schemaValidator,
|
|
1303
|
-
contractDetailsIO.body
|
|
1304
|
-
)?.schema
|
|
1305
|
-
} : { body: schemaValidator.unknown }
|
|
1306
|
-
})
|
|
1307
|
-
),
|
|
1308
|
-
responseSchemas: {
|
|
1309
|
-
...contractDetailsIO.responseHeaders != null ? {
|
|
1310
|
-
headers: schemaValidator.compile(
|
|
1311
|
-
schemaValidator.schemify(contractDetailsIO.responseHeaders)
|
|
1312
|
-
)
|
|
1313
|
-
} : { headers: schemaValidator.unknown },
|
|
1314
|
-
responses: Object.fromEntries(
|
|
1315
|
-
Object.entries(responseSchemas).map(([key, value]) => {
|
|
1316
|
-
return [
|
|
1317
|
-
key,
|
|
1318
|
-
schemaValidator.compile(schemaValidator.schemify(value))
|
|
1319
|
-
];
|
|
1320
|
-
})
|
|
1321
|
-
)
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
}
|
|
1325
|
-
#compile(contractDetails) {
|
|
1326
|
-
const schemaValidator = this.schemaValidator;
|
|
1327
|
-
let requestSchema;
|
|
1328
|
-
let responseSchemas;
|
|
1329
|
-
if (hasVersionedSchema(contractDetails)) {
|
|
1330
|
-
requestSchema = {};
|
|
1331
|
-
responseSchemas = {};
|
|
1332
|
-
Object.entries(contractDetails.versions ?? {}).forEach(
|
|
1333
|
-
([version, versionedContractDetails]) => {
|
|
1334
|
-
const {
|
|
1335
|
-
requestSchema: versionedRequestSchema,
|
|
1336
|
-
responseSchemas: versionedResponseSchemas
|
|
1337
|
-
} = this.#processContractDetailsIO(
|
|
1338
|
-
versionedContractDetails,
|
|
1339
|
-
contractDetails.params
|
|
1340
|
-
);
|
|
1341
|
-
if ((0, import_common9.isRecord)(requestSchema)) {
|
|
1342
|
-
requestSchema = {
|
|
1343
|
-
...requestSchema,
|
|
1344
|
-
[version]: versionedRequestSchema
|
|
1345
|
-
};
|
|
1346
|
-
}
|
|
1347
|
-
if ((0, import_common9.isRecord)(responseSchemas)) {
|
|
1348
|
-
responseSchemas = {
|
|
1349
|
-
...responseSchemas,
|
|
1350
|
-
[version]: versionedResponseSchemas
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
);
|
|
1355
|
-
} else {
|
|
1356
|
-
const {
|
|
1357
|
-
requestSchema: unversionedRequestSchema,
|
|
1358
|
-
responseSchemas: unversionedResponseSchemas
|
|
1359
|
-
} = this.#processContractDetailsIO(
|
|
1360
|
-
{
|
|
1361
|
-
..."params" in contractDetails && contractDetails.params != null ? { params: contractDetails.params } : { params: schemaValidator.unknown },
|
|
1362
|
-
..."requestHeaders" in contractDetails && contractDetails.requestHeaders != null ? { requestHeaders: contractDetails.requestHeaders } : {
|
|
1363
|
-
requestHeaders: schemaValidator.unknown
|
|
1364
|
-
},
|
|
1365
|
-
..."responseHeaders" in contractDetails && contractDetails.responseHeaders != null ? { responseHeaders: contractDetails.responseHeaders } : {
|
|
1366
|
-
responseHeaders: schemaValidator.unknown
|
|
1367
|
-
},
|
|
1368
|
-
..."query" in contractDetails && contractDetails.query != null ? { query: contractDetails.query } : {
|
|
1369
|
-
query: schemaValidator.unknown
|
|
1370
|
-
},
|
|
1371
|
-
..."body" in contractDetails && contractDetails.body != null ? { body: contractDetails.body } : {
|
|
1372
|
-
body: schemaValidator.unknown
|
|
1373
|
-
},
|
|
1374
|
-
responses: "responses" in contractDetails && contractDetails.responses != null ? contractDetails.responses : schemaValidator.unknown
|
|
1375
|
-
},
|
|
1376
|
-
contractDetails.params
|
|
1377
|
-
);
|
|
1378
|
-
requestSchema = unversionedRequestSchema;
|
|
1379
|
-
responseSchemas = unversionedResponseSchemas;
|
|
1380
|
-
}
|
|
1381
|
-
return {
|
|
1382
|
-
requestSchema,
|
|
1383
|
-
responseSchemas
|
|
1384
|
-
};
|
|
1385
|
-
}
|
|
1386
1518
|
/**
|
|
1387
1519
|
* Fetches a route from the route map and executes it with the given parameters.
|
|
1388
1520
|
*
|
|
@@ -1472,92 +1604,71 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
1472
1604
|
};
|
|
1473
1605
|
}
|
|
1474
1606
|
registerRoute(method, path, registrationMethod, contractDetailsOrMiddlewareOrTypedHandler, ...middlewareOrMiddlewareAndTypedHandler) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
path
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
[method.toUpperCase()]: contractDetails.versions ? Object.fromEntries(
|
|
1539
|
-
Object.keys(contractDetails.versions).map((version) => [
|
|
1540
|
-
version,
|
|
1541
|
-
this.#localParamRequest(handlers, controllerHandler, version)
|
|
1542
|
-
])
|
|
1543
|
-
) : this.#localParamRequest(handlers, controllerHandler)
|
|
1544
|
-
};
|
|
1545
|
-
(0, import_common9.toRecord)(this.sdk)[(0, import_common9.toPrettyCamelCase)(contractDetails.name)] = contractDetails.versions ? Object.fromEntries(
|
|
1546
|
-
Object.keys(contractDetails.versions).map((version) => [
|
|
1547
|
-
version,
|
|
1548
|
-
(req) => this.#localParamRequest(
|
|
1549
|
-
handlers,
|
|
1550
|
-
controllerHandler,
|
|
1551
|
-
version
|
|
1552
|
-
)(`${this.basePath}${path}`, req)
|
|
1553
|
-
])
|
|
1554
|
-
) : (req) => this.#localParamRequest(handlers, controllerHandler)(
|
|
1555
|
-
`${this.basePath}${path}`,
|
|
1556
|
-
req
|
|
1557
|
-
);
|
|
1558
|
-
return this;
|
|
1559
|
-
}
|
|
1607
|
+
const { contractDetails, handlers } = resolveContractDetailsAndHandlers(
|
|
1608
|
+
contractDetailsOrMiddlewareOrTypedHandler,
|
|
1609
|
+
middlewareOrMiddlewareAndTypedHandler
|
|
1610
|
+
);
|
|
1611
|
+
validateContractDetails(contractDetails, this.schemaValidator);
|
|
1612
|
+
this.routes.push({
|
|
1613
|
+
basePath: this.basePath,
|
|
1614
|
+
path,
|
|
1615
|
+
method,
|
|
1616
|
+
contractDetails
|
|
1617
|
+
});
|
|
1618
|
+
const { requestSchema, responseSchemas } = compileRouteSchemas(
|
|
1619
|
+
contractDetails,
|
|
1620
|
+
this.schemaValidator
|
|
1621
|
+
);
|
|
1622
|
+
const { middlewares, controllerHandler } = resolveRouteMiddlewares({
|
|
1623
|
+
basePath: this.basePath,
|
|
1624
|
+
path,
|
|
1625
|
+
contractDetails,
|
|
1626
|
+
requestSchema,
|
|
1627
|
+
responseSchemas,
|
|
1628
|
+
openTelemetryCollector: this.openTelemetryCollector,
|
|
1629
|
+
routerOptions: this.routerOptions,
|
|
1630
|
+
postEnrichMiddleware: this.postEnrichMiddleware,
|
|
1631
|
+
includeCreateContext: false,
|
|
1632
|
+
handlers
|
|
1633
|
+
});
|
|
1634
|
+
registrationMethod.bind(this.internal)(
|
|
1635
|
+
path,
|
|
1636
|
+
...middlewares,
|
|
1637
|
+
this.#parseAndRunControllerHandler(controllerHandler)
|
|
1638
|
+
);
|
|
1639
|
+
(0, import_common11.toRecord)(this._fetchMap)[(0, import_common11.sanitizePathSlashes)(`${this.basePath}${path}`)] = {
|
|
1640
|
+
...this._fetchMap[(0, import_common11.sanitizePathSlashes)(`${this.basePath}${path}`)] ?? {},
|
|
1641
|
+
[method.toUpperCase()]: contractDetails.versions ? Object.fromEntries(
|
|
1642
|
+
Object.keys(contractDetails.versions).map((version) => [
|
|
1643
|
+
version,
|
|
1644
|
+
this.#localParamRequest(
|
|
1645
|
+
middlewares,
|
|
1646
|
+
controllerHandler,
|
|
1647
|
+
version
|
|
1648
|
+
)
|
|
1649
|
+
])
|
|
1650
|
+
) : this.#localParamRequest(
|
|
1651
|
+
middlewares,
|
|
1652
|
+
controllerHandler
|
|
1653
|
+
)
|
|
1654
|
+
};
|
|
1655
|
+
const contractDetailsName = contractDetails.name;
|
|
1656
|
+
if (contractDetailsName) {
|
|
1657
|
+
(0, import_common11.toRecord)(this.sdk)[(0, import_common11.toPrettyCamelCase)(contractDetailsName)] = contractDetails.versions ? Object.fromEntries(
|
|
1658
|
+
Object.keys(contractDetails.versions).map((version) => [
|
|
1659
|
+
version,
|
|
1660
|
+
(req) => this.#localParamRequest(
|
|
1661
|
+
middlewares,
|
|
1662
|
+
controllerHandler,
|
|
1663
|
+
version
|
|
1664
|
+
)(`${this.basePath}${path}`, req)
|
|
1665
|
+
])
|
|
1666
|
+
) : (req) => this.#localParamRequest(
|
|
1667
|
+
middlewares,
|
|
1668
|
+
controllerHandler
|
|
1669
|
+
)(`${this.basePath}${path}`, req);
|
|
1560
1670
|
}
|
|
1671
|
+
return this;
|
|
1561
1672
|
}
|
|
1562
1673
|
#extractHandlers(handlers, processMiddleware) {
|
|
1563
1674
|
const last = handlers.pop();
|
|
@@ -1641,10 +1752,10 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
1641
1752
|
}
|
|
1642
1753
|
addRouterToSdk(router) {
|
|
1643
1754
|
Object.entries(router._fetchMap).map(
|
|
1644
|
-
([key, value]) => (0,
|
|
1755
|
+
([key, value]) => (0, import_common11.toRecord)(this._fetchMap)[(0, import_common11.sanitizePathSlashes)(`${this.basePath}${key}`)] = value
|
|
1645
1756
|
);
|
|
1646
|
-
const existingSdk = this.sdk[router.sdkName ?? (0,
|
|
1647
|
-
(0,
|
|
1757
|
+
const existingSdk = this.sdk[router.sdkName ?? (0, import_common11.toPrettyCamelCase)(router.basePath)];
|
|
1758
|
+
(0, import_common11.toRecord)(this.sdk)[router.sdkName ?? (0, import_common11.toPrettyCamelCase)(router.basePath)] = {
|
|
1648
1759
|
...typeof existingSdk === "object" ? existingSdk : {},
|
|
1649
1760
|
...router.sdk
|
|
1650
1761
|
};
|
|
@@ -1936,7 +2047,7 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
|
|
|
1936
2047
|
unpackSdks(sdks, path, routerUniquenessCache) {
|
|
1937
2048
|
Object.entries(sdks).forEach(([key, maybeHandler]) => {
|
|
1938
2049
|
if (isSdkHandler(maybeHandler)) {
|
|
1939
|
-
const cacheKey = (0,
|
|
2050
|
+
const cacheKey = (0, import_common11.hashString)((0, import_common11.safeStringify)(maybeHandler));
|
|
1940
2051
|
if (routerUniquenessCache.has(cacheKey)) {
|
|
1941
2052
|
throw new Error(`SDK handler ${key} is already registered`);
|
|
1942
2053
|
}
|
|
@@ -2030,6 +2141,30 @@ function isPortBound(port, host = "localhost") {
|
|
|
2030
2141
|
});
|
|
2031
2142
|
}
|
|
2032
2143
|
|
|
2144
|
+
// src/http/generateHmacAuthHeaders.ts
|
|
2145
|
+
var import_crypto2 = require("crypto");
|
|
2146
|
+
function generateHmacAuthHeaders({
|
|
2147
|
+
secretKey,
|
|
2148
|
+
method,
|
|
2149
|
+
path,
|
|
2150
|
+
body,
|
|
2151
|
+
keyId = "default"
|
|
2152
|
+
}) {
|
|
2153
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
2154
|
+
const nonce = (0, import_crypto2.randomUUID)();
|
|
2155
|
+
const signature = createHmacToken({
|
|
2156
|
+
secretKey,
|
|
2157
|
+
method,
|
|
2158
|
+
path,
|
|
2159
|
+
timestamp,
|
|
2160
|
+
nonce,
|
|
2161
|
+
body
|
|
2162
|
+
});
|
|
2163
|
+
return {
|
|
2164
|
+
authorization: `HMAC keyId=${keyId} ts=${timestamp.toISOString()} nonce=${nonce} signature=${signature}`
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2033
2168
|
// src/http/guards/isPath.ts
|
|
2034
2169
|
function isPath(path) {
|
|
2035
2170
|
return path.startsWith("/");
|
|
@@ -3100,9 +3235,9 @@ var getCodeForStatus = (status) => {
|
|
|
3100
3235
|
var httpStatusCodes_default = HTTPStatuses;
|
|
3101
3236
|
|
|
3102
3237
|
// src/http/mcpGenerator/mcpGenerator.ts
|
|
3103
|
-
var
|
|
3104
|
-
var import_fastmcp_fork = require("@forklaunch/fastmcp-fork");
|
|
3238
|
+
var import_common12 = require("@forklaunch/common");
|
|
3105
3239
|
var import_zod = require("@forklaunch/validator/zod");
|
|
3240
|
+
var import_fastmcp = require("fastmcp");
|
|
3106
3241
|
|
|
3107
3242
|
// src/http/router/unpackRouters.ts
|
|
3108
3243
|
function unpackRouters(routers, recursiveBasePath = []) {
|
|
@@ -3157,7 +3292,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3157
3292
|
"Schema validator must be an instance of ZodSchemaValidator"
|
|
3158
3293
|
);
|
|
3159
3294
|
}
|
|
3160
|
-
const mcpServer = new
|
|
3295
|
+
const mcpServer = new import_fastmcp.FastMCP({
|
|
3161
3296
|
...options2,
|
|
3162
3297
|
name: options2?.name ?? "mcp-server",
|
|
3163
3298
|
version,
|
|
@@ -3235,7 +3370,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3235
3370
|
if (discriminatedBody) {
|
|
3236
3371
|
switch (discriminatedBody.parserType) {
|
|
3237
3372
|
case "json": {
|
|
3238
|
-
parsedBody = (0,
|
|
3373
|
+
parsedBody = (0, import_common12.safeStringify)(body);
|
|
3239
3374
|
break;
|
|
3240
3375
|
}
|
|
3241
3376
|
case "text": {
|
|
@@ -3243,12 +3378,12 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3243
3378
|
break;
|
|
3244
3379
|
}
|
|
3245
3380
|
case "file": {
|
|
3246
|
-
parsedBody = Buffer.from((0,
|
|
3381
|
+
parsedBody = Buffer.from((0, import_common12.safeStringify)(body));
|
|
3247
3382
|
break;
|
|
3248
3383
|
}
|
|
3249
3384
|
case "multipart": {
|
|
3250
3385
|
const formData = new FormData();
|
|
3251
|
-
if ((0,
|
|
3386
|
+
if ((0, import_common12.isRecord)(body)) {
|
|
3252
3387
|
for (const key in body) {
|
|
3253
3388
|
if (typeof body[key] === "string") {
|
|
3254
3389
|
if (schemaValidator.isInstanceOf(
|
|
@@ -3273,11 +3408,11 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3273
3408
|
break;
|
|
3274
3409
|
}
|
|
3275
3410
|
case "urlEncoded": {
|
|
3276
|
-
if ((0,
|
|
3411
|
+
if ((0, import_common12.isRecord)(body)) {
|
|
3277
3412
|
parsedBody = new URLSearchParams(
|
|
3278
3413
|
Object.entries(body).map(([key, value]) => [
|
|
3279
3414
|
key,
|
|
3280
|
-
(0,
|
|
3415
|
+
(0, import_common12.safeStringify)(value)
|
|
3281
3416
|
])
|
|
3282
3417
|
);
|
|
3283
3418
|
} else {
|
|
@@ -3286,8 +3421,8 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3286
3421
|
break;
|
|
3287
3422
|
}
|
|
3288
3423
|
default: {
|
|
3289
|
-
(0,
|
|
3290
|
-
parsedBody = (0,
|
|
3424
|
+
(0, import_common12.isNever)(discriminatedBody.parserType);
|
|
3425
|
+
parsedBody = (0, import_common12.safeStringify)(body);
|
|
3291
3426
|
break;
|
|
3292
3427
|
}
|
|
3293
3428
|
}
|
|
@@ -3296,7 +3431,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3296
3431
|
const queryString = new URLSearchParams(
|
|
3297
3432
|
Object.entries(query).map(([key, value]) => [
|
|
3298
3433
|
key,
|
|
3299
|
-
(0,
|
|
3434
|
+
(0, import_common12.safeStringify)(value)
|
|
3300
3435
|
])
|
|
3301
3436
|
).toString();
|
|
3302
3437
|
url += queryString ? `?${queryString}` : "";
|
|
@@ -3329,7 +3464,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
|
3329
3464
|
content: [
|
|
3330
3465
|
{
|
|
3331
3466
|
type: "text",
|
|
3332
|
-
text: (0,
|
|
3467
|
+
text: (0, import_common12.safeStringify)(await response.json())
|
|
3333
3468
|
}
|
|
3334
3469
|
]
|
|
3335
3470
|
};
|
|
@@ -3471,7 +3606,7 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
|
3471
3606
|
}
|
|
3472
3607
|
return;
|
|
3473
3608
|
case "warning":
|
|
3474
|
-
req.openTelemetryCollector
|
|
3609
|
+
req.openTelemetryCollector?.warn(
|
|
3475
3610
|
`Invalid response:
|
|
3476
3611
|
${parseErrors.join("\n\n")}`
|
|
3477
3612
|
);
|
|
@@ -3484,18 +3619,19 @@ ${parseErrors.join("\n\n")}`
|
|
|
3484
3619
|
}
|
|
3485
3620
|
|
|
3486
3621
|
// src/http/middleware/response/enrichExpressLikeSend.middleware.ts
|
|
3487
|
-
var
|
|
3622
|
+
var import_common14 = require("@forklaunch/common");
|
|
3488
3623
|
var import_stream = require("stream");
|
|
3489
3624
|
|
|
3490
3625
|
// src/http/telemetry/recordMetric.ts
|
|
3491
|
-
var
|
|
3626
|
+
var import_common13 = require("@forklaunch/common");
|
|
3492
3627
|
var import_semantic_conventions3 = require("@opentelemetry/semantic-conventions");
|
|
3493
3628
|
function recordMetric(req, res) {
|
|
3494
3629
|
if (res.metricRecorded) {
|
|
3495
3630
|
return;
|
|
3496
3631
|
}
|
|
3497
3632
|
httpRequestsTotalCounter.add(1, {
|
|
3498
|
-
[import_semantic_conventions3.ATTR_SERVICE_NAME]: (0,
|
|
3633
|
+
[import_semantic_conventions3.ATTR_SERVICE_NAME]: (0, import_common13.getEnvVar)("OTEL_SERVICE_NAME"),
|
|
3634
|
+
[ATTR_APPLICATION_ID]: (0, import_common13.getEnvVar)("OTEL_APPLICATION_ID"),
|
|
3499
3635
|
[ATTR_API_NAME]: req.contractDetails?.name,
|
|
3500
3636
|
[import_semantic_conventions3.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
|
3501
3637
|
[import_semantic_conventions3.ATTR_HTTP_ROUTE]: req.originalPath,
|
|
@@ -3514,7 +3650,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
|
3514
3650
|
if (res.statusCode === 404) {
|
|
3515
3651
|
res.type("text/plain");
|
|
3516
3652
|
res.status(404);
|
|
3517
|
-
req.openTelemetryCollector
|
|
3653
|
+
req.openTelemetryCollector?.error("Not Found");
|
|
3518
3654
|
originalSend.call(instance, "Not Found");
|
|
3519
3655
|
errorSent = true;
|
|
3520
3656
|
}
|
|
@@ -3544,8 +3680,8 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
|
3544
3680
|
`attachment; filename="${data.name}"`
|
|
3545
3681
|
);
|
|
3546
3682
|
}
|
|
3547
|
-
if ((0,
|
|
3548
|
-
import_stream.Readable.from((0,
|
|
3683
|
+
if ((0, import_common14.isNodeJsWriteableStream)(res)) {
|
|
3684
|
+
import_stream.Readable.from((0, import_common14.readableStreamToAsyncIterable)(data.stream())).pipe(
|
|
3549
3685
|
res
|
|
3550
3686
|
);
|
|
3551
3687
|
} else {
|
|
@@ -3554,7 +3690,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
|
3554
3690
|
originalSend.call(instance, "Not a NodeJS WritableStream");
|
|
3555
3691
|
errorSent = true;
|
|
3556
3692
|
}
|
|
3557
|
-
} else if ((0,
|
|
3693
|
+
} else if ((0, import_common14.isAsyncGenerator)(data)) {
|
|
3558
3694
|
let firstPass = true;
|
|
3559
3695
|
const transformer = new import_stream.Transform({
|
|
3560
3696
|
objectMode: true,
|
|
@@ -3569,7 +3705,7 @@ function enrichExpressLikeSend(instance, req, res, originalOperation, originalSe
|
|
|
3569
3705
|
------------------
|
|
3570
3706
|
${res.locals.errorMessage}`;
|
|
3571
3707
|
}
|
|
3572
|
-
req.openTelemetryCollector
|
|
3708
|
+
req.openTelemetryCollector?.error(errorString);
|
|
3573
3709
|
res.type("text/plain");
|
|
3574
3710
|
res.status(500);
|
|
3575
3711
|
originalSend.call(instance, errorString);
|
|
@@ -3578,7 +3714,7 @@ ${res.locals.errorMessage}`;
|
|
|
3578
3714
|
} else {
|
|
3579
3715
|
let data2 = "";
|
|
3580
3716
|
for (const [key, value] of Object.entries(chunk)) {
|
|
3581
|
-
data2 += `${key}: ${typeof value === "string" ? value : (0,
|
|
3717
|
+
data2 += `${key}: ${typeof value === "string" ? value : (0, import_common14.safeStringify)(value)}
|
|
3582
3718
|
`;
|
|
3583
3719
|
}
|
|
3584
3720
|
data2 += "\n";
|
|
@@ -3589,7 +3725,7 @@ ${res.locals.errorMessage}`;
|
|
|
3589
3725
|
} else if (!errorSent) {
|
|
3590
3726
|
let data2 = "";
|
|
3591
3727
|
for (const [key, value] of Object.entries(chunk)) {
|
|
3592
|
-
data2 += `${key}: ${typeof value === "string" ? value : (0,
|
|
3728
|
+
data2 += `${key}: ${typeof value === "string" ? value : (0, import_common14.safeStringify)(value)}
|
|
3593
3729
|
`;
|
|
3594
3730
|
}
|
|
3595
3731
|
data2 += "\n";
|
|
@@ -3597,7 +3733,7 @@ ${res.locals.errorMessage}`;
|
|
|
3597
3733
|
}
|
|
3598
3734
|
}
|
|
3599
3735
|
});
|
|
3600
|
-
if ((0,
|
|
3736
|
+
if ((0, import_common14.isNodeJsWriteableStream)(res)) {
|
|
3601
3737
|
import_stream.Readable.from(data).pipe(transformer).pipe(res);
|
|
3602
3738
|
} else {
|
|
3603
3739
|
res.type("text/plain");
|
|
@@ -3608,7 +3744,7 @@ ${res.locals.errorMessage}`;
|
|
|
3608
3744
|
} else {
|
|
3609
3745
|
const parserType = responseBodies?.[Number(res.statusCode)]?.parserType;
|
|
3610
3746
|
res.bodyData = data;
|
|
3611
|
-
if ((0,
|
|
3747
|
+
if ((0, import_common14.isRecord)(data)) {
|
|
3612
3748
|
switch (parserType) {
|
|
3613
3749
|
case "json":
|
|
3614
3750
|
res.bodyData = "json" in data ? data.json : data;
|
|
@@ -3629,7 +3765,7 @@ ${res.locals.errorMessage}`;
|
|
|
3629
3765
|
res.bodyData = data;
|
|
3630
3766
|
break;
|
|
3631
3767
|
default:
|
|
3632
|
-
(0,
|
|
3768
|
+
(0, import_common14.isNever)(parserType);
|
|
3633
3769
|
res.bodyData = data;
|
|
3634
3770
|
break;
|
|
3635
3771
|
}
|
|
@@ -3642,7 +3778,7 @@ ${res.locals.errorMessage}`;
|
|
|
3642
3778
|
------------------
|
|
3643
3779
|
${res.locals.errorMessage}`;
|
|
3644
3780
|
}
|
|
3645
|
-
req.openTelemetryCollector
|
|
3781
|
+
req.openTelemetryCollector?.error(errorString);
|
|
3646
3782
|
res.type("text/plain");
|
|
3647
3783
|
res.status(500);
|
|
3648
3784
|
originalSend.call(instance, errorString);
|
|
@@ -3664,8 +3800,8 @@ ${res.locals.errorMessage}`;
|
|
|
3664
3800
|
}
|
|
3665
3801
|
|
|
3666
3802
|
// src/http/openApiV3Generator/openApiV3Generator.ts
|
|
3667
|
-
var
|
|
3668
|
-
var OPENAPI_DEFAULT_VERSION = Symbol("default");
|
|
3803
|
+
var import_common15 = require("@forklaunch/common");
|
|
3804
|
+
var OPENAPI_DEFAULT_VERSION = /* @__PURE__ */ Symbol("default");
|
|
3669
3805
|
function toUpperCase(str) {
|
|
3670
3806
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
3671
3807
|
}
|
|
@@ -3887,7 +4023,7 @@ function generateOpenApiSpecs(schemaValidator, serverUrls, serverDescriptions, a
|
|
|
3887
4023
|
].forEach(({ fullPath, router }) => {
|
|
3888
4024
|
const controllerName = transformBasePath(fullPath);
|
|
3889
4025
|
router.routes.forEach((route) => {
|
|
3890
|
-
const openApiPath = (0,
|
|
4026
|
+
const openApiPath = (0, import_common15.openApiCompliantPath)(
|
|
3891
4027
|
`${fullPath}${route.path === "/" ? "" : route.path}`
|
|
3892
4028
|
);
|
|
3893
4029
|
const { name, summary, params, versions, auth, options: options2 } = route.contractDetails;
|
|
@@ -4014,6 +4150,7 @@ function metricsDefinitions(metrics2) {
|
|
|
4014
4150
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4015
4151
|
0 && (module.exports = {
|
|
4016
4152
|
ATTR_API_NAME,
|
|
4153
|
+
ATTR_APPLICATION_ID,
|
|
4017
4154
|
ATTR_CORRELATION_ID,
|
|
4018
4155
|
ATTR_HTTP_REQUEST_METHOD,
|
|
4019
4156
|
ATTR_HTTP_RESPONSE_STATUS_CODE,
|
|
@@ -4025,6 +4162,7 @@ function metricsDefinitions(metrics2) {
|
|
|
4025
4162
|
OPENAPI_DEFAULT_VERSION,
|
|
4026
4163
|
OpenTelemetryCollector,
|
|
4027
4164
|
PinoLogger,
|
|
4165
|
+
createContext,
|
|
4028
4166
|
createHmacToken,
|
|
4029
4167
|
delete_,
|
|
4030
4168
|
discriminateAuthMethod,
|
|
@@ -4032,6 +4170,8 @@ function metricsDefinitions(metrics2) {
|
|
|
4032
4170
|
discriminateResponseBodies,
|
|
4033
4171
|
enrichExpressLikeSend,
|
|
4034
4172
|
evaluateTelemetryOptions,
|
|
4173
|
+
extractRouteHandlers,
|
|
4174
|
+
generateHmacAuthHeaders,
|
|
4035
4175
|
generateMcpServer,
|
|
4036
4176
|
generateOpenApiSpecs,
|
|
4037
4177
|
get,
|