@forklaunch/core 0.3.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,48 @@
1
+ // src/http/middleware/request/cors.middleware.ts
2
+ import corsMiddleware from "cors";
3
+ function cors(req, res, next) {
4
+ if (req.method === "OPTIONS") {
5
+ res.cors = true;
6
+ }
7
+ corsMiddleware()(req, res, next ?? (() => {
8
+ }));
9
+ }
10
+
11
+ // src/http/middleware/request/createContext.middleware.ts
12
+ import { trace } from "@opentelemetry/api";
13
+ import { v4 } from "uuid";
14
+
15
+ // src/http/telemetry/constants.ts
16
+ import {
17
+ ATTR_HTTP_REQUEST_METHOD,
18
+ ATTR_HTTP_RESPONSE_STATUS_CODE,
19
+ ATTR_HTTP_ROUTE,
20
+ ATTR_SERVICE_NAME
21
+ } from "@opentelemetry/semantic-conventions";
22
+ var ATTR_API_NAME = "api.name";
23
+ var ATTR_CORRELATION_ID = "correlation.id";
24
+
25
+ // src/http/middleware/request/createContext.middleware.ts
26
+ function createContext(schemaValidator) {
27
+ return function setContext(req, res, next) {
28
+ req.schemaValidator = schemaValidator;
29
+ let correlationId = v4();
30
+ if (req.headers["x-correlation-id"]) {
31
+ correlationId = req.headers["x-correlation-id"];
32
+ }
33
+ res.setHeader("x-correlation-id", correlationId);
34
+ req.context = {
35
+ correlationId
36
+ };
37
+ const span = trace.getActiveSpan();
38
+ if (span != null) {
39
+ req.context.span = span;
40
+ req.context.span?.setAttribute(ATTR_CORRELATION_ID, correlationId);
41
+ }
42
+ next?.();
43
+ };
44
+ }
45
+
1
46
  // src/http/guards/isForklaunchRouter.ts
2
47
  function isForklaunchRouter(maybeForklaunchRouter) {
3
48
  return maybeForklaunchRouter != null && typeof maybeForklaunchRouter === "object" && "basePath" in maybeForklaunchRouter && "routes" in maybeForklaunchRouter && Array.isArray(maybeForklaunchRouter.routes);
@@ -157,58 +202,29 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
157
202
  return [401, "Invalid Authorization method."];
158
203
  }
159
204
  async function parseRequestAuth(req, res, next) {
160
- console.debug("[MIDDLEWARE] parseRequest started");
161
205
  const auth = req.contractDetails.auth;
162
206
  if (auth) {
163
- const errorAndMessage = await checkAuthorizationToken(
207
+ const [error, message] = await checkAuthorizationToken(
164
208
  auth,
165
209
  req.headers[(auth.method === "other" ? auth.headerName : void 0) ?? "Authorization"],
166
210
  req
167
- );
168
- if (Array.isArray(errorAndMessage)) {
169
- res.status(errorAndMessage[0]).send(errorAndMessage[1]);
170
- next?.(new Error(errorAndMessage[1]));
211
+ ) ?? [];
212
+ if (error != null) {
213
+ res.status(error).send(message);
214
+ next?.(new Error(message));
171
215
  }
172
216
  }
173
217
  next?.();
174
218
  }
175
219
 
176
- // src/http/middleware/request/cors.middleware.ts
177
- import corsMiddleware from "cors";
178
- function cors(req, res, next) {
179
- console.debug("[MIDDLEWARE] cors started");
180
- if (req.method === "OPTIONS") {
181
- res.cors = true;
182
- }
183
- corsMiddleware()(req, res, next ?? (() => {
184
- }));
185
- }
186
-
187
- // src/http/middleware/request/createContext.middleware.ts
188
- import { v4 } from "uuid";
189
- function createContext(schemaValidator) {
190
- return (req, res, next) => {
191
- console.debug("[MIDDLEWARE] createRequestContext started");
192
- req.schemaValidator = schemaValidator;
193
- let correlationId = v4();
194
- if (req.headers["x-correlation-id"]) {
195
- correlationId = req.headers["x-correlation-id"];
196
- }
197
- res.setHeader("x-correlation-id", correlationId);
198
- req.context = {
199
- correlationId
200
- };
201
- next?.();
202
- };
203
- }
204
-
205
220
  // src/http/middleware/request/enrichDetails.middleware.ts
206
- function enrichDetails(contractDetails, requestSchema, responseSchemas) {
221
+ function enrichDetails(path, contractDetails, requestSchema, responseSchemas) {
207
222
  return (req, res, next) => {
208
- console.debug("[MIDDLEWARE] enrichRequestDetails started");
223
+ req.originalPath = path;
209
224
  req.contractDetails = contractDetails;
210
225
  req.requestSchema = requestSchema;
211
226
  res.responseSchemas = responseSchemas;
227
+ req.context.span?.setAttribute(ATTR_API_NAME, req.contractDetails?.name);
212
228
  next?.();
213
229
  };
214
230
  }
@@ -225,14 +241,16 @@ function isResponseShape(maybeResponseShape) {
225
241
 
226
242
  // src/http/middleware/request/parse.middleware.ts
227
243
  function parse(req, _res, next) {
228
- console.debug("[MIDDLEWARE] parseRequest started");
229
244
  const request = {
230
245
  params: req.params,
231
246
  query: req.query,
232
247
  headers: req.headers,
233
248
  body: req.body
234
249
  };
235
- const parsedRequest = req.schemaValidator.parse(req.requestSchema, request);
250
+ const parsedRequest = req.schemaValidator.parse(
251
+ req.requestSchema,
252
+ request
253
+ );
236
254
  if (parsedRequest.ok && isResponseShape(parsedRequest.value)) {
237
255
  req.body = parsedRequest.value.body;
238
256
  req.params = parsedRequest.value.params;
@@ -263,8 +281,6 @@ var ForklaunchExpressLikeRouter = class {
263
281
  this.schemaValidator = schemaValidator;
264
282
  this.internal = internal;
265
283
  this.basePath = basePath;
266
- this.internal.use(createContext(this.schemaValidator));
267
- this.internal.use(cors);
268
284
  }
269
285
  requestHandler;
270
286
  routers = [];
@@ -276,9 +292,14 @@ var ForklaunchExpressLikeRouter = class {
276
292
  * @param {PathParamHttpContractDetails<SV> | HttpContractDetails<SV>} contractDetails - The contract details.
277
293
  * @returns {MiddlewareHandler<SV>[]} - The resolved middlewares.
278
294
  */
279
- #resolveMiddlewares(contractDetails, requestSchema, responseSchemas) {
295
+ #resolveMiddlewares(path, contractDetails, requestSchema, responseSchemas) {
280
296
  return [
281
- enrichDetails(contractDetails, requestSchema, responseSchemas),
297
+ enrichDetails(
298
+ `${this.basePath}${path}`,
299
+ contractDetails,
300
+ requestSchema,
301
+ responseSchemas
302
+ ),
282
303
  parse,
283
304
  parseRequestAuth
284
305
  ];
@@ -303,10 +324,10 @@ var ForklaunchExpressLikeRouter = class {
303
324
  try {
304
325
  await requestHandler(req, res, next);
305
326
  } catch (error) {
306
- next?.(error);
307
- console.error(error);
308
- if (!res.headersSent) {
309
- res.status(500).send("Internal Server Error");
327
+ if (next && typeof next === "function") {
328
+ next(error);
329
+ } else {
330
+ throw error;
310
331
  }
311
332
  }
312
333
  };
@@ -339,7 +360,7 @@ var ForklaunchExpressLikeRouter = class {
339
360
  ...contractDetails.params ? { params: contractDetails.params } : {},
340
361
  ...contractDetails.requestHeaders ? { headers: contractDetails.requestHeaders } : {},
341
362
  ...contractDetails.query ? { query: contractDetails.query } : {},
342
- ...isHttpContractDetails(contractDetails) && contractDetails.body ? { body: contractDetails.body } : {}
363
+ ...isHttpContractDetails(contractDetails) && contractDetails.body != null ? { body: contractDetails.body } : {}
343
364
  })
344
365
  );
345
366
  const responseEntries = {
@@ -348,7 +369,9 @@ var ForklaunchExpressLikeRouter = class {
348
369
  403: schemaValidator.string,
349
370
  404: schemaValidator.string,
350
371
  500: schemaValidator.string,
351
- ...isPathParamHttpContractDetails(contractDetails) || isHttpContractDetails(contractDetails) ? { ...contractDetails.responses } : {}
372
+ ...isPathParamHttpContractDetails(contractDetails) || isHttpContractDetails(contractDetails) ? {
373
+ ...contractDetails.responses
374
+ } : {}
352
375
  };
353
376
  const responseSchemas = {
354
377
  responses: {},
@@ -478,9 +501,12 @@ var ForklaunchExpressLikeRouter = class {
478
501
  const controllerHandler = this.#extractControllerHandler(handlers);
479
502
  registrationMethod.bind(this.internal)(
480
503
  path,
481
- ...this.#resolveMiddlewares(contractDetails, requestSchema, responseSchemas).concat(
482
- handlers
483
- ),
504
+ ...this.#resolveMiddlewares(
505
+ path,
506
+ contractDetails,
507
+ requestSchema,
508
+ responseSchemas
509
+ ).concat(handlers),
484
510
  this.#parseAndRunControllerHandler(controllerHandler)
485
511
  );
486
512
  return this.#localParamRequest(
@@ -536,9 +562,7 @@ var ForklaunchExpressLikeRouter = class {
536
562
  contractDetailsOrMiddlewareOrTypedHandler,
537
563
  middleware2
538
564
  );
539
- if (isForklaunchExpressLikeRouter(
540
- contractDetailsOrMiddlewareOrTypedHandler
541
- )) {
565
+ if (isForklaunchExpressLikeRouter(contractDetailsOrMiddlewareOrTypedHandler)) {
542
566
  middleware2.push(contractDetailsOrMiddlewareOrTypedHandler.internal);
543
567
  }
544
568
  middleware2.push(
@@ -839,11 +863,23 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
839
863
  super("/", schemaValidator, internal);
840
864
  this.schemaValidator = schemaValidator;
841
865
  this.internal = internal;
866
+ this.internal.use(createContext(this.schemaValidator));
867
+ this.internal.use(cors);
842
868
  }
843
869
  };
844
870
 
871
+ // src/http/guards/isForklaunchRequest.ts
872
+ function isForklaunchRequest(request) {
873
+ return request != null && typeof request === "object" && "contractDetails" in request;
874
+ }
875
+
876
+ // src/http/guards/isPath.ts
877
+ function isPath(path) {
878
+ return path.startsWith("/");
879
+ }
880
+
845
881
  // src/http/handlers/typedHandler.ts
846
- function typedHandler(_schemaValidator, _pathOrContractDetails, contractMethodOrContractDetails, contractDetailsOrHandler, ...handlerArray) {
882
+ function typedHandler(_schemaValidator, pathOrContractMethod, contractMethodOrContractDetails, contractDetailsOrHandler, ...handlerArray) {
847
883
  let contractDetails;
848
884
  let handlers;
849
885
  if (typeof contractMethodOrContractDetails === "string") {
@@ -863,6 +899,7 @@ function typedHandler(_schemaValidator, _pathOrContractDetails, contractMethodOr
863
899
  }
864
900
  return {
865
901
  _typedHandler: true,
902
+ _path: isPath(pathOrContractMethod) ? pathOrContractMethod : void 0,
866
903
  contractDetails,
867
904
  handlers
868
905
  };
@@ -909,11 +946,11 @@ var put = (_schemaValidator, path, contractDetails, ...handlers) => {
909
946
  };
910
947
 
911
948
  // src/http/handlers/trace.ts
912
- var trace = (_schemaValidator, path, contractDetails, ...handlers) => {
949
+ var trace2 = (_schemaValidator, path, contractDetails, ...handlers) => {
913
950
  return typedHandler(_schemaValidator, path, "trace", contractDetails, ...handlers);
914
951
  };
915
952
 
916
- // src/http/utils/httpStatusCodes.ts
953
+ // src/http/httpStatusCodes.ts
917
954
  var HTTPStatuses = {
918
955
  /**
919
956
  * The initial part of a request has been received and has not yet been
@@ -1896,6 +1933,324 @@ var getCodeForStatus = (status) => {
1896
1933
  };
1897
1934
  var httpStatusCodes_default = HTTPStatuses;
1898
1935
 
1936
+ // src/http/middleware/response/parse.middleware.ts
1937
+ import {
1938
+ prettyPrintParseErrors as prettyPrintParseErrors2
1939
+ } from "@forklaunch/validator";
1940
+ function parse2(req, res, next) {
1941
+ const { headers, responses } = res.responseSchemas;
1942
+ const parsedResponse = req.schemaValidator.parse(
1943
+ responses?.[res.statusCode],
1944
+ res.bodyData
1945
+ );
1946
+ const parsedHeaders = req.schemaValidator.parse(
1947
+ headers ?? req.schemaValidator.unknown,
1948
+ res.getHeaders()
1949
+ );
1950
+ const parseErrors = [];
1951
+ if (!parsedHeaders.ok) {
1952
+ const headerErrors = prettyPrintParseErrors2(parsedHeaders.errors, "Header");
1953
+ if (headerErrors) {
1954
+ parseErrors.push(headerErrors);
1955
+ }
1956
+ }
1957
+ if (!parsedResponse.ok) {
1958
+ const responseErrors = prettyPrintParseErrors2(
1959
+ parsedResponse.errors,
1960
+ "Response"
1961
+ );
1962
+ if (responseErrors) {
1963
+ parseErrors.push(responseErrors);
1964
+ }
1965
+ }
1966
+ if (parseErrors.length > 0) {
1967
+ switch (req.contractDetails.options?.responseValidation) {
1968
+ default:
1969
+ case "error":
1970
+ next?.(new Error(`Invalid response:
1971
+ ${parseErrors.join("\n\n")}`));
1972
+ break;
1973
+ case "warning":
1974
+ console.warn(`Invalid response:
1975
+ ${parseErrors.join("\n\n")}`);
1976
+ break;
1977
+ case "none":
1978
+ break;
1979
+ }
1980
+ }
1981
+ next?.();
1982
+ }
1983
+
1984
+ // src/http/telemetry/pinoLogger.ts
1985
+ import { isNever } from "@forklaunch/common";
1986
+ import { trace as trace3 } from "@opentelemetry/api";
1987
+ import { logs } from "@opentelemetry/api-logs";
1988
+ import pino from "pino";
1989
+ function mapSeverity(level) {
1990
+ switch (level) {
1991
+ case "silent":
1992
+ return 0;
1993
+ case "trace":
1994
+ return 1;
1995
+ case "debug":
1996
+ return 5;
1997
+ case "info":
1998
+ return 9;
1999
+ case "warn":
2000
+ return 13;
2001
+ case "error":
2002
+ return 17;
2003
+ case "fatal":
2004
+ return 21;
2005
+ default:
2006
+ isNever(level);
2007
+ return 0;
2008
+ }
2009
+ }
2010
+ var PinoLogger = class _PinoLogger {
2011
+ pinoLogger;
2012
+ meta;
2013
+ constructor(level, meta = {}) {
2014
+ this.pinoLogger = pino({
2015
+ level: level || "info",
2016
+ formatters: {
2017
+ level(label) {
2018
+ return { level: label };
2019
+ }
2020
+ },
2021
+ timestamp: pino.stdTimeFunctions.isoTime,
2022
+ transport: {
2023
+ target: "pino-pretty",
2024
+ options: { colorize: true }
2025
+ }
2026
+ });
2027
+ this.meta = meta;
2028
+ }
2029
+ log(level, msg, meta = {}) {
2030
+ const activeSpan = trace3.getActiveSpan();
2031
+ if (activeSpan) {
2032
+ const activeSpanContext = activeSpan.spanContext();
2033
+ meta.trace_id = activeSpanContext.traceId;
2034
+ meta.span_id = activeSpanContext.spanId;
2035
+ meta.trace_flags = activeSpanContext.traceFlags;
2036
+ if (!meta.api_name) {
2037
+ meta = { ...meta, ...activeSpan?.attributes };
2038
+ }
2039
+ }
2040
+ this.pinoLogger[level](msg);
2041
+ logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
2042
+ severityText: level,
2043
+ severityNumber: mapSeverity(level),
2044
+ body: msg,
2045
+ attributes: { ...this.meta, ...meta }
2046
+ });
2047
+ }
2048
+ error(msg, meta = {}) {
2049
+ this.log("error", msg, meta);
2050
+ }
2051
+ info(msg, meta = {}) {
2052
+ this.log("info", msg, meta);
2053
+ }
2054
+ debug(msg, meta = {}) {
2055
+ this.log("debug", msg, meta);
2056
+ }
2057
+ warn(msg, meta = {}) {
2058
+ this.log("warn", msg, meta);
2059
+ }
2060
+ trace(msg, meta = {}) {
2061
+ this.log("trace", msg, meta);
2062
+ }
2063
+ child(meta = {}) {
2064
+ return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta });
2065
+ }
2066
+ getBaseLogger() {
2067
+ return this.pinoLogger;
2068
+ }
2069
+ };
2070
+ function logger(level, meta = {}) {
2071
+ return new PinoLogger(level, meta);
2072
+ }
2073
+
2074
+ // src/http/telemetry/recordMetric.ts
2075
+ import {
2076
+ ATTR_HTTP_REQUEST_METHOD as ATTR_HTTP_REQUEST_METHOD3,
2077
+ ATTR_HTTP_RESPONSE_STATUS_CODE as ATTR_HTTP_RESPONSE_STATUS_CODE3,
2078
+ ATTR_HTTP_ROUTE as ATTR_HTTP_ROUTE3,
2079
+ ATTR_SERVICE_NAME as ATTR_SERVICE_NAME3
2080
+ } from "@opentelemetry/semantic-conventions";
2081
+
2082
+ // src/services/configInjector.ts
2083
+ import { extractArgumentNames as extractArgumentNames2, isNever as isNever2 } from "@forklaunch/common";
2084
+ import {
2085
+ prettyPrintParseErrors as prettyPrintParseErrors3
2086
+ } from "@forklaunch/validator";
2087
+
2088
+ // src/services/getEnvVar.ts
2089
+ function getEnvVar(name) {
2090
+ const value = process.env[name];
2091
+ return value;
2092
+ }
2093
+
2094
+ // src/http/telemetry/openTelemetryCollector.ts
2095
+ import { HyperExpressInstrumentation } from "@forklaunch/opentelemetry-instrumentation-hyper-express";
2096
+ import {
2097
+ metrics
2098
+ } from "@opentelemetry/api";
2099
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
2100
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
2101
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
2102
+ import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
2103
+ import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
2104
+ import { Resource } from "@opentelemetry/resources";
2105
+ import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
2106
+ import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
2107
+ import { NodeSDK } from "@opentelemetry/sdk-node";
2108
+ import {
2109
+ ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2
2110
+ } from "@opentelemetry/semantic-conventions";
2111
+ import dotenv from "dotenv";
2112
+ var OpenTelemetryCollector = class {
2113
+ // scoped creation and create this in middleware when api execute. Also add correlation id
2114
+ constructor(serviceName, level, metricDefinitions) {
2115
+ this.serviceName = serviceName;
2116
+ this.logger = logger(level ?? "info");
2117
+ this.metrics = {};
2118
+ for (const [metricId, metricType] of Object.entries(
2119
+ metricDefinitions ?? {}
2120
+ )) {
2121
+ switch (metricType) {
2122
+ case "counter":
2123
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createCounter(metricId);
2124
+ break;
2125
+ case "gauge":
2126
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createGauge(metricId);
2127
+ break;
2128
+ case "histogram":
2129
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createHistogram(metricId);
2130
+ break;
2131
+ case "upDownCounter":
2132
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createUpDownCounter(metricId);
2133
+ break;
2134
+ case "observableCounter":
2135
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableCounter(metricId);
2136
+ break;
2137
+ case "observableGauge":
2138
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableGauge(metricId);
2139
+ break;
2140
+ case "observableUpDownCounter":
2141
+ this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableUpDownCounter(metricId);
2142
+ break;
2143
+ }
2144
+ }
2145
+ this.log("info", "OpenTelemetry (Traces + Logs + Metrics) started");
2146
+ }
2147
+ logger;
2148
+ metrics;
2149
+ log(level, msg, meta = {}) {
2150
+ this.logger.log(level, msg, meta);
2151
+ }
2152
+ info(msg, meta = {}) {
2153
+ this.logger.info(msg, meta);
2154
+ }
2155
+ error(msg, meta = {}) {
2156
+ this.logger.error(msg, meta);
2157
+ }
2158
+ warn(msg, meta = {}) {
2159
+ this.logger.warn(msg, meta);
2160
+ }
2161
+ debug(msg, meta = {}) {
2162
+ this.logger.debug(msg, meta);
2163
+ }
2164
+ trace(msg, meta = {}) {
2165
+ this.logger.trace(msg, meta);
2166
+ }
2167
+ getMetric(metricId) {
2168
+ return this.metrics[metricId];
2169
+ }
2170
+ };
2171
+ dotenv.config({ path: getEnvVar("ENV_FILE_PATH") });
2172
+ new NodeSDK({
2173
+ resource: new Resource({
2174
+ [ATTR_SERVICE_NAME2]: getEnvVar("OTEL_SERVICE_NAME")
2175
+ }),
2176
+ traceExporter: new OTLPTraceExporter({
2177
+ url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
2178
+ }),
2179
+ metricReader: new PeriodicExportingMetricReader({
2180
+ exporter: new OTLPMetricExporter({
2181
+ url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
2182
+ }),
2183
+ exportIntervalMillis: 5e3
2184
+ }),
2185
+ logRecordProcessors: [
2186
+ new BatchLogRecordProcessor(
2187
+ new OTLPLogExporter({
2188
+ url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
2189
+ })
2190
+ )
2191
+ ],
2192
+ instrumentations: [
2193
+ new HttpInstrumentation({
2194
+ applyCustomAttributesOnSpan: (span, request) => {
2195
+ span.setAttribute(
2196
+ "service.name",
2197
+ getEnvVar("OTEL_SERVICE_NAME") ?? "unknown"
2198
+ );
2199
+ if (isForklaunchRequest(request)) {
2200
+ span.setAttribute("api.name", request.contractDetails?.name);
2201
+ }
2202
+ }
2203
+ }),
2204
+ new ExpressInstrumentation(),
2205
+ new HyperExpressInstrumentation()
2206
+ ]
2207
+ }).start();
2208
+ var httpRequestsTotalCounter = metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
2209
+ description: "Number of HTTP requests"
2210
+ });
2211
+
2212
+ // src/http/telemetry/recordMetric.ts
2213
+ function recordMetric(req, res) {
2214
+ httpRequestsTotalCounter.add(1, {
2215
+ [ATTR_SERVICE_NAME3]: getEnvVar("OTEL_SERVICE_NAME"),
2216
+ [ATTR_API_NAME]: req.contractDetails?.name,
2217
+ [ATTR_CORRELATION_ID]: req.context.correlationId,
2218
+ [ATTR_HTTP_REQUEST_METHOD3]: req.method,
2219
+ [ATTR_HTTP_ROUTE3]: req.originalPath,
2220
+ [ATTR_HTTP_RESPONSE_STATUS_CODE3]: res.statusCode || 0
2221
+ });
2222
+ }
2223
+
2224
+ // src/http/middleware/response/enrichExpressLikeSend.middleware.ts
2225
+ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnrich) {
2226
+ let parseErrorSent;
2227
+ if (shouldEnrich) {
2228
+ recordMetric(req, res);
2229
+ if (res.statusCode === 404) {
2230
+ res.status(404);
2231
+ logger("error").error("Not Found");
2232
+ originalSend.call(instance, "Not Found");
2233
+ }
2234
+ parse2(req, res, (err) => {
2235
+ if (err) {
2236
+ let errorString = err.message;
2237
+ if (res.locals.errorMessage) {
2238
+ errorString += `
2239
+ ------------------
2240
+ ${res.locals.errorMessage}`;
2241
+ }
2242
+ logger("error").error(errorString);
2243
+ res.status(500);
2244
+ originalSend.call(instance, errorString);
2245
+ parseErrorSent = true;
2246
+ }
2247
+ });
2248
+ }
2249
+ if (!parseErrorSent) {
2250
+ originalSend.call(instance, data);
2251
+ }
2252
+ }
2253
+
1899
2254
  // src/http/openApiV3Generator/openApiV3Generator.ts
1900
2255
  function toUpperCase(str) {
1901
2256
  return str.charAt(0).toUpperCase() + str.slice(1);
@@ -1906,7 +2261,7 @@ function transformBasePath(basePath) {
1906
2261
  }
1907
2262
  return `/${basePath}`;
1908
2263
  }
1909
- function swaggerDocument(port, tags, paths) {
2264
+ function generateOpenApiDocument(port, tags, paths) {
1910
2265
  return {
1911
2266
  openapi: "3.1.0",
1912
2267
  info: {
@@ -1978,7 +2333,10 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
1978
2333
  for (const key in route.contractDetails.params) {
1979
2334
  pathItemObject.parameters?.push({
1980
2335
  name: key,
1981
- in: "path"
2336
+ in: "path",
2337
+ schema: schemaValidator.openapi(
2338
+ route.contractDetails.params[key]
2339
+ )
1982
2340
  });
1983
2341
  }
1984
2342
  }
@@ -1993,7 +2351,10 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
1993
2351
  for (const key in requestHeaders) {
1994
2352
  pathItemObject.parameters?.push({
1995
2353
  name: key,
1996
- in: "header"
2354
+ in: "header",
2355
+ schema: schemaValidator.openapi(
2356
+ requestHeaders[key]
2357
+ )
1997
2358
  });
1998
2359
  }
1999
2360
  }
@@ -2001,7 +2362,8 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
2001
2362
  for (const key in query) {
2002
2363
  pathItemObject.parameters?.push({
2003
2364
  name: key,
2004
- in: "query"
2365
+ in: "query",
2366
+ schema: schemaValidator.openapi(query[key])
2005
2367
  });
2006
2368
  }
2007
2369
  }
@@ -2029,107 +2391,48 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
2029
2391
  }
2030
2392
  });
2031
2393
  });
2032
- return swaggerDocument(port, tags, paths);
2033
- }
2034
-
2035
- // src/http/middleware/response/parse.middleware.ts
2036
- import {
2037
- prettyPrintParseErrors as prettyPrintParseErrors2
2038
- } from "@forklaunch/validator";
2039
- function parse2(req, res, next) {
2040
- console.debug("[MIDDLEWARE] parseResponse started");
2041
- const { headers, responses } = res.responseSchemas;
2042
- const parsedResponse = req.schemaValidator.parse(
2043
- responses?.[res.statusCode],
2044
- res.bodyData
2045
- );
2046
- const parsedHeaders = req.schemaValidator.parse(
2047
- headers ?? req.schemaValidator.unknown,
2048
- res.getHeaders()
2049
- );
2050
- const parseErrors = [];
2051
- if (!parsedHeaders.ok) {
2052
- const headerErrors = prettyPrintParseErrors2(parsedHeaders.errors, "Header");
2053
- if (headerErrors) {
2054
- parseErrors.push(headerErrors);
2055
- }
2056
- }
2057
- if (!parsedResponse.ok) {
2058
- const responseErrors = prettyPrintParseErrors2(
2059
- parsedResponse.errors,
2060
- "Response"
2061
- );
2062
- if (responseErrors) {
2063
- parseErrors.push(responseErrors);
2064
- }
2065
- }
2066
- if (parseErrors.length > 0) {
2067
- switch (req.contractDetails.options?.responseValidation) {
2068
- default:
2069
- case "error":
2070
- next?.(new Error(`Invalid response:
2071
- ${parseErrors.join("\n\n")}`));
2072
- break;
2073
- case "warning":
2074
- console.warn(`Invalid response:
2075
- ${parseErrors.join("\n\n")}`);
2076
- break;
2077
- case "none":
2078
- break;
2079
- }
2080
- }
2081
- next?.();
2394
+ return generateOpenApiDocument(port, tags, paths);
2082
2395
  }
2083
2396
 
2084
- // src/http/utils/enrichExpressLikeSend.ts
2085
- function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnrich) {
2086
- let parseErrorSent;
2087
- if (shouldEnrich) {
2088
- if (res.statusCode === 404) {
2089
- res.status(404);
2090
- originalSend.call(instance, "Not Found");
2091
- }
2092
- parse2(req, res, (err) => {
2093
- if (err) {
2094
- let errorString = err.message;
2095
- if (res.locals.errorMessage) {
2096
- errorString += `
2097
- ------------------
2098
- ${res.locals.errorMessage}`;
2099
- }
2100
- res.status(500);
2101
- originalSend.call(instance, errorString);
2102
- parseErrorSent = true;
2103
- }
2104
- });
2105
- }
2106
- if (!parseErrorSent) {
2107
- originalSend.call(instance, data);
2108
- }
2397
+ // src/http/telemetry/metricsDefinition.ts
2398
+ function metricsDefinitions(metrics2) {
2399
+ return metrics2;
2109
2400
  }
2110
2401
  export {
2402
+ ATTR_API_NAME,
2403
+ ATTR_CORRELATION_ID,
2404
+ ATTR_HTTP_REQUEST_METHOD,
2405
+ ATTR_HTTP_RESPONSE_STATUS_CODE,
2406
+ ATTR_HTTP_ROUTE,
2407
+ ATTR_SERVICE_NAME,
2111
2408
  ForklaunchExpressLikeApplication,
2112
2409
  ForklaunchExpressLikeRouter,
2113
2410
  HTTPStatuses,
2411
+ OpenTelemetryCollector,
2114
2412
  delete_,
2115
2413
  enrichExpressLikeSend,
2116
2414
  generateSwaggerDocument,
2117
2415
  get,
2118
2416
  getCodeForStatus,
2119
2417
  head,
2418
+ httpRequestsTotalCounter,
2120
2419
  isClientError,
2420
+ isForklaunchRequest,
2121
2421
  isForklaunchRouter,
2122
2422
  isInformational,
2123
2423
  isRedirection,
2124
2424
  isServerError,
2125
2425
  isSuccessful,
2126
2426
  isValidStatusCode,
2427
+ logger,
2428
+ metricsDefinitions,
2127
2429
  middleware,
2128
2430
  options,
2129
2431
  patch,
2130
2432
  post,
2131
2433
  put,
2132
- trace,
2434
+ recordMetric,
2435
+ trace2 as trace,
2133
2436
  typedHandler
2134
2437
  };
2135
2438
  //# sourceMappingURL=index.mjs.map