apitally 0.8.0 → 0.8.2

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.
Files changed (53) hide show
  1. package/dist/common/client.cjs +8 -3
  2. package/dist/common/client.cjs.map +1 -1
  3. package/dist/common/client.js +8 -3
  4. package/dist/common/client.js.map +1 -1
  5. package/dist/express/index.cjs +24 -16
  6. package/dist/express/index.cjs.map +1 -1
  7. package/dist/express/index.d.cts +2 -2
  8. package/dist/express/index.d.ts +2 -2
  9. package/dist/express/index.js +24 -16
  10. package/dist/express/index.js.map +1 -1
  11. package/dist/express/listEndpoints.cjs +16 -13
  12. package/dist/express/listEndpoints.cjs.map +1 -1
  13. package/dist/express/listEndpoints.d.cts +24 -2
  14. package/dist/express/listEndpoints.d.ts +24 -2
  15. package/dist/express/listEndpoints.js +16 -13
  16. package/dist/express/listEndpoints.js.map +1 -1
  17. package/dist/express/middleware.cjs +24 -16
  18. package/dist/express/middleware.cjs.map +1 -1
  19. package/dist/express/middleware.d.cts +2 -2
  20. package/dist/express/middleware.d.ts +2 -2
  21. package/dist/express/middleware.js +24 -16
  22. package/dist/express/middleware.js.map +1 -1
  23. package/dist/fastify/index.cjs +8 -3
  24. package/dist/fastify/index.cjs.map +1 -1
  25. package/dist/fastify/index.d.cts +2 -2
  26. package/dist/fastify/index.d.ts +2 -2
  27. package/dist/fastify/index.js +8 -3
  28. package/dist/fastify/index.js.map +1 -1
  29. package/dist/fastify/plugin.cjs +8 -3
  30. package/dist/fastify/plugin.cjs.map +1 -1
  31. package/dist/fastify/plugin.d.cts +1 -1
  32. package/dist/fastify/plugin.d.ts +1 -1
  33. package/dist/fastify/plugin.js +8 -3
  34. package/dist/fastify/plugin.js.map +1 -1
  35. package/dist/koa/index.cjs +8 -3
  36. package/dist/koa/index.cjs.map +1 -1
  37. package/dist/koa/index.d.cts +2 -2
  38. package/dist/koa/index.d.ts +2 -2
  39. package/dist/koa/index.js +8 -3
  40. package/dist/koa/index.js.map +1 -1
  41. package/dist/koa/middleware.cjs +8 -3
  42. package/dist/koa/middleware.cjs.map +1 -1
  43. package/dist/koa/middleware.d.cts +1 -1
  44. package/dist/koa/middleware.d.ts +1 -1
  45. package/dist/koa/middleware.js +8 -3
  46. package/dist/koa/middleware.js.map +1 -1
  47. package/dist/nestjs/index.cjs +24 -16
  48. package/dist/nestjs/index.cjs.map +1 -1
  49. package/dist/nestjs/index.d.cts +2 -2
  50. package/dist/nestjs/index.d.ts +2 -2
  51. package/dist/nestjs/index.js +24 -16
  52. package/dist/nestjs/index.js.map +1 -1
  53. package/package.json +1 -1
@@ -527,7 +527,7 @@ var _ApitallyClient = class _ApitallyClient {
527
527
  Date.now(),
528
528
  newPayload
529
529
  ]);
530
- const failedItems = [];
530
+ let i = 0;
531
531
  while (this.syncDataQueue.length > 0) {
532
532
  const queueItem = this.syncDataQueue.shift();
533
533
  if (queueItem) {
@@ -535,8 +535,13 @@ var _ApitallyClient = class _ApitallyClient {
535
535
  try {
536
536
  const timeOffset = Date.now() - time;
537
537
  if (timeOffset <= MAX_QUEUE_TIME) {
538
+ if (i > 0) {
539
+ const waitMs = 100 + Math.random() * 200;
540
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
541
+ }
538
542
  payload.time_offset = timeOffset / 1e3;
539
543
  await this.sendData("sync", payload);
544
+ i += 1;
540
545
  }
541
546
  } catch (error) {
542
547
  const handled = this.handleHubError(error);
@@ -544,12 +549,12 @@ var _ApitallyClient = class _ApitallyClient {
544
549
  this.logger.debug("Error while synchronizing data with Apitally Hub (will retry)", {
545
550
  error
546
551
  });
547
- failedItems.push(queueItem);
552
+ this.syncDataQueue.push(queueItem);
553
+ break;
548
554
  }
549
555
  }
550
556
  }
551
557
  }
552
- this.syncDataQueue = failedItems;
553
558
  }
554
559
  handleHubError(error) {
555
560
  if (error instanceof HTTPError) {
@@ -584,9 +589,10 @@ function getPackageVersion(name) {
584
589
  __name(getPackageVersion, "getPackageVersion");
585
590
 
586
591
  // src/express/listEndpoints.js
587
- var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\(\[\^\\\/]\+\?\)\)))\\\/.*/;
588
- var regExpToReplaceExpressPathRegExpParams = /\(\?:\(\[\^\\\/]\+\?\)\)/;
589
- var regexpExpressParamRegexp = /\(\?:\(\[\^\\\/]\+\?\)\)/g;
592
+ var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\([^)]+\)\)))\\\/.*/;
593
+ var regExpToReplaceExpressPathRegExpParams = /\(\?:\([^)]+\)\)/;
594
+ var regexpExpressParamRegexp = /\(\?:\([^)]+\)\)/g;
595
+ var regexpExpressPathParamRegexp = /(:[^)]+)\([^)]+\)/g;
590
596
  var EXPRESS_ROOT_PATH_REGEXP_VALUE = "/^\\/?(?=\\/|$)/i";
591
597
  var STACK_ITEM_VALID_NAMES = [
592
598
  "router",
@@ -617,7 +623,7 @@ var parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
617
623
  const endpoints = paths.map((path) => {
618
624
  const completePath = basePath && path === "/" ? basePath : `${basePath}${path}`;
619
625
  const endpoint = {
620
- path: completePath,
626
+ path: completePath.replace(regexpExpressPathParamRegexp, "$1"),
621
627
  methods: getRouteMethods(route),
622
628
  middlewares: getRouteMiddlewares(route)
623
629
  };
@@ -626,8 +632,8 @@ var parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
626
632
  return endpoints;
627
633
  }, "parseExpressRoute");
628
634
  var parseExpressPath = /* @__PURE__ */ __name(function(expressPathRegExp, params) {
629
- let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(expressPathRegExp);
630
635
  let parsedRegExp = expressPathRegExp.toString();
636
+ let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
631
637
  let paramIndex = 0;
632
638
  while (hasParams(parsedRegExp)) {
633
639
  const paramName = params[paramIndex].name;
@@ -646,13 +652,15 @@ var parseEndpoints = /* @__PURE__ */ __name(function(app, basePath, endpoints) {
646
652
  endpoints = endpoints || [];
647
653
  basePath = basePath || "";
648
654
  if (!stack) {
649
- endpoints = addEndpoints(endpoints, [
650
- {
651
- path: basePath,
652
- methods: [],
653
- middlewares: []
654
- }
655
- ]);
655
+ if (endpoints.length) {
656
+ endpoints = addEndpoints(endpoints, [
657
+ {
658
+ path: basePath,
659
+ methods: [],
660
+ middlewares: []
661
+ }
662
+ ]);
663
+ }
656
664
  } else {
657
665
  endpoints = parseStack(stack, basePath, endpoints);
658
666
  }
@@ -660,7 +668,7 @@ var parseEndpoints = /* @__PURE__ */ __name(function(app, basePath, endpoints) {
660
668
  }, "parseEndpoints");
661
669
  var addEndpoints = /* @__PURE__ */ __name(function(currentEndpoints, endpointsToAdd) {
662
670
  endpointsToAdd.forEach((newEndpoint) => {
663
- const existingEndpoint = currentEndpoints.find((item) => item.path === newEndpoint.path);
671
+ const existingEndpoint = currentEndpoints.find((endpoint) => endpoint.path === newEndpoint.path);
664
672
  if (existingEndpoint !== void 0) {
665
673
  const newMethods = newEndpoint.methods.filter((method) => !existingEndpoint.methods.includes(method));
666
674
  existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/express/middleware.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/serverErrorCounter.ts","../../src/common/validationErrorCounter.ts","../../src/common/packageVersions.ts","../../src/express/listEndpoints.js"],"sourcesContent":["import type { Express, NextFunction, Request, Response } from \"express\";\nimport { performance } from \"perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport listEndpoints from \"./listEndpoints.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport const useApitally = (app: Express, config: ApitallyConfig) => {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n setTimeout(() => {\n client.setStartupData(getAppInfo(app, config.appVersion));\n }, 1000);\n};\n\nconst getMiddleware = (app: Express, client: ApitallyClient) => {\n const validatorInstalled = getPackageVersion(\"express-validator\") !== null;\n const celebrateInstalled = getPackageVersion(\"celebrate\") !== null;\n const nestInstalled = getPackageVersion(\"@nestjs/core\") !== null;\n const classValidatorInstalled = getPackageVersion(\"class-validator\") !== null;\n let errorHandlerConfigured = false;\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use(\n (err: Error, req: Request, res: Response, next: NextFunction): void => {\n res.locals.serverError = err;\n next(err);\n },\n );\n errorHandlerConfigured = true;\n }\n try {\n const startTime = performance.now();\n const originalJson = res.json;\n res.json = (body) => {\n res.locals.body = body;\n return originalJson.call(res, body);\n };\n res.on(\"finish\", () => {\n try {\n if (req.route) {\n const responseTime = performance.now() - startTime;\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize: req.get(\"content-length\"),\n responseSize: res.get(\"content-length\"),\n });\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n const validationErrors: ValidationError[] = [];\n if (validatorInstalled) {\n validationErrors.push(\n ...extractExpressValidatorErrors(res.locals.body),\n );\n }\n if (celebrateInstalled) {\n validationErrors.push(\n ...extractCelebrateErrors(res.locals.body),\n );\n }\n if (nestInstalled && classValidatorInstalled) {\n validationErrors.push(\n ...extractNestValidationErrors(res.locals.body),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n ...error,\n });\n });\n }\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware.\",\n { request: req, response: res, error },\n );\n }\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware.\", {\n request: req,\n response: res,\n error,\n });\n } finally {\n next();\n }\n };\n};\n\nconst getConsumer = (req: Request) => {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n};\n\nconst extractExpressValidatorErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n};\n\nconst extractCelebrateErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n};\n\nconst extractNestValidationErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n};\n\nconst subsetJoiMessage = (message: string, key: string) => {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n};\n\nconst getAppInfo = (app: Express, appVersion?: string): StartupData => {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: listEndpoints(app),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n};\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: Array<[number, SyncPayload]>;\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n\n public requestCounter: RequestCounter;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({ clientId, env = \"dev\", logger }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n if (!isValidClientId(clientId)) {\n throw new Error(\n `Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`,\n );\n }\n if (!isValidEnv(env)) {\n throw new Error(\n `Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`,\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = randomUUID();\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.logger = logger || getLogger();\n\n this.startSync();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.stopSync();\n await this.sendSyncData();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n private startSync() {\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n this.sendStartupData();\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n time_offset: 0,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n };\n this.syncDataQueue.push([Date.now(), newPayload]);\n\n const failedItems: [number, SyncPayload][] = [];\n while (this.syncDataQueue.length > 0) {\n const queueItem = this.syncDataQueue.shift();\n if (queueItem) {\n const [time, payload] = queueItem;\n try {\n const timeOffset = Date.now() - time;\n if (timeOffset <= MAX_QUEUE_TIME) {\n payload.time_offset = timeOffset / 1000.0; // In seconds\n await this.sendData(\"sync\", payload);\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n failedItems.push(queueItem);\n }\n }\n }\n }\n this.syncDataQueue = failedItems;\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n}\n","import { ApitallyConsumer } from \"./types.js\";\n\nexport const consumerFromStringOrObject = (\n consumer: ApitallyConsumer | string,\n) => {\n if (typeof consumer === \"string\") {\n consumer = String(consumer).trim().substring(0, 128);\n return consumer ? { identifier: consumer } : null;\n } else {\n consumer.identifier = String(consumer.identifier).trim().substring(0, 128);\n consumer.name = consumer.name?.trim().substring(0, 64);\n consumer.group = consumer.group?.trim().substring(0, 64);\n return consumer.identifier ? consumer : null;\n }\n};\n\nexport default class ConsumerRegistry {\n private consumers: Map<string, ApitallyConsumer>;\n private updated: Set<string>;\n\n constructor() {\n this.consumers = new Map();\n this.updated = new Set();\n }\n\n public addOrUpdateConsumer(consumer?: ApitallyConsumer | null) {\n if (!consumer || (!consumer.name && !consumer.group)) {\n return;\n }\n const existing = this.consumers.get(consumer.identifier);\n if (!existing) {\n this.consumers.set(consumer.identifier, consumer);\n this.updated.add(consumer.identifier);\n } else {\n if (consumer.name && consumer.name !== existing.name) {\n existing.name = consumer.name;\n this.updated.add(consumer.identifier);\n }\n if (consumer.group && consumer.group !== existing.group) {\n existing.group = consumer.group;\n this.updated.add(consumer.identifier);\n }\n }\n }\n\n public getAndResetUpdatedConsumers() {\n const data: Array<ApitallyConsumer> = [];\n this.updated.forEach((identifier) => {\n const consumer = this.consumers.get(identifier);\n if (consumer) {\n data.push(consumer);\n }\n });\n this.updated.clear();\n return data;\n }\n}\n","import { createLogger, format, transports } from \"winston\";\n\nexport interface Logger {\n debug: (message: string, meta?: object) => void;\n info: (message: string, meta?: object) => void;\n warn: (message: string, meta?: object) => void;\n error: (message: string, meta?: object) => void;\n}\n\nexport const getLogger = () => {\n return createLogger({\n level: process.env.APITALLY_DEBUG ? \"debug\" : \"warn\",\n format: format.combine(\n format.colorize(),\n format.timestamp(),\n format.printf(\n (info) => `${info.timestamp} ${info.level}: ${info.message}`,\n ),\n ),\n transports: [new transports.Console()],\n });\n};\n","export function isValidClientId(clientId: string): boolean {\n const regexExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return regexExp.test(clientId);\n}\n\nexport function isValidEnv(env: string): boolean {\n const regexExp = /^[\\w-]{1,32}$/;\n return regexExp.test(env);\n}\n","import { RequestInfo, RequestsItem } from \"./types.js\";\n\nexport default class RequestCounter {\n private requestCounts: Map<string, number>;\n private requestSizeSums: Map<string, number>;\n private responseSizeSums: Map<string, number>;\n private responseTimes: Map<string, Map<number, number>>;\n private requestSizes: Map<string, Map<number, number>>;\n private responseSizes: Map<string, Map<number, number>>;\n\n constructor() {\n this.requestCounts = new Map<string, number>();\n this.requestSizeSums = new Map<string, number>();\n this.responseSizeSums = new Map<string, number>();\n this.responseTimes = new Map<string, Map<number, number>>();\n this.requestSizes = new Map<string, Map<number, number>>();\n this.responseSizes = new Map<string, Map<number, number>>();\n }\n\n private getKey(requestInfo: RequestInfo) {\n return [\n requestInfo.consumer || \"\",\n requestInfo.method.toUpperCase(),\n requestInfo.path,\n requestInfo.statusCode,\n ].join(\"|\");\n }\n\n addRequest(requestInfo: RequestInfo) {\n const key = this.getKey(requestInfo);\n\n // Increment request count\n this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);\n\n // Add response time\n if (!this.responseTimes.has(key)) {\n this.responseTimes.set(key, new Map<number, number>());\n }\n const responseTimeMap = this.responseTimes.get(key)!;\n const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10; // Rounded to nearest 10ms\n responseTimeMap.set(\n responseTimeMsBin,\n (responseTimeMap.get(responseTimeMsBin) || 0) + 1,\n );\n\n // Add request size\n if (requestInfo.requestSize !== undefined) {\n requestInfo.requestSize = Number(requestInfo.requestSize);\n this.requestSizeSums.set(\n key,\n (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize,\n );\n if (!this.requestSizes.has(key)) {\n this.requestSizes.set(key, new Map<number, number>());\n }\n const requestSizeMap = this.requestSizes.get(key)!;\n const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1000); // Rounded down to nearest KB\n requestSizeMap.set(\n requestSizeKbBin,\n (requestSizeMap.get(requestSizeKbBin) || 0) + 1,\n );\n }\n\n // Add response size\n if (requestInfo.responseSize !== undefined) {\n requestInfo.responseSize = Number(requestInfo.responseSize);\n this.responseSizeSums.set(\n key,\n (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize,\n );\n if (!this.responseSizes.has(key)) {\n this.responseSizes.set(key, new Map<number, number>());\n }\n const responseSizeMap = this.responseSizes.get(key)!;\n const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1000); // Rounded down to nearest KB\n responseSizeMap.set(\n responseSizeKbBin,\n (responseSizeMap.get(responseSizeKbBin) || 0) + 1,\n );\n }\n }\n\n getAndResetRequests() {\n const data: Array<RequestsItem> = [];\n this.requestCounts.forEach((count, key) => {\n const [consumer, method, path, statusCodeStr] = key.split(\"|\");\n const responseTimes =\n this.responseTimes.get(key) || new Map<number, number>();\n const requestSizes =\n this.requestSizes.get(key) || new Map<number, number>();\n const responseSizes =\n this.responseSizes.get(key) || new Map<number, number>();\n data.push({\n consumer: consumer || null,\n method,\n path,\n status_code: parseInt(statusCodeStr),\n request_count: count,\n request_size_sum: this.requestSizeSums.get(key) || 0,\n response_size_sum: this.responseSizeSums.get(key) || 0,\n response_times: Object.fromEntries(responseTimes),\n request_sizes: Object.fromEntries(requestSizes),\n response_sizes: Object.fromEntries(responseSizes),\n });\n });\n\n // Reset the counts and times\n this.requestCounts.clear();\n this.requestSizeSums.clear();\n this.responseSizeSums.clear();\n this.responseTimes.clear();\n this.requestSizes.clear();\n this.responseSizes.clear();\n\n return data;\n }\n}\n","import type * as Sentry from \"@sentry/node\";\nimport { createHash } from \"crypto\";\n\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n private sentry: typeof Sentry | undefined;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n this.tryImportSentry();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n this.captureSentryEventId(key);\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: this.getTruncatedMessage(serverError.msg),\n traceback: this.getTruncatedStack(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n\n private getTruncatedMessage(msg: string) {\n msg = msg.trim();\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n }\n\n private getTruncatedStack(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n }\n\n private captureSentryEventId(serverErrorKey: string) {\n if (this.sentry && this.sentry.lastEventId) {\n const eventId = this.sentry.lastEventId();\n if (eventId) {\n this.sentryEventIds.set(serverErrorKey, eventId);\n }\n }\n }\n\n private async tryImportSentry() {\n try {\n this.sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n }\n}\n","import { createHash } from \"crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\"),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc,\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n","import { createRequire } from \"module\";\n\nexport function getPackageVersion(name: string): string | null {\n try {\n const _require = createRequire(import.meta.url);\n return _require(`${name}/package.json`).version || null;\n } catch (error) {\n return null;\n }\n}\n","// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/ed926dd5186761e7b721ad20938ce6eb52d104d3/src/index.js\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\\\/(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\(\\[\\^\\\\\\/]\\+\\?\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\(\\[\\^\\\\\\/]\\+\\?\\)\\)/;\nconst regexpExpressParamRegexp = /\\(\\?:\\(\\[\\^\\\\\\/]\\+\\?\\)\\)/g;\n\nconst EXPRESS_ROOT_PATH_REGEXP_VALUE = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst STACK_ITEM_VALID_NAMES = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Returns all the verbs detected for the passed route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Object} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regexpExpressParamRegexp.test(expressPathRegExp);\n};\n\n/**\n * @param {Object} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Object[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n const paths = [];\n\n if (Array.isArray(route.path)) {\n paths.push(...route.path);\n } else {\n paths.push(route.path);\n }\n\n const endpoints = paths.map((path) => {\n const completePath =\n basePath && path === \"/\" ? basePath : `${basePath}${path}`;\n\n const endpoint = {\n path: completePath,\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n };\n\n return endpoint;\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {Object[]} params\n * @returns {string}\n */\nconst parseExpressPath = function (expressPathRegExp, params) {\n let expressPathRegExpExec =\n regExpToParseExpressPathRegExp.exec(expressPathRegExp);\n let parsedRegExp = expressPathRegExp.toString();\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = params[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n paramId,\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n const parsedPath = expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n\n return parsedPath;\n};\n\n/**\n * @param {Object} app\n * @param {string} [basePath]\n * @param {Object[]} [endpoints]\n * @returns {Object[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const stack = app.stack || (app._router && app._router.stack);\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n } else {\n endpoints = parseStack(stack, basePath, endpoints);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Object[]} currentEndpoints Array of current endpoints\n * @param {Object[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Object[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (item) => item.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {Object} stack\n * @param {string} basePath\n * @param {Object[]} endpoints\n * @returns {Object[]}\n */\nconst parseStack = function (stack, basePath, endpoints) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {\n const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n\n let newBasePath = basePath;\n\n if (isExpressPathRegexp) {\n const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys);\n\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE\n ) {\n const regExpPath = ` RegExp(${stackItem.regexp}) `;\n\n newBasePath += `/${regExpPath}`;\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nconst getEndpoints = function (app) {\n const endpoints = parseEndpoints(app);\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => ![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: route.path,\n })),\n );\n};\n\nexport default getEndpoints;\n"],"mappings":"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","names":["import_crypto","consumerFromStringOrObject","consumer","_a","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","constructor","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear","getLogger","createLogger","level","process","env","APITALLY_DEBUG","format","combine","colorize","timestamp","printf","info","message","transports","Console","isValidClientId","clientId","regexExp","test","isValidEnv","env","RequestCounter","requestCounts","requestSizeSums","responseSizeSums","responseTimes","requestSizes","responseSizes","constructor","Map","getKey","requestInfo","consumer","method","toUpperCase","path","statusCode","join","addRequest","key","set","get","has","responseTimeMap","responseTimeMsBin","Math","floor","responseTime","requestSize","undefined","Number","requestSizeMap","requestSizeKbBin","responseSize","responseSizeMap","responseSizeKbBin","getAndResetRequests","data","forEach","count","statusCodeStr","split","push","status_code","parseInt","request_count","request_size_sum","response_size_sum","response_times","Object","fromEntries","request_sizes","response_sizes","clear","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","sentry","constructor","Map","tryImportSentry","addServerError","serverError","key","getKey","has","set","get","captureSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","getTruncatedMessage","traceback","getTruncatedStack","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","serverErrorKey","lastEventId","eventId","e","import_crypto","ValidationErrorCounter","errorCounts","errorDetails","constructor","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","constructor","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","requestCounter","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","instance","isValidClientId","isValidEnv","randomUUID","RequestCounter","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","getLogger","startSync","handleShutdown","bind","getInstance","shutdown","stopSync","sendSyncData","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","error","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","time_offset","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","Date","now","failedItems","length","queueItem","shift","time","timeOffset","getPackageVersion","name","_require","createRequire","url","version","error","regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regexpExpressParamRegexp","EXPRESS_ROOT_PATH_REGEXP_VALUE","STACK_ITEM_VALID_NAMES","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","stack","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","path","push","endpoints","completePath","endpoint","middlewares","parseExpressPath","params","expressPathRegExpExec","exec","parsedRegExp","toString","paramIndex","paramName","paramId","replace","parsedPath","parseEndpoints","app","_router","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","undefined","newMethods","includes","concat","stackItem","newEndpoints","isExpressPathRegexp","regexp","newBasePath","regExpPath","getEndpoints","flatMap","useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setTimeout","setStartupData","getAppInfo","appVersion","validatorInstalled","getPackageVersion","celebrateInstalled","nestInstalled","classValidatorInstalled","errorHandlerConfigured","req","res","next","err","locals","serverError","startTime","performance","now","originalJson","json","body","call","on","route","responseTime","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","method","path","statusCode","requestSize","get","responseSize","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","logger","request","response","apitallyConsumer","consumerFromStringOrObject","consumerIdentifier","process","emitWarning","responseBody","errors","Array","isArray","location","loc","validation","Object","values","source","keys","key","subsetJoiMessage","messageWithKey","split","find","includes","versions","version","replace","expressVersion","apitallyVersion","paths","listEndpoints","fromEntries"]}
1
+ {"version":3,"sources":["../../src/express/middleware.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/serverErrorCounter.ts","../../src/common/validationErrorCounter.ts","../../src/common/packageVersions.ts","../../src/express/listEndpoints.js"],"sourcesContent":["import type { Express, NextFunction, Request, Response, Router } from \"express\";\nimport { performance } from \"perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport listEndpoints from \"./listEndpoints.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport const useApitally = (app: Express | Router, config: ApitallyConfig) => {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n setTimeout(() => {\n client.setStartupData(getAppInfo(app, config.appVersion));\n }, 1000);\n};\n\nconst getMiddleware = (app: Express | Router, client: ApitallyClient) => {\n const validatorInstalled = getPackageVersion(\"express-validator\") !== null;\n const celebrateInstalled = getPackageVersion(\"celebrate\") !== null;\n const nestInstalled = getPackageVersion(\"@nestjs/core\") !== null;\n const classValidatorInstalled = getPackageVersion(\"class-validator\") !== null;\n let errorHandlerConfigured = false;\n\n return (req: Request, res: Response, next: NextFunction) => {\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use(\n (err: Error, req: Request, res: Response, next: NextFunction): void => {\n res.locals.serverError = err;\n next(err);\n },\n );\n errorHandlerConfigured = true;\n }\n try {\n const startTime = performance.now();\n const originalJson = res.json;\n res.json = (body) => {\n res.locals.body = body;\n return originalJson.call(res, body);\n };\n res.on(\"finish\", () => {\n try {\n if (req.route) {\n const responseTime = performance.now() - startTime;\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize: req.get(\"content-length\"),\n responseSize: res.get(\"content-length\"),\n });\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n const validationErrors: ValidationError[] = [];\n if (validatorInstalled) {\n validationErrors.push(\n ...extractExpressValidatorErrors(res.locals.body),\n );\n }\n if (celebrateInstalled) {\n validationErrors.push(\n ...extractCelebrateErrors(res.locals.body),\n );\n }\n if (nestInstalled && classValidatorInstalled) {\n validationErrors.push(\n ...extractNestValidationErrors(res.locals.body),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n ...error,\n });\n });\n }\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path: req.route.path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware.\",\n { request: req, response: res, error },\n );\n }\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware.\", {\n request: req,\n response: res,\n error,\n });\n } finally {\n next();\n }\n };\n};\n\nconst getConsumer = (req: Request) => {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n};\n\nconst extractExpressValidatorErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n};\n\nconst extractCelebrateErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n};\n\nconst extractNestValidationErrors = (responseBody: any) => {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n};\n\nconst subsetJoiMessage = (message: string, key: string) => {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n};\n\nconst getAppInfo = (\n app: Express | Router,\n appVersion?: string,\n): StartupData => {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: listEndpoints(app),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n};\n","import { randomUUID } from \"crypto\";\nimport fetchRetry from \"fetch-retry\";\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: Array<[number, SyncPayload]>;\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n\n public requestCounter: RequestCounter;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({ clientId, env = \"dev\", logger }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n if (!isValidClientId(clientId)) {\n throw new Error(\n `Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`,\n );\n }\n if (!isValidEnv(env)) {\n throw new Error(\n `Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`,\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = randomUUID();\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.logger = logger || getLogger();\n\n this.startSync();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.stopSync();\n await this.sendSyncData();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n private startSync() {\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n this.sendStartupData();\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n time_offset: 0,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n };\n this.syncDataQueue.push([Date.now(), newPayload]);\n\n let i = 0;\n while (this.syncDataQueue.length > 0) {\n const queueItem = this.syncDataQueue.shift();\n if (queueItem) {\n const [time, payload] = queueItem;\n try {\n const timeOffset = Date.now() - time;\n if (timeOffset <= MAX_QUEUE_TIME) {\n if (i > 0) {\n const waitMs = 100 + Math.random() * 200;\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n payload.time_offset = timeOffset / 1000.0; // in seconds\n await this.sendData(\"sync\", payload);\n i += 1;\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n this.syncDataQueue.push(queueItem);\n break;\n }\n }\n }\n }\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n}\n","import { ApitallyConsumer } from \"./types.js\";\n\nexport const consumerFromStringOrObject = (\n consumer: ApitallyConsumer | string,\n) => {\n if (typeof consumer === \"string\") {\n consumer = String(consumer).trim().substring(0, 128);\n return consumer ? { identifier: consumer } : null;\n } else {\n consumer.identifier = String(consumer.identifier).trim().substring(0, 128);\n consumer.name = consumer.name?.trim().substring(0, 64);\n consumer.group = consumer.group?.trim().substring(0, 64);\n return consumer.identifier ? consumer : null;\n }\n};\n\nexport default class ConsumerRegistry {\n private consumers: Map<string, ApitallyConsumer>;\n private updated: Set<string>;\n\n constructor() {\n this.consumers = new Map();\n this.updated = new Set();\n }\n\n public addOrUpdateConsumer(consumer?: ApitallyConsumer | null) {\n if (!consumer || (!consumer.name && !consumer.group)) {\n return;\n }\n const existing = this.consumers.get(consumer.identifier);\n if (!existing) {\n this.consumers.set(consumer.identifier, consumer);\n this.updated.add(consumer.identifier);\n } else {\n if (consumer.name && consumer.name !== existing.name) {\n existing.name = consumer.name;\n this.updated.add(consumer.identifier);\n }\n if (consumer.group && consumer.group !== existing.group) {\n existing.group = consumer.group;\n this.updated.add(consumer.identifier);\n }\n }\n }\n\n public getAndResetUpdatedConsumers() {\n const data: Array<ApitallyConsumer> = [];\n this.updated.forEach((identifier) => {\n const consumer = this.consumers.get(identifier);\n if (consumer) {\n data.push(consumer);\n }\n });\n this.updated.clear();\n return data;\n }\n}\n","import { createLogger, format, transports } from \"winston\";\n\nexport interface Logger {\n debug: (message: string, meta?: object) => void;\n info: (message: string, meta?: object) => void;\n warn: (message: string, meta?: object) => void;\n error: (message: string, meta?: object) => void;\n}\n\nexport const getLogger = () => {\n return createLogger({\n level: process.env.APITALLY_DEBUG ? \"debug\" : \"warn\",\n format: format.combine(\n format.colorize(),\n format.timestamp(),\n format.printf(\n (info) => `${info.timestamp} ${info.level}: ${info.message}`,\n ),\n ),\n transports: [new transports.Console()],\n });\n};\n","export function isValidClientId(clientId: string): boolean {\n const regexExp =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return regexExp.test(clientId);\n}\n\nexport function isValidEnv(env: string): boolean {\n const regexExp = /^[\\w-]{1,32}$/;\n return regexExp.test(env);\n}\n","import { RequestInfo, RequestsItem } from \"./types.js\";\n\nexport default class RequestCounter {\n private requestCounts: Map<string, number>;\n private requestSizeSums: Map<string, number>;\n private responseSizeSums: Map<string, number>;\n private responseTimes: Map<string, Map<number, number>>;\n private requestSizes: Map<string, Map<number, number>>;\n private responseSizes: Map<string, Map<number, number>>;\n\n constructor() {\n this.requestCounts = new Map<string, number>();\n this.requestSizeSums = new Map<string, number>();\n this.responseSizeSums = new Map<string, number>();\n this.responseTimes = new Map<string, Map<number, number>>();\n this.requestSizes = new Map<string, Map<number, number>>();\n this.responseSizes = new Map<string, Map<number, number>>();\n }\n\n private getKey(requestInfo: RequestInfo) {\n return [\n requestInfo.consumer || \"\",\n requestInfo.method.toUpperCase(),\n requestInfo.path,\n requestInfo.statusCode,\n ].join(\"|\");\n }\n\n addRequest(requestInfo: RequestInfo) {\n const key = this.getKey(requestInfo);\n\n // Increment request count\n this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);\n\n // Add response time\n if (!this.responseTimes.has(key)) {\n this.responseTimes.set(key, new Map<number, number>());\n }\n const responseTimeMap = this.responseTimes.get(key)!;\n const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10; // Rounded to nearest 10ms\n responseTimeMap.set(\n responseTimeMsBin,\n (responseTimeMap.get(responseTimeMsBin) || 0) + 1,\n );\n\n // Add request size\n if (requestInfo.requestSize !== undefined) {\n requestInfo.requestSize = Number(requestInfo.requestSize);\n this.requestSizeSums.set(\n key,\n (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize,\n );\n if (!this.requestSizes.has(key)) {\n this.requestSizes.set(key, new Map<number, number>());\n }\n const requestSizeMap = this.requestSizes.get(key)!;\n const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1000); // Rounded down to nearest KB\n requestSizeMap.set(\n requestSizeKbBin,\n (requestSizeMap.get(requestSizeKbBin) || 0) + 1,\n );\n }\n\n // Add response size\n if (requestInfo.responseSize !== undefined) {\n requestInfo.responseSize = Number(requestInfo.responseSize);\n this.responseSizeSums.set(\n key,\n (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize,\n );\n if (!this.responseSizes.has(key)) {\n this.responseSizes.set(key, new Map<number, number>());\n }\n const responseSizeMap = this.responseSizes.get(key)!;\n const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1000); // Rounded down to nearest KB\n responseSizeMap.set(\n responseSizeKbBin,\n (responseSizeMap.get(responseSizeKbBin) || 0) + 1,\n );\n }\n }\n\n getAndResetRequests() {\n const data: Array<RequestsItem> = [];\n this.requestCounts.forEach((count, key) => {\n const [consumer, method, path, statusCodeStr] = key.split(\"|\");\n const responseTimes =\n this.responseTimes.get(key) || new Map<number, number>();\n const requestSizes =\n this.requestSizes.get(key) || new Map<number, number>();\n const responseSizes =\n this.responseSizes.get(key) || new Map<number, number>();\n data.push({\n consumer: consumer || null,\n method,\n path,\n status_code: parseInt(statusCodeStr),\n request_count: count,\n request_size_sum: this.requestSizeSums.get(key) || 0,\n response_size_sum: this.responseSizeSums.get(key) || 0,\n response_times: Object.fromEntries(responseTimes),\n request_sizes: Object.fromEntries(requestSizes),\n response_sizes: Object.fromEntries(responseSizes),\n });\n });\n\n // Reset the counts and times\n this.requestCounts.clear();\n this.requestSizeSums.clear();\n this.responseSizeSums.clear();\n this.responseTimes.clear();\n this.requestSizes.clear();\n this.responseSizes.clear();\n\n return data;\n }\n}\n","import type * as Sentry from \"@sentry/node\";\nimport { createHash } from \"crypto\";\n\nimport { ConsumerMethodPath, ServerError, ServerErrorsItem } from \"./types.js\";\n\nconst MAX_MSG_LENGTH = 2048;\nconst MAX_STACKTRACE_LENGTH = 65536;\n\nexport default class ServerErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ServerError>;\n private sentryEventIds: Map<string, string>;\n private sentry: typeof Sentry | undefined;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n this.sentryEventIds = new Map();\n this.tryImportSentry();\n }\n\n public addServerError(serverError: ConsumerMethodPath & ServerError) {\n const key = this.getKey(serverError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, serverError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n this.captureSentryEventId(key);\n }\n\n public getAndResetServerErrors() {\n const data: Array<ServerErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const serverError = this.errorDetails.get(key);\n if (serverError) {\n data.push({\n consumer: serverError.consumer || null,\n method: serverError.method,\n path: serverError.path,\n type: serverError.type,\n msg: this.getTruncatedMessage(serverError.msg),\n traceback: this.getTruncatedStack(serverError.traceback),\n sentry_event_id: this.sentryEventIds.get(key) || null,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(serverError: ConsumerMethodPath & ServerError) {\n const hashInput = [\n serverError.consumer || \"\",\n serverError.method.toUpperCase(),\n serverError.path,\n serverError.type,\n serverError.msg.trim(),\n serverError.traceback.trim(),\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n\n private getTruncatedMessage(msg: string) {\n msg = msg.trim();\n if (msg.length <= MAX_MSG_LENGTH) {\n return msg;\n }\n const suffix = \"... (truncated)\";\n const cutoff = MAX_MSG_LENGTH - suffix.length;\n return msg.substring(0, cutoff) + suffix;\n }\n\n private getTruncatedStack(stack: string) {\n const suffix = \"... (truncated) ...\";\n const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;\n const lines = stack.trim().split(\"\\n\");\n const truncatedLines: string[] = [];\n let length = 0;\n for (const line of lines) {\n if (length + line.length + 1 > cutoff) {\n truncatedLines.push(suffix);\n break;\n }\n truncatedLines.push(line);\n length += line.length + 1;\n }\n return truncatedLines.join(\"\\n\");\n }\n\n private captureSentryEventId(serverErrorKey: string) {\n if (this.sentry && this.sentry.lastEventId) {\n const eventId = this.sentry.lastEventId();\n if (eventId) {\n this.sentryEventIds.set(serverErrorKey, eventId);\n }\n }\n }\n\n private async tryImportSentry() {\n try {\n this.sentry = await import(\"@sentry/node\");\n } catch (e) {\n // Sentry SDK is not installed, ignore\n }\n }\n}\n","import { createHash } from \"crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\"),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc,\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n","import { createRequire } from \"module\";\n\nexport function getPackageVersion(name: string): string | null {\n try {\n const _require = createRequire(import.meta.url);\n return _require(`${name}/package.json`).version || null;\n } catch (error) {\n return null;\n }\n}\n","// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/305535d43008b46f34e18b01947762e039af6d2d/src/index.js\n\n/**\n * @typedef {Object} Route\n * @property {Object} methods\n * @property {string | string[]} path\n * @property {any[]} stack\n *\n * @typedef {Object} Endpoint\n * @property {string} path Path name\n * @property {string[]} methods Methods handled\n * @property {string[]} middlewares Mounted middlewares\n */\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\\\/(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\([^)]+\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\([^)]+\\)\\)/;\nconst regexpExpressParamRegexp = /\\(\\?:\\([^)]+\\)\\)/g;\nconst regexpExpressPathParamRegexp = /(:[^)]+)\\([^)]+\\)/g;\n\nconst EXPRESS_ROOT_PATH_REGEXP_VALUE = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst STACK_ITEM_VALID_NAMES = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Returns all the verbs detected for the passed route\n * @param {Route} route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Route} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regexpExpressParamRegexp.test(expressPathRegExp);\n};\n\n/**\n * @param {Route} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Endpoint[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n const paths = [];\n\n if (Array.isArray(route.path)) {\n paths.push(...route.path);\n } else {\n paths.push(route.path);\n }\n\n /** @type {Endpoint[]} */\n const endpoints = paths.map((path) => {\n const completePath =\n basePath && path === \"/\" ? basePath : `${basePath}${path}`;\n\n /** @type {Endpoint} */\n const endpoint = {\n path: completePath.replace(regexpExpressPathParamRegexp, \"$1\"),\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n };\n\n return endpoint;\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {any[]} params\n * @returns {string}\n */\nconst parseExpressPath = function (expressPathRegExp, params) {\n let parsedRegExp = expressPathRegExp.toString();\n let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = params[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n paramId,\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n const parsedPath = expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n\n return parsedPath;\n};\n\n/**\n * @param {import('express').Express | import('express').Router | any} app\n * @param {string} [basePath]\n * @param {Endpoint[]} [endpoints]\n * @returns {Endpoint[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const stack = app.stack || (app._router && app._router.stack);\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n if (endpoints.length) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n }\n } else {\n endpoints = parseStack(stack, basePath, endpoints);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Endpoint[]} currentEndpoints Array of current endpoints\n * @param {Endpoint[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Endpoint[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (endpoint) => endpoint.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {any[]} stack\n * @param {string} basePath\n * @param {Endpoint[]} endpoints\n * @returns {Endpoint[]}\n */\nconst parseStack = function (stack, basePath, endpoints) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {\n const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n\n let newBasePath = basePath;\n\n if (isExpressPathRegexp) {\n const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys);\n\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE\n ) {\n const regExpPath = ` RegExp(${stackItem.regexp}) `;\n\n newBasePath += `/${regExpPath}`;\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nconst getEndpoints = function (app) {\n const endpoints = parseEndpoints(app);\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => ![\"HEAD\", \"OPTIONS\"].includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: route.path,\n })),\n );\n};\n\nexport default getEndpoints;\n"],"mappings":"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","names":["import_crypto","consumerFromStringOrObject","consumer","_a","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","constructor","Map","Set","addOrUpdateConsumer","existing","get","set","add","getAndResetUpdatedConsumers","data","forEach","push","clear","getLogger","createLogger","level","process","env","APITALLY_DEBUG","format","combine","colorize","timestamp","printf","info","message","transports","Console","isValidClientId","clientId","regexExp","test","isValidEnv","env","RequestCounter","requestCounts","requestSizeSums","responseSizeSums","responseTimes","requestSizes","responseSizes","constructor","Map","getKey","requestInfo","consumer","method","toUpperCase","path","statusCode","join","addRequest","key","set","get","has","responseTimeMap","responseTimeMsBin","Math","floor","responseTime","requestSize","undefined","Number","requestSizeMap","requestSizeKbBin","responseSize","responseSizeMap","responseSizeKbBin","getAndResetRequests","data","forEach","count","statusCodeStr","split","push","status_code","parseInt","request_count","request_size_sum","response_size_sum","response_times","Object","fromEntries","request_sizes","response_sizes","clear","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","sentry","constructor","Map","tryImportSentry","addServerError","serverError","key","getKey","has","set","get","captureSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","getTruncatedMessage","traceback","getTruncatedStack","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","serverErrorKey","lastEventId","eventId","e","import_crypto","ValidationErrorCounter","errorCounts","errorDetails","constructor","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","constructor","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","requestCounter","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","instance","isValidClientId","isValidEnv","randomUUID","RequestCounter","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","getLogger","startSync","handleShutdown","bind","getInstance","shutdown","stopSync","sendSyncData","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","error","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","time_offset","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","Date","now","i","length","queueItem","shift","time","timeOffset","waitMs","Math","random","resolve","getPackageVersion","name","_require","createRequire","url","version","error","regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regexpExpressParamRegexp","regexpExpressPathParamRegexp","EXPRESS_ROOT_PATH_REGEXP_VALUE","STACK_ITEM_VALID_NAMES","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","stack","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","path","push","endpoints","completePath","endpoint","replace","middlewares","parseExpressPath","params","parsedRegExp","toString","expressPathRegExpExec","exec","paramIndex","paramName","paramId","parsedPath","parseEndpoints","app","_router","length","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","undefined","newMethods","includes","concat","stackItem","newEndpoints","isExpressPathRegexp","regexp","newBasePath","regExpPath","getEndpoints","flatMap","useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setTimeout","setStartupData","getAppInfo","appVersion","validatorInstalled","getPackageVersion","celebrateInstalled","nestInstalled","classValidatorInstalled","errorHandlerConfigured","req","res","next","err","locals","serverError","startTime","performance","now","originalJson","json","body","call","on","route","responseTime","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","method","path","statusCode","requestSize","get","responseSize","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","logger","request","response","apitallyConsumer","consumerFromStringOrObject","consumerIdentifier","process","emitWarning","responseBody","errors","Array","isArray","location","loc","validation","Object","values","source","keys","key","subsetJoiMessage","messageWithKey","split","find","includes","versions","version","replace","expressVersion","apitallyVersion","paths","listEndpoints","fromEntries"]}
@@ -1,5 +1,5 @@
1
- import { Express } from 'express';
2
1
  import { ApitallyConsumer, ApitallyConfig } from '../common/types.cjs';
2
+ import { Express, Router } from 'express';
3
3
  import '../common/logging.cjs';
4
4
  import 'winston';
5
5
 
@@ -9,6 +9,6 @@ declare module "express" {
9
9
  consumerIdentifier?: ApitallyConsumer | string | null;
10
10
  }
11
11
  }
12
- declare const useApitally: (app: Express, config: ApitallyConfig) => void;
12
+ declare const useApitally: (app: Express | Router, config: ApitallyConfig) => void;
13
13
 
14
14
  export { useApitally };
@@ -1,5 +1,5 @@
1
- import { Express } from 'express';
2
1
  import { ApitallyConsumer, ApitallyConfig } from '../common/types.js';
2
+ import { Express, Router } from 'express';
3
3
  import '../common/logging.js';
4
4
  import 'winston';
5
5
 
@@ -9,6 +9,6 @@ declare module "express" {
9
9
  consumerIdentifier?: ApitallyConsumer | string | null;
10
10
  }
11
11
  }
12
- declare const useApitally: (app: Express, config: ApitallyConfig) => void;
12
+ declare const useApitally: (app: Express | Router, config: ApitallyConfig) => void;
13
13
 
14
14
  export { useApitally };
@@ -495,7 +495,7 @@ var _ApitallyClient = class _ApitallyClient {
495
495
  Date.now(),
496
496
  newPayload
497
497
  ]);
498
- const failedItems = [];
498
+ let i = 0;
499
499
  while (this.syncDataQueue.length > 0) {
500
500
  const queueItem = this.syncDataQueue.shift();
501
501
  if (queueItem) {
@@ -503,8 +503,13 @@ var _ApitallyClient = class _ApitallyClient {
503
503
  try {
504
504
  const timeOffset = Date.now() - time;
505
505
  if (timeOffset <= MAX_QUEUE_TIME) {
506
+ if (i > 0) {
507
+ const waitMs = 100 + Math.random() * 200;
508
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
509
+ }
506
510
  payload.time_offset = timeOffset / 1e3;
507
511
  await this.sendData("sync", payload);
512
+ i += 1;
508
513
  }
509
514
  } catch (error) {
510
515
  const handled = this.handleHubError(error);
@@ -512,12 +517,12 @@ var _ApitallyClient = class _ApitallyClient {
512
517
  this.logger.debug("Error while synchronizing data with Apitally Hub (will retry)", {
513
518
  error
514
519
  });
515
- failedItems.push(queueItem);
520
+ this.syncDataQueue.push(queueItem);
521
+ break;
516
522
  }
517
523
  }
518
524
  }
519
525
  }
520
- this.syncDataQueue = failedItems;
521
526
  }
522
527
  handleHubError(error) {
523
528
  if (error instanceof HTTPError) {
@@ -551,9 +556,10 @@ function getPackageVersion(name) {
551
556
  __name(getPackageVersion, "getPackageVersion");
552
557
 
553
558
  // src/express/listEndpoints.js
554
- var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\(\[\^\\\/]\+\?\)\)))\\\/.*/;
555
- var regExpToReplaceExpressPathRegExpParams = /\(\?:\(\[\^\\\/]\+\?\)\)/;
556
- var regexpExpressParamRegexp = /\(\?:\(\[\^\\\/]\+\?\)\)/g;
559
+ var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\([^)]+\)\)))\\\/.*/;
560
+ var regExpToReplaceExpressPathRegExpParams = /\(\?:\([^)]+\)\)/;
561
+ var regexpExpressParamRegexp = /\(\?:\([^)]+\)\)/g;
562
+ var regexpExpressPathParamRegexp = /(:[^)]+)\([^)]+\)/g;
557
563
  var EXPRESS_ROOT_PATH_REGEXP_VALUE = "/^\\/?(?=\\/|$)/i";
558
564
  var STACK_ITEM_VALID_NAMES = [
559
565
  "router",
@@ -584,7 +590,7 @@ var parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
584
590
  const endpoints = paths.map((path) => {
585
591
  const completePath = basePath && path === "/" ? basePath : `${basePath}${path}`;
586
592
  const endpoint = {
587
- path: completePath,
593
+ path: completePath.replace(regexpExpressPathParamRegexp, "$1"),
588
594
  methods: getRouteMethods(route),
589
595
  middlewares: getRouteMiddlewares(route)
590
596
  };
@@ -593,8 +599,8 @@ var parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
593
599
  return endpoints;
594
600
  }, "parseExpressRoute");
595
601
  var parseExpressPath = /* @__PURE__ */ __name(function(expressPathRegExp, params) {
596
- let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(expressPathRegExp);
597
602
  let parsedRegExp = expressPathRegExp.toString();
603
+ let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
598
604
  let paramIndex = 0;
599
605
  while (hasParams(parsedRegExp)) {
600
606
  const paramName = params[paramIndex].name;
@@ -613,13 +619,15 @@ var parseEndpoints = /* @__PURE__ */ __name(function(app, basePath, endpoints) {
613
619
  endpoints = endpoints || [];
614
620
  basePath = basePath || "";
615
621
  if (!stack) {
616
- endpoints = addEndpoints(endpoints, [
617
- {
618
- path: basePath,
619
- methods: [],
620
- middlewares: []
621
- }
622
- ]);
622
+ if (endpoints.length) {
623
+ endpoints = addEndpoints(endpoints, [
624
+ {
625
+ path: basePath,
626
+ methods: [],
627
+ middlewares: []
628
+ }
629
+ ]);
630
+ }
623
631
  } else {
624
632
  endpoints = parseStack(stack, basePath, endpoints);
625
633
  }
@@ -627,7 +635,7 @@ var parseEndpoints = /* @__PURE__ */ __name(function(app, basePath, endpoints) {
627
635
  }, "parseEndpoints");
628
636
  var addEndpoints = /* @__PURE__ */ __name(function(currentEndpoints, endpointsToAdd) {
629
637
  endpointsToAdd.forEach((newEndpoint) => {
630
- const existingEndpoint = currentEndpoints.find((item) => item.path === newEndpoint.path);
638
+ const existingEndpoint = currentEndpoints.find((endpoint) => endpoint.path === newEndpoint.path);
631
639
  if (existingEndpoint !== void 0) {
632
640
  const newMethods = newEndpoint.methods.filter((method) => !existingEndpoint.methods.includes(method));
633
641
  existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);