import { o as logger } from "./logger-CfDSdx1q.js";
import { t as getDirectory } from "./esm-B1AS3f6u.js";
import { t as getTraceStore } from "./store-BOrmVNFa.js";
import { n as PROMPTFOO_RESOURCE_ATTR_TRACE_ID, t as PROMPTFOO_RESOURCE_ATTR_PARENT_SPAN_ID } from "./resourceAttributes-C1tzh4Ol.js";
import path from "path";
import crypto from "node:crypto";
import express from "express";
import protobuf from "protobufjs";
//#region src/tracing/protobuf.ts
/**
* OTLP Protobuf decoder for trace data
*
* Uses protobufjs to decode binary OTLP trace requests sent with
* Content-Type: application/x-protobuf
*/
let protoRoot = null;
let ExportTraceServiceRequest = null;
/**
* Get the path to the proto files directory.
* This works correctly in both development (tsx) and production (bundled) environments.
*/
function getProtoDir() {
	return path.join(getDirectory(), "tracing", "proto");
}
/**
* Load and cache the OTLP proto definitions
*/
async function loadProtoDefinitions() {
	if (protoRoot) return protoRoot;
	logger.debug("[Protobuf] Loading OTLP proto definitions");
	const protoDir = getProtoDir();
	logger.debug(`[Protobuf] Proto directory: ${protoDir}`);
	try {
		const root = new protobuf.Root();
		root.resolvePath = (_origin, target) => {
			return path.join(protoDir, target);
		};
		await root.load("opentelemetry/proto/collector/trace/v1/trace_service.proto");
		protoRoot = root;
		logger.debug("[Protobuf] Successfully loaded OTLP proto definitions");
		return protoRoot;
	} catch (error) {
		logger.error(`[Protobuf] Failed to load proto definitions: ${error}`);
		throw error;
	}
}
/**
* Get the ExportTraceServiceRequest message type
*/
async function getExportTraceServiceRequestType() {
	if (ExportTraceServiceRequest) return ExportTraceServiceRequest;
	ExportTraceServiceRequest = (await loadProtoDefinitions()).lookupType("opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest");
	return ExportTraceServiceRequest;
}
/**
* Convert a Uint8Array to a hex string
*/
function bytesToHex(bytes, expectedLength) {
	if (!bytes || bytes.length === 0) return "0".repeat(expectedLength);
	return Buffer.from(bytes).toString("hex").padStart(expectedLength, "0");
}
/**
* Decode a binary OTLP ExportTraceServiceRequest
*
* @param data - The binary protobuf data
* @returns The decoded request object
*/
async function decodeExportTraceServiceRequest(data) {
	const messageType = await getExportTraceServiceRequestType();
	try {
		const message = messageType.decode(data instanceof Buffer ? new Uint8Array(data) : data);
		const decoded = messageType.toObject(message, {
			longs: Number,
			bytes: Uint8Array,
			defaults: true,
			arrays: true
		});
		logger.debug(`[Protobuf] Decoded ExportTraceServiceRequest with ${decoded.resourceSpans?.length || 0} resource spans`);
		return decoded;
	} catch (error) {
		logger.error(`[Protobuf] Failed to decode ExportTraceServiceRequest: ${error}`);
		throw new Error(`Invalid protobuf data: ${error instanceof Error ? error.message : error}`);
	}
}
//#endregion
//#region src/tracing/otlpReceiver.ts
const LOG_EVENT_NAME_DENYLIST = new Set(["claude_code.tracing"]);
const LOG_SPAN_DURATION_MS = 1;
const MAX_BODY_AS_NAME_LENGTH = 128;
const SEVERITY_NUMBER_ERROR = 17;
const MAX_LOG_BODY_ATTR_LENGTH = 8192;
function truncateLogBody(value) {
	if (typeof value !== "string") return value;
	if (value.length <= MAX_LOG_BODY_ATTR_LENGTH) return value;
	return `${value.slice(0, MAX_LOG_BODY_ATTR_LENGTH - 15)}... [truncated]`;
}
const BASE64_ZERO_SPAN_ID = /^A{11,12}=?$/;
function isZeroSpanId(id) {
	return /^0+$/.test(id) || BASE64_ZERO_SPAN_ID.test(id);
}
function randomSpanId() {
	return crypto.randomBytes(8).toString("hex");
}
function getStringAttribute(attributes, key) {
	const value = attributes[key];
	return typeof value === "string" ? value : void 0;
}
function resolveLogSpanName(attributes, bodyValue) {
	const eventName = attributes["event.name"] ?? attributes["claude_code.event.name"];
	if (typeof eventName === "string" && eventName.length > 0) return eventName;
	if (typeof bodyValue === "string" && bodyValue.length > 0 && bodyValue.length <= MAX_BODY_AS_NAME_LENGTH) return bodyValue;
	return "otel.log";
}
const SPAN_KIND_MAP = {
	0: "unspecified",
	1: "internal",
	2: "server",
	3: "client",
	4: "producer",
	5: "consumer"
};
const DEFAULT_ACCEPT_FORMATS = ["json", "protobuf"];
const OTLP_CONTENT_TYPES = {
	json: "application/json",
	protobuf: "application/x-protobuf"
};
function normalizeAcceptFormats(acceptFormats) {
	const normalized = [...new Set(acceptFormats ?? DEFAULT_ACCEPT_FORMATS)];
	return normalized.length > 0 ? normalized : [...DEFAULT_ACCEPT_FORMATS];
}
function normalizeRedactAttributePatterns(redactAttributes) {
	return [...new Set((redactAttributes ?? []).map((pattern) => typeof pattern === "string" ? pattern.trim().toLowerCase() : "").filter((pattern) => pattern.length > 0))];
}
function normalizeCommandToolNames(commandToolNames) {
	const normalized = [...new Set((commandToolNames ?? []).map((name) => typeof name === "string" ? name.trim() : "").filter((name) => name.length > 0))];
	return normalized.length > 0 ? normalized : void 0;
}
function normalizeTracePolicy(policy) {
	return {
		commandToolNames: normalizeCommandToolNames(policy.commandToolNames),
		redactAttributePatterns: normalizeRedactAttributePatterns(policy.redactAttributes)
	};
}
function metadataFromTracePolicy(policy) {
	const metadata = {};
	if (policy.commandToolNames) metadata.commandToolNames = policy.commandToolNames;
	if (policy.redactAttributePatterns.length > 0) metadata.otlpHttpRedactAttributes = policy.redactAttributePatterns;
	return Object.keys(metadata).length > 0 ? metadata : void 0;
}
function getRequestFormat(contentType) {
	const mimeType = (Array.isArray(contentType) ? contentType[0] : contentType)?.split(";", 1)[0]?.trim().toLowerCase();
	if (mimeType === OTLP_CONTENT_TYPES.json) return "json";
	if (mimeType === OTLP_CONTENT_TYPES.protobuf) return "protobuf";
	return null;
}
var OTLPReceiver = class {
	app;
	acceptFormats;
	traceStore;
	port;
	server;
	commandToolNames;
	redactAttributePatterns = [];
	tracePoliciesByEvaluationId = /* @__PURE__ */ new Map();
	constructor(options = {}) {
		this.app = express();
		this.acceptFormats = normalizeAcceptFormats(options.acceptFormats);
		this.traceStore = getTraceStore();
		this.setCommandToolNames(options.commandToolNames);
		this.setRedactAttributes(options.redactAttributes);
		this.registerTracePolicy(options.tracePolicy);
		logger.debug("[OtlpReceiver] Initializing OTLP receiver");
		this.setupMiddleware();
		this.setupRoutes();
	}
	setRedactAttributes(redactAttributes) {
		this.redactAttributePatterns = normalizeRedactAttributePatterns(redactAttributes);
	}
	setCommandToolNames(commandToolNames) {
		this.commandToolNames = normalizeCommandToolNames(commandToolNames);
	}
	registerTracePolicy(policy) {
		if (!policy?.evaluationId) return;
		this.tracePoliciesByEvaluationId.set(policy.evaluationId, normalizeTracePolicy(policy));
	}
	deregisterTracePolicy(evaluationId) {
		if (evaluationId) this.tracePoliciesByEvaluationId.delete(evaluationId);
	}
	shouldRedactAttribute(key, redactAttributePatterns) {
		if (redactAttributePatterns.length === 0) return false;
		const lowered = key.toLowerCase();
		return redactAttributePatterns.some((pattern) => lowered.includes(pattern));
	}
	redactAttributeValue(value, redactAttributePatterns) {
		if (Array.isArray(value)) return value.map((item) => this.redactAttributeValue(item, redactAttributePatterns));
		if (!value || typeof value !== "object") return value;
		return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [key, this.shouldRedactAttribute(key, redactAttributePatterns) ? "[REDACTED]" : this.redactAttributeValue(nestedValue, redactAttributePatterns)]));
	}
	redactAttributes(attributes, redactAttributePatterns = this.redactAttributePatterns) {
		if (!attributes || redactAttributePatterns.length === 0) return attributes ?? {};
		const redacted = {};
		for (const [key, value] of Object.entries(attributes)) redacted[key] = this.shouldRedactAttribute(key, redactAttributePatterns) ? "[REDACTED]" : this.redactAttributeValue(value, redactAttributePatterns);
		return redacted;
	}
	redactSpan(span, redactAttributePatterns) {
		if (redactAttributePatterns.length === 0) return span;
		const attributes = span.attributes ?? {};
		const redactedSourceValues = /* @__PURE__ */ new Set();
		for (const [key, value] of Object.entries(attributes)) if (typeof value === "string" && this.shouldRedactAttribute(key, redactAttributePatterns)) redactedSourceValues.add(value);
		const scrubEcho = (value) => typeof value === "string" && redactedSourceValues.has(value) ? "[REDACTED]" : value;
		return {
			...span,
			name: scrubEcho(span.name),
			statusMessage: scrubEcho(span.statusMessage),
			attributes: this.redactAttributes(attributes, redactAttributePatterns)
		};
	}
	setupMiddleware() {
		this.app.use("/v1/traces", (req, res, next) => {
			if (req.method !== "POST") {
				next();
				return;
			}
			const format = getRequestFormat(req.headers["content-type"]);
			if (!format || !this.acceptFormats.includes(format)) {
				res.status(415).json({ error: "Unsupported content type" });
				return;
			}
			next();
		});
		this.app.use("/v1/traces", express.json({
			limit: "10mb",
			type: (req) => this.acceptFormats.includes("json") && getRequestFormat(req.headers["content-type"]) === "json"
		}));
		this.app.use("/v1/traces", express.raw({
			limit: "10mb",
			type: (req) => this.acceptFormats.includes("protobuf") && getRequestFormat(req.headers["content-type"]) === "protobuf"
		}));
		this.app.use("/v1/logs", (req, res, next) => {
			if (req.method !== "POST") {
				next();
				return;
			}
			if (getRequestFormat(req.headers["content-type"]) !== "json") {
				res.status(415).json({ error: "Only application/json is supported for /v1/logs" });
				return;
			}
			next();
		});
		this.app.use("/v1/logs", express.json({
			limit: "10mb",
			type: (req) => getRequestFormat(req.headers["content-type"]) === "json"
		}));
		logger.debug("[OtlpReceiver] Middleware configured for accepted OTLP formats");
	}
	setupRoutes() {
		this.app.post("/v1/traces", async (req, res) => {
			const contentType = req.headers["content-type"] || "unknown";
			const bodySize = req.body ? JSON.stringify(req.body).length : 0;
			logger.debug(`[OtlpReceiver] Received trace request: ${req.headers["content-type"]} with ${bodySize} bytes`);
			logger.debug("[OtlpReceiver] Starting to process traces");
			const format = getRequestFormat(contentType);
			if (!format || !this.acceptFormats.includes(format)) {
				res.status(415).json({ error: "Unsupported content type" });
				return;
			}
			try {
				const traces = await this.parseIncomingRequest(format, req.body);
				logger.debug(`[OtlpReceiver] Parsed ${traces.length} traces from request`);
				await this.persistTraces(this.groupTraces(traces));
				res.status(200).json({ partialSuccess: {} });
				logger.debug("[OtlpReceiver] Successfully processed traces");
			} catch (error) {
				this.handleProcessingError(error, res);
			}
		});
		this.app.post("/v1/logs", async (req, res) => {
			logger.debug("[OtlpReceiver] Received logs request");
			try {
				const traces = this.parseOTLPLogsJSONRequest(req.body);
				logger.debug(`[OtlpReceiver] Parsed ${traces.length} logs into span records`);
				if (traces.length > 0) await this.persistTraces(this.groupTraces(traces));
				res.status(200).json({ partialSuccess: {} });
			} catch (error) {
				this.handleProcessingError(error, res);
			}
		});
		this.app.get("/health", (_req, res) => {
			logger.debug("[OtlpReceiver] Health check requested");
			res.status(200).json({ status: "ok" });
		});
		this.app.get("/v1/traces", (_req, res) => {
			res.status(200).json({
				service: "promptfoo-otlp-receiver",
				version: "1.0.0",
				supported_formats: this.acceptFormats
			});
		});
		this.app.get("/debug/status", async (_req, res) => {
			res.status(200).json({
				status: "running",
				uptime: process.uptime(),
				timestamp: (/* @__PURE__ */ new Date()).toISOString(),
				port: this.port || 4318
			});
		});
		this.app.use((error, _req, res, _next) => {
			logger.error(`[OtlpReceiver] Global error handler: ${error}`);
			logger.error(`[OtlpReceiver] Error stack: ${error.stack}`);
			if (error instanceof SyntaxError && "body" in error) {
				res.status(400).json({ error: "Invalid JSON" });
				return;
			}
			res.status(500).json({ error: "Internal server error" });
		});
	}
	async parseIncomingRequest(format, body) {
		if (format === "json") {
			logger.debug("[OtlpReceiver] Parsing OTLP JSON request");
			logger.debug(`[OtlpReceiver] Request body: ${JSON.stringify(body).substring(0, 500)}...`);
			return this.parseOTLPJSONRequest(body);
		}
		logger.debug("[OtlpReceiver] Parsing OTLP protobuf request");
		logger.debug(`[OtlpReceiver] Request body size: ${body?.length || 0} bytes`);
		return this.parseOTLPProtobufRequest(body);
	}
	groupTraces(traces) {
		const spansByTrace = /* @__PURE__ */ new Map();
		const traceInfoById = /* @__PURE__ */ new Map();
		for (const trace of traces) {
			const spans = spansByTrace.get(trace.traceId) ?? [];
			spans.push(trace.span);
			spansByTrace.set(trace.traceId, spans);
			this.recordTraceInfo(traceInfoById, trace);
		}
		logger.debug(`[OtlpReceiver] Grouped spans into ${spansByTrace.size} traces`);
		return {
			spansByTrace,
			traceInfoById
		};
	}
	recordTraceInfo(traceInfoById, trace) {
		const evaluationId = trace.span.attributes?.["evaluation.id"];
		const testCaseId = trace.span.attributes?.["test.case.id"];
		const info = traceInfoById.get(trace.traceId) ?? {};
		if (evaluationId) info.evaluationId = evaluationId;
		if (testCaseId) info.testCaseId = testCaseId;
		traceInfoById.set(trace.traceId, info);
	}
	async persistTraces({ spansByTrace, traceInfoById }) {
		await this.createTraceRecords(traceInfoById);
		await this.storeSpans(spansByTrace, traceInfoById);
	}
	async createTraceRecords(traceInfoById) {
		for (const [traceId, info] of traceInfoById) {
			if (!info.evaluationId || !info.testCaseId) {
				logger.debug(`[OtlpReceiver] Skipping trace record creation for unlinked trace ${traceId}`);
				continue;
			}
			try {
				logger.debug(`[OtlpReceiver] Creating trace record for ${traceId}`);
				await this.traceStore.createTrace({
					traceId,
					evaluationId: info.evaluationId,
					testCaseId: info.testCaseId,
					metadata: this.getTraceMetadata(info)
				});
			} catch (error) {
				logger.debug(`[OtlpReceiver] Trace ${traceId} may already exist: ${error}`);
			}
		}
	}
	getRegisteredTracePolicy(info) {
		return info?.evaluationId ? this.tracePoliciesByEvaluationId.get(info.evaluationId) : void 0;
	}
	getFallbackTracePolicy() {
		return {
			commandToolNames: this.commandToolNames,
			redactAttributePatterns: this.redactAttributePatterns
		};
	}
	getTraceMetadata(info) {
		return metadataFromTracePolicy(this.getRegisteredTracePolicy(info) ?? this.getFallbackTracePolicy());
	}
	async storeSpans(spansByTrace, traceInfoById) {
		for (const [traceId, spans] of spansByTrace) {
			logger.debug(`[OtlpReceiver] Storing ${spans.length} spans for trace ${traceId}`);
			const redactAttributePatterns = await this.getRedactAttributePatterns(traceId, traceInfoById.get(traceId));
			const sanitized = redactAttributePatterns.length > 0 ? spans.map((span) => this.redactSpan(span, redactAttributePatterns)) : spans;
			await this.traceStore.addSpans(traceId, sanitized, {
				skipTraceCheck: false,
				warnIfMissingTrace: false
			});
		}
	}
	async getRedactAttributePatterns(traceId, info) {
		const metadata = await this.traceStore.getTraceMetadata(traceId);
		if (metadata === void 0) return this.getRegisteredTracePolicy(info)?.redactAttributePatterns ?? this.getFallbackTracePolicy().redactAttributePatterns;
		return Array.isArray(metadata.otlpHttpRedactAttributes) ? normalizeRedactAttributePatterns(metadata.otlpHttpRedactAttributes) : [];
	}
	handleProcessingError(error, res) {
		logger.error(`[OtlpReceiver] Failed to process OTLP traces: ${error}`);
		logger.error(`[OtlpReceiver] Error stack: ${error instanceof Error ? error.stack : "No stack"}`);
		const errorMessage = error instanceof Error ? error.message : String(error);
		if (errorMessage.toLowerCase().includes("invalid protobuf")) {
			res.status(400).json({ error: errorMessage });
			return;
		}
		res.status(500).json({ error: "Internal server error" });
	}
	parseOTLPJSONRequest(body) {
		const traces = [];
		logger.debug(`[OtlpReceiver] Parsing request with ${body.resourceSpans?.length || 0} resource spans`);
		for (const resourceSpan of body.resourceSpans) {
			const resourceAttributes = this.parseAttributes(resourceSpan.resource?.attributes);
			logger.debug(`[OtlpReceiver] Parsed ${Object.keys(resourceAttributes).length} resource attributes`);
			for (const scopeSpan of resourceSpan.scopeSpans) for (const span of scopeSpan.spans) {
				const traceId = this.convertId(span.traceId, 32);
				const spanId = this.convertId(span.spanId, 16);
				const parentSpanId = span.parentSpanId ? this.convertId(span.parentSpanId, 16) : void 0;
				logger.debug(`[OtlpReceiver] Processing span: ${span.name} (${spanId}) in trace ${traceId}`);
				const spanKindName = SPAN_KIND_MAP[span.kind] ?? "unspecified";
				const attributes = {
					...resourceAttributes,
					...this.parseAttributes(span.attributes),
					"otel.scope.name": scopeSpan.scope?.name,
					"otel.scope.version": scopeSpan.scope?.version,
					"otel.span.kind": spanKindName,
					"otel.span.kind_code": span.kind
				};
				traces.push({
					traceId,
					span: {
						spanId,
						parentSpanId,
						name: span.name,
						startTime: Number(span.startTimeUnixNano) / 1e6,
						endTime: span.endTimeUnixNano ? Number(span.endTimeUnixNano) / 1e6 : void 0,
						attributes,
						statusCode: span.status?.code,
						statusMessage: span.status?.message
					}
				});
			}
		}
		return traces;
	}
	parseOTLPLogsJSONRequest(body) {
		const traces = [];
		const resourceLogs = body?.resourceLogs ?? [];
		logger.debug(`[OtlpReceiver] Parsing logs request with ${resourceLogs.length} resource logs`);
		for (const resourceLog of resourceLogs) {
			const resourceAttributes = this.parseAttributes(resourceLog.resource?.attributes);
			for (const scopeLog of resourceLog.scopeLogs ?? []) for (const log of scopeLog.logRecords ?? []) try {
				const parsed = this.logRecordToParsedTrace(log, scopeLog, resourceAttributes);
				if (parsed) traces.push(parsed);
			} catch (err) {
				logger.warn(`[OtlpReceiver] Skipping malformed log record in scope ${scopeLog.scope?.name ?? "(unknown)"}: ${err}`);
			}
		}
		return traces;
	}
	logRecordToParsedTrace(log, scopeLog, resourceAttributes) {
		const rawTraceId = log.traceId ?? getStringAttribute(resourceAttributes, "promptfoo.trace_id");
		if (!rawTraceId) {
			logger.debug(`[OtlpReceiver] Dropping log: no traceId and no ${PROMPTFOO_RESOURCE_ATTR_TRACE_ID} resource attribute (scope=${scopeLog.scope?.name ?? "unknown"}). Ensure TRACEPARENT is propagated or OTEL_RESOURCE_ATTRIBUTES is set by the provider.`);
			return null;
		}
		const traceId = this.convertId(rawTraceId, 32);
		if (traceId.length !== 32 || !/^[0-9a-f]+$/.test(traceId)) {
			logger.debug(`[OtlpReceiver] Dropping log: invalid trace_id shape '${rawTraceId}'`);
			return null;
		}
		const attributes = {
			...resourceAttributes,
			...this.parseAttributes(log.attributes),
			"otel.scope.name": scopeLog.scope?.name,
			"otel.scope.version": scopeLog.scope?.version,
			"otel.log.severity_number": log.severityNumber,
			"otel.log.severity_text": log.severityText
		};
		const bodyValue = log.body ? this.parseAttributeValue(log.body) : void 0;
		const name = resolveLogSpanName(attributes, bodyValue);
		if (LOG_EVENT_NAME_DENYLIST.has(name)) {
			logger.debug(`[OtlpReceiver] Dropping log: event '${name}' is in the denylist`);
			return null;
		}
		if (bodyValue !== void 0) attributes["otel.log.body"] = truncateLogBody(bodyValue);
		const timeNano = log.timeUnixNano ?? log.observedTimeUnixNano;
		const startTime = timeNano ? Number(timeNano) / 1e6 : Date.now();
		const endTime = startTime + LOG_SPAN_DURATION_MS;
		const rawParentSpanId = !!log.spanId && !isZeroSpanId(log.spanId) ? log.spanId : getStringAttribute(resourceAttributes, PROMPTFOO_RESOURCE_ATTR_PARENT_SPAN_ID);
		const parentSpanId = rawParentSpanId ? this.convertId(rawParentSpanId, 16) : void 0;
		const severityIsError = typeof log.severityNumber === "number" && log.severityNumber >= SEVERITY_NUMBER_ERROR;
		return {
			traceId,
			span: {
				spanId: randomSpanId(),
				parentSpanId,
				name,
				startTime,
				endTime,
				attributes,
				statusCode: 1,
				statusMessage: severityIsError ? log.severityText : void 0
			}
		};
	}
	async parseOTLPProtobufRequest(body) {
		const decoded = await decodeExportTraceServiceRequest(body);
		logger.debug(`[OtlpReceiver] Parsing protobuf request with ${decoded.resourceSpans?.length || 0} resource spans`);
		return (decoded.resourceSpans || []).flatMap((resourceSpan) => this.parseDecodedResourceSpan(resourceSpan));
	}
	parseDecodedResourceSpan(resourceSpan) {
		const resourceAttributes = this.parseDecodedAttributes(resourceSpan.resource?.attributes);
		logger.debug(`[OtlpReceiver] Parsed ${Object.keys(resourceAttributes).length} resource attributes from protobuf`);
		return (resourceSpan.scopeSpans || []).flatMap((scopeSpan) => (scopeSpan.spans || []).map((span) => this.createDecodedParsedTrace(resourceAttributes, scopeSpan, span)));
	}
	createDecodedParsedTrace(resourceAttributes, scopeSpan, span) {
		const traceId = bytesToHex(span.traceId, 32);
		const spanId = bytesToHex(span.spanId, 16);
		const parentSpanId = span.parentSpanId?.length ? bytesToHex(span.parentSpanId, 16) : void 0;
		logger.debug(`[OtlpReceiver] Processing protobuf span: ${span.name} (${spanId}) in trace ${traceId}`);
		const spanKindCode = span.kind ?? 0;
		const spanKindName = SPAN_KIND_MAP[spanKindCode] ?? "unspecified";
		return {
			traceId,
			span: {
				spanId,
				parentSpanId,
				name: span.name,
				startTime: this.toMilliseconds(span.startTimeUnixNano) ?? 0,
				endTime: this.toMilliseconds(span.endTimeUnixNano),
				attributes: {
					...resourceAttributes,
					...this.parseDecodedAttributes(span.attributes),
					"otel.scope.name": scopeSpan.scope?.name,
					"otel.scope.version": scopeSpan.scope?.version,
					"otel.span.kind": spanKindName,
					"otel.span.kind_code": spanKindCode
				},
				statusCode: span.status?.code,
				statusMessage: span.status?.message
			}
		};
	}
	parseDecodedAttributes(attributes) {
		if (!attributes) return {};
		const result = {};
		for (const attr of attributes) {
			const value = this.parseDecodedAttributeValue(attr.value);
			if (value !== void 0) result[attr.key] = value;
		}
		return result;
	}
	parseDecodedAttributeValue(value) {
		if (!value) return;
		if (value.stringValue !== void 0) return value.stringValue;
		if (value.intValue !== void 0) return typeof value.intValue === "number" ? value.intValue : Number(value.intValue);
		if (value.doubleValue !== void 0) return value.doubleValue;
		if (value.boolValue !== void 0) return value.boolValue;
		if (value.bytesValue !== void 0) return Buffer.from(value.bytesValue).toString("base64");
		if (value.arrayValue?.values) return value.arrayValue.values.map((v) => this.parseDecodedAttributeValue(v));
		if (value.kvlistValue?.values) {
			const kvMap = {};
			for (const kv of value.kvlistValue.values) kvMap[kv.key] = this.parseDecodedAttributeValue(kv.value);
			return kvMap;
		}
	}
	parseAttributes(attributes) {
		if (!attributes) return {};
		const result = {};
		for (const attr of attributes) {
			const value = this.parseAttributeValue(attr.value);
			if (value !== void 0) result[attr.key] = value;
		}
		return result;
	}
	parseAttributeValue(value) {
		if (value.stringValue !== void 0) return value.stringValue;
		if (value.intValue !== void 0) return Number(value.intValue);
		if (value.doubleValue !== void 0) return value.doubleValue;
		if (value.boolValue !== void 0) return value.boolValue;
		if (value.arrayValue?.values) return value.arrayValue.values.map((v) => this.parseAttributeValue(v));
		if (value.kvlistValue?.values) {
			const kvMap = {};
			for (const kv of value.kvlistValue.values) kvMap[kv.key] = this.parseAttributeValue(kv.value);
			return kvMap;
		}
	}
	convertId(id, expectedHexLength) {
		logger.debug(`[OtlpReceiver] Converting ID: ${id} (length: ${id.length}, expected hex length: ${expectedHexLength})`);
		if (id.length === expectedHexLength && /^[0-9a-f]+$/i.test(id)) {
			logger.debug(`[OtlpReceiver] ID is already hex format`);
			return id.toLowerCase();
		}
		try {
			const buffer = Buffer.from(id, "base64");
			const hex = buffer.toString("hex");
			logger.debug(`[OtlpReceiver] Base64 decoded: ${id} -> ${hex} (${buffer.length} bytes)`);
			const utf8String = buffer.toString("utf8");
			if (utf8String.length === expectedHexLength && /^[0-9a-f]+$/i.test(utf8String)) {
				logger.debug(`[OtlpReceiver] Detected hex string encoded as UTF-8: ${utf8String}`);
				return utf8String.toLowerCase();
			}
			if (hex.length === expectedHexLength) return hex;
			logger.warn(`[OtlpReceiver] Unexpected ID format: ${id} -> ${hex} (expected ${expectedHexLength} hex chars)`);
			return id.toLowerCase();
		} catch (error) {
			logger.error(`[OtlpReceiver] Failed to convert ID: ${error}`);
			return id.toLowerCase();
		}
	}
	listen(port = 4318, host = "127.0.0.1") {
		this.port = port;
		logger.debug(`[OtlpReceiver] Starting receiver on ${host}:${port}`);
		return new Promise((resolve, reject) => {
			let settled = false;
			const server = this.app.listen(port, host, () => {
				if (settled || !server.listening) return;
				settled = true;
				logger.info(`[OtlpReceiver] Listening on http://${host}:${port}`);
				logger.debug("[OtlpReceiver] Receiver fully initialized and ready to accept traces");
				resolve();
			});
			this.server = server;
			server.on("error", (error) => {
				if (settled) return;
				settled = true;
				logger.error(`[OtlpReceiver] Failed to start: ${error}`);
				reject(error);
			});
		});
	}
	stop() {
		logger.debug("[OtlpReceiver] Stopping receiver");
		return new Promise((resolve) => {
			if (this.server) this.server.close(() => {
				logger.info("[OtlpReceiver] Server stopped");
				this.server = void 0;
				resolve();
			});
			else {
				logger.debug("[OtlpReceiver] No server to stop");
				resolve();
			}
		});
	}
	getApp() {
		return this.app;
	}
	setAcceptFormats(acceptFormats) {
		this.acceptFormats = normalizeAcceptFormats(acceptFormats);
	}
	toMilliseconds(value) {
		if (value === void 0) return;
		return Number(value) / 1e6;
	}
};
let otlpReceiver = null;
function getOTLPReceiver(options) {
	if (otlpReceiver) {
		otlpReceiver.setAcceptFormats(options?.acceptFormats);
		otlpReceiver.setCommandToolNames(options?.commandToolNames);
		otlpReceiver.setRedactAttributes(options?.redactAttributes);
		otlpReceiver.registerTracePolicy(options?.tracePolicy);
		return otlpReceiver;
	}
	otlpReceiver = new OTLPReceiver(options);
	return otlpReceiver;
}
async function startOTLPReceiver(port, host, acceptFormats, extra) {
	logger.debug("[OtlpReceiver] Starting receiver through startOTLPReceiver function");
	const receiver = getOTLPReceiver({
		acceptFormats,
		...extra
	});
	try {
		await receiver.listen(port, host);
	} catch (error) {
		if (otlpReceiver === receiver) otlpReceiver = null;
		throw error;
	}
}
function registerOTLPReceiverTracePolicy(policy) {
	otlpReceiver?.registerTracePolicy(policy);
}
function deregisterOTLPReceiverTracePolicy(evaluationId) {
	otlpReceiver?.deregisterTracePolicy(evaluationId);
}
async function stopOTLPReceiver() {
	logger.debug("[OtlpReceiver] Stopping receiver through stopOTLPReceiver function");
	if (otlpReceiver) {
		await otlpReceiver.stop();
		otlpReceiver = null;
	}
}
//#endregion
export { deregisterOTLPReceiverTracePolicy, registerOTLPReceiverTracePolicy, startOTLPReceiver, stopOTLPReceiver };

//# sourceMappingURL=otlpReceiver-V1lrVQUP.js.map