apitally 0.25.7 → 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.
- package/dist/common/client.cjs +12 -12
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.d.cts +6 -6
- package/dist/common/client.d.ts +6 -6
- package/dist/common/client.js +6 -6
- package/dist/common/client.js.map +1 -1
- package/dist/common/consumerRegistry.cjs +2 -0
- package/dist/common/consumerRegistry.cjs.map +1 -1
- package/dist/common/consumerRegistry.d.cts +1 -1
- package/dist/common/consumerRegistry.d.ts +1 -1
- package/dist/common/consumerRegistry.js +1 -0
- package/dist/common/consumerRegistry.js.map +1 -1
- package/dist/common/requestCounter.cjs +5 -0
- package/dist/common/requestCounter.cjs.map +1 -1
- package/dist/common/requestCounter.d.cts +1 -1
- package/dist/common/requestCounter.d.ts +1 -1
- package/dist/common/requestCounter.js +1 -0
- package/dist/common/requestCounter.js.map +1 -1
- package/dist/common/requestLogger.cjs +4 -2
- package/dist/common/requestLogger.cjs.map +1 -1
- package/dist/common/requestLogger.d.cts +2 -2
- package/dist/common/requestLogger.d.ts +2 -2
- package/dist/common/requestLogger.js +2 -1
- package/dist/common/requestLogger.js.map +1 -1
- package/dist/common/serverErrorCounter.cjs +2 -0
- package/dist/common/serverErrorCounter.cjs.map +1 -1
- package/dist/common/serverErrorCounter.d.cts +1 -1
- package/dist/common/serverErrorCounter.d.ts +1 -1
- package/dist/common/serverErrorCounter.js +1 -0
- package/dist/common/serverErrorCounter.js.map +1 -1
- package/dist/common/spanCollector.cjs +3 -1
- package/dist/common/spanCollector.cjs.map +1 -1
- package/dist/common/spanCollector.d.cts +1 -1
- package/dist/common/spanCollector.d.ts +1 -1
- package/dist/common/spanCollector.js +1 -0
- package/dist/common/spanCollector.js.map +1 -1
- package/dist/common/tempGzipFile.cjs +2 -0
- package/dist/common/tempGzipFile.cjs.map +1 -1
- package/dist/common/tempGzipFile.d.cts +1 -1
- package/dist/common/tempGzipFile.d.ts +1 -1
- package/dist/common/tempGzipFile.js +1 -0
- package/dist/common/tempGzipFile.js.map +1 -1
- package/dist/common/validationErrorCounter.cjs +5 -0
- package/dist/common/validationErrorCounter.cjs.map +1 -1
- package/dist/common/validationErrorCounter.d.cts +1 -1
- package/dist/common/validationErrorCounter.d.ts +1 -1
- package/dist/common/validationErrorCounter.js +1 -0
- package/dist/common/validationErrorCounter.js.map +1 -1
- package/dist/elysia/index.cjs +2 -12
- package/dist/elysia/index.cjs.map +1 -1
- package/dist/elysia/index.d.cts +1 -1
- package/dist/elysia/index.d.ts +1 -1
- package/dist/elysia/index.js +2 -2
- package/dist/elysia/index.js.map +1 -1
- package/dist/elysia/plugin.cjs +5 -0
- package/dist/elysia/plugin.cjs.map +1 -1
- package/dist/elysia/plugin.d.cts +1 -1
- package/dist/elysia/plugin.d.ts +1 -1
- package/dist/elysia/plugin.js +1 -0
- package/dist/elysia/plugin.js.map +1 -1
- package/dist/fastify/index.cjs +2 -12
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +1 -1
- package/dist/fastify/index.d.ts +1 -1
- package/dist/fastify/index.js +2 -2
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.cjs +4 -1
- package/dist/fastify/plugin.cjs.map +1 -1
- package/dist/fastify/plugin.d.cts +2 -2
- package/dist/fastify/plugin.d.ts +2 -2
- package/dist/fastify/plugin.js +3 -1
- package/dist/fastify/plugin.js.map +1 -1
- package/dist/hapi/index.cjs +2 -12
- package/dist/hapi/index.cjs.map +1 -1
- package/dist/hapi/index.d.cts +1 -1
- package/dist/hapi/index.d.ts +1 -1
- package/dist/hapi/index.js +2 -2
- package/dist/hapi/index.js.map +1 -1
- package/dist/hapi/plugin.cjs +2 -0
- package/dist/hapi/plugin.cjs.map +1 -1
- package/dist/hapi/plugin.d.cts +1 -1
- package/dist/hapi/plugin.d.ts +1 -1
- package/dist/hapi/plugin.js +1 -0
- package/dist/hapi/plugin.js.map +1 -1
- package/package.json +3 -3
|
@@ -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
|
});
|
|
@@ -120,6 +121,7 @@ __name(_TempGzipFile, "TempGzipFile");
|
|
|
120
121
|
let TempGzipFile = _TempGzipFile;
|
|
121
122
|
// Annotate the CommonJS export names for ESM import in node:
|
|
122
123
|
0 && (module.exports = {
|
|
124
|
+
TempGzipFile,
|
|
123
125
|
checkWritableFs
|
|
124
126
|
});
|
|
125
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 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"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA
|
|
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"]}
|
|
@@ -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 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"],"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"]}
|
|
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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/validationErrorCounter.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\").filter(Boolean),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc.split(\".\").filter(Boolean),\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA
|
|
1
|
+
{"version":3,"sources":["../../src/common/validationErrorCounter.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\").filter(Boolean),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc.split(\".\").filter(Boolean),\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n\nexport { ValidationErrorCounter };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;;AAAA,yBAA2B;AAQ3B,MAAqBA,0BAArB,MAAqBA,wBAAAA;EACXC;EACAC;EAER,cAAc;AACZ,SAAKD,cAAc,oBAAIE,IAAAA;AACvB,SAAKD,eAAe,oBAAIC,IAAAA;EAC1B;EAEOC,mBACLC,iBACA;AACA,UAAMC,MAAM,KAAKC,OAAOF,eAAAA;AACxB,QAAI,CAAC,KAAKH,aAAaM,IAAIF,GAAAA,GAAM;AAC/B,WAAKJ,aAAaO,IAAIH,KAAKD,eAAAA;IAC7B;AACA,SAAKJ,YAAYQ,IAAIH,MAAM,KAAKL,YAAYS,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;EAC/D;EAEOK,8BAA8B;AACnC,UAAMC,OAAoC,CAAA;AAC1C,SAAKX,YAAYY,QAAQ,CAACC,OAAOR,QAAAA;AAC/B,YAAMD,kBAAkB,KAAKH,aAAaQ,IAAIJ,GAAAA;AAC9C,UAAID,iBAAiB;AACnBO,aAAKG,KAAK;UACRC,UAAUX,gBAAgBW,YAAY;UACtCC,QAAQZ,gBAAgBY;UACxBC,MAAMb,gBAAgBa;UACtBC,KAAKd,gBAAgBc,IAAIC,MAAM,GAAA,EAAKC,OAAOC,OAAAA;UAC3CC,KAAKlB,gBAAgBkB;UACrBC,MAAMnB,gBAAgBmB;UACtBC,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKb,YAAYyB,MAAK;AACtB,SAAKxB,aAAawB,MAAK;AACvB,WAAOd;EACT;EAEQL,OAAOF,iBAAuD;AACpE,UAAMsB,YAAY;MAChBtB,gBAAgBW,YAAY;MAC5BX,gBAAgBY,OAAOW,YAAW;MAClCvB,gBAAgBa;MAChBb,gBAAgBc,IAAIC,MAAM,GAAA,EAAKC,OAAOC,OAAAA;MACtCjB,gBAAgBkB,IAAIM,KAAI;MACxBxB,gBAAgBmB;MAChBM,KAAK,GAAA;AACP,eAAOC,+BAAW,KAAA,EAAOC,OAAOL,SAAAA,EAAWM,OAAO,KAAA;EACpD;AACF;AAnDqBjC;AAArB,IAAqBA,yBAArB;","names":["ValidationErrorCounter","errorCounts","errorDetails","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","filter","Boolean","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","createHash","update","digest"]}
|
|
@@ -50,6 +50,7 @@ const _ValidationErrorCounter = class _ValidationErrorCounter {
|
|
|
50
50
|
__name(_ValidationErrorCounter, "ValidationErrorCounter");
|
|
51
51
|
let ValidationErrorCounter = _ValidationErrorCounter;
|
|
52
52
|
export {
|
|
53
|
+
ValidationErrorCounter,
|
|
53
54
|
ValidationErrorCounter as default
|
|
54
55
|
};
|
|
55
56
|
//# sourceMappingURL=validationErrorCounter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/validationErrorCounter.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\").filter(Boolean),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc.split(\".\").filter(Boolean),\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n"],"mappings":";;AAAA,SAASA,kBAAkB;AAQ3B,MAAqBC,0BAArB,MAAqBA,wBAAAA;EACXC;EACAC;EAER,cAAc;AACZ,SAAKD,cAAc,oBAAIE,IAAAA;AACvB,SAAKD,eAAe,oBAAIC,IAAAA;EAC1B;EAEOC,mBACLC,iBACA;AACA,UAAMC,MAAM,KAAKC,OAAOF,eAAAA;AACxB,QAAI,CAAC,KAAKH,aAAaM,IAAIF,GAAAA,GAAM;AAC/B,WAAKJ,aAAaO,IAAIH,KAAKD,eAAAA;IAC7B;AACA,SAAKJ,YAAYQ,IAAIH,MAAM,KAAKL,YAAYS,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;EAC/D;EAEOK,8BAA8B;AACnC,UAAMC,OAAoC,CAAA;AAC1C,SAAKX,YAAYY,QAAQ,CAACC,OAAOR,QAAAA;AAC/B,YAAMD,kBAAkB,KAAKH,aAAaQ,IAAIJ,GAAAA;AAC9C,UAAID,iBAAiB;AACnBO,aAAKG,KAAK;UACRC,UAAUX,gBAAgBW,YAAY;UACtCC,QAAQZ,gBAAgBY;UACxBC,MAAMb,gBAAgBa;UACtBC,KAAKd,gBAAgBc,IAAIC,MAAM,GAAA,EAAKC,OAAOC,OAAAA;UAC3CC,KAAKlB,gBAAgBkB;UACrBC,MAAMnB,gBAAgBmB;UACtBC,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKb,YAAYyB,MAAK;AACtB,SAAKxB,aAAawB,MAAK;AACvB,WAAOd;EACT;EAEQL,OAAOF,iBAAuD;AACpE,UAAMsB,YAAY;MAChBtB,gBAAgBW,YAAY;MAC5BX,gBAAgBY,OAAOW,YAAW;MAClCvB,gBAAgBa;MAChBb,gBAAgBc,IAAIC,MAAM,GAAA,EAAKC,OAAOC,OAAAA;MACtCjB,gBAAgBkB,IAAIM,KAAI;MACxBxB,gBAAgBmB;MAChBM,KAAK,GAAA;AACP,WAAO/B,WAAW,KAAA,EAAOgC,OAAOJ,SAAAA,EAAWK,OAAO,KAAA;EACpD;AACF;AAnDqBhC;AAArB,IAAqBA,yBAArB;","names":["createHash","ValidationErrorCounter","errorCounts","errorDetails","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","filter","Boolean","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","update","digest"]}
|
|
1
|
+
{"version":3,"sources":["../../src/common/validationErrorCounter.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport {\n ConsumerMethodPath,\n ValidationError,\n ValidationErrorsItem,\n} from \"./types.js\";\n\nexport default class ValidationErrorCounter {\n private errorCounts: Map<string, number>;\n private errorDetails: Map<string, ConsumerMethodPath & ValidationError>;\n\n constructor() {\n this.errorCounts = new Map();\n this.errorDetails = new Map();\n }\n\n public addValidationError(\n validationError: ConsumerMethodPath & ValidationError,\n ) {\n const key = this.getKey(validationError);\n if (!this.errorDetails.has(key)) {\n this.errorDetails.set(key, validationError);\n }\n this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);\n }\n\n public getAndResetValidationErrors() {\n const data: Array<ValidationErrorsItem> = [];\n this.errorCounts.forEach((count, key) => {\n const validationError = this.errorDetails.get(key);\n if (validationError) {\n data.push({\n consumer: validationError.consumer || null,\n method: validationError.method,\n path: validationError.path,\n loc: validationError.loc.split(\".\").filter(Boolean),\n msg: validationError.msg,\n type: validationError.type,\n error_count: count,\n });\n }\n });\n this.errorCounts.clear();\n this.errorDetails.clear();\n return data;\n }\n\n private getKey(validationError: ConsumerMethodPath & ValidationError) {\n const hashInput = [\n validationError.consumer || \"\",\n validationError.method.toUpperCase(),\n validationError.path,\n validationError.loc.split(\".\").filter(Boolean),\n validationError.msg.trim(),\n validationError.type,\n ].join(\"|\");\n return createHash(\"md5\").update(hashInput).digest(\"hex\");\n }\n}\n\nexport { ValidationErrorCounter };\n"],"mappings":";;AAAA,SAASA,kBAAkB;AAQ3B,MAAqBC,0BAArB,MAAqBA,wBAAAA;EACXC;EACAC;EAER,cAAc;AACZ,SAAKD,cAAc,oBAAIE,IAAAA;AACvB,SAAKD,eAAe,oBAAIC,IAAAA;EAC1B;EAEOC,mBACLC,iBACA;AACA,UAAMC,MAAM,KAAKC,OAAOF,eAAAA;AACxB,QAAI,CAAC,KAAKH,aAAaM,IAAIF,GAAAA,GAAM;AAC/B,WAAKJ,aAAaO,IAAIH,KAAKD,eAAAA;IAC7B;AACA,SAAKJ,YAAYQ,IAAIH,MAAM,KAAKL,YAAYS,IAAIJ,GAAAA,KAAQ,KAAK,CAAA;EAC/D;EAEOK,8BAA8B;AACnC,UAAMC,OAAoC,CAAA;AAC1C,SAAKX,YAAYY,QAAQ,CAACC,OAAOR,QAAAA;AAC/B,YAAMD,kBAAkB,KAAKH,aAAaQ,IAAIJ,GAAAA;AAC9C,UAAID,iBAAiB;AACnBO,aAAKG,KAAK;UACRC,UAAUX,gBAAgBW,YAAY;UACtCC,QAAQZ,gBAAgBY;UACxBC,MAAMb,gBAAgBa;UACtBC,KAAKd,gBAAgBc,IAAIC,MAAM,GAAA,EAAKC,OAAOC,OAAAA;UAC3CC,KAAKlB,gBAAgBkB;UACrBC,MAAMnB,gBAAgBmB;UACtBC,aAAaX;QACf,CAAA;MACF;IACF,CAAA;AACA,SAAKb,YAAYyB,MAAK;AACtB,SAAKxB,aAAawB,MAAK;AACvB,WAAOd;EACT;EAEQL,OAAOF,iBAAuD;AACpE,UAAMsB,YAAY;MAChBtB,gBAAgBW,YAAY;MAC5BX,gBAAgBY,OAAOW,YAAW;MAClCvB,gBAAgBa;MAChBb,gBAAgBc,IAAIC,MAAM,GAAA,EAAKC,OAAOC,OAAAA;MACtCjB,gBAAgBkB,IAAIM,KAAI;MACxBxB,gBAAgBmB;MAChBM,KAAK,GAAA;AACP,WAAO/B,WAAW,KAAA,EAAOgC,OAAOJ,SAAAA,EAAWK,OAAO,KAAA;EACpD;AACF;AAnDqBhC;AAArB,IAAqBA,yBAArB;","names":["createHash","ValidationErrorCounter","errorCounts","errorDetails","Map","addValidationError","validationError","key","getKey","has","set","get","getAndResetValidationErrors","data","forEach","count","push","consumer","method","path","loc","split","filter","Boolean","msg","type","error_count","clear","hashInput","toUpperCase","trim","join","update","digest"]}
|
package/dist/elysia/index.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,21 +15,13 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
var elysia_exports = {};
|
|
30
20
|
__export(elysia_exports, {
|
|
31
|
-
apitallyPlugin: () => import_plugin.
|
|
21
|
+
apitallyPlugin: () => import_plugin.apitallyPlugin
|
|
32
22
|
});
|
|
33
23
|
module.exports = __toCommonJS(elysia_exports);
|
|
34
|
-
var import_plugin =
|
|
24
|
+
var import_plugin = require('./plugin.cjs');
|
|
35
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
36
26
|
0 && (module.exports = {
|
|
37
27
|
apitallyPlugin
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport {
|
|
1
|
+
{"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { apitallyPlugin } from \"./plugin.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AACA;;;;;oBAA+B;","names":[]}
|
package/dist/elysia/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ApitallyConfig, ApitallyConsumer } from '../common/types.cjs';
|
|
2
|
-
export {
|
|
2
|
+
export { apitallyPlugin } from './plugin.cjs';
|
|
3
3
|
import '../common/logging.cjs';
|
|
4
4
|
import 'winston';
|
|
5
5
|
import '../common/requestLogger.cjs';
|
package/dist/elysia/index.d.ts
CHANGED
package/dist/elysia/index.js
CHANGED
package/dist/elysia/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport {
|
|
1
|
+
{"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { apitallyPlugin } from \"./plugin.js\";\n"],"mappings":"AACA,SAASA,sBAAsB;","names":["apitallyPlugin"]}
|
package/dist/elysia/plugin.cjs
CHANGED
|
@@ -19,6 +19,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
var plugin_exports = {};
|
|
21
21
|
__export(plugin_exports, {
|
|
22
|
+
apitallyPlugin: () => apitallyPlugin,
|
|
22
23
|
default: () => apitallyPlugin
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(plugin_exports);
|
|
@@ -234,4 +235,8 @@ function getStatusCode(set) {
|
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
237
|
__name(getStatusCode, "getStatusCode");
|
|
238
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
239
|
+
0 && (module.exports = {
|
|
240
|
+
apitallyPlugin
|
|
241
|
+
});
|
|
237
242
|
//# sourceMappingURL=plugin.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport type { SpanHandle } from \"../common/spanCollector.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\nconst SPAN_HANDLE_SYMBOL = Symbol(\"apitally.spanHandle\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n [SPAN_HANDLE_SYMBOL]?: SpanHandle;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Start span and enter the context for subsequent handlers\n const spanHandle = client.spanCollector.startSpan();\n request[SPAN_HANDLE_SYMBOL] = spanHandle;\n spanHandle.enterContext();\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const spanHandle = request[SPAN_HANDLE_SYMBOL];\n spanHandle?.setName(`${request.method} ${route}`);\n const spans = spanHandle?.end();\n const traceId = spanHandle?.traceId;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n spans,\n traceId,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n"],"mappings":"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","names":["START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","SPAN_HANDLE_SYMBOL","config","client","ApitallyClient","logsContext","AsyncLocalStorage","requestLogger","enabled","captureLogs","patchConsole","patchWinston","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureResponse","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","getAppInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","performance","now","enterWith","spanHandle","spanCollector","startSpan","enterContext","logRequestBody","contentType","headers","get","requestSize","parseContentLength","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","setName","spans","end","traceId","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerFromStringOrObject","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","ValidationError","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin","StatusMap"]}
|
|
1
|
+
{"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport type { SpanHandle } from \"../common/spanCollector.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\nconst SPAN_HANDLE_SYMBOL = Symbol(\"apitally.spanHandle\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n [SPAN_HANDLE_SYMBOL]?: SpanHandle;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Start span and enter the context for subsequent handlers\n const spanHandle = client.spanCollector.startSpan();\n request[SPAN_HANDLE_SYMBOL] = spanHandle;\n spanHandle.enterContext();\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const spanHandle = request[SPAN_HANDLE_SYMBOL];\n spanHandle?.setName(`${request.method} ${route}`);\n const spans = spanHandle?.end();\n const traceId = spanHandle?.traceId;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n spans,\n traceId,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n\nexport { apitallyPlugin };\n"],"mappings":"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","names":["START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","SPAN_HANDLE_SYMBOL","config","client","ApitallyClient","logsContext","AsyncLocalStorage","requestLogger","enabled","captureLogs","patchConsole","patchWinston","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureResponse","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","getAppInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","performance","now","enterWith","spanHandle","spanCollector","startSpan","enterContext","logRequestBody","contentType","headers","get","requestSize","parseContentLength","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","setName","spans","end","traceId","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerFromStringOrObject","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","convertHeaders","Object","fromEntries","entries","ValidationError","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin","StatusMap"]}
|
package/dist/elysia/plugin.d.cts
CHANGED
package/dist/elysia/plugin.d.ts
CHANGED
package/dist/elysia/plugin.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport type { SpanHandle } from \"../common/spanCollector.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\nconst SPAN_HANDLE_SYMBOL = Symbol(\"apitally.spanHandle\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n [SPAN_HANDLE_SYMBOL]?: SpanHandle;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Start span and enter the context for subsequent handlers\n const spanHandle = client.spanCollector.startSpan();\n request[SPAN_HANDLE_SYMBOL] = spanHandle;\n spanHandle.enterContext();\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const spanHandle = request[SPAN_HANDLE_SYMBOL];\n spanHandle?.setName(`${request.method} ${route}`);\n const spans = spanHandle?.end();\n const traceId = spanHandle?.traceId;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n spans,\n traceId,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n"],"mappings":"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","names":["StatusMap","ValidationError","AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","convertHeaders","captureResponse","patchConsole","patchWinston","getAppInfo","START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","SPAN_HANDLE_SYMBOL","config","client","logsContext","requestLogger","enabled","captureLogs","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","now","enterWith","spanHandle","spanCollector","startSpan","enterContext","logRequestBody","contentType","headers","get","requestSize","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","setName","spans","end","traceId","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","Object","fromEntries","entries","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin"]}
|
|
1
|
+
{"version":3,"sources":["../../src/elysia/plugin.ts"],"sourcesContent":["import { Context, Elysia, StatusMap, ValidationError } from \"elysia\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertHeaders } from \"../common/requestLogger.js\";\nimport { CapturedResponse, captureResponse } from \"../common/response.js\";\nimport type { SpanHandle } from \"../common/spanCollector.js\";\nimport { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nimport { patchConsole, patchWinston } from \"../loggers/index.js\";\nimport { getAppInfo } from \"./utils.js\";\n\nconst START_TIME_SYMBOL = Symbol(\"apitally.startTime\");\nconst REQUEST_BODY_SYMBOL = Symbol(\"apitally.requestBody\");\nconst RESPONSE_SYMBOL = Symbol(\"apitally.response\");\nconst RESPONSE_PROMISE_SYMBOL = Symbol(\"apitally.responsePromise\");\nconst ERROR_SYMBOL = Symbol(\"apitally.error\");\nconst CLIENT_SYMBOL = Symbol(\"apitally.client\");\nconst REQUEST_SYMBOL = Symbol(\"apitally.request\");\nconst SPAN_HANDLE_SYMBOL = Symbol(\"apitally.spanHandle\");\n\ndeclare global {\n interface Request {\n [START_TIME_SYMBOL]?: number;\n [REQUEST_BODY_SYMBOL]?: Buffer;\n [RESPONSE_SYMBOL]?: Response;\n [RESPONSE_PROMISE_SYMBOL]?: Promise<CapturedResponse>;\n [ERROR_SYMBOL]?: Readonly<Error>;\n [CLIENT_SYMBOL]?: ApitallyClient;\n [SPAN_HANDLE_SYMBOL]?: SpanHandle;\n }\n}\n\ntype ContextSet = Context[\"set\"] & {\n [REQUEST_SYMBOL]?: Request;\n};\n\ninterface ApitallyContext {\n consumer?: ApitallyConsumer | string;\n}\n\nexport default function apitallyPlugin(config: ApitallyConfig) {\n const client = new ApitallyClient(config);\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.enabled && client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n }\n\n return (app: Elysia) => {\n const handler = app[\"~adapter\"].handler;\n\n if (!handler.mapResponse.name.startsWith(\"wrapped\")) {\n const originalMapResponse = handler.mapResponse;\n const originalMapCompactResponse = handler.mapCompactResponse;\n const originalMapEarlyResponse = handler.mapEarlyResponse;\n\n const captureMappedResponse = (\n originalResponse: unknown,\n mappedResponse: unknown,\n set?: ContextSet,\n ) => {\n const request = set?.[REQUEST_SYMBOL];\n if (\n request instanceof Request &&\n mappedResponse instanceof Response &&\n !(RESPONSE_SYMBOL in request) &&\n CLIENT_SYMBOL in request\n ) {\n if (typeof originalResponse === \"string\") {\n // Preserve the response body value as Blob if the original response is a string,\n // so that Bun adds a Content-Type header.\n const responseBody = Buffer.from(originalResponse as string);\n request[RESPONSE_SYMBOL] = mappedResponse;\n request[RESPONSE_PROMISE_SYMBOL] = Promise.resolve({\n body: responseBody,\n size: responseBody.length,\n completed: true,\n });\n } else {\n // Otherwise capture the response using streaming\n const client = request[CLIENT_SYMBOL]!;\n const [newResponse, responsePromise] = captureResponse(\n mappedResponse,\n {\n captureBody:\n client.requestLogger.enabled &&\n client.requestLogger.config.logResponseBody,\n maxBodySize: client.requestLogger.maxBodySize,\n },\n );\n request[RESPONSE_SYMBOL] = newResponse;\n request[RESPONSE_PROMISE_SYMBOL] = responsePromise;\n return newResponse;\n }\n }\n return mappedResponse;\n };\n\n handler.mapResponse = function wrappedMapResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n handler.mapCompactResponse = function wrappedMapCompactResponse(\n response: unknown,\n ) {\n const mappedResponse = originalMapCompactResponse(response);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n undefined,\n );\n return newResponse;\n };\n handler.mapEarlyResponse = function wrappedMapEarlyResponse(\n response: unknown,\n set: ContextSet,\n ) {\n const mappedResponse = originalMapEarlyResponse(response, set);\n const newResponse = captureMappedResponse(\n response,\n mappedResponse,\n set,\n );\n return newResponse;\n };\n }\n\n return app\n .decorate(\"apitally\", {} as ApitallyContext)\n .onStart(() => {\n const appInfo = getAppInfo(app, config.appVersion);\n client.setStartupData(appInfo);\n client.startSync();\n })\n .onStop(async () => {\n await client.handleShutdown();\n })\n .onRequest(async ({ request, set }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n request[CLIENT_SYMBOL] = client;\n request[START_TIME_SYMBOL] = performance.now();\n (set as ContextSet)[REQUEST_SYMBOL] = request;\n logsContext.enterWith([]);\n\n // Start span and enter the context for subsequent handlers\n const spanHandle = client.spanCollector.startSpan();\n request[SPAN_HANDLE_SYMBOL] = spanHandle;\n spanHandle.enterContext();\n\n // Capture request body\n if (\n client.requestLogger.enabled &&\n client.requestLogger.config.logRequestBody\n ) {\n const contentType = request.headers.get(\"content-type\");\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ?? 0;\n\n if (\n client.requestLogger.isSupportedContentType(contentType) &&\n requestSize <= client.requestLogger.maxBodySize\n ) {\n try {\n request[REQUEST_BODY_SYMBOL] = Buffer.from(\n await request.clone().arrayBuffer(),\n );\n } catch (error) {\n // ignore\n }\n }\n }\n })\n .onAfterResponse(async ({ request, set, route, apitally }) => {\n if (!client.isEnabled() || request.method.toUpperCase() === \"OPTIONS\") {\n return;\n }\n\n const startTime = request[START_TIME_SYMBOL];\n const responseTime = startTime ? performance.now() - startTime : 0;\n\n const spanHandle = request[SPAN_HANDLE_SYMBOL];\n spanHandle?.setName(`${request.method} ${route}`);\n const spans = spanHandle?.end();\n const traceId = spanHandle?.traceId;\n\n const requestBody = request[REQUEST_BODY_SYMBOL];\n const requestSize =\n parseContentLength(request.headers.get(\"content-length\")) ??\n requestBody?.length;\n\n let responsePromise = request[RESPONSE_PROMISE_SYMBOL];\n let response = request[RESPONSE_SYMBOL];\n const error = request[ERROR_SYMBOL];\n\n if (\n !response &&\n error &&\n \"toResponse\" in error &&\n typeof error.toResponse === \"function\"\n ) {\n // Convert error to response\n try {\n response = error.toResponse() as Response;\n const errorResponseBody = Buffer.from(await response.arrayBuffer());\n responsePromise = Promise.resolve({\n body: errorResponseBody,\n size: errorResponseBody.length,\n completed: true,\n });\n } catch (error) {\n // ignore\n }\n }\n\n const statusCode = response?.status ?? getStatusCode(set) ?? 200;\n\n if (!response) {\n // Create empty fake response for errors without the toResponse method\n response = new Response(null, {\n status: statusCode,\n statusText: \"\",\n headers: new Headers(),\n });\n responsePromise = Promise.resolve({\n body: undefined,\n size: 0,\n completed: true,\n });\n }\n\n const consumer = apitally.consumer\n ? consumerFromStringOrObject(apitally.consumer)\n : null;\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n // Log request when response has been fully captured\n responsePromise?.then(async (capturedResponse) => {\n const responseHeaders = response?.headers ?? set.headers;\n const responseSize = capturedResponse.completed\n ? capturedResponse.size\n : undefined;\n\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n statusCode,\n responseTime,\n requestSize,\n responseSize,\n });\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: (Date.now() - responseTime) / 1000,\n method: request.method,\n path: route,\n url: request.url,\n headers: convertHeaders(\n Object.fromEntries(request.headers.entries()),\n ),\n size: requestSize,\n consumer: consumer?.identifier,\n body: requestBody,\n },\n {\n statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(responseHeaders),\n size: responseSize,\n body: capturedResponse.body,\n },\n error,\n logs,\n spans,\n traceId,\n );\n }\n });\n\n // Handle validation errors\n if (\n (statusCode === 400 || statusCode === 422) &&\n error instanceof ValidationError\n ) {\n try {\n const parsedMessage = JSON.parse(error.message);\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n loc:\n (parsedMessage.on ?? \"\") + \".\" + (parsedMessage.property ?? \"\"),\n msg: parsedMessage.message,\n type: \"\",\n });\n } catch (error) {\n // ignore\n }\n }\n\n // Handle server errors\n if (statusCode === 500 && error) {\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: request.method,\n path: route,\n type: error.name,\n msg: error.message,\n traceback: error.stack || \"\",\n });\n }\n })\n .onError(({ request, error }) => {\n if (client.isEnabled() && error instanceof Error) {\n request[ERROR_SYMBOL] = error;\n }\n });\n };\n}\n\nfunction getStatusCode(set: Context[\"set\"]) {\n if (typeof set.status === \"number\") {\n return set.status;\n } else if (typeof set.status === \"string\") {\n return StatusMap[set.status];\n }\n}\n\nexport { apitallyPlugin };\n"],"mappings":"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","names":["StatusMap","ValidationError","AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","convertHeaders","captureResponse","patchConsole","patchWinston","getAppInfo","START_TIME_SYMBOL","Symbol","REQUEST_BODY_SYMBOL","RESPONSE_SYMBOL","RESPONSE_PROMISE_SYMBOL","ERROR_SYMBOL","CLIENT_SYMBOL","REQUEST_SYMBOL","SPAN_HANDLE_SYMBOL","config","client","logsContext","requestLogger","enabled","captureLogs","app","handler","mapResponse","name","startsWith","originalMapResponse","originalMapCompactResponse","mapCompactResponse","originalMapEarlyResponse","mapEarlyResponse","captureMappedResponse","originalResponse","mappedResponse","set","request","Request","Response","responseBody","Buffer","from","Promise","resolve","body","size","length","completed","newResponse","responsePromise","captureBody","logResponseBody","maxBodySize","wrappedMapResponse","response","wrappedMapCompactResponse","undefined","wrappedMapEarlyResponse","decorate","onStart","appInfo","appVersion","setStartupData","startSync","onStop","handleShutdown","onRequest","isEnabled","method","toUpperCase","now","enterWith","spanHandle","spanCollector","startSpan","enterContext","logRequestBody","contentType","headers","get","requestSize","isSupportedContentType","clone","arrayBuffer","error","onAfterResponse","route","apitally","startTime","responseTime","setName","spans","end","traceId","requestBody","toResponse","errorResponseBody","statusCode","status","getStatusCode","statusText","Headers","consumer","consumerRegistry","addOrUpdateConsumer","then","capturedResponse","responseHeaders","responseSize","requestCounter","addRequest","identifier","path","logs","getStore","logRequest","timestamp","Date","url","Object","fromEntries","entries","parsedMessage","JSON","parse","message","validationErrorCounter","addValidationError","loc","on","property","msg","type","serverErrorCounter","addServerError","traceback","stack","onError","Error","apitallyPlugin"]}
|
package/dist/fastify/index.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,22 +15,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
var fastify_exports = {};
|
|
30
20
|
__export(fastify_exports, {
|
|
31
|
-
apitallyPlugin: () => import_plugin.
|
|
21
|
+
apitallyPlugin: () => import_plugin.apitallyFastifyPlugin,
|
|
32
22
|
setConsumer: () => import_plugin.setConsumer
|
|
33
23
|
});
|
|
34
24
|
module.exports = __toCommonJS(fastify_exports);
|
|
35
|
-
var import_plugin =
|
|
25
|
+
var import_plugin = require('./plugin.cjs');
|
|
36
26
|
// Annotate the CommonJS export names for ESM import in node:
|
|
37
27
|
0 && (module.exports = {
|
|
38
28
|
apitallyPlugin,
|