#!/usr/bin/env node
import { o as logger_default } from "./logger-CjS9Mbik.js";
import { f as spansTable, g as getDb, m as tracesTable } from "./tables-DZVyuvxI.js";
import { asc, eq, lt } from "drizzle-orm";

//#region src/tracing/store.ts
const SENSITIVE_ATTRIBUTE_KEYS = [
	"authorization",
	"cookie",
	"set-cookie",
	"token",
	"api_key",
	"apikey",
	"secret",
	"password",
	"passphrase"
];
function sanitizeAttributes(attributes) {
	if (!attributes) return {};
	const sanitizeValue = (value) => {
		if (typeof value === "string") return value.length > 400 ? `${value.slice(0, 400)}…` : value;
		if (Array.isArray(value)) return value.map(sanitizeValue);
		if (value && typeof value === "object") return sanitizeAttributes(value);
		return value;
	};
	const sanitized = {};
	for (const [key, value] of Object.entries(attributes)) {
		const lowerKey = key.toLowerCase();
		if (SENSITIVE_ATTRIBUTE_KEYS.some((sensitiveKey) => lowerKey.includes(sensitiveKey))) {
			sanitized[key] = "<redacted>";
			continue;
		}
		sanitized[key] = sanitizeValue(value);
	}
	return sanitized;
}
function computeDepth(span, spanMap, depthCache) {
	if (depthCache.has(span.spanId)) return depthCache.get(span.spanId);
	if (!span.parentSpanId || !spanMap.has(span.parentSpanId)) {
		depthCache.set(span.spanId, 0);
		return 0;
	}
	const currentDepth = computeDepth(spanMap.get(span.parentSpanId), spanMap, depthCache) + 1;
	depthCache.set(span.spanId, currentDepth);
	return currentDepth;
}
function deriveSpanKind(span) {
	const attributes = span.attributes || {};
	const attributeKind = attributes["span.kind"] || attributes["otel.span.kind"] || attributes["spanKind"];
	if (typeof attributeKind === "string") return attributeKind.toLowerCase();
	return "internal";
}
var TraceStore = class {
	db = null;
	getDatabase() {
		if (!this.db) {
			logger_default.debug("[TraceStore] Initializing database connection");
			this.db = getDb();
		}
		return this.db;
	}
	async createTrace(trace) {
		try {
			logger_default.debug(`[TraceStore] Creating trace ${trace.traceId} for evaluation ${trace.evaluationId}`);
			await this.getDatabase().insert(tracesTable).values({
				id: crypto.randomUUID(),
				traceId: trace.traceId,
				evaluationId: trace.evaluationId,
				testCaseId: trace.testCaseId,
				metadata: trace.metadata
			}).onConflictDoNothing({ target: tracesTable.traceId });
			logger_default.debug(`[TraceStore] Successfully created or found existing trace ${trace.traceId}`);
		} catch (error) {
			logger_default.error(`[TraceStore] Failed to create trace: ${error}`);
			throw error;
		}
	}
	async addSpans(traceId, spans, options) {
		try {
			logger_default.debug(`[TraceStore] Adding ${spans.length} spans to trace ${traceId}`);
			const db = this.getDatabase();
			if (options?.skipTraceCheck) logger_default.debug(`[TraceStore] Skipping trace existence check for OTLP scenario`);
			else {
				logger_default.debug(`[TraceStore] Verifying trace ${traceId} exists`);
				if ((await db.select().from(tracesTable).where(eq(tracesTable.traceId, traceId)).limit(1)).length === 0) {
					logger_default.warn(`[TraceStore] Trace ${traceId} not found, skipping ${spans.length} spans. This may indicate spans arrived before trace was created.`);
					return {
						stored: false,
						reason: `Trace ${traceId} not found`
					};
				}
				logger_default.debug(`[TraceStore] Trace ${traceId} found, proceeding with span insertion`);
			}
			const spanRecords = spans.map((span) => {
				logger_default.debug(`[TraceStore] Preparing span ${span.spanId} (${span.name}) for insertion`);
				return {
					id: crypto.randomUUID(),
					traceId,
					spanId: span.spanId,
					parentSpanId: span.parentSpanId,
					name: span.name,
					startTime: span.startTime,
					endTime: span.endTime,
					attributes: span.attributes,
					statusCode: span.statusCode,
					statusMessage: span.statusMessage
				};
			});
			await db.insert(spansTable).values(spanRecords);
			logger_default.debug(`[TraceStore] Successfully added ${spans.length} spans to trace ${traceId}`);
			return { stored: true };
		} catch (error) {
			logger_default.error(`[TraceStore] Failed to add spans: ${error}`);
			throw error;
		}
	}
	async getTracesByEvaluation(evaluationId) {
		try {
			logger_default.debug(`[TraceStore] Fetching traces for evaluation ${evaluationId}`);
			const db = this.getDatabase();
			const traces = await db.select().from(tracesTable).where(eq(tracesTable.evaluationId, evaluationId));
			logger_default.debug(`[TraceStore] Found ${traces.length} traces for evaluation ${evaluationId}`);
			const tracesWithSpans = await Promise.all(traces.map(async (trace) => {
				logger_default.debug(`[TraceStore] Fetching spans for trace ${trace.traceId}`);
				const spans = await db.select().from(spansTable).where(eq(spansTable.traceId, trace.traceId));
				logger_default.debug(`[TraceStore] Found ${spans.length} spans for trace ${trace.traceId}`);
				return {
					...trace,
					spans
				};
			}));
			logger_default.debug(`[TraceStore] Returning ${tracesWithSpans.length} traces with spans`);
			return tracesWithSpans;
		} catch (error) {
			logger_default.error(`[TraceStore] Failed to get traces for evaluation: ${error}`);
			throw error;
		}
	}
	async getTrace(traceId) {
		try {
			logger_default.debug(`[TraceStore] Fetching trace ${traceId}`);
			const db = this.getDatabase();
			const traces = await db.select().from(tracesTable).where(eq(tracesTable.traceId, traceId)).limit(1);
			if (traces.length === 0) {
				logger_default.debug(`[TraceStore] Trace ${traceId} not found`);
				return null;
			}
			const trace = traces[0];
			logger_default.debug(`[TraceStore] Found trace ${traceId}, fetching spans`);
			const spans = await db.select().from(spansTable).where(eq(spansTable.traceId, traceId));
			logger_default.debug(`[TraceStore] Found ${spans.length} spans for trace ${traceId}`);
			return {
				...trace,
				spans
			};
		} catch (error) {
			logger_default.error(`[TraceStore] Failed to get trace: ${error}`);
			throw error;
		}
	}
	async deleteOldTraces(retentionDays) {
		try {
			logger_default.debug(`[TraceStore] Deleting traces older than ${retentionDays} days`);
			const db = this.getDatabase();
			const cutoffTime = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
			await db.delete(tracesTable).where(lt(tracesTable.createdAt, cutoffTime));
			logger_default.debug(`[TraceStore] Successfully deleted traces older than ${retentionDays} days`);
		} catch (error) {
			logger_default.error(`[TraceStore] Failed to delete old traces: ${error}`);
			throw error;
		}
	}
	async getSpans(traceId, options = {}) {
		const { earliestStartTime, maxSpans, maxDepth, includeInternalSpans = true, spanFilter, sanitizeAttributes: shouldSanitize = true } = options;
		try {
			logger_default.debug(`[TraceStore] Fetching spans for trace ${traceId}`);
			const rows = await this.getDatabase().select().from(spansTable).where(eq(spansTable.traceId, traceId)).orderBy(asc(spansTable.startTime));
			const spanMap = /* @__PURE__ */ new Map();
			const depthCache = /* @__PURE__ */ new Map();
			for (const row of rows) {
				if (earliestStartTime && row.startTime < earliestStartTime) continue;
				const rawAttributes = row.attributes ?? {};
				const spanData = {
					spanId: row.spanId,
					parentSpanId: row.parentSpanId ?? void 0,
					name: row.name,
					startTime: row.startTime,
					endTime: row.endTime ?? void 0,
					attributes: shouldSanitize ? sanitizeAttributes(rawAttributes) : rawAttributes,
					statusCode: row.statusCode ?? void 0,
					statusMessage: row.statusMessage ?? void 0
				};
				const spanKind = deriveSpanKind({
					...spanData,
					attributes: rawAttributes
				});
				if (!includeInternalSpans && spanKind === "internal") continue;
				if (spanFilter && spanFilter.length > 0) {
					if (!spanFilter.some((filterName) => spanData.name.toLowerCase().includes(filterName.toLowerCase()))) continue;
				}
				spanMap.set(spanData.spanId, spanData);
			}
			let spans = Array.from(spanMap.values());
			if (maxDepth !== void 0) spans = spans.filter((span) => computeDepth(span, spanMap, depthCache) < maxDepth);
			if (maxSpans !== void 0) spans = spans.slice(0, maxSpans);
			logger_default.debug(`[TraceStore] Returning ${spans.length} spans for trace ${traceId}`);
			return spans;
		} catch (error) {
			logger_default.error(`[TraceStore] Failed to fetch spans for trace ${traceId}: ${error}`);
			throw error;
		}
	}
};
let traceStore = null;
function getTraceStore() {
	if (!traceStore) {
		logger_default.debug("[TraceStore] Creating new TraceStore instance");
		traceStore = new TraceStore();
	}
	return traceStore;
}

//#endregion
export { getTraceStore as n, TraceStore as t };
//# sourceMappingURL=store-BLuNqe1j.js.map