apitally 0.9.0 → 0.9.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.
@@ -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, 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":["performance","randomUUID","fetchRetry","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","createLogger","format","transports","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","createHash","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","createHash","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","createRequire","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
+ {"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/utils.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 { getEndpoints, parseExpressPath } from \"./utils.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 = (\n app: Express | Router,\n config: ApitallyConfig & { basePath?: string },\n) => {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n setTimeout(() => {\n client.setStartupData(getAppInfo(app, config.basePath, 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 const path = getRoutePath(req);\n if (path) {\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,\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 getRoutePath = (req: Request) => {\n if (!req.route) {\n return;\n }\n if (req.baseUrl) {\n const routerPath = getRouterPath(req.app._router.stack, req.baseUrl);\n return routerPath + req.route.path;\n }\n return req.route.path;\n};\n\nconst getRouterPath = (stack: any[], baseUrl: string) => {\n const routerPaths: string[] = [];\n while (stack && stack.length > 0) {\n const routerLayer = stack.find(\n (layer) => layer.name === \"router\" && layer.regexp?.test(baseUrl),\n );\n if (routerLayer) {\n if (routerLayer.keys.length > 0) {\n const parsedPath = parseExpressPath(\n routerLayer.regexp,\n routerLayer.keys,\n );\n routerPaths.push(\"/\" + parsedPath);\n } else {\n routerPaths.push(routerLayer.path);\n }\n stack = routerLayer.handle?.stack;\n baseUrl = baseUrl.slice(routerLayer.path.length);\n } else {\n break;\n }\n }\n return routerPaths.join(\"\");\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 basePath?: string,\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: getEndpoints(app, basePath || \"\"),\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// and also incorporated changes from https://github.com/AlbertoFdzM/express-list-endpoints/pull/96\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 */\nexport const 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 (str) => {\n // Express >= 4.20.0 uses a different RegExp for parameters: it\n // captures the slash as part of the parameter. We need to check\n // for this case and add the slash to the value that will replace\n // the parameter in the path.\n if (str.startsWith(\"(?:\\\\/\")) {\n return `\\\\/${paramId}`;\n }\n\n return paramId;\n },\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\nexport const getEndpoints = function (app, basePath) {\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: basePath + route.path,\n })),\n );\n};\n"],"mappings":"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","names":["performance","randomUUID","fetchRetry","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","createLogger","format","transports","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","createHash","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","createHash","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","createRequire","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","str","startsWith","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","basePath","appVersion","validatorInstalled","getPackageVersion","celebrateInstalled","nestInstalled","classValidatorInstalled","errorHandlerConfigured","req","res","next","err","locals","serverError","startTime","performance","now","originalJson","json","body","call","on","path","getRoutePath","responseTime","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","method","statusCode","requestSize","get","responseSize","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","route","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","logger","request","response","baseUrl","routerPath","getRouterPath","_router","_a","routerPaths","length","routerLayer","find","layer","regexp","test","keys","parsedPath","parseExpressPath","handle","slice","join","apitallyConsumer","consumerFromStringOrObject","consumerIdentifier","process","emitWarning","responseBody","errors","Array","isArray","location","loc","validation","Object","values","source","key","subsetJoiMessage","messageWithKey","split","includes","versions","version","replace","expressVersion","apitallyVersion","paths","getEndpoints","fromEntries"]}
@@ -588,10 +588,10 @@ function getPackageVersion(name) {
588
588
  }
589
589
  __name(getPackageVersion, "getPackageVersion");
590
590
 
591
- // src/express/listEndpoints.js
592
- var regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\([^)]+\)\)))\\\/.*/;
593
- var regExpToReplaceExpressPathRegExpParams = /\(\?:\([^)]+\)\)/;
594
- var regexpExpressParamRegexp = /\(\?:\([^)]+\)\)/g;
591
+ // src/express/utils.js
592
+ var regExpToParseExpressPathRegExp = /^\/\^\\?\/?(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\\?\/?\([^)]+\)\)))\\\/.*/;
593
+ var regExpToReplaceExpressPathRegExpParams = /\(\?:\\?\/?\([^)]+\)\)/;
594
+ var regexpExpressParamRegexp = /\(\?:\\?\\?\/?\([^)]+\)\)/g;
595
595
  var regexpExpressPathParamRegexp = /(:[^)]+)\([^)]+\)/g;
596
596
  var EXPRESS_ROOT_PATH_REGEXP_VALUE = "/^\\/?(?=\\/|$)/i";
597
597
  var STACK_ITEM_VALID_NAMES = [
@@ -638,7 +638,12 @@ var parseExpressPath = /* @__PURE__ */ __name(function(expressPathRegExp, params
638
638
  while (hasParams(parsedRegExp)) {
639
639
  const paramName = params[paramIndex].name;
640
640
  const paramId = `:${paramName}`;
641
- parsedRegExp = parsedRegExp.replace(regExpToReplaceExpressPathRegExpParams, paramId);
641
+ parsedRegExp = parsedRegExp.replace(regExpToReplaceExpressPathRegExpParams, (str) => {
642
+ if (str.startsWith("(?:\\/")) {
643
+ return `\\/${paramId}`;
644
+ }
645
+ return paramId;
646
+ });
642
647
  paramIndex++;
643
648
  }
644
649
  if (parsedRegExp !== expressPathRegExp.toString()) {
@@ -698,17 +703,16 @@ var parseStack = /* @__PURE__ */ __name(function(stack, basePath, endpoints) {
698
703
  });
699
704
  return endpoints;
700
705
  }, "parseStack");
701
- var getEndpoints = /* @__PURE__ */ __name(function(app) {
706
+ var getEndpoints = /* @__PURE__ */ __name(function(app, basePath) {
702
707
  const endpoints = parseEndpoints(app);
703
708
  return endpoints.flatMap((route) => route.methods.filter((method) => ![
704
709
  "HEAD",
705
710
  "OPTIONS"
706
711
  ].includes(method.toUpperCase())).map((method) => ({
707
712
  method,
708
- path: route.path
713
+ path: basePath + route.path
709
714
  })));
710
715
  }, "getEndpoints");
711
- var listEndpoints_default = getEndpoints;
712
716
 
713
717
  // src/express/middleware.ts
714
718
  var useApitally = /* @__PURE__ */ __name((app, config) => {
@@ -716,7 +720,7 @@ var useApitally = /* @__PURE__ */ __name((app, config) => {
716
720
  const middleware = getMiddleware(app, client);
717
721
  app.use(middleware);
718
722
  setTimeout(() => {
719
- client.setStartupData(getAppInfo(app, config.appVersion));
723
+ client.setStartupData(getAppInfo(app, config.basePath, config.appVersion));
720
724
  }, 1e3);
721
725
  }, "useApitally");
722
726
  var getMiddleware = /* @__PURE__ */ __name((app, client) => {
@@ -742,14 +746,15 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
742
746
  };
743
747
  res.on("finish", () => {
744
748
  try {
745
- if (req.route) {
749
+ const path = getRoutePath(req);
750
+ if (path) {
746
751
  const responseTime = import_perf_hooks.performance.now() - startTime;
747
752
  const consumer = getConsumer(req);
748
753
  client.consumerRegistry.addOrUpdateConsumer(consumer);
749
754
  client.requestCounter.addRequest({
750
755
  consumer: consumer == null ? void 0 : consumer.identifier,
751
756
  method: req.method,
752
- path: req.route.path,
757
+ path,
753
758
  statusCode: res.statusCode,
754
759
  responseTime,
755
760
  requestSize: req.get("content-length"),
@@ -806,6 +811,39 @@ var getMiddleware = /* @__PURE__ */ __name((app, client) => {
806
811
  }
807
812
  };
808
813
  }, "getMiddleware");
814
+ var getRoutePath = /* @__PURE__ */ __name((req) => {
815
+ if (!req.route) {
816
+ return;
817
+ }
818
+ if (req.baseUrl) {
819
+ const routerPath = getRouterPath(req.app._router.stack, req.baseUrl);
820
+ return routerPath + req.route.path;
821
+ }
822
+ return req.route.path;
823
+ }, "getRoutePath");
824
+ var getRouterPath = /* @__PURE__ */ __name((stack, baseUrl) => {
825
+ var _a2;
826
+ const routerPaths = [];
827
+ while (stack && stack.length > 0) {
828
+ const routerLayer = stack.find((layer) => {
829
+ var _a3;
830
+ return layer.name === "router" && ((_a3 = layer.regexp) == null ? void 0 : _a3.test(baseUrl));
831
+ });
832
+ if (routerLayer) {
833
+ if (routerLayer.keys.length > 0) {
834
+ const parsedPath = parseExpressPath(routerLayer.regexp, routerLayer.keys);
835
+ routerPaths.push("/" + parsedPath);
836
+ } else {
837
+ routerPaths.push(routerLayer.path);
838
+ }
839
+ stack = (_a2 = routerLayer.handle) == null ? void 0 : _a2.stack;
840
+ baseUrl = baseUrl.slice(routerLayer.path.length);
841
+ } else {
842
+ break;
843
+ }
844
+ }
845
+ return routerPaths.join("");
846
+ }, "getRouterPath");
809
847
  var getConsumer = /* @__PURE__ */ __name((req) => {
810
848
  if (req.apitallyConsumer) {
811
849
  return consumerFromStringOrObject(req.apitallyConsumer);
@@ -864,7 +902,7 @@ var subsetJoiMessage = /* @__PURE__ */ __name((message, key) => {
864
902
  const messageWithKey = message.split(". ").find((message2) => message2.includes(`"${key}"`));
865
903
  return messageWithKey ? messageWithKey : message;
866
904
  }, "subsetJoiMessage");
867
- var getAppInfo = /* @__PURE__ */ __name((app, appVersion) => {
905
+ var getAppInfo = /* @__PURE__ */ __name((app, basePath, appVersion) => {
868
906
  const versions = [
869
907
  [
870
908
  "nodejs",
@@ -892,7 +930,7 @@ var getAppInfo = /* @__PURE__ */ __name((app, appVersion) => {
892
930
  ]);
893
931
  }
894
932
  return {
895
- paths: listEndpoints_default(app),
933
+ paths: getEndpoints(app, basePath || ""),
896
934
  versions: Object.fromEntries(versions),
897
935
  client: "js:express"
898
936
  };