@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.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 import_common5 = require("@forklaunch/common");
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
- switch (authorizationMethod.method) {
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
- // TODO: Check this at application startup if there is any route with jwt checking
182
- process.env.JWT_SECRET
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.payload.sub;
227
+ resourceId = decodedJwt;
189
228
  } catch (error) {
190
- req.openTelemetryCollector.error(error);
229
+ req?.openTelemetryCollector.error(error);
191
230
  return invalidAuthorizationToken;
192
231
  }
193
232
  break;
194
233
  }
195
234
  case "basic": {
196
- if (authorizationToken !== "Basic") {
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 (!authorizationMethod.login(username, password)) {
204
- return invalidAuthorizationLogin;
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
- case "other":
210
- if (tokenPrefix !== authorizationMethod.tokenPrefix) {
211
- return invalidAuthorizationTokenFormat;
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.allowedPermissions || authorizationMethod.forbiddenPermissions) {
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[(auth.method === "other" ? auth.headerName : void 0) ?? "Authorization"],
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
- next?.(new Error(message));
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 import_common4 = require("@forklaunch/common");
345
+ var import_common5 = require("@forklaunch/common");
304
346
 
305
347
  // src/http/telemetry/openTelemetryCollector.ts
306
- var import_common3 = require("@forklaunch/common");
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 import_common2 = require("@forklaunch/common");
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, import_common2.isNever)(level);
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(import_common2.safeStringify);
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, import_common3.getEnvVar)("DOTENV_FILE_PATH") });
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, import_common3.getEnvVar)("OTEL_SERVICE_NAME")
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, import_common3.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
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, import_common3.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
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, import_common3.getEnvVar)("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
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, import_common3.getEnvVar)("OTEL_SERVICE_NAME") ?? "unknown"
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, import_common3.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
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, import_common3.getEnvVar)("OTEL_SERVICE_NAME") || "unknown").createHistogram("http_server_duration", {
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, import_common4.getEnvVar)("OTEL_SERVICE_NAME") || "unknown",
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
- req.headers = parsedRequest.value.headers ?? {};
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, import_common5.toRecord)(this.fetchMap)[(0, import_common5.sanitizePathSlashes)(`${this.basePath}${path}`)] = localParamRequest;
1056
- (0, import_common5.toRecord)(this.sdk)[(0, import_common5.toPrettyCamelCase)(contractDetails.name ?? this.basePath)] = (req) => localParamRequest(`${this.basePath}${path}`, req);
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, import_common5.toRecord)(this.fetchMap)[(0, import_common5.sanitizePathSlashes)(`${this.basePath}${key}`)] = value
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, import_common5.toPrettyCamelCase)(router.basePath)];
1146
- (0, import_common5.toRecord)(this.sdk)[router.sdkName ?? (0, import_common5.toPrettyCamelCase)(router.basePath)] = {
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 import_common7 = require("@forklaunch/common");
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 import_common6 = require("@forklaunch/common");
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, import_common6.toPrettyCamelCase)(router.sdkName ?? router.basePath)
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, import_common6.toPrettyCamelCase)(router.sdkName ?? router.basePath)
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, import_common7.safeStringify)(body);
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, import_common7.isRecord)(body)) {
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, import_common7.isRecord)(body)) {
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, import_common7.safeStringify)(value)
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, import_common7.isNever)(discriminatedBody.parserType);
2633
- parsedBody = (0, import_common7.safeStringify)(body);
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, import_common7.safeStringify)(value)
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, import_common7.safeStringify)(await response.json())
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 import_common9 = require("@forklaunch/common");
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 import_common8 = require("@forklaunch/common");
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, import_common8.getEnvVar)("OTEL_SERVICE_NAME"),
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, import_common9.isNodeJsWriteableStream)(res)) {
2828
- import_stream.Readable.from((0, import_common9.readableStreamToAsyncIterable)(data.stream())).pipe(
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, import_common9.isAsyncGenerator)(data)) {
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, import_common9.safeStringify)(value)}
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, import_common9.isNodeJsWriteableStream)(res)) {
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, import_common9.isRecord)(data)) {
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, import_common9.isNever)(parserType);
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 import_common10 = require("@forklaunch/common");
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, import_common10.openApiCompliantPath)(
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, import_common10.toPrettyCamelCase)(name)}`
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.method === "jwt") {
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