apitally 0.25.6 → 0.25.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/common/client.cjs +12 -12
  2. package/dist/common/client.cjs.map +1 -1
  3. package/dist/common/client.d.cts +6 -6
  4. package/dist/common/client.d.ts +6 -6
  5. package/dist/common/client.js +6 -6
  6. package/dist/common/client.js.map +1 -1
  7. package/dist/common/consumerRegistry.cjs +2 -0
  8. package/dist/common/consumerRegistry.cjs.map +1 -1
  9. package/dist/common/consumerRegistry.d.cts +1 -1
  10. package/dist/common/consumerRegistry.d.ts +1 -1
  11. package/dist/common/consumerRegistry.js +1 -0
  12. package/dist/common/consumerRegistry.js.map +1 -1
  13. package/dist/common/requestCounter.cjs +5 -0
  14. package/dist/common/requestCounter.cjs.map +1 -1
  15. package/dist/common/requestCounter.d.cts +1 -1
  16. package/dist/common/requestCounter.d.ts +1 -1
  17. package/dist/common/requestCounter.js +1 -0
  18. package/dist/common/requestCounter.js.map +1 -1
  19. package/dist/common/requestLogger.cjs +53 -37
  20. package/dist/common/requestLogger.cjs.map +1 -1
  21. package/dist/common/requestLogger.d.cts +3 -2
  22. package/dist/common/requestLogger.d.ts +3 -2
  23. package/dist/common/requestLogger.js +51 -36
  24. package/dist/common/requestLogger.js.map +1 -1
  25. package/dist/common/serverErrorCounter.cjs +2 -0
  26. package/dist/common/serverErrorCounter.cjs.map +1 -1
  27. package/dist/common/serverErrorCounter.d.cts +1 -1
  28. package/dist/common/serverErrorCounter.d.ts +1 -1
  29. package/dist/common/serverErrorCounter.js +1 -0
  30. package/dist/common/serverErrorCounter.js.map +1 -1
  31. package/dist/common/spanCollector.cjs +3 -1
  32. package/dist/common/spanCollector.cjs.map +1 -1
  33. package/dist/common/spanCollector.d.cts +1 -1
  34. package/dist/common/spanCollector.d.ts +1 -1
  35. package/dist/common/spanCollector.js +1 -0
  36. package/dist/common/spanCollector.js.map +1 -1
  37. package/dist/common/tempGzipFile.cjs +11 -5
  38. package/dist/common/tempGzipFile.cjs.map +1 -1
  39. package/dist/common/tempGzipFile.d.cts +2 -2
  40. package/dist/common/tempGzipFile.d.ts +2 -2
  41. package/dist/common/tempGzipFile.js +10 -5
  42. package/dist/common/tempGzipFile.js.map +1 -1
  43. package/dist/common/validationErrorCounter.cjs +5 -0
  44. package/dist/common/validationErrorCounter.cjs.map +1 -1
  45. package/dist/common/validationErrorCounter.d.cts +1 -1
  46. package/dist/common/validationErrorCounter.d.ts +1 -1
  47. package/dist/common/validationErrorCounter.js +1 -0
  48. package/dist/common/validationErrorCounter.js.map +1 -1
  49. package/dist/elysia/index.cjs +2 -12
  50. package/dist/elysia/index.cjs.map +1 -1
  51. package/dist/elysia/index.d.cts +1 -1
  52. package/dist/elysia/index.d.ts +1 -1
  53. package/dist/elysia/index.js +2 -2
  54. package/dist/elysia/index.js.map +1 -1
  55. package/dist/elysia/plugin.cjs +5 -0
  56. package/dist/elysia/plugin.cjs.map +1 -1
  57. package/dist/elysia/plugin.d.cts +1 -1
  58. package/dist/elysia/plugin.d.ts +1 -1
  59. package/dist/elysia/plugin.js +1 -0
  60. package/dist/elysia/plugin.js.map +1 -1
  61. package/dist/fastify/index.cjs +2 -12
  62. package/dist/fastify/index.cjs.map +1 -1
  63. package/dist/fastify/index.d.cts +1 -1
  64. package/dist/fastify/index.d.ts +1 -1
  65. package/dist/fastify/index.js +2 -2
  66. package/dist/fastify/index.js.map +1 -1
  67. package/dist/fastify/plugin.cjs +4 -1
  68. package/dist/fastify/plugin.cjs.map +1 -1
  69. package/dist/fastify/plugin.d.cts +2 -2
  70. package/dist/fastify/plugin.d.ts +2 -2
  71. package/dist/fastify/plugin.js +3 -1
  72. package/dist/fastify/plugin.js.map +1 -1
  73. package/dist/hapi/index.cjs +2 -12
  74. package/dist/hapi/index.cjs.map +1 -1
  75. package/dist/hapi/index.d.cts +1 -1
  76. package/dist/hapi/index.d.ts +1 -1
  77. package/dist/hapi/index.js +2 -2
  78. package/dist/hapi/index.js.map +1 -1
  79. package/dist/hapi/plugin.cjs +2 -0
  80. package/dist/hapi/plugin.cjs.map +1 -1
  81. package/dist/hapi/plugin.d.cts +1 -1
  82. package/dist/hapi/plugin.d.ts +1 -1
  83. package/dist/hapi/plugin.js +1 -0
  84. package/dist/hapi/plugin.js.map +1 -1
  85. package/package.json +9 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/requestLogger.ts"],"sourcesContent":["import AsyncLock from \"async-lock\";\nimport { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport type { IncomingHttpHeaders, OutgoingHttpHeaders } from \"node:http\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport {\n truncateExceptionMessage,\n truncateExceptionStackTrace,\n} from \"./serverErrorCounter.js\";\nimport type { SpanData } from \"./spanCollector.js\";\nimport TempGzipFile, { checkWritableFs } 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/ld+json\",\n \"application/problem+json\",\n \"application/vnd.api+json\",\n \"application/x-ndjson\",\n \"text/plain\",\n \"text/html\",\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 /\\/favicon(?:-[\\w-]+)?\\.(ico|png|svg)$/,\n /\\/apple-touch-icon(?:-[\\w-]+)?\\.png$/,\n /\\/robots\\.txt$/,\n /\\/sitemap\\.xml$/,\n /\\/manifest\\.json$/,\n /\\/site\\.webmanifest$/,\n /\\/service-worker\\.js$/,\n /\\/sw\\.js$/,\n /\\/\\.well-known\\//,\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 captureTraces: 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 captureTraces: 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 spans?: SpanData[];\n traceId?: string;\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 getContentType(headers: [string, string][]) {\n return headers.find(([k]) => k.toLowerCase() === \"content-type\")?.[1];\n }\n\n private hasSupportedContentType(headers: [string, string][]) {\n const contentType = this.getContentType(headers);\n return this.isSupportedContentType(contentType);\n }\n\n public isSupportedContentType(contentType?: string | string[] | null) {\n if (Array.isArray(contentType) && contentType.length > 0) {\n contentType = contentType[0];\n }\n return (\n typeof contentType === \"string\" &&\n ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n );\n }\n\n private static isHttps(headers: [string, string][]): boolean {\n return headers.some(([k, v]) => {\n switch (k.toLowerCase()) {\n case \"x-forwarded-proto\":\n case \"x-forwarded-protocol\":\n case \"x-forwarded-scheme\":\n case \"x-url-scheme\":\n case \"x-scheme\":\n return v.split(\",\")[0].trim().toLowerCase() === \"https\";\n case \"front-end-https\":\n case \"x-forwarded-ssl\":\n return v.toLowerCase() === \"on\";\n case \"forwarded\":\n return v.split(\",\")[0].trim().toLowerCase().includes(\"proto=https\");\n default:\n return false;\n }\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 try {\n const contentType = this.getContentType(item[key].headers);\n if (!contentType || /\\bjson\\b/i.test(contentType)) {\n const parsedBody = JSON.parse(bodyData.toString());\n const maskedBody = this.maskBody(parsedBody);\n item[key].body = Buffer.from(JSON.stringify(maskedBody));\n } else if (/\\bndjson\\b/i.test(contentType)) {\n const lines = bodyData\n .toString()\n .split(\"\\n\")\n .filter((line) => line.trim());\n const maskedLines = lines.map((line) => {\n try {\n const parsed = JSON.parse(line);\n const masked = this.maskBody(parsed);\n return JSON.stringify(masked);\n } catch {\n return line; // Keep unparseable lines as is\n }\n });\n item[key].body = Buffer.from(maskedLines.join(\"\\n\"));\n }\n } catch {\n // If parsing fails, leave body as is\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 spans?: SpanData[],\n traceId?: string,\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 (url.protocol === \"http:\" && RequestLogger.isHttps(request.headers)) {\n url.protocol = \"https:\";\n request.url = url.toString();\n }\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 if (spans && spans.length > 0) {\n item.spans = spans;\n }\n if (traceId) {\n item.traceId = traceId;\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(\"request_logs\");\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 spans: item.spans,\n traceId: item.traceId,\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"],"mappings":"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","names":["AsyncLock","Buffer","randomUUID","getSentryEventId","truncateExceptionMessage","truncateExceptionStackTrace","TempGzipFile","checkWritableFs","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","MAX_LOG_MSG_LENGTH","BODY_TOO_LARGE","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","captureTraces","maskQueryParams","maskHeaders","maskBodyFields","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","lock","setInterval","maintain","maxBodySize","shouldExcludePath","urlPath","patterns","matchPatterns","shouldExcludeUserAgent","userAgent","shouldMaskQueryParam","name","shouldMaskHeader","shouldMaskBodyField","getContentType","headers","find","k","toLowerCase","hasSupportedContentType","contentType","isSupportedContentType","Array","isArray","length","some","t","startsWith","isHttps","v","split","trim","includes","search","params","URLSearchParams","key","set","toString","map","maskBody","data","result","value","Object","entries","item","applyMasking","maskRequestBodyCallback","request","body","maskedBody","undefined","maskResponseBodyCallback","response","bodyData","test","parsedBody","JSON","parse","stringify","lines","filter","line","maskedLines","parsed","masked","join","url","URL","logRequest","error","logs","spans","traceId","path","pathname","protocol","excludeCallback","size","uuid","exception","type","message","stacktrace","stack","sentryEventId","log","timestamp","logger","level","truncateLogMessage","push","shift","writeToFile","acquire","finalItem","skipEmptyValues","forEach","toJSON","writeLine","getFile","retryFileLater","file","unshift","rotateFile","close","delete","Date","now","clear","clearInterval","convertHeaders","Headers","flatMap","convertBody","isValidJsonString","pattern","fromEntries","_","Number","isNaN","isBuffer","msg","suffix","slice"]}
1
+ {"version":3,"sources":["../../src/common/requestLogger.ts"],"sourcesContent":["import AsyncLock from \"async-lock\";\nimport { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport type { IncomingHttpHeaders, OutgoingHttpHeaders } from \"node:http\";\n\nimport { getSentryEventId } from \"./sentry.js\";\nimport {\n truncateExceptionMessage,\n truncateExceptionStackTrace,\n} from \"./serverErrorCounter.js\";\nimport type { SpanData } from \"./spanCollector.js\";\nimport { checkWritableFs, 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/ld+json\",\n \"application/problem+json\",\n \"application/vnd.api+json\",\n \"application/x-ndjson\",\n \"text/plain\",\n \"text/html\",\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 /\\/favicon(?:-[\\w-]+)?\\.(ico|png|svg)$/,\n /\\/apple-touch-icon(?:-[\\w-]+)?\\.png$/,\n /\\/robots\\.txt$/,\n /\\/sitemap\\.xml$/,\n /\\/manifest\\.json$/,\n /\\/site\\.webmanifest$/,\n /\\/service-worker\\.js$/,\n /\\/sw\\.js$/,\n /\\/\\.well-known\\//,\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 captureTraces: 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 captureTraces: 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 spans?: SpanData[];\n traceId?: string;\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 maintainInProgress = false;\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().catch(() => {});\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 getContentType(headers: [string, string][]) {\n return headers.find(([k]) => k.toLowerCase() === \"content-type\")?.[1];\n }\n\n private hasSupportedContentType(headers: [string, string][]) {\n const contentType = this.getContentType(headers);\n return this.isSupportedContentType(contentType);\n }\n\n public isSupportedContentType(contentType?: string | string[] | null) {\n if (Array.isArray(contentType) && contentType.length > 0) {\n contentType = contentType[0];\n }\n return (\n typeof contentType === \"string\" &&\n ALLOWED_CONTENT_TYPES.some((t) => contentType.startsWith(t))\n );\n }\n\n private static isHttps(headers: [string, string][]): boolean {\n return headers.some(([k, v]) => {\n switch (k.toLowerCase()) {\n case \"x-forwarded-proto\":\n case \"x-forwarded-protocol\":\n case \"x-forwarded-scheme\":\n case \"x-url-scheme\":\n case \"x-scheme\":\n return v.split(\",\")[0].trim().toLowerCase() === \"https\";\n case \"front-end-https\":\n case \"x-forwarded-ssl\":\n return v.toLowerCase() === \"on\";\n case \"forwarded\":\n return v.split(\",\")[0].trim().toLowerCase().includes(\"proto=https\");\n default:\n return false;\n }\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 try {\n const contentType = this.getContentType(item[key].headers);\n if (!contentType || /\\bjson\\b/i.test(contentType)) {\n const parsedBody = JSON.parse(bodyData.toString());\n const maskedBody = this.maskBody(parsedBody);\n item[key].body = Buffer.from(JSON.stringify(maskedBody));\n } else if (/\\bndjson\\b/i.test(contentType)) {\n const lines = bodyData\n .toString()\n .split(\"\\n\")\n .filter((line) => line.trim());\n const maskedLines = lines.map((line) => {\n try {\n const parsed = JSON.parse(line);\n const masked = this.maskBody(parsed);\n return JSON.stringify(masked);\n } catch {\n return line; // Keep unparseable lines as is\n }\n });\n item[key].body = Buffer.from(maskedLines.join(\"\\n\"));\n }\n } catch {\n // If parsing fails, leave body as is\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 spans?: SpanData[],\n traceId?: string,\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 (url.protocol === \"http:\" && RequestLogger.isHttps(request.headers)) {\n url.protocol = \"https:\";\n request.url = url.toString();\n }\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 if (spans && spans.length > 0) {\n item.spans = spans;\n }\n if (traceId) {\n item.traceId = traceId;\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 // Snapshot the queue so the drain is bounded by what was pending when\n // the lock was acquired. Items pushed during this drain land in a fresh\n // array and are picked up on the next tick. Without this snapshot,\n // under sustained traffic the while-loop could hold the lock for far\n // longer than the maintain() interval, stacking up subsequent acquires.\n const items = this.pendingWrites;\n this.pendingWrites = [];\n if (items.length === 0) {\n return;\n }\n if (!this.currentFile) {\n this.currentFile = new TempGzipFile(\"request_logs\");\n }\n\n const lines: Buffer[] = [];\n for (let item of items) {\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 spans: item.spans,\n traceId: item.traceId,\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 lines.push(Buffer.from(JSON.stringify(finalItem)));\n }\n\n await this.currentFile.writeLines(lines);\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 // Non-reentrant: if a previous maintain() is still running, drop this\n // tick. Without this, every interval tick that arrives while the\n // current drain is in progress would push another acquire onto the\n // \"file\" lock queue, eventually exceeding async-lock's maxPending.\n if (this.maintainInProgress) {\n return;\n }\n this.maintainInProgress = true;\n try {\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 } finally {\n this.maintainInProgress = false;\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\nexport { RequestLogger };\n"],"mappings":"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","names":["AsyncLock","Buffer","randomUUID","getSentryEventId","truncateExceptionMessage","truncateExceptionStackTrace","checkWritableFs","TempGzipFile","MAX_BODY_SIZE","MAX_FILE_SIZE","MAX_FILES","MAX_PENDING_WRITES","MAX_LOG_MSG_LENGTH","BODY_TOO_LARGE","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","captureTraces","maskQueryParams","maskHeaders","maskBodyFields","excludePaths","RequestLogger","config","suspendUntil","pendingWrites","currentFile","files","maintainIntervalId","maintainInProgress","lock","setInterval","maintain","catch","maxBodySize","shouldExcludePath","urlPath","patterns","matchPatterns","shouldExcludeUserAgent","userAgent","shouldMaskQueryParam","name","shouldMaskHeader","shouldMaskBodyField","getContentType","headers","find","k","toLowerCase","hasSupportedContentType","contentType","isSupportedContentType","Array","isArray","length","some","t","startsWith","isHttps","v","split","trim","includes","search","params","URLSearchParams","key","set","toString","map","maskBody","data","result","value","Object","entries","item","applyMasking","maskRequestBodyCallback","request","body","maskedBody","undefined","maskResponseBodyCallback","response","bodyData","test","parsedBody","JSON","parse","stringify","lines","filter","line","maskedLines","parsed","masked","join","url","URL","logRequest","error","logs","spans","traceId","path","pathname","protocol","excludeCallback","size","uuid","exception","type","message","stacktrace","stack","sentryEventId","log","timestamp","logger","level","truncateLogMessage","push","shift","writeToFile","acquire","items","finalItem","skipEmptyValues","forEach","toJSON","writeLines","getFile","retryFileLater","file","unshift","rotateFile","close","delete","Date","now","clear","clearInterval","convertHeaders","Headers","flatMap","convertBody","isValidJsonString","pattern","fromEntries","_","Number","isNaN","isBuffer","msg","suffix","slice"]}
@@ -19,6 +19,7 @@ var __copyProps = (to, from, except, desc) => {
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
  var serverErrorCounter_exports = {};
21
21
  __export(serverErrorCounter_exports, {
22
+ ServerErrorCounter: () => ServerErrorCounter,
22
23
  default: () => ServerErrorCounter,
23
24
  truncateExceptionMessage: () => truncateExceptionMessage,
24
25
  truncateExceptionStackTrace: () => truncateExceptionStackTrace
@@ -115,6 +116,7 @@ function truncateExceptionStackTrace(stack) {
115
116
  __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
116
117
  // Annotate the CommonJS export names for ESM import in node:
117
118
  0 && (module.exports = {
119
+ ServerErrorCounter,
118
120
  truncateExceptionMessage,
119
121
  truncateExceptionStackTrace
120
122
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/serverErrorCounter.ts"],"sourcesContent":["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 if (stack.length <= MAX_STACKTRACE_LENGTH) {\n return stack;\n }\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"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;;;AAAA,yBAA2B;AAE3B,oBAAiC;AAGjC,MAAMA,iBAAiB;AACvB,MAAMC,wBAAwB;AAE9B,MAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EAER,cAAc;AACZ,SAAKF,cAAc,oBAAIG,IAAAA;AACvB,SAAKF,eAAe,oBAAIE,IAAAA;AACxB,SAAKD,iBAAiB,oBAAIC,IAAAA;EAC5B;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKJ,aAAaO,IAAIF,GAAAA,GAAM;AAC/B,WAAKL,aAAaQ,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKL,YAAYS,IAAIH,MAAM,KAAKN,YAAYU,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAE7D,UAAMK,oBAAgBC,gCAAAA;AACtB,QAAID,eAAe;AACjB,WAAKT,eAAeO,IAAIH,KAAKK,aAAAA;IAC/B;EACF;EAEOE,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKd,YAAYe,QAAQ,CAACC,OAAOV,QAAAA;AAC/B,YAAMD,cAAc,KAAKJ,aAAaS,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfS,aAAKG,KAAK;UACRC,UAAUb,YAAYa,YAAY;UAClCC,QAAQd,YAAYc;UACpBC,MAAMf,YAAYe;UAClBC,MAAMhB,YAAYgB;UAClBC,KAAKC,yBAAyBlB,YAAYiB,GAAG;UAC7CE,WAAWC,4BAA4BpB,YAAYmB,SAAS;UAC5DE,iBAAiB,KAAKxB,eAAeQ,IAAIJ,GAAAA,KAAQ;UACjDqB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKhB,YAAY4B,MAAK;AACtB,SAAK3B,aAAa2B,MAAK;AACvB,SAAK1B,eAAe0B,MAAK;AACzB,WAAOd;EACT;EAEQP,OAAOF,aAA+C;AAC5D,UAAMwB,YAAY;MAChBxB,YAAYa,YAAY;MACxBb,YAAYc,OAAOW,YAAW;MAC9BzB,YAAYe;MACZf,YAAYgB;MACZhB,YAAYiB,IAAIS,KAAI;MACpB1B,YAAYmB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,eAAOC,+BAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;AACF;AA1DqBpC;AAArB,IAAqBA,qBAArB;AA4DO,SAASwB,yBAAyBD,KAAW;AAClD,MAAIA,IAAIc,UAAUvC,gBAAgB;AAChC,WAAOyB;EACT;AACA,QAAMe,SAAS;AACf,QAAMC,SAASzC,iBAAiBwC,OAAOD;AACvC,SAAOd,IAAIiB,UAAU,GAAGD,MAAAA,IAAUD;AACpC;AAPgBd;AAST,SAASE,4BAA4Be,OAAa;AACvD,MAAIA,MAAMJ,UAAUtC,uBAAuB;AACzC,WAAO0C;EACT;AACA,QAAMH,SAAS;AACf,QAAMC,SAASxC,wBAAwBuC,OAAOD;AAC9C,QAAMK,QAAQD,MAAMT,KAAI,EAAGW,MAAM,IAAA;AACjC,QAAMC,iBAA2B,CAAA;AACjC,MAAIP,SAAS;AACb,aAAWQ,QAAQH,OAAO;AACxB,QAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,qBAAe1B,KAAKoB,MAAAA;AACpB;IACF;AACAM,mBAAe1B,KAAK2B,IAAAA;AACpBR,cAAUQ,KAAKR,SAAS;EAC1B;AACA,SAAOO,eAAeX,KAAK,IAAA;AAC7B;AAlBgBP;","names":["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"]}
1
+ {"version":3,"sources":["../../src/common/serverErrorCounter.ts"],"sourcesContent":["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 if (stack.length <= MAX_STACKTRACE_LENGTH) {\n return stack;\n }\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\nexport { ServerErrorCounter };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;AAAA,yBAA2B;AAE3B,oBAAiC;AAGjC,MAAMA,iBAAiB;AACvB,MAAMC,wBAAwB;AAE9B,MAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EAER,cAAc;AACZ,SAAKF,cAAc,oBAAIG,IAAAA;AACvB,SAAKF,eAAe,oBAAIE,IAAAA;AACxB,SAAKD,iBAAiB,oBAAIC,IAAAA;EAC5B;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKJ,aAAaO,IAAIF,GAAAA,GAAM;AAC/B,WAAKL,aAAaQ,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKL,YAAYS,IAAIH,MAAM,KAAKN,YAAYU,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAE7D,UAAMK,oBAAgBC,gCAAAA;AACtB,QAAID,eAAe;AACjB,WAAKT,eAAeO,IAAIH,KAAKK,aAAAA;IAC/B;EACF;EAEOE,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKd,YAAYe,QAAQ,CAACC,OAAOV,QAAAA;AAC/B,YAAMD,cAAc,KAAKJ,aAAaS,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfS,aAAKG,KAAK;UACRC,UAAUb,YAAYa,YAAY;UAClCC,QAAQd,YAAYc;UACpBC,MAAMf,YAAYe;UAClBC,MAAMhB,YAAYgB;UAClBC,KAAKC,yBAAyBlB,YAAYiB,GAAG;UAC7CE,WAAWC,4BAA4BpB,YAAYmB,SAAS;UAC5DE,iBAAiB,KAAKxB,eAAeQ,IAAIJ,GAAAA,KAAQ;UACjDqB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKhB,YAAY4B,MAAK;AACtB,SAAK3B,aAAa2B,MAAK;AACvB,SAAK1B,eAAe0B,MAAK;AACzB,WAAOd;EACT;EAEQP,OAAOF,aAA+C;AAC5D,UAAMwB,YAAY;MAChBxB,YAAYa,YAAY;MACxBb,YAAYc,OAAOW,YAAW;MAC9BzB,YAAYe;MACZf,YAAYgB;MACZhB,YAAYiB,IAAIS,KAAI;MACpB1B,YAAYmB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,eAAOC,+BAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;AACF;AA1DqBpC;AAArB,IAAqBA,qBAArB;AA4DO,SAASwB,yBAAyBD,KAAW;AAClD,MAAIA,IAAIc,UAAUvC,gBAAgB;AAChC,WAAOyB;EACT;AACA,QAAMe,SAAS;AACf,QAAMC,SAASzC,iBAAiBwC,OAAOD;AACvC,SAAOd,IAAIiB,UAAU,GAAGD,MAAAA,IAAUD;AACpC;AAPgBd;AAST,SAASE,4BAA4Be,OAAa;AACvD,MAAIA,MAAMJ,UAAUtC,uBAAuB;AACzC,WAAO0C;EACT;AACA,QAAMH,SAAS;AACf,QAAMC,SAASxC,wBAAwBuC,OAAOD;AAC9C,QAAMK,QAAQD,MAAMT,KAAI,EAAGW,MAAM,IAAA;AACjC,QAAMC,iBAA2B,CAAA;AACjC,MAAIP,SAAS;AACb,aAAWQ,QAAQH,OAAO;AACxB,QAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,qBAAe1B,KAAKoB,MAAAA;AACpB;IACF;AACAM,mBAAe1B,KAAK2B,IAAAA;AACpBR,cAAUQ,KAAKR,SAAS;EAC1B;AACA,SAAOO,eAAeX,KAAK,IAAA;AAC7B;AAlBgBP;","names":["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"]}
@@ -20,4 +20,4 @@ declare class ServerErrorCounter {
20
20
  declare function truncateExceptionMessage(msg: string): string;
21
21
  declare function truncateExceptionStackTrace(stack: string): string;
22
22
 
23
- export { ServerErrorCounter as default, truncateExceptionMessage, truncateExceptionStackTrace };
23
+ export { ServerErrorCounter, ServerErrorCounter as default, truncateExceptionMessage, truncateExceptionStackTrace };
@@ -20,4 +20,4 @@ declare class ServerErrorCounter {
20
20
  declare function truncateExceptionMessage(msg: string): string;
21
21
  declare function truncateExceptionStackTrace(stack: string): string;
22
22
 
23
- export { ServerErrorCounter as default, truncateExceptionMessage, truncateExceptionStackTrace };
23
+ export { ServerErrorCounter, ServerErrorCounter as default, truncateExceptionMessage, truncateExceptionStackTrace };
@@ -90,6 +90,7 @@ function truncateExceptionStackTrace(stack) {
90
90
  }
91
91
  __name(truncateExceptionStackTrace, "truncateExceptionStackTrace");
92
92
  export {
93
+ ServerErrorCounter,
93
94
  ServerErrorCounter as default,
94
95
  truncateExceptionMessage,
95
96
  truncateExceptionStackTrace
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/serverErrorCounter.ts"],"sourcesContent":["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 if (stack.length <= MAX_STACKTRACE_LENGTH) {\n return stack;\n }\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"],"mappings":";;AAAA,SAASA,kBAAkB;AAE3B,SAASC,wBAAwB;AAGjC,MAAMC,iBAAiB;AACvB,MAAMC,wBAAwB;AAE9B,MAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EAER,cAAc;AACZ,SAAKF,cAAc,oBAAIG,IAAAA;AACvB,SAAKF,eAAe,oBAAIE,IAAAA;AACxB,SAAKD,iBAAiB,oBAAIC,IAAAA;EAC5B;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKJ,aAAaO,IAAIF,GAAAA,GAAM;AAC/B,WAAKL,aAAaQ,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKL,YAAYS,IAAIH,MAAM,KAAKN,YAAYU,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAE7D,UAAMK,gBAAgBf,iBAAAA;AACtB,QAAIe,eAAe;AACjB,WAAKT,eAAeO,IAAIH,KAAKK,aAAAA;IAC/B;EACF;EAEOC,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKb,YAAYc,QAAQ,CAACC,OAAOT,QAAAA;AAC/B,YAAMD,cAAc,KAAKJ,aAAaS,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfQ,aAAKG,KAAK;UACRC,UAAUZ,YAAYY,YAAY;UAClCC,QAAQb,YAAYa;UACpBC,MAAMd,YAAYc;UAClBC,MAAMf,YAAYe;UAClBC,KAAKC,yBAAyBjB,YAAYgB,GAAG;UAC7CE,WAAWC,4BAA4BnB,YAAYkB,SAAS;UAC5DE,iBAAiB,KAAKvB,eAAeQ,IAAIJ,GAAAA,KAAQ;UACjDoB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKf,YAAY2B,MAAK;AACtB,SAAK1B,aAAa0B,MAAK;AACvB,SAAKzB,eAAeyB,MAAK;AACzB,WAAOd;EACT;EAEQN,OAAOF,aAA+C;AAC5D,UAAMuB,YAAY;MAChBvB,YAAYY,YAAY;MACxBZ,YAAYa,OAAOW,YAAW;MAC9BxB,YAAYc;MACZd,YAAYe;MACZf,YAAYgB,IAAIS,KAAI;MACpBzB,YAAYkB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,WAAOpC,WAAW,KAAA,EAAOqC,OAAOJ,SAAAA,EAAWK,OAAO,KAAA;EACpD;AACF;AA1DqBlC;AAArB,IAAqBA,qBAArB;AA4DO,SAASuB,yBAAyBD,KAAW;AAClD,MAAIA,IAAIa,UAAUrC,gBAAgB;AAChC,WAAOwB;EACT;AACA,QAAMc,SAAS;AACf,QAAMC,SAASvC,iBAAiBsC,OAAOD;AACvC,SAAOb,IAAIgB,UAAU,GAAGD,MAAAA,IAAUD;AACpC;AAPgBb;AAST,SAASE,4BAA4Bc,OAAa;AACvD,MAAIA,MAAMJ,UAAUpC,uBAAuB;AACzC,WAAOwC;EACT;AACA,QAAMH,SAAS;AACf,QAAMC,SAAStC,wBAAwBqC,OAAOD;AAC9C,QAAMK,QAAQD,MAAMR,KAAI,EAAGU,MAAM,IAAA;AACjC,QAAMC,iBAA2B,CAAA;AACjC,MAAIP,SAAS;AACb,aAAWQ,QAAQH,OAAO;AACxB,QAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,qBAAezB,KAAKmB,MAAAA;AACpB;IACF;AACAM,mBAAezB,KAAK0B,IAAAA;AACpBR,cAAUQ,KAAKR,SAAS;EAC1B;AACA,SAAOO,eAAeV,KAAK,IAAA;AAC7B;AAlBgBP;","names":["createHash","getSentryEventId","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line"]}
1
+ {"version":3,"sources":["../../src/common/serverErrorCounter.ts"],"sourcesContent":["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 if (stack.length <= MAX_STACKTRACE_LENGTH) {\n return stack;\n }\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\nexport { ServerErrorCounter };\n"],"mappings":";;AAAA,SAASA,kBAAkB;AAE3B,SAASC,wBAAwB;AAGjC,MAAMC,iBAAiB;AACvB,MAAMC,wBAAwB;AAE9B,MAAqBC,sBAArB,MAAqBA,oBAAAA;EACXC;EACAC;EACAC;EAER,cAAc;AACZ,SAAKF,cAAc,oBAAIG,IAAAA;AACvB,SAAKF,eAAe,oBAAIE,IAAAA;AACxB,SAAKD,iBAAiB,oBAAIC,IAAAA;EAC5B;EAEOC,eAAeC,aAA+C;AACnE,UAAMC,MAAM,KAAKC,OAAOF,WAAAA;AACxB,QAAI,CAAC,KAAKJ,aAAaO,IAAIF,GAAAA,GAAM;AAC/B,WAAKL,aAAaQ,IAAIH,KAAKD,WAAAA;IAC7B;AACA,SAAKL,YAAYS,IAAIH,MAAM,KAAKN,YAAYU,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;AAE7D,UAAMK,gBAAgBf,iBAAAA;AACtB,QAAIe,eAAe;AACjB,WAAKT,eAAeO,IAAIH,KAAKK,aAAAA;IAC/B;EACF;EAEOC,0BAA0B;AAC/B,UAAMC,OAAgC,CAAA;AACtC,SAAKb,YAAYc,QAAQ,CAACC,OAAOT,QAAAA;AAC/B,YAAMD,cAAc,KAAKJ,aAAaS,IAAIJ,GAAAA;AAC1C,UAAID,aAAa;AACfQ,aAAKG,KAAK;UACRC,UAAUZ,YAAYY,YAAY;UAClCC,QAAQb,YAAYa;UACpBC,MAAMd,YAAYc;UAClBC,MAAMf,YAAYe;UAClBC,KAAKC,yBAAyBjB,YAAYgB,GAAG;UAC7CE,WAAWC,4BAA4BnB,YAAYkB,SAAS;UAC5DE,iBAAiB,KAAKvB,eAAeQ,IAAIJ,GAAAA,KAAQ;UACjDoB,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKf,YAAY2B,MAAK;AACtB,SAAK1B,aAAa0B,MAAK;AACvB,SAAKzB,eAAeyB,MAAK;AACzB,WAAOd;EACT;EAEQN,OAAOF,aAA+C;AAC5D,UAAMuB,YAAY;MAChBvB,YAAYY,YAAY;MACxBZ,YAAYa,OAAOW,YAAW;MAC9BxB,YAAYc;MACZd,YAAYe;MACZf,YAAYgB,IAAIS,KAAI;MACpBzB,YAAYkB,UAAUO,KAAI;MAC1BC,KAAK,GAAA;AACP,WAAOpC,WAAW,KAAA,EAAOqC,OAAOJ,SAAAA,EAAWK,OAAO,KAAA;EACpD;AACF;AA1DqBlC;AAArB,IAAqBA,qBAArB;AA4DO,SAASuB,yBAAyBD,KAAW;AAClD,MAAIA,IAAIa,UAAUrC,gBAAgB;AAChC,WAAOwB;EACT;AACA,QAAMc,SAAS;AACf,QAAMC,SAASvC,iBAAiBsC,OAAOD;AACvC,SAAOb,IAAIgB,UAAU,GAAGD,MAAAA,IAAUD;AACpC;AAPgBb;AAST,SAASE,4BAA4Bc,OAAa;AACvD,MAAIA,MAAMJ,UAAUpC,uBAAuB;AACzC,WAAOwC;EACT;AACA,QAAMH,SAAS;AACf,QAAMC,SAAStC,wBAAwBqC,OAAOD;AAC9C,QAAMK,QAAQD,MAAMR,KAAI,EAAGU,MAAM,IAAA;AACjC,QAAMC,iBAA2B,CAAA;AACjC,MAAIP,SAAS;AACb,aAAWQ,QAAQH,OAAO;AACxB,QAAIL,SAASQ,KAAKR,SAAS,IAAIE,QAAQ;AACrCK,qBAAezB,KAAKmB,MAAAA;AACpB;IACF;AACAM,mBAAezB,KAAK0B,IAAAA;AACpBR,cAAUQ,KAAKR,SAAS;EAC1B;AACA,SAAOO,eAAeV,KAAK,IAAA;AAC7B;AAlBgBP;","names":["createHash","getSentryEventId","MAX_MSG_LENGTH","MAX_STACKTRACE_LENGTH","ServerErrorCounter","errorCounts","errorDetails","sentryEventIds","Map","addServerError","serverError","key","getKey","has","set","get","sentryEventId","getAndResetServerErrors","data","forEach","count","push","consumer","method","path","type","msg","truncateExceptionMessage","traceback","truncateExceptionStackTrace","sentry_event_id","error_count","clear","hashInput","toUpperCase","trim","join","update","digest","length","suffix","cutoff","substring","stack","lines","split","truncatedLines","line"]}
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  var spanCollector_exports = {};
21
21
  __export(spanCollector_exports, {
22
22
  ApitallySpanProcessor: () => ApitallySpanProcessor,
23
+ SpanCollector: () => SpanCollector,
23
24
  default: () => SpanCollector
24
25
  });
25
26
  module.exports = __toCommonJS(spanCollector_exports);
@@ -194,6 +195,7 @@ __name(_ApitallySpanProcessor, "ApitallySpanProcessor");
194
195
  let ApitallySpanProcessor = _ApitallySpanProcessor;
195
196
  // Annotate the CommonJS export names for ESM import in node:
196
197
  0 && (module.exports = {
197
- ApitallySpanProcessor
198
+ ApitallySpanProcessor,
199
+ SpanCollector
198
200
  });
199
201
  //# sourceMappingURL=spanCollector.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport {\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private tracer?: Tracer;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n\n if (enabled) {\n this.tracer = trace.getTracer(\"apitally\");\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n try {\n // Access the global context manager's internal AsyncLocalStorage\n const contextManager = (context as any)._getContextManager?.();\n contextManager?._asyncLocalStorage?.enterWith(ctx);\n } catch {\n // Ignore errors accessing internals\n }\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","tracer","trace","getTracer","setInterval","maintain","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","ctx","setSpan","context","active","ended","set","Set","spanId","Date","now","name","updateName","with","contextManager","_getContextManager","_asyncLocalStorage","enterWith","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","SpanKind","startTime","BigInt","toString","endTime","status","code","SpanStatusCode","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","ApitallyClient","getInstance","spanCollector"]}
1
+ {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport {\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private tracer?: Tracer;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n\n if (enabled) {\n this.tracer = trace.getTracer(\"apitally\");\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n try {\n // Access the global context manager's internal AsyncLocalStorage\n const contextManager = (context as any)._getContextManager?.();\n contextManager?._asyncLocalStorage?.enterWith(ctx);\n } catch {\n // Ignore errors accessing internals\n }\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n\nexport { SpanCollector };\n"],"mappings":"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","names":["TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","tracer","trace","getTracer","setInterval","maintain","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","ctx","setSpan","context","active","ended","set","Set","spanId","Date","now","name","updateName","with","contextManager","_getContextManager","_asyncLocalStorage","enterWith","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","SpanKind","startTime","BigInt","toString","endTime","status","code","SpanStatusCode","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","ApitallyClient","getInstance","spanCollector"]}
@@ -42,4 +42,4 @@ declare class ApitallySpanProcessor implements SpanProcessor {
42
42
  forceFlush(): Promise<void>;
43
43
  }
44
44
 
45
- export { ApitallySpanProcessor, type SpanData, type SpanHandle, SpanCollector as default };
45
+ export { ApitallySpanProcessor, SpanCollector, type SpanData, type SpanHandle, SpanCollector as default };
@@ -42,4 +42,4 @@ declare class ApitallySpanProcessor implements SpanProcessor {
42
42
  forceFlush(): Promise<void>;
43
43
  }
44
44
 
45
- export { ApitallySpanProcessor, type SpanData, type SpanHandle, SpanCollector as default };
45
+ export { ApitallySpanProcessor, SpanCollector, type SpanData, type SpanHandle, SpanCollector as default };
@@ -171,6 +171,7 @@ __name(_ApitallySpanProcessor, "ApitallySpanProcessor");
171
171
  let ApitallySpanProcessor = _ApitallySpanProcessor;
172
172
  export {
173
173
  ApitallySpanProcessor,
174
+ SpanCollector,
174
175
  SpanCollector as default
175
176
  };
176
177
  //# sourceMappingURL=spanCollector.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport {\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private tracer?: Tracer;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n\n if (enabled) {\n this.tracer = trace.getTracer(\"apitally\");\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n try {\n // Access the global context manager's internal AsyncLocalStorage\n const contextManager = (context as any)._getContextManager?.();\n contextManager?._asyncLocalStorage?.enterWith(ctx);\n } catch {\n // Ignore errors accessing internals\n }\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["context","SpanKind","SpanStatusCode","trace","ApitallyClient","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","tracer","getTracer","setInterval","maintain","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","ctx","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","contextManager","_getContextManager","_asyncLocalStorage","enterWith","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","startTime","BigInt","toString","endTime","status","code","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","getInstance","spanCollector"]}
1
+ {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport {\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private tracer?: Tracer;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n\n if (enabled) {\n this.tracer = trace.getTracer(\"apitally\");\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n try {\n // Access the global context manager's internal AsyncLocalStorage\n const contextManager = (context as any)._getContextManager?.();\n contextManager?._asyncLocalStorage?.enterWith(ctx);\n } catch {\n // Ignore errors accessing internals\n }\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n\nexport { SpanCollector };\n"],"mappings":"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","names":["context","SpanKind","SpanStatusCode","trace","ApitallyClient","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","tracer","getTracer","setInterval","maintain","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","ctx","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","contextManager","_getContextManager","_asyncLocalStorage","enterWith","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","startTime","BigInt","toString","endTime","status","code","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","getInstance","spanCollector"]}
@@ -19,6 +19,7 @@ var __copyProps = (to, from, except, desc) => {
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
  var tempGzipFile_exports = {};
21
21
  __export(tempGzipFile_exports, {
22
+ TempGzipFile: () => TempGzipFile,
22
23
  checkWritableFs: () => checkWritableFs,
23
24
  default: () => TempGzipFile
24
25
  });
@@ -73,13 +74,17 @@ const _TempGzipFile = class _TempGzipFile {
73
74
  get size() {
74
75
  return this.writeStream.bytesWritten;
75
76
  }
76
- async writeLine(data) {
77
+ async writeLines(lines) {
78
+ if (lines.length === 0) return;
77
79
  await this.readyPromise;
80
+ const parts = [];
81
+ const newline = import_node_buffer.Buffer.from("\n");
82
+ for (const line of lines) {
83
+ parts.push(line, newline);
84
+ }
85
+ const combined = import_node_buffer.Buffer.concat(parts);
78
86
  return new Promise((resolve, reject) => {
79
- this.gzip.write(import_node_buffer.Buffer.concat([
80
- data,
81
- import_node_buffer.Buffer.from("\n")
82
- ]), (error) => {
87
+ this.gzip.write(combined, (error) => {
83
88
  if (error) {
84
89
  reject(error);
85
90
  } else {
@@ -116,6 +121,7 @@ __name(_TempGzipFile, "TempGzipFile");
116
121
  let TempGzipFile = _TempGzipFile;
117
122
  // Annotate the CommonJS export names for ESM import in node:
118
123
  0 && (module.exports = {
124
+ TempGzipFile,
119
125
  checkWritableFs
120
126
  });
121
127
  //# sourceMappingURL=tempGzipFile.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n createWriteStream,\n mkdirSync,\n readFile,\n unlinkSync,\n writeFileSync,\n WriteStream,\n} 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\nconst TEMP_DIR = join(tmpdir(), \"apitally\");\n\nexport function checkWritableFs() {\n try {\n mkdirSync(TEMP_DIR, { recursive: true });\n const testPath = join(TEMP_DIR, `test_${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\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(name: string) {\n mkdirSync(TEMP_DIR, { recursive: true });\n this.uuid = randomUUID();\n this.filePath = join(TEMP_DIR, `${name}_${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"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;;AAAA,yBAAuB;AACvB,yBAA2B;AAC3B,qBAOO;AACP,sBAAuB;AACvB,qBAAuB;AACvB,uBAAqB;AACrB,uBAAiC;AAEjC,MAAMA,eAAWC,2BAAKC,uBAAAA,GAAU,UAAA;AAEzB,SAASC,kBAAAA;AACd,MAAI;AACFC,kCAAUJ,UAAU;MAAEK,WAAW;IAAK,CAAA;AACtC,UAAMC,eAAWL,uBAAKD,UAAU,YAAQO,+BAAAA,CAAAA,EAAc;AACtDC,sCAAcF,UAAU,MAAA;AACxBG,mCAAWH,QAAAA;AACX,WAAO;EACT,SAASI,OAAO;AACd,WAAO;EACT;AACF;AAVgBP;AAYhB,MAAqBQ,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EACAC;EAER,YAAYC,MAAc;AACxBd,kCAAUJ,UAAU;MAAEK,WAAW;IAAK,CAAA;AACtC,SAAKO,WAAOL,+BAAAA;AACZ,SAAKM,eAAWZ,uBAAKD,UAAU,GAAGkB,IAAAA,IAAQ,KAAKN,IAAI,KAAK;AACxD,SAAKG,kBAAcI,kCAAkB,KAAKN,QAAQ;AAClD,SAAKG,eAAe,IAAII,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKP,YAAYQ,KAAK,SAASF,OAAAA;AAC/B,WAAKN,YAAYQ,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKL,gBAAgB,IAAIG,QAAc,CAACC,SAASC,WAAAA;AAC/C,WAAKP,YAAYQ,KAAK,SAASF,OAAAA;AAC/B,WAAKN,YAAYQ,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKR,WAAOU,6BAAAA;AACZ,SAAKV,KAAKW,KAAK,KAAKV,WAAW;EACjC;EAEA,IAAIW,OAAO;AACT,WAAO,KAAKX,YAAYY;EAC1B;EAEA,MAAMC,UAAUC,MAAc;AAC5B,UAAM,KAAKb;AACX,WAAO,IAAII,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKR,KAAKgB,MAAMC,0BAAOC,OAAO;QAACH;QAAME,0BAAOE,KAAK,IAAA;OAAM,GAAG,CAACvB,UAAAA;AACzD,YAAIA,OAAO;AACTY,iBAAOZ,KAAAA;QACT,OAAO;AACLW,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMa,aAAa;AACjB,WAAO,IAAId,QAAgB,CAACC,SAASC,WAAAA;AACnCa,mCAAS,KAAKtB,UAAU,CAACH,OAAOmB,SAAAA;AAC9B,YAAInB,OAAO;AACTY,iBAAOZ,KAAAA;QACT,OAAO;AACLW,kBAAQQ,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMO,QAAQ;AACZ,UAAM,IAAIhB,QAAc,CAACC,YAAAA;AACvB,WAAKP,KAAKuB,IAAI,MAAA;AACZhB,gBAAAA;MACF,CAAA;IACF,CAAA;AACA,UAAM,KAAKJ;EACb;EAEA,MAAMqB,SAAS;AACb,UAAM,KAAKF,MAAK;AAChB,cAAMG,wBAAO,KAAK1B,QAAQ;EAC5B;AACF;AAnEqBF;AAArB,IAAqBA,eAArB;","names":["TEMP_DIR","join","tmpdir","checkWritableFs","mkdirSync","recursive","testPath","randomUUID","writeFileSync","unlinkSync","error","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","name","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLine","data","write","Buffer","concat","from","getContent","readFile","close","end","delete","unlink"]}
1
+ {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n createWriteStream,\n mkdirSync,\n readFile,\n unlinkSync,\n writeFileSync,\n WriteStream,\n} 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\nconst TEMP_DIR = join(tmpdir(), \"apitally\");\n\nexport function checkWritableFs() {\n try {\n mkdirSync(TEMP_DIR, { recursive: true });\n const testPath = join(TEMP_DIR, `test_${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\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(name: string) {\n mkdirSync(TEMP_DIR, { recursive: true });\n this.uuid = randomUUID();\n this.filePath = join(TEMP_DIR, `${name}_${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 writeLines(lines: Buffer[]) {\n if (lines.length === 0) return;\n await this.readyPromise;\n const parts: Buffer[] = [];\n const newline = Buffer.from(\"\\n\");\n for (const line of lines) {\n parts.push(line, newline);\n }\n const combined = Buffer.concat(parts);\n return new Promise<void>((resolve, reject) => {\n this.gzip.write(combined, (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\nexport { TempGzipFile };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;;;AAAA,yBAAuB;AACvB,yBAA2B;AAC3B,qBAOO;AACP,sBAAuB;AACvB,qBAAuB;AACvB,uBAAqB;AACrB,uBAAiC;AAEjC,MAAMA,eAAWC,2BAAKC,uBAAAA,GAAU,UAAA;AAEzB,SAASC,kBAAAA;AACd,MAAI;AACFC,kCAAUJ,UAAU;MAAEK,WAAW;IAAK,CAAA;AACtC,UAAMC,eAAWL,uBAAKD,UAAU,YAAQO,+BAAAA,CAAAA,EAAc;AACtDC,sCAAcF,UAAU,MAAA;AACxBG,mCAAWH,QAAAA;AACX,WAAO;EACT,SAASI,OAAO;AACd,WAAO;EACT;AACF;AAVgBP;AAYhB,MAAqBQ,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EACAC;EAER,YAAYC,MAAc;AACxBd,kCAAUJ,UAAU;MAAEK,WAAW;IAAK,CAAA;AACtC,SAAKO,WAAOL,+BAAAA;AACZ,SAAKM,eAAWZ,uBAAKD,UAAU,GAAGkB,IAAAA,IAAQ,KAAKN,IAAI,KAAK;AACxD,SAAKG,kBAAcI,kCAAkB,KAAKN,QAAQ;AAClD,SAAKG,eAAe,IAAII,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKP,YAAYQ,KAAK,SAASF,OAAAA;AAC/B,WAAKN,YAAYQ,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKL,gBAAgB,IAAIG,QAAc,CAACC,SAASC,WAAAA;AAC/C,WAAKP,YAAYQ,KAAK,SAASF,OAAAA;AAC/B,WAAKN,YAAYQ,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKR,WAAOU,6BAAAA;AACZ,SAAKV,KAAKW,KAAK,KAAKV,WAAW;EACjC;EAEA,IAAIW,OAAO;AACT,WAAO,KAAKX,YAAYY;EAC1B;EAEA,MAAMC,WAAWC,OAAiB;AAChC,QAAIA,MAAMC,WAAW,EAAG;AACxB,UAAM,KAAKd;AACX,UAAMe,QAAkB,CAAA;AACxB,UAAMC,UAAUC,0BAAOC,KAAK,IAAA;AAC5B,eAAWC,QAAQN,OAAO;AACxBE,YAAMK,KAAKD,MAAMH,OAAAA;IACnB;AACA,UAAMK,WAAWJ,0BAAOK,OAAOP,KAAAA;AAC/B,WAAO,IAAIX,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKR,KAAKyB,MAAMF,UAAU,CAAC3B,UAAAA;AACzB,YAAIA,OAAO;AACTY,iBAAOZ,KAAAA;QACT,OAAO;AACLW,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMmB,aAAa;AACjB,WAAO,IAAIpB,QAAgB,CAACC,SAASC,WAAAA;AACnCmB,mCAAS,KAAK5B,UAAU,CAACH,OAAOgC,SAAAA;AAC9B,YAAIhC,OAAO;AACTY,iBAAOZ,KAAAA;QACT,OAAO;AACLW,kBAAQqB,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMC,QAAQ;AACZ,UAAM,IAAIvB,QAAc,CAACC,YAAAA;AACvB,WAAKP,KAAK8B,IAAI,MAAA;AACZvB,gBAAAA;MACF,CAAA;IACF,CAAA;AACA,UAAM,KAAKJ;EACb;EAEA,MAAM4B,SAAS;AACb,UAAM,KAAKF,MAAK;AAChB,cAAMG,wBAAO,KAAKjC,QAAQ;EAC5B;AACF;AA1EqBF;AAArB,IAAqBA,eAArB;","names":["TEMP_DIR","join","tmpdir","checkWritableFs","mkdirSync","recursive","testPath","randomUUID","writeFileSync","unlinkSync","error","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","name","createWriteStream","Promise","resolve","reject","once","createGzip","pipe","size","bytesWritten","writeLines","lines","length","parts","newline","Buffer","from","line","push","combined","concat","write","getContent","readFile","data","close","end","delete","unlink"]}
@@ -10,10 +10,10 @@ declare class TempGzipFile {
10
10
  private closedPromise;
11
11
  constructor(name: string);
12
12
  get size(): number;
13
- writeLine(data: Buffer): Promise<void>;
13
+ writeLines(lines: Buffer[]): Promise<void>;
14
14
  getContent(): Promise<Buffer<ArrayBufferLike>>;
15
15
  close(): Promise<void>;
16
16
  delete(): Promise<void>;
17
17
  }
18
18
 
19
- export { checkWritableFs, TempGzipFile as default };
19
+ export { TempGzipFile, checkWritableFs, TempGzipFile as default };
@@ -10,10 +10,10 @@ declare class TempGzipFile {
10
10
  private closedPromise;
11
11
  constructor(name: string);
12
12
  get size(): number;
13
- writeLine(data: Buffer): Promise<void>;
13
+ writeLines(lines: Buffer[]): Promise<void>;
14
14
  getContent(): Promise<Buffer<ArrayBufferLike>>;
15
15
  close(): Promise<void>;
16
16
  delete(): Promise<void>;
17
17
  }
18
18
 
19
- export { checkWritableFs, TempGzipFile as default };
19
+ export { TempGzipFile, checkWritableFs, TempGzipFile as default };
@@ -50,13 +50,17 @@ const _TempGzipFile = class _TempGzipFile {
50
50
  get size() {
51
51
  return this.writeStream.bytesWritten;
52
52
  }
53
- async writeLine(data) {
53
+ async writeLines(lines) {
54
+ if (lines.length === 0) return;
54
55
  await this.readyPromise;
56
+ const parts = [];
57
+ const newline = Buffer2.from("\n");
58
+ for (const line of lines) {
59
+ parts.push(line, newline);
60
+ }
61
+ const combined = Buffer2.concat(parts);
55
62
  return new Promise((resolve, reject) => {
56
- this.gzip.write(Buffer2.concat([
57
- data,
58
- Buffer2.from("\n")
59
- ]), (error) => {
63
+ this.gzip.write(combined, (error) => {
60
64
  if (error) {
61
65
  reject(error);
62
66
  } else {
@@ -92,6 +96,7 @@ const _TempGzipFile = class _TempGzipFile {
92
96
  __name(_TempGzipFile, "TempGzipFile");
93
97
  let TempGzipFile = _TempGzipFile;
94
98
  export {
99
+ TempGzipFile,
95
100
  checkWritableFs,
96
101
  TempGzipFile as default
97
102
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n createWriteStream,\n mkdirSync,\n readFile,\n unlinkSync,\n writeFileSync,\n WriteStream,\n} 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\nconst TEMP_DIR = join(tmpdir(), \"apitally\");\n\nexport function checkWritableFs() {\n try {\n mkdirSync(TEMP_DIR, { recursive: true });\n const testPath = join(TEMP_DIR, `test_${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\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(name: string) {\n mkdirSync(TEMP_DIR, { recursive: true });\n this.uuid = randomUUID();\n this.filePath = join(TEMP_DIR, `${name}_${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"],"mappings":";;AAAA,SAASA,UAAAA,eAAc;AACvB,SAASC,kBAAkB;AAC3B,SACEC,mBACAC,WACAC,UACAC,YACAC,qBAEK;AACP,SAASC,cAAc;AACvB,SAASC,cAAc;AACvB,SAASC,YAAY;AACrB,SAASC,kBAAwB;AAEjC,MAAMC,WAAWF,KAAKD,OAAAA,GAAU,UAAA;AAEzB,SAASI,kBAAAA;AACd,MAAI;AACFT,cAAUQ,UAAU;MAAEE,WAAW;IAAK,CAAA;AACtC,UAAMC,WAAWL,KAAKE,UAAU,QAAQV,WAAAA,CAAAA,EAAc;AACtDK,kBAAcQ,UAAU,MAAA;AACxBT,eAAWS,QAAAA;AACX,WAAO;EACT,SAASC,OAAO;AACd,WAAO;EACT;AACF;AAVgBH;AAYhB,MAAqBI,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EACAC;EAER,YAAYC,MAAc;AACxBpB,cAAUQ,UAAU;MAAEE,WAAW;IAAK,CAAA;AACtC,SAAKI,OAAOhB,WAAAA;AACZ,SAAKiB,WAAWT,KAAKE,UAAU,GAAGY,IAAAA,IAAQ,KAAKN,IAAI,KAAK;AACxD,SAAKG,cAAclB,kBAAkB,KAAKgB,QAAQ;AAClD,SAAKG,eAAe,IAAIG,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKN,YAAYO,KAAK,SAASF,OAAAA;AAC/B,WAAKL,YAAYO,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKJ,gBAAgB,IAAIE,QAAc,CAACC,SAASC,WAAAA;AAC/C,WAAKN,YAAYO,KAAK,SAASF,OAAAA;AAC/B,WAAKL,YAAYO,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKP,OAAOT,WAAAA;AACZ,SAAKS,KAAKS,KAAK,KAAKR,WAAW;EACjC;EAEA,IAAIS,OAAO;AACT,WAAO,KAAKT,YAAYU;EAC1B;EAEA,MAAMC,UAAUC,MAAc;AAC5B,UAAM,KAAKX;AACX,WAAO,IAAIG,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKP,KAAKc,MAAMjC,QAAOkC,OAAO;QAACF;QAAMhC,QAAOmC,KAAK,IAAA;OAAM,GAAG,CAACpB,UAAAA;AACzD,YAAIA,OAAO;AACTW,iBAAOX,KAAAA;QACT,OAAO;AACLU,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMW,aAAa;AACjB,WAAO,IAAIZ,QAAgB,CAACC,SAASC,WAAAA;AACnCtB,eAAS,KAAKc,UAAU,CAACH,OAAOiB,SAAAA;AAC9B,YAAIjB,OAAO;AACTW,iBAAOX,KAAAA;QACT,OAAO;AACLU,kBAAQO,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMK,QAAQ;AACZ,UAAM,IAAIb,QAAc,CAACC,YAAAA;AACvB,WAAKN,KAAKmB,IAAI,MAAA;AACZb,gBAAAA;MACF,CAAA;IACF,CAAA;AACA,UAAM,KAAKH;EACb;EAEA,MAAMiB,SAAS;AACb,UAAM,KAAKF,MAAK;AAChB,UAAM9B,OAAO,KAAKW,QAAQ;EAC5B;AACF;AAnEqBF;AAArB,IAAqBA,eAArB;","names":["Buffer","randomUUID","createWriteStream","mkdirSync","readFile","unlinkSync","writeFileSync","unlink","tmpdir","join","createGzip","TEMP_DIR","checkWritableFs","recursive","testPath","error","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","name","Promise","resolve","reject","once","pipe","size","bytesWritten","writeLine","data","write","concat","from","getContent","close","end","delete"]}
1
+ {"version":3,"sources":["../../src/common/tempGzipFile.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n createWriteStream,\n mkdirSync,\n readFile,\n unlinkSync,\n writeFileSync,\n WriteStream,\n} 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\nconst TEMP_DIR = join(tmpdir(), \"apitally\");\n\nexport function checkWritableFs() {\n try {\n mkdirSync(TEMP_DIR, { recursive: true });\n const testPath = join(TEMP_DIR, `test_${randomUUID()}`);\n writeFileSync(testPath, \"test\");\n unlinkSync(testPath);\n return true;\n } catch (error) {\n return false;\n }\n}\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(name: string) {\n mkdirSync(TEMP_DIR, { recursive: true });\n this.uuid = randomUUID();\n this.filePath = join(TEMP_DIR, `${name}_${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 writeLines(lines: Buffer[]) {\n if (lines.length === 0) return;\n await this.readyPromise;\n const parts: Buffer[] = [];\n const newline = Buffer.from(\"\\n\");\n for (const line of lines) {\n parts.push(line, newline);\n }\n const combined = Buffer.concat(parts);\n return new Promise<void>((resolve, reject) => {\n this.gzip.write(combined, (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\nexport { TempGzipFile };\n"],"mappings":";;AAAA,SAASA,UAAAA,eAAc;AACvB,SAASC,kBAAkB;AAC3B,SACEC,mBACAC,WACAC,UACAC,YACAC,qBAEK;AACP,SAASC,cAAc;AACvB,SAASC,cAAc;AACvB,SAASC,YAAY;AACrB,SAASC,kBAAwB;AAEjC,MAAMC,WAAWF,KAAKD,OAAAA,GAAU,UAAA;AAEzB,SAASI,kBAAAA;AACd,MAAI;AACFT,cAAUQ,UAAU;MAAEE,WAAW;IAAK,CAAA;AACtC,UAAMC,WAAWL,KAAKE,UAAU,QAAQV,WAAAA,CAAAA,EAAc;AACtDK,kBAAcQ,UAAU,MAAA;AACxBT,eAAWS,QAAAA;AACX,WAAO;EACT,SAASC,OAAO;AACd,WAAO;EACT;AACF;AAVgBH;AAYhB,MAAqBI,gBAArB,MAAqBA,cAAAA;EACZC;EACCC;EACAC;EACAC;EACAC;EACAC;EAER,YAAYC,MAAc;AACxBpB,cAAUQ,UAAU;MAAEE,WAAW;IAAK,CAAA;AACtC,SAAKI,OAAOhB,WAAAA;AACZ,SAAKiB,WAAWT,KAAKE,UAAU,GAAGY,IAAAA,IAAQ,KAAKN,IAAI,KAAK;AACxD,SAAKG,cAAclB,kBAAkB,KAAKgB,QAAQ;AAClD,SAAKG,eAAe,IAAIG,QAAc,CAACC,SAASC,WAAAA;AAC9C,WAAKN,YAAYO,KAAK,SAASF,OAAAA;AAC/B,WAAKL,YAAYO,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKJ,gBAAgB,IAAIE,QAAc,CAACC,SAASC,WAAAA;AAC/C,WAAKN,YAAYO,KAAK,SAASF,OAAAA;AAC/B,WAAKL,YAAYO,KAAK,SAASD,MAAAA;IACjC,CAAA;AACA,SAAKP,OAAOT,WAAAA;AACZ,SAAKS,KAAKS,KAAK,KAAKR,WAAW;EACjC;EAEA,IAAIS,OAAO;AACT,WAAO,KAAKT,YAAYU;EAC1B;EAEA,MAAMC,WAAWC,OAAiB;AAChC,QAAIA,MAAMC,WAAW,EAAG;AACxB,UAAM,KAAKZ;AACX,UAAMa,QAAkB,CAAA;AACxB,UAAMC,UAAUnC,QAAOoC,KAAK,IAAA;AAC5B,eAAWC,QAAQL,OAAO;AACxBE,YAAMI,KAAKD,MAAMF,OAAAA;IACnB;AACA,UAAMI,WAAWvC,QAAOwC,OAAON,KAAAA;AAC/B,WAAO,IAAIV,QAAc,CAACC,SAASC,WAAAA;AACjC,WAAKP,KAAKsB,MAAMF,UAAU,CAACxB,UAAAA;AACzB,YAAIA,OAAO;AACTW,iBAAOX,KAAAA;QACT,OAAO;AACLU,kBAAAA;QACF;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMiB,aAAa;AACjB,WAAO,IAAIlB,QAAgB,CAACC,SAASC,WAAAA;AACnCtB,eAAS,KAAKc,UAAU,CAACH,OAAO4B,SAAAA;AAC9B,YAAI5B,OAAO;AACTW,iBAAOX,KAAAA;QACT,OAAO;AACLU,kBAAQkB,IAAAA;QACV;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMC,QAAQ;AACZ,UAAM,IAAIpB,QAAc,CAACC,YAAAA;AACvB,WAAKN,KAAK0B,IAAI,MAAA;AACZpB,gBAAAA;MACF,CAAA;IACF,CAAA;AACA,UAAM,KAAKH;EACb;EAEA,MAAMwB,SAAS;AACb,UAAM,KAAKF,MAAK;AAChB,UAAMrC,OAAO,KAAKW,QAAQ;EAC5B;AACF;AA1EqBF;AAArB,IAAqBA,eAArB;","names":["Buffer","randomUUID","createWriteStream","mkdirSync","readFile","unlinkSync","writeFileSync","unlink","tmpdir","join","createGzip","TEMP_DIR","checkWritableFs","recursive","testPath","error","TempGzipFile","uuid","filePath","gzip","writeStream","readyPromise","closedPromise","name","Promise","resolve","reject","once","pipe","size","bytesWritten","writeLines","lines","length","parts","newline","from","line","push","combined","concat","write","getContent","data","close","end","delete"]}
@@ -19,6 +19,7 @@ var __copyProps = (to, from, except, desc) => {
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
  var validationErrorCounter_exports = {};
21
21
  __export(validationErrorCounter_exports, {
22
+ ValidationErrorCounter: () => ValidationErrorCounter,
22
23
  default: () => ValidationErrorCounter
23
24
  });
24
25
  module.exports = __toCommonJS(validationErrorCounter_exports);
@@ -71,4 +72,8 @@ const _ValidationErrorCounter = class _ValidationErrorCounter {
71
72
  };
72
73
  __name(_ValidationErrorCounter, "ValidationErrorCounter");
73
74
  let ValidationErrorCounter = _ValidationErrorCounter;
75
+ // Annotate the CommonJS export names for ESM import in node:
76
+ 0 && (module.exports = {
77
+ ValidationErrorCounter
78
+ });
74
79
  //# sourceMappingURL=validationErrorCounter.cjs.map