UNPKG

apitally

Version:

Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, and Koa.

1 lines 99.5 kB
{"version":3,"sources":["../../src/h3/index.ts","../../src/h3/plugin.ts","../../src/common/client.ts","../../src/common/consumerRegistry.ts","../../src/common/logging.ts","../../src/common/paramValidation.ts","../../src/common/requestCounter.ts","../../src/common/requestLogger.ts","../../src/common/sentry.ts","../../src/common/serverErrorCounter.ts","../../src/common/tempGzipFile.ts","../../src/common/validationErrorCounter.ts","../../src/common/headers.ts","../../src/common/response.ts","../../src/loggers/console.ts","../../src/loggers/utils.ts","../../src/loggers/pino.ts","../../src/loggers/winston.ts","../../src/common/packageVersions.ts","../../src/h3/utils.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { apitallyPlugin, setConsumer } from \"./plugin.js\";\n","import type { H3Event, HTTPError } from \"h3\";\nimport { definePlugin, onError, onRequest, onResponse } from \"h3\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\nimport type { ZodError } from \"zod\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { mergeHeaders, parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { getResponseBody, measureResponseSize } from \"../common/response.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst REQUEST_TIMESTAMP_SYMBOL = Symbol(\"apitally.requestTimestamp\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\n\ndeclare module \"h3\" {\n  interface H3EventContext {\n    apitallyConsumer?: ApitallyConsumer | string;\n\n    [REQUEST_TIMESTAMP_SYMBOL]?: number;\n    [REQUEST_BODY_SYMBOL]?: Buffer;\n  }\n}\n\nconst jsonHeaders = new Headers({\n  \"content-type\": \"application/json;charset=UTF-8\",\n});\n\nexport const apitallyPlugin = definePlugin<ApitallyConfig>((app, config) => {\n  const client = new ApitallyClient(config);\n  const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n  const setStartupData = (attempt: number = 1) => {\n    const appInfo = getAppInfo(app, config.appVersion);\n    if (appInfo.paths.length > 0 || attempt >= 10) {\n      client.setStartupData(appInfo);\n    } else {\n      setTimeout(() => setStartupData(attempt + 1), 500);\n    }\n  };\n  setTimeout(() => setStartupData(), 500);\n\n  if (client.requestLogger.config.captureLogs) {\n    patchConsole(logsContext);\n    patchWinston(logsContext);\n  }\n\n  const handleResponse = async (\n    event: H3Event,\n    response?: Response,\n    error?: HTTPError,\n  ) => {\n    if (event.req.method.toUpperCase() === \"OPTIONS\") {\n      return response;\n    }\n\n    const startTime = event.context[REQUEST_TIMESTAMP_SYMBOL];\n    const responseTime = startTime ? performance.now() - startTime : 0;\n    const path = event.context.matchedRoute?.route;\n    const statusCode = response?.status || error?.status || 500;\n\n    const requestSize = parseContentLength(\n      event.req.headers.get(\"content-length\"),\n    );\n    let responseSize = 0;\n    let newResponse = response;\n    if (response) {\n      [responseSize, newResponse] = await measureResponseSize(response);\n    }\n\n    const consumer = getConsumer(event);\n    client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n    if (path) {\n      client.requestCounter.addRequest({\n        consumer: consumer?.identifier,\n        method: event.req.method,\n        path,\n        statusCode,\n        responseTime,\n        requestSize,\n        responseSize,\n      });\n\n      if (error?.status === 400 && (error.data as any).name === \"ZodError\") {\n        const zodError = error.data as ZodError;\n        zodError.issues?.forEach((issue) => {\n          client.validationErrorCounter.addValidationError({\n            consumer: consumer?.identifier,\n            method: event.req.method,\n            path,\n            loc: issue.path.join(\".\"),\n            msg: issue.message,\n            type: issue.code,\n          });\n        });\n      }\n\n      if (error?.status === 500 && error.cause instanceof Error) {\n        client.serverErrorCounter.addServerError({\n          consumer: consumer?.identifier,\n          method: event.req.method,\n          path,\n          type: error.cause.name,\n          msg: error.cause.message,\n          traceback: error.cause.stack || \"\",\n        });\n      }\n    }\n\n    if (client.requestLogger.enabled) {\n      const responseHeaders = response\n        ? response.headers\n        : error?.headers\n          ? mergeHeaders(jsonHeaders, error.headers)\n          : jsonHeaders;\n      const responseContentType = responseHeaders.get(\"content-type\");\n      let responseBody;\n\n      if (\n        newResponse &&\n        client.requestLogger.config.logResponseBody &&\n        client.requestLogger.isSupportedContentType(responseContentType)\n      ) {\n        [responseBody, newResponse] = await getResponseBody(newResponse);\n      } else if (error && client.requestLogger.config.logResponseBody) {\n        responseBody = Buffer.from(JSON.stringify(error.toJSON()));\n      }\n\n      const logs = logsContext.getStore();\n      client.requestLogger.logRequest(\n        {\n          timestamp: (Date.now() - responseTime) / 1000,\n          method: event.req.method,\n          path,\n          url: event.req.url,\n          headers: convertHeaders(\n            Object.fromEntries(event.req.headers.entries()),\n          ),\n          size: requestSize,\n          consumer: consumer?.identifier,\n          body: event.context[REQUEST_BODY_SYMBOL],\n        },\n        {\n          statusCode,\n          responseTime: responseTime / 1000,\n          headers: convertHeaders(\n            Object.fromEntries(responseHeaders.entries()),\n          ),\n          size: responseSize,\n          body: responseBody,\n        },\n        error?.cause instanceof Error ? error.cause : undefined,\n        logs,\n      );\n    }\n\n    return newResponse;\n  };\n\n  app\n    .use(\n      onRequest(async (event) => {\n        logsContext.enterWith([]);\n        event.context[REQUEST_TIMESTAMP_SYMBOL] = performance.now();\n        const requestContentType = event.req.headers.get(\"content-type\");\n        const requestSize =\n          parseContentLength(event.req.headers.get(\"content-length\")) ?? 0;\n\n        if (\n          client.requestLogger.enabled &&\n          client.requestLogger.config.logRequestBody &&\n          client.requestLogger.isSupportedContentType(requestContentType) &&\n          requestSize <= client.requestLogger.maxBodySize\n        ) {\n          const clonedRequest = event.req.clone();\n          const requestBody = Buffer.from(await clonedRequest.arrayBuffer());\n          event.context[REQUEST_BODY_SYMBOL] = requestBody;\n        }\n      }),\n    )\n    .use(\n      onResponse((response, event) => {\n        if (client.isEnabled()) {\n          return handleResponse(event, response, undefined);\n        }\n      }),\n    )\n    .use(\n      onError((error, event) => {\n        if (client.isEnabled()) {\n          return handleResponse(event, undefined, error);\n        }\n      }),\n    );\n});\n\nexport function setConsumer(\n  event: H3Event,\n  consumer: ApitallyConsumer | string | null | undefined,\n) {\n  event.context.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(event: H3Event) {\n  const consumer = event.context.apitallyConsumer;\n  if (consumer) {\n    return consumerFromStringOrObject(consumer);\n  }\n  return null;\n}\n","import fetchRetry from \"fetch-retry\";\nimport { randomUUID } from \"node:crypto\";\n\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport RequestLogger from \"./requestLogger.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: SyncPayload[];\n  private syncIntervalId?: NodeJS.Timeout;\n  public startupData?: StartupData;\n  private startupDataSent: boolean = false;\n  private enabled: boolean = true;\n\n  public requestCounter: RequestCounter;\n  public requestLogger: RequestLogger;\n  public validationErrorCounter: ValidationErrorCounter;\n  public serverErrorCounter: ServerErrorCounter;\n  public consumerRegistry: ConsumerRegistry;\n  public logger: Logger;\n\n  constructor({\n    clientId,\n    env = \"dev\",\n    requestLogging,\n    requestLoggingConfig,\n    logger,\n  }: 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 Apitally client ID '${clientId}' (expecting hexadecimal 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    if (requestLoggingConfig && !requestLogging) {\n      console.warn(\n        \"requestLoggingConfig is deprecated, use requestLogging instead.\",\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.requestLogger = new RequestLogger(\n      requestLogging ?? requestLoggingConfig,\n    );\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 isEnabled() {\n    return this.enabled;\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.enabled = false;\n    this.stopSync();\n    await this.sendSyncData();\n    await this.sendLogData();\n    await this.requestLogger.close();\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(), this.sendLogData()];\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      timestamp: Date.now() / 1000,\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(newPayload);\n\n    let i = 0;\n    while (this.syncDataQueue.length > 0) {\n      const payload = this.syncDataQueue.shift();\n      if (payload) {\n        try {\n          if (Date.now() - payload.timestamp * 1000 <= MAX_QUEUE_TIME) {\n            if (i > 0) {\n              await this.randomDelay();\n            }\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(payload);\n            break;\n          }\n        }\n      }\n    }\n  }\n\n  private async sendLogData() {\n    this.logger.debug(\"Sending request log data to Apitally Hub\");\n    await this.requestLogger.rotateFile();\n\n    const fetchWithRetry = fetchRetry(fetch, {\n      retries: 3,\n      retryDelay: 1000,\n      retryOn: [408, 429, 500, 502, 503, 504],\n    });\n\n    let i = 0;\n    let logFile;\n    while ((logFile = this.requestLogger.getFile())) {\n      if (i > 0) {\n        await this.randomDelay();\n      }\n\n      try {\n        const response = await fetchWithRetry(\n          `${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`,\n          {\n            method: \"POST\",\n            body: (await logFile.getContent()) as any,\n          },\n        );\n\n        if (response.status === 402 && response.headers.has(\"Retry-After\")) {\n          const retryAfter = parseInt(\n            response.headers.get(\"Retry-After\") ?? \"0\",\n          );\n          if (retryAfter > 0) {\n            this.requestLogger.suspendUntil = Date.now() + retryAfter * 1000;\n            this.requestLogger.clear();\n            return;\n          }\n        }\n\n        if (!response.ok) {\n          throw new HTTPError(response);\n        }\n\n        logFile.delete();\n      } catch (error) {\n        this.requestLogger.retryFileLater(logFile);\n        break;\n      }\n\n      i++;\n      if (i >= 10) break;\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.enabled = false;\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  private async randomDelay() {\n    const delay = 100 + Math.random() * 400;\n    await new Promise((resolve) => setTimeout(resolve, delay));\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 function 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 AsyncLock from \"async-lock\";\nimport { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { IncomingHttpHeaders, OutgoingHttpHeaders } from \"node:http\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport {\n  truncateExceptionMessage,\n  truncateExceptionStackTrace,\n} from \"./serverErrorCounter.js\";\nimport TempGzipFile from \"./tempGzipFile.js\";\n\nconst MAX_BODY_SIZE = 50_000; // 50 KB (uncompressed)\nconst MAX_FILE_SIZE = 1_000_000; // 1 MB (compressed)\nconst MAX_FILES = 50;\nconst MAX_PENDING_WRITES = 100;\nconst MAX_LOG_MSG_LENGTH = 2048;\nconst BODY_TOO_LARGE = Buffer.from(\"<body too large>\");\nconst BODY_MASKED = Buffer.from(\"<masked>\");\nconst MASKED = \"******\";\nconst ALLOWED_CONTENT_TYPES = [\n  \"application/json\",\n  \"application/problem+json\",\n  \"application/vnd.api+json\",\n  \"text/plain\",\n];\nconst EXCLUDE_PATH_PATTERNS = [\n  /\\/_?healthz?$/i,\n  /\\/_?health[_-]?checks?$/i,\n  /\\/_?heart[_-]?beats?$/i,\n  /\\/ping$/i,\n  /\\/ready$/i,\n  /\\/live$/i,\n];\nconst EXCLUDE_USER_AGENT_PATTERNS = [\n  /health[-_ ]?check/i,\n  /microsoft-azure-application-lb/i,\n  /googlehc/i,\n  /kube-probe/i,\n];\nconst MASK_QUERY_PARAM_PATTERNS = [\n  /auth/i,\n  /api-?key/i,\n  /secret/i,\n  /token/i,\n  /password/i,\n  /pwd/i,\n];\nconst MASK_HEADER_PATTERNS = [\n  /auth/i,\n  /api-?key/i,\n  /secret/i,\n  /token/i,\n  /cookie/i,\n];\nconst MASK_BODY_FIELD_PATTERNS = [\n  /password/i,\n  /pwd/i,\n  /token/i,\n  /secret/i,\n  /auth/i,\n  /card[-_ ]?number/i,\n  /ccv/i,\n  /ssn/i,\n];\n\nexport type Request = {\n  timestamp: number;\n  method: string;\n  path?: string;\n  url: string;\n  headers: [string, string][];\n  size?: number;\n  consumer?: string;\n  body?: Buffer;\n};\n\nexport type Response = {\n  statusCode: number;\n  responseTime: number;\n  headers: [string, string][];\n  size?: number;\n  body?: Buffer;\n};\n\nexport type LogRecord = {\n  timestamp: number;\n  logger?: string;\n  level: string;\n  message: string;\n};\n\nexport type RequestLoggingConfig = {\n  enabled: boolean;\n  logQueryParams: boolean;\n  logRequestHeaders: boolean;\n  logRequestBody: boolean;\n  logResponseHeaders: boolean;\n  logResponseBody: boolean;\n  logException: boolean;\n  captureLogs: boolean;\n  maskQueryParams: RegExp[];\n  maskHeaders: RegExp[];\n  maskBodyFields: RegExp[];\n  maskRequestBodyCallback?: (request: Request) => Buffer | null | undefined;\n  maskResponseBodyCallback?: (\n    request: Request,\n    response: Response,\n  ) => Buffer | null | undefined;\n  excludePaths: RegExp[];\n  excludeCallback?: (request: Request, response: Response) => boolean;\n};\n\nconst DEFAULT_CONFIG: RequestLoggingConfig = {\n  enabled: false,\n  logQueryParams: true,\n  logRequestHeaders: false,\n  logRequestBody: false,\n  logResponseHeaders: true,\n  logResponseBody: false,\n  logException: true,\n  captureLogs: false,\n  maskQueryParams: [],\n  maskHeaders: [],\n  maskBodyFields: [],\n  excludePaths: [],\n};\n\ntype RequestLogItem = {\n  uuid: string;\n  request: Request;\n  response: Response;\n  exception?: {\n    type: string;\n    message: string;\n    stacktrace: string;\n    sentryEventId?: string;\n  };\n  logs?: LogRecord[];\n};\n\nexport default class RequestLogger {\n  public config: RequestLoggingConfig;\n  public enabled: boolean;\n  public suspendUntil: number | null = null;\n  private pendingWrites: RequestLogItem[] = [];\n  private currentFile: TempGzipFile | null = null;\n  private files: TempGzipFile[] = [];\n  private maintainIntervalId?: NodeJS.Timeout;\n  private lock = new AsyncLock();\n\n  constructor(config?: Partial<RequestLoggingConfig>) {\n    this.config = { ...DEFAULT_CONFIG, ...config };\n    this.enabled = this.config.enabled && checkWritableFs();\n\n    if (this.enabled) {\n      this.maintainIntervalId = setInterval(() => {\n        this.maintain();\n      }, 1000);\n    }\n  }\n\n  get maxBodySize() {\n    return MAX_BODY_SIZE;\n  }\n\n  private shouldExcludePath(urlPath: string) {\n    const patterns = [...this.config.excludePaths, ...EXCLUDE_PATH_PATTERNS];\n    return matchPatterns(urlPath, patterns);\n  }\n\n  private shouldExcludeUserAgent(userAgent?: string) {\n    return userAgent\n      ? matchPatterns(userAgent, EXCLUDE_USER_AGENT_PATTERNS)\n      : false;\n  }\n\n  private shouldMaskQueryParam(name: string) {\n    const patterns = [\n      ...this.config.maskQueryParams,\n      ...MASK_QUERY_PARAM_PATTERNS,\n    ];\n    return matchPatterns(name, patterns);\n  }\n\n  private shouldMaskHeader(name: string) {\n    const patterns = [...this.config.maskHeaders, ...MASK_HEADER_PATTERNS];\n    return matchPatterns(name, patterns);\n  }\n\n  private shouldMaskBodyField(name: string) {\n    const patterns = [\n      ...this.config.maskBodyFields,\n      ...MASK_BODY_FIELD_PATTERNS,\n    ];\n    return matchPatterns(name, patterns);\n  }\n\n  private hasSupportedContentType(headers: [string, string][]) {\n    const contentType = headers.find(\n      ([k]) => k.toLowerCase() === \"content-type\",\n    )?.[1];\n    return this.isSupportedContentType(contentType);\n  }\n\n  private hasJsonContentType(headers: [string, string][]) {\n    const contentType = headers.find(\n      ([k]) => k.toLowerCase() === \"content-type\",\n    )?.[1];\n    return contentType ? /\\bjson\\b/i.test(contentType) : null;\n  }\n\n  public isSupportedContentType(contentType?: string | null) {\n    return (\n      typeof contentType === \"string\" &&\n      ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n    );\n  }\n\n  private maskQueryParams(search: string) {\n    const params = new URLSearchParams(search);\n    for (const [key] of params) {\n      if (this.shouldMaskQueryParam(key)) {\n        params.set(key, MASKED);\n      }\n    }\n    return params.toString();\n  }\n\n  private maskHeaders(headers: [string, string][]): [string, string][] {\n    return headers.map(([k, v]) => [k, this.shouldMaskHeader(k) ? MASKED : v]);\n  }\n\n  private maskBody(data: any): any {\n    if (typeof data === \"object\" && data !== null && !Array.isArray(data)) {\n      const result: any = {};\n      for (const [key, value] of Object.entries(data)) {\n        if (typeof value === \"string\" && this.shouldMaskBodyField(key)) {\n          result[key] = MASKED;\n        } else {\n          result[key] = this.maskBody(value);\n        }\n      }\n      return result;\n    }\n    if (Array.isArray(data)) {\n      return data.map((item) => this.maskBody(item));\n    }\n    return data;\n  }\n\n  private applyMasking(item: RequestLogItem) {\n    // Apply user-provided maskRequestBodyCallback function\n    if (\n      this.config.maskRequestBodyCallback &&\n      item.request.body &&\n      item.request.body !== BODY_TOO_LARGE\n    ) {\n      try {\n        const maskedBody = this.config.maskRequestBodyCallback(item.request);\n        item.request.body = maskedBody ?? BODY_MASKED;\n      } catch {\n        item.request.body = undefined;\n      }\n    }\n\n    // Apply user-provided maskResponseBodyCallback function\n    if (\n      this.config.maskResponseBodyCallback &&\n      item.response.body &&\n      item.response.body !== BODY_TOO_LARGE\n    ) {\n      try {\n        const maskedBody = this.config.maskResponseBodyCallback(\n          item.request,\n          item.response,\n        );\n        item.response.body = maskedBody ?? BODY_MASKED;\n      } catch {\n        item.response.body = undefined;\n      }\n    }\n\n    // Check request and response body sizes\n    if (item.request.body && item.request.body.length > MAX_BODY_SIZE) {\n      item.request.body = BODY_TOO_LARGE;\n    }\n    if (item.response.body && item.response.body.length > MAX_BODY_SIZE) {\n      item.response.body = BODY_TOO_LARGE;\n    }\n\n    // Mask request and response body fields\n    for (const key of [\"request\", \"response\"] as const) {\n      const bodyData = item[key].body;\n      if (\n        !bodyData ||\n        bodyData === BODY_TOO_LARGE ||\n        bodyData === BODY_MASKED\n      ) {\n        continue;\n      }\n\n      const headers = item[key].headers;\n      const hasJsonContent = this.hasJsonContentType(headers);\n      if (hasJsonContent === null || hasJsonContent) {\n        try {\n          const parsedBody = JSON.parse(bodyData.toString());\n          const maskedBody = this.maskBody(parsedBody);\n          item[key].body = Buffer.from(JSON.stringify(maskedBody));\n        } catch {\n          // If parsing fails, leave body as is\n        }\n      }\n    }\n\n    // Mask request and response headers\n    item.request.headers = this.config.logRequestHeaders\n      ? this.maskHeaders(item.request.headers)\n      : [];\n    item.response.headers = this.config.logResponseHeaders\n      ? this.maskHeaders(item.response.headers)\n      : [];\n\n    // Mask query params\n    const url = new URL(item.request.url);\n    url.search = this.config.logQueryParams\n      ? this.maskQueryParams(url.search)\n      : \"\";\n    item.request.url = url.toString();\n\n    return item;\n  }\n\n  logRequest(\n    request: Request,\n    response: Response,\n    error?: Error,\n    logs?: LogRecord[],\n  ) {\n    if (!this.enabled || this.suspendUntil !== null) return;\n\n    const url = new URL(request.url);\n    const path = request.path ?? url.pathname;\n    const userAgent = request.headers.find(\n      ([k]) => k.toLowerCase() === \"user-agent\",\n    )?.[1];\n\n    if (\n      this.shouldExcludePath(path) ||\n      this.shouldExcludeUserAgent(userAgent) ||\n      (this.config.excludeCallback?.(request, response) ?? false)\n    ) {\n      return;\n    }\n\n    if (\n      !this.config.logRequestBody ||\n      !this.hasSupportedContentType(request.headers)\n    ) {\n      request.body = undefined;\n    }\n    if (\n      !this.config.logResponseBody ||\n      !this.hasSupportedContentType(response.headers)\n    ) {\n      response.body = undefined;\n    }\n\n    if (request.size !== undefined && request.size < 0) {\n      request.size = undefined;\n    }\n    if (response.size !== undefined && response.size < 0) {\n      response.size = undefined;\n    }\n\n    const item: RequestLogItem = {\n      uuid: randomUUID(),\n      request: request,\n      response: response,\n      exception:\n        error && this.config.logException\n          ? {\n              type: error.name,\n              message: truncateExceptionMessage(error.message),\n              stacktrace: truncateExceptionStackTrace(error.stack || \"\"),\n              sentryEventId: getSentryEventId(),\n            }\n          : undefined,\n    };\n\n    if (logs && logs.length > 0) {\n      item.logs = logs.map((log) => ({\n        timestamp: log.timestamp,\n        logger: log.logger,\n        level: log.level,\n        message: truncateLogMessage(log.message),\n      }));\n    }\n    this.pendingWrites.push(item);\n\n    if (this.pendingWrites.length > MAX_PENDING_WRITES) {\n      this.pendingWrites.shift();\n    }\n  }\n\n  async writeToFile() {\n    if (!this.enabled || this.pendingWrites.length === 0) {\n      return;\n    }\n    return this.lock.acquire(\"file\", async () => {\n      if (!this.currentFile) {\n        this.currentFile = new TempGzipFile();\n      }\n      while (this.pendingWrites.length > 0) {\n        let item = this.pendingWrites.shift();\n        if (item) {\n          item = this.applyMasking(item);\n\n          const finalItem = {\n            uuid: item.uuid,\n            request: skipEmptyValues(item.request),\n            response: skipEmptyValues(item.response),\n            exception: item.exception,\n            logs: item.logs,\n          };\n\n          // Set up body serialization for JSON\n          [finalItem.request.body, finalItem.response.body].forEach((body) => {\n            if (body) {\n              // @ts-expect-error Override Buffer's default JSON serialization\n              body.toJSON = function () {\n                return this.toString(\"base64\");\n              };\n            }\n          });\n\n          await this.currentFile.writeLine(\n            Buffer.from(JSON.stringify(finalItem)),\n          );\n        }\n      }\n    });\n  }\n\n  getFile() {\n    return this.files.shift();\n  }\n\n  retryFileLater(file: TempGzipFile) {\n    this.files.unshift(file);\n  }\n\n  async rotateFile() {\n    return this.lock.acquire(\"file\", async () => {\n      if (this.currentFile) {\n        await this.currentFile.close();\n        this.files.push(this.currentFile);\n        this.currentFile = null;\n      }\n    });\n  }\n\n  async maintain() {\n    await this.writeToFile();\n    if (this.currentFile && this.currentFile.size > MAX_FILE_SIZE) {\n      await this.rotateFile();\n    }\n    while (this.files.length > MAX_FILES) {\n      const file = this.files.shift();\n      file?.delete();\n    }\n    if (this.suspendUntil !== null && this.suspendUntil < Date.now()) {\n      this.suspendUntil = null;\n    }\n  }\n\n  async clear() {\n    this.pendingWrites = [];\n    await this.rotateFile();\n    this.files.forEach((file) => {\n      file.delete();\n    });\n    this.files = [];\n  }\n\n  async close() {\n    this.enabled = false;\n    await this.clear();\n    if (this.maintainIntervalId) {\n      clearInterval(this.maintainIntervalId);\n    }\n  }\n}\n\nexport function convertHeaders(\n  headers:\n    | Headers\n    | IncomingHttpHeaders\n    | OutgoingHttpHeaders\n    | Record<string, string | string[] | number | undefined>\n    | undefined,\n) {\n  if (!headers) {\n    return [];\n  }\n  if (headers instanceof Headers) {\n    return Array.from(headers.entries());\n  }\n  return Object.entries(headers).flatMap(([key, value]) => {\n    if (value === undefined) {\n      return [];\n    }\n    if (Array.isArray(value)) {\n      return value.map((v) => [key, v]);\n    }\n    return [[key, value.toString()]];\n  }) as [string, string][];\n}\n\nexport function convertBody(body: any, contentType?: string | null) {\n  if (!body || !contentType) {\n    return;\n  }\n  try {\n    if (contentType.startsWith(\"application/json\")) {\n      if (isValidJsonString(body)) {\n        return Buffer.from(body);\n      } else {\n        return Buffer.from(JSON.stringify(body));\n      }\n    }\n    if (contentType.startsWith(\"text/\") && typeof body === \"string\") {\n      return Buffer.from(body);\n    }\n  } catch (error) {\n    return;\n  }\n}\n\nfunction isValidJsonString(body: any) {\n  if (typeof body !== \"string\") {\n    return false;\n  }\n  try {\n    JSON.parse(body);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nfunction matchPatterns(value: string, patterns: RegExp[]) {\n  return patterns.some((pattern) => {\n    return pattern.test(value);\n  });\n}\n\nfunction skipEmptyValues<T extends Record<string, any>>(data: T) {\n  return Object.fromEntries(\n    Object.entries(data).filter(([_, v]) => {\n      if (v == null || Number.isNaN(v)) return false;\n      if (Array.isArray(v) || Buffer.isBuffer(v) || typeof v === \"string\") {\n        return v.length > 0;\n      }\n      return true;\n    }),\n  ) as Partial<T>;\n}\n\nfunction truncateLogMessage(msg: string) {\n  if (msg.length > MAX_LOG_MSG_LENGTH) {\n    const suffix = \"... (truncated)\";\n    return msg.slice(0, MAX_LOG_MSG_LENGTH - suffix.length) + suffix;\n  }\n  return msg;\n}\n\nfunction checkWritableFs() {\n  try {\n    const testPath = join(tmpdir(), `apitally-${randomUUID()}`);\n    writeFileSync(testPath, \"test\");\n    unlinkSync(testPath);\n    return true;\n  } catch (error) {\n    return false;\n  }\n}\n","import type * as Sentry from \"@sentry/node\";\n\nlet sentry: typeof Sentry | undefined;\n\n// Initialize Sentry when the module is loaded\n(async () => {\n  try {\n    sentry = await import(\"@sentry/node\");\n  } catch (e) {\n    // Sentry SDK is not installed, ignore\n  }\n})();\n\n/**\n * Returns the last Sentry event ID if available\n */\nexport function getSentryEventId(): string | undefined {\n  if (sentry && sentry.lastEventId) {\n    return sentry.lastEventId();\n  }\n  return undefined;\n}\n","import { createHash } from \"node:crypto\";\n\nimport { getSentryEventId } from \"./sentry.js\";\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\n  constructor() {\n    this.errorCounts = new Map();\n    this.errorDetails = new Map();\n    this.sentryEventIds = new Map();\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\n    const sentryEventId = getSentryEventId();\n    if (sentryEventId) {\n      this.sentryEventIds.set(key, sentryEventId);\n    }\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: truncateExceptionMessage(serverError.msg),\n          traceback: truncateExceptionStackTrace(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    this.sentryEventIds.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\nexport function truncateExceptionMessage(msg: string) {\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\nexport function truncateExceptionStackTrace(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","import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport { createWriteStream, readFile, WriteStream } from \"node:fs\";\nimport { unlink } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createGzip, Gzip } from \"node:zlib\";\n\nexport default class TempGzipFile {\n  public uuid: string;\n  private filePath: string;\n  private gzip: Gzip;\n  private writeStream: WriteStream;\n  private readyPromise: Promise<void>;\n  private closedPromise: Promise<void>;\n\n  constructor() {\n    this.uuid = randomUUID();\n    this.filePath = join(tmpdir(), `apitally-${this.uuid}.gz`);\n    this.writeStream = createWriteStream(this.filePath);\n    this.readyPromise = new Promise<void>((resolve, reject) => {\n      this.writeStream.once(\"ready\", resolve);\n      this.writeStream.once(\"error\", reject);\n    });\n    this.closedPromise = new Promise<void>((resolve, reject) => {\n      this.writeStream.once(\"close\", resolve);\n      this.writeStream.once(\"error\", reject);\n    });\n    this.gzip = createGzip();\n    this.gzip.pipe(this.writeStream);\n  }\n\n  get size() {\n    return this.writeStream.bytesWritten;\n  }\n\n  async writeLine(data: Buffer) {\n    await this.readyPromise;\n    return new Promise<void>((resolve, reject) => {\n      this.gzip.write(Buffer.concat([data, Buffer.from(\"\\n\")]), (error) => {\n        if (error) {\n          reject(error);\n        } else {\n          resolve();\n        }\n      });\n    });\n  }\n\n  async getContent() {\n    return new Promise<Buffer>((resolve, reject) => {\n      readFile(this.filePath, (error, data) => {\n        if (error) {\n          reject(error);\n        } else {\n          resolve(data);\n        }\n      });\n    });\n  }\n\n  async close() {\n    await new Promise<void>((resolve) => {\n      this.gzip.end(() => {\n        resolve();\n      });\n    });\n    await this.closedPromise;\n  }\n\n  async delete() {\n    await this.close();\n    await unlink(this.filePath);\n  }\n}\n","import { createHash } from \"node: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(\".\").filter(Boolean),\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.split(\".\").filter(Boolean),\n      validationError.msg.trim(),\n      validationError.type,\n    ].join(\"|\");\n    return createHash(\"md5\").update(hashInput).digest(\"hex\");\n  }\n}\n","import { OutgoingHttpHeader } from \"node:http\";\n\nexport function parseContentLength(\n  contentLength: OutgoingHttpHeader | undefined | null,\n): number | undefined {\n  if (contentLength === undefined || contentLength === null) {\n    return undefined;\n  }\n  if (typeof contentLength === \"number\") {\n    return contentLength;\n  }\n  if (typeof contentLength === \"string\") {\n    const parsed = parseInt(contentLength);\n    return isNaN(parsed) ? undefined : parsed;\n  }\n  if (Array.isArray(contentLength)) {\n    return parseContentLength(contentLength[0]);\n  }\n  return undefined;\n}\n\nexport function mergeHeaders(base: Headers, merge: Headers) {\n  const mergedHeaders = new Headers(base);\n  for (const [name, value] of merge)\n    if (name === \"set-cookie\") mergedHeaders.append(name, value);\n    else mergedHeaders.set(name, value);\n  return mergedHeaders;\n}\n","export async function measureResponseSize(\n  response: Response,\n  tee: boolean = true,\n): Promise<[number, Response]> {\n  const [newResponse1, newResponse2] = tee\n    ? teeResponse(response)\n    : [response, response];\n  let size = 0;\n  if (newResponse2.body) {\n    let done = false;\n    const reader = newResponse2.body.getReader();\n    while (!done) {\n      const result = await reader.read();\n      done = result.done;\n      if (!done && result.value) {\n        size += result.value.byteLength;\n      }\n    }\n  }\n  return [size, newResponse1];\n}\n\nexport async function getResponseBody(\n  response: Response,\n  tee: boolean = true,\n): Promise<[Buffer, Response]> {\n  const [newResponse1, newResponse2] = tee\n    ? teeResponse(response)\n    : [response, response];\n  const responseBuffer = Buffer.from(await newResponse2.arrayBuffer());\n  return [responseBuffer, newResponse1];\n}\n\nexport async function getResponseJson(\n  response: Response,\n): Promise<[any, Response]> {\n  const contentType = response.headers.get(\"content-type\");\n  if (contentType?.includes(\"application/json\")) {\n    const [newResponse1, newResponse2] = teeResponse(response);\n    const responseJson = await newResponse2.json();\n    return [responseJson, newResponse1];\n  }\n  return [null, response];\n}\n\nexport function teeResponse(response: Response): [Response, Response] {\n  if (!response.body) {\n    return [response, response];\n  }\n  const [stream1, stream2] = response.body.tee();\n  const newResponse1 = new Response(stream1, {\n    status: response.status,\n    statusText: response.statusText,\n    headers: response.headers,\n  });\n  const newResponse2 = new Response(stream2, {\n    status: response.status,\n    statusText: response.statusText,\n    headers: response.headers,\n  });\n  return [newResponse1, newResponse2];\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { format } from \"node:util\";\n\nimport type { LogRecord } from \"../common/requestLogger.js\";\n\ntype LogLevel = \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n\nconst MAX_BUFFER_SIZE = 1000;\n\nlet isPatched = false;\nlet globalLogsContext: AsyncLocalStorage<LogRecord[]>;\n\nexport function patchConsole(logsContext: AsyncLocalStorage<LogRecord[]>) {\n  globalLogsContext = logsContext;\n\n  if (isPatched) {\n    return;\n  }\n\n  const logMethods: LogLevel[] = [\"log\", \"warn\", \"error\", \"info\", \"debug\"];\n  logMethods.forEach((method) => {\n    const originalMethod = console[method];\n    console[method] = function (...args: any[]) {\n      captureLog(method, args);\n      return originalMethod.apply(console, args);\n    };\n  });\n\n  isPatched = true;\n}\n\nfunction captureLog(level: LogLevel, args: any[]) {\n  const logs = globalLogsContext?.getStore();\n  if (logs && logs.length < MAX_BUFFER_SIZE) {\n    logs.push({\n      timestamp: Date.now() / 1000,\n      logger: \"console\",\n      level,\n      message: format(...args),\n    });\n  }\n}\n","import { format } from \"node:util\";\n\nexport function formatMessage(message: any, ...args: any[]) {\n  return [message, ...args]\n    .map(formatArg)\n    .filter((arg) => arg !== \"\")\n    .join(\"\\n\");\n}\n\nexport function removeKeys(obj: any, keys: string[]) {\n  return Object.fromEntries(\n    Object.entries(obj).filter(([key]) => !keys.includes(key)),\n  );\n}\n\nfunction formatArg(arg: any) {\n  if (typeof arg === \"string\") {\n    return arg.trim();\n  }\n  if (arg instanceof Error) {\n    return format(arg).trim();\n  }\n  if (arg === undefined || arg === null || isEmptyObject(arg)) {\n    return \"\";\n  }\n  try {\n    return JSON.stringify(arg);\n  } catch {\n    return format(arg).trim();\n  }\n}\n\nfunction isEmptyObject(obj: any) {\n  return (\n    obj !== null &&\n    typeof obj === \"object\" &&\n    Object.getPrototypeOf(obj) === Object.prototype &&\n    Object.keys(obj).length === 0\n  );\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { formatMessage, removeKeys } from \"./utils.js\";\n\nconst MAX_BUFFER_SIZE = 1000;\n\nconst originalStreamSym = Symbol.for(\"apitally.originalStream\");\nconst logLevelMap: Record<number, string> = {\n  10: \"trace\",\n  20: \"debug\",\n  30: \"info\",\n  40: \"warn\",\n  50: \"error\",\n  60: \"fatal\",\n};\n\nexport async function patchPinoLogger(\n  logger: any,\n  logsContext: AsyncLocalStorage<LogRecord[]>,\n) {\n  try {\n    const pino = await import(\"pino\");\n    if (!(pino.default.symbols.streamSym in logger)) {\n      return;\n    }\n    if (!(originalStreamSym in logger)) {\n      logger[originalStreamSym] = logger[pino.default.symbols.streamSym];\n    }\n\n    const originalStream = logger[originalStreamSym];\n    if (originalStream) {\n      const messageKey = logger[pino.default.symbols.messageKeySym];\n      const captureStream = new ApitallyLogCaptureStream(\n        logsContext,\n        messageKey,\n      );\n      logger[pino.default.symbols.streamSym] = pino.default.multistream(\n        [\n          { level: 0, stream: originalStream },\n          { level: 0, stream: captureStream },\n        ],\n        {\n          levels: logger.levels,\n        },\n      );\n    }\n  } catch {\n    // pino is not installed, silently ignore\n  }\n}\n\nfunction filterLogs(obj: any, messageKey: string) {\n  return obj[messageKey] !== \"request completed\";\n}\n\nclass ApitallyLogCaptureStream {\n  private logsContext: AsyncLocalStorage<LogRecord[]>;\n  private messageKey: string;\n\n  constructor(logsContext: AsyncLocalStorage<LogRecord[]>, messageKey: string) {\n    this.logsContext = logsContext;\n    this.messageKey = messageKey;\n  }\n\n  write(msg: string): void {\n    const logs = this.logsContext.getStore();\n    if (!logs || !msg || logs.length >= MAX_BUFFER_SIZE) {\n      return;\n    }\n\n    let obj: any;\n    try {\n      obj = JSON.parse(msg);\n    } catch (e) {\n      return;\n    }\n    if (\n      obj === null ||\n      typeof obj !== \"object\" ||\n      !filterLogs(obj, this.messageKey)\n    ) {\n      return;\n    }\n\n    try {\n      const message = obj[this.messageKey];\n      const rest = removeKeys(obj, [\n        \"hostname\",\n        \"level\",\n        this.messageKey,\n        \"pid\",\n        \"time\",\n        \"reqId\",\n        \"req\",\n        \"res\",\n      ]);\n      const formattedMessage = formatMessage(message, rest);\n      if (formattedMessage) {\n        logs.push({\n          timestamp: this.convertTime(obj.time),\n          level: logLevelMap[obj.level] || \"info\",\n          message: formattedMessage,\n        });\n      }\n    } catch (e) {\n      // ignore\n    }\n  }\n\n  private convertTime(time: any): number {\n    if (typeof time === \"number\" && !isNaN(time)) {\n      return time / 1000; // Convert milliseconds to seconds\n    }\n    return Date.now() / 1000; // Fallback to current time\n  }\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { formatMessage, removeKeys } from \"./utils.js\";\n\nconst MAX_BUFFER_SIZE = 1000;\n\nlet isPatched = false;\nlet globalLogsContext: AsyncLocalStorage<LogRecord[]>;\n\nexport async function patchWinston(\n  logsContext: AsyncLocalStorage<LogRecord[]>,\n) {\n  globalLogsContext = logsContext;\n\n  if (isPatched) {\n    return;\n  }\n\n  try {\n    // @ts-expect-error - file is not typed\n    const loggerModule = await import(\"winston/lib/winston/logger.js\");\n    if (loggerModule.default?.prototype?.write) {\n      const originalWrite = loggerModule.default.prototype.write;\n      loggerModule.default.prototype.write = function (info: any) {\n        captureLog(info);\n        return originalWrite.call(this, info);\n      };\n    }\n  } catch {\n    // winston is not installed, silently ignore\n  }\n\n  isPatched = true;\n}\n\nfunction captureLog(info: any) {\n  const logs = globalLogsContext?.getStore();\n  if (!logs || !info || logs.length >= MAX_BUFFER_SIZE) {\n    return;\n  }\n\n  try {\n    const rest = removeKeys(info, [\"timestamp\", \"level\", \"message\", \"splat\"]);\n    const formattedMessage = formatMessage(info.message, rest);\n    if (formattedMessage) {\n      logs.push({\n        timestamp: parseTimestamp(info.timestamp),\n        level: info.level || \"info\",\n        message: formattedMessage.trim(),\n      });\n    }\n  } catch (e) {\n    // ignore\n  }\n}\n\nfunction parseTimestamp(timestamp: any) {\n  if (timestamp) {\n    const ts = new Date(timestamp).getTime();\n    if (!isNaN(ts)) {\n      return ts / 1000;\n    }\n  }\n  return Date.now() / 1000;\n}\n","import { createRequire } from \"node:module\";\n\nexport function getPackageVersion(name: string): string | null {\n  const packageJsonPath = `${name}/package.json`;\n  try {\n    return require(packageJsonPath).version || null;\n  } catch (error) {\n    try {\n      const _require = createRequire(import.meta.url);\n      return _require(packageJsonPath).version || null;\n    } catch (error) {\n      return null;\n    }\n  }\n}\n","import { H3Core } from \"h3\";\n\nimport { getPackageVersion } from \"../common/packageVersions.js\";\n\nexport function getAppInfo(h3: H3Core, appVersion?: string) {\n  const versions: Array<[string, string]> = [];\n  if (process.versions.node) {\n    versions.push([\"nodejs\", process.versions.node]);\n  }\n  if (process.versions.bun) {\n    versions.push([\"bun\", process.versions.bun]);\n  }\n  const h3Version = getPackageVersion(\"h3\");\n  const apitallyVersion = getPackageVersion(\"../..\");\n  if (h3Version) {\n    versions.push([\"h3\", h3Version]);\n  }\n  if (apitallyVersion) {\n    versions.push([\"apitally\", apitallyVersion]);\n  }\n  if (appVersion) {\n    versions.push([\"app\", appVersion]);\n  }\n\n  return {\n    paths: h3._routes\n      .map((route) => ({\n        method: route.method || \"\",\n        path: route.route || \"\",\n      }))\n      .filter(\n        (route) =>\n          route.method &&\n          route.path &&\n          ![\"HEAD\", \"OPTIONS\"].includes(route.method.toUpperCase()),\n      ),\n    versions: Object.fromEntries(versions),\n    client: \"js:h3\",\n  };\n}\n"],"mappings":"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","names":["import_node_crypto","consumerFromStringOrObject","consumer","_a","String","trim","substring","identifier","name","group","ConsumerRegistry","consumers","updated","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","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","import_node_buffer","import_node_crypto","import_node_fs","import_node_os","import_node_path","sentry","e","getSentryEventId","lastEventId","undefined","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getSentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line","import_node_crypto","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","randomUUID","join","tmpdir","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","error","getContent","readFile","close","end","delete","unlink","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","MAX_LOG_MSG_LENGTH","BODY_TOO_LARGE","Buffer","from","BODY_MASKED","MASKED","ALLOWED_CONTENT_TYPES","EXCLUDE_PATH_PATTERNS","EXCLUDE_USER_AGENT_PATTERNS","MASK_QUERY_PARAM_PATTERNS","MASK_HEADER_PATTERNS","MASK_BODY_FIELD_PATTERNS","DEFAULT_CONFIG","enabled","logQueryParams","logRequestHeaders","logRequestBody","logResponseHeaders","logResponseBody","logException","captureLogs","maskQueryParams","maskHeaders","maskBodyFields","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","lock","AsyncLock","checkWritableFs","setInterval","maintain","maxBodySize","shouldExcludePath","urlPath","patterns","matchPatterns","shouldExcludeUserAgent","userAgent","shouldMaskQueryParam","name","shouldMaskHeader","shouldMaskBodyField","hasSupportedContentType","headers","_a","contentType","find","k","toLowerCase","isSupportedContentType","hasJsonContentType","test","some","t","startsWith","search","params","URLSearchParams","key","set","toString","map","v","maskBody","data","Array","isArray","result","value","Object","entries","item","applyMasking","maskRequestBodyCallback","request","body","maskedBody","undefined","maskResponseBodyCallback","response","length","bodyData","hasJsonContent","parsedBody","JSON","parse","stringify","url","URL","logRequest","error","logs","path","pathname","excludeCallback","size","uuid","randomUUID","exception","type","message","truncateExceptionMessage","stacktrace","truncateExceptionStackTrace","stack","sentryEventId","getSentryEventId","log","timestamp","logger","level","truncateLogMessage","push","shift","writeToFile","acquire","TempGzipFile","finalItem","skipEmptyValues","forEach","toJSON","writeLine","getFile","retryFileLater","file","unshift","rotateFile","close","delete","Date","now","clear","clearInterval","convertHeaders","Headers","flatMap","matchPatterns","value","patterns","some","pattern","test","skipEmptyValues","data","Object","fromEntries","entries","filter","_","v","Number","isNaN","Array","isArray","Buffer","isBuffer","length","truncateLogMessage","msg","MAX_LOG_MSG_LENGTH","suffix","slice","checkWritableFs","testPath","join","tmpdir","randomUUID","writeFileSync","unlinkSync","error","import_node_crypto","ValidationErrorCounter","errorCounts","errorDetails","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","filter","Boolean","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","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","enabled","requestCounter","requestLogger","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","requestLogging","requestLoggingConfig","instance","isValidClientId","isValidEnv","console","warn","randomUUID","RequestCounter","RequestLogger","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","getLogger","startSync","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","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","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","i","length","shift","randomDelay","rotateFile","logFile","getFile","uuid","getContent","has","retryAfter","parseInt","get","suspendUntil","clear","delete","retryFileLater","delay","Math","random","resolve","parseContentLength","contentLength","undefined","parsed","parseInt","isNaN","Array","isArray","mergeHeaders","base","merge","mergedHeaders","Headers","name","value","append","set","measureResponseSize","response","tee","newResponse1","newResponse2","teeResponse","size","body","done","reader","getReader","result","read","value","byteLength","getResponseBody","responseBuffer","Buffer","from","arrayBuffer","teeResponse","response","body","stream1","stream2","tee","newResponse1","Response","status","statusText","headers","newResponse2","MAX_BUFFER_SIZE","isPatched","globalLogsContext","patchConsole","logsContext","logMethods","forEach","method","originalMethod","console","args","captureLog","apply","level","logs","getStore","length","push","timestamp","Date","now","logger","message","format","import_node_util","formatMessage","message","args","map","formatArg","filter","arg","join","removeKeys","obj","keys","Object","fromEntries","entries","key","includes","trim","Error","format","undefined","isEmptyObject","JSON","stringify","getPrototypeOf","prototype","length","originalStreamSym","Symbol","for","MAX_BUFFER_SIZE","isPatched","globalLogsContext","patchWinston","logsContext","_a","loggerModule","default","prototype","write","originalWrite","info","captureLog","call","logs","getStore","length","rest","removeKeys","formattedMessage","formatMessage","message","push","timestamp","parseTimestamp","level","trim","e","ts","Date","getTime","isNaN","now","getPackageVersion","name","packageJsonPath","require","version","error","_require","createRequire","url","getAppInfo","h3","appVersion","versions","process","node","push","bun","h3Version","getPackageVersion","apitallyVersion","paths","_routes","map","route","method","path","filter","includes","toUpperCase","Object","fromEntries","client","REQUEST_TIMESTAMP_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","jsonHeaders","Headers","apitallyPlugin","definePlugin","app","config","client","ApitallyClient","logsContext","AsyncLocalStorage","setStartupData","attempt","appInfo","getAppInfo","appVersion","paths","length","setTimeout","requestLogger","captureLogs","patchConsole","patchWinston","handleResponse","event","response","error","_a","req","method","toUpperCase","startTime","context","responseTime","performance","now","path","matchedRoute","route","statusCode","status","requestSize","parseContentLength","headers","get","responseSize","newResponse","measureResponseSize","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestCounter","addRequest","identifier","data","name","zodError","issues","forEach","issue","validationErrorCounter","addValidationError","loc","join","msg","message","type","code","cause","Error","serverErrorCounter","addServerError","traceback","stack","enabled","responseHeaders","mergeHeaders","responseContentType","responseBody","logResponseBody","isSupportedContentType","getResponseBody","Buffer","from","JSON","stringify","toJSON","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","size","body","undefined","use","onRequest","enterWith","requestContentType","logRequestBody","maxBodySize","clonedRequest","clone","requestBody","arrayBuffer","onResponse","isEnabled","onError","setConsumer","apitallyConsumer","consumerFromStringOrObject"]}