@iii-dev/helpers 0.21.8-next.1 → 0.21.8-next.3

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.
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_telemetry_system = require('../telemetry-system-Dd45rFx-.cjs');
2
+ const require_telemetry_system = require('../telemetry-system-BH119njX.cjs');
3
3
  let _opentelemetry_api_logs = require("@opentelemetry/api-logs");
4
4
  let _opentelemetry_api = require("@opentelemetry/api");
5
5
  let node_perf_hooks = require("node:perf_hooks");
@@ -1,4 +1,4 @@
1
- import { A as BaggageSpanProcessor, C as extractTraceparent, D as injectTraceparent, E as injectBaggage, O as removeBaggageEntry, S as extractContext, T as getBaggageEntry, _ as patchGlobalFetch, b as currentTraceId, c as withSpan, d as redactAndTruncate, f as resolveMaxBytesFromEnv, g as setCurrentSpanError, h as setCurrentSpanAttribute, k as setBaggageEntry, l as REDACTED_PLACEHOLDER, m as recordSpanEvent, n as flushOtel, o as initOtel, p as currentSpanIsRecording, r as getLogger, s as shutdownOtel, t as SeverityNumber, u as redact, v as unpatchGlobalFetch, w as getAllBaggage, x as extractBaggage, y as currentSpanId } from "../telemetry-system-AxDF-K2R.mjs";
1
+ import { A as BaggageSpanProcessor, C as extractTraceparent, D as injectTraceparent, E as injectBaggage, O as removeBaggageEntry, S as extractContext, T as getBaggageEntry, _ as patchGlobalFetch, b as currentTraceId, c as withSpan, d as redactAndTruncate, f as resolveMaxBytesFromEnv, g as setCurrentSpanError, h as setCurrentSpanAttribute, k as setBaggageEntry, l as REDACTED_PLACEHOLDER, m as recordSpanEvent, n as flushOtel, o as initOtel, p as currentSpanIsRecording, r as getLogger, s as shutdownOtel, t as SeverityNumber, u as redact, v as unpatchGlobalFetch, w as getAllBaggage, x as extractBaggage, y as currentSpanId } from "../telemetry-system-Pyz9irBj.mjs";
2
2
  import { SeverityNumber as SeverityNumber$1 } from "@opentelemetry/api-logs";
3
3
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
4
4
  import { monitorEventLoopDelay, performance } from "node:perf_hooks";
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_telemetry_system = require('../telemetry-system-Dd45rFx-.cjs');
2
+ const require_telemetry_system = require('../telemetry-system-BH119njX.cjs');
3
3
 
4
4
  exports.getMeter = require_telemetry_system.getMeter;
5
5
  exports.getTracer = require_telemetry_system.getTracer;
@@ -1,3 +1,3 @@
1
- import { a as getTracer, i as getMeter } from "../telemetry-system-AxDF-K2R.mjs";
1
+ import { a as getTracer, i as getMeter } from "../telemetry-system-Pyz9irBj.mjs";
2
2
 
3
3
  export { getMeter, getTracer };
@@ -101,7 +101,7 @@ var SharedEngineConnection = class SharedEngineConnection {
101
101
  this.connecting = true;
102
102
  this.state = "connecting";
103
103
  try {
104
- this.ws = new ws.WebSocket(this.wsUrl);
104
+ this.ws = new ws.WebSocket(this.wsUrl, { handshakeTimeout: 1e4 });
105
105
  this.ws.on("open", () => {
106
106
  this.connecting = false;
107
107
  this.state = "connected";
@@ -1336,4 +1336,4 @@ Object.defineProperty(exports, 'withSpan', {
1336
1336
  return withSpan;
1337
1337
  }
1338
1338
  });
1339
- //# sourceMappingURL=telemetry-system-Dd45rFx-.cjs.map
1339
+ //# sourceMappingURL=telemetry-system-BH119njX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry-system-BH119njX.cjs","names":["propagation","WebSocket","ExportResultCode","JsonTraceSerializer","ExportResultCode","JsonMetricsSerializer","ExportResultCode","JsonLogsSerializer","trace","context","propagation","SpanKind","context","SpanStatusCode","trace","SpanStatusCode","ATTR_SERVICE_NAME","Resource","NodeTracerProvider","BatchSpanProcessor","CompositePropagator","W3CTraceContextPropagator","W3CBaggagePropagator","trace","MeterProvider","PeriodicExportingMetricReader","LoggerProvider","BatchLogRecordProcessor","context","SpanKind","SpanStatusCode"],"sources":["../src/observability/telemetry-system/baggage-span-processor.ts","../src/observability/telemetry-system/types.ts","../src/observability/telemetry-system/connection.ts","../src/observability/telemetry-system/span-exporter.ts","../src/observability/telemetry-system/metrics-exporter.ts","../src/observability/telemetry-system/log-exporter.ts","../src/observability/telemetry-system/context.ts","../src/observability/telemetry-system/fetch-instrumentation.ts","../src/observability/telemetry-system/utils.ts","../src/observability/telemetry-system/span-ops.ts","../src/observability/telemetry-system/payload.ts","../src/observability/telemetry-system/index.ts"],"sourcesContent":["// Baggage -> span attribute processor.\n//\n// Copies EVERY baggage entry onto every span started in its scope,\n// unconditionally — the same contract as the upstream OTel contrib\n// BaggageSpanProcessor. There is deliberately no key filtering here: a\n// filtering policy baked into worker binaries has to be kept in lockstep\n// across every SDK language and every deployed worker, and a stale binary\n// silently drops newer keys. Which attributes *mean* something (e.g. the\n// `iii.tag.*` trace-tag namespace, `iii.session.*`) is a query-side\n// convention owned by the engine's traces API, where it can evolve without\n// touching workers.\n\nimport type { Context } from '@opentelemetry/api'\nimport { propagation } from '@opentelemetry/api'\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base'\n\n/**\n * OpenTelemetry span processor that copies OTel baggage entries onto each\n * started span as attributes.\n */\nexport class BaggageSpanProcessor implements SpanProcessor {\n onStart(span: Span, parentContext: Context): void {\n // NoOp guard: skip allocation when sampler drops the span.\n if (!span.isRecording()) {\n return\n }\n\n const baggage = propagation.getBaggage(parentContext)\n if (!baggage) {\n return\n }\n\n for (const [key, entry] of baggage.getAllEntries()) {\n span.setAttribute(key, entry.value)\n }\n }\n\n onEnd(_span: ReadableSpan): void {\n /* no-op */\n }\n\n async shutdown(): Promise<void> {\n /* no-op */\n }\n\n async forceFlush(): Promise<void> {\n /* no-op */\n }\n}\n","/**\n * Types, interfaces, and constants for the OpenTelemetry module.\n */\n\nimport type { Instrumentation } from '@opentelemetry/instrumentation'\n\n// Semantic convention constants for compatibility across versions\nexport const ATTR_SERVICE_VERSION = 'service.version'\nexport const ATTR_SERVICE_NAMESPACE = 'service.namespace'\nexport const ATTR_SERVICE_INSTANCE_ID = 'service.instance.id'\n\n/** Magic prefixes for binary frames over WebSocket */\nexport const PREFIX_TRACES = 'OTLP'\nexport const PREFIX_METRICS = 'MTRC'\nexport const PREFIX_LOGS = 'LOGS'\n\n/** Connection state for the shared WebSocket */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface ReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_RECONNECTION_CONFIG: ReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Configuration for OpenTelemetry initialization. */\nexport interface OtelConfig {\n /** Whether OpenTelemetry export is enabled. Defaults to true. Set to false or OTEL_ENABLED=false/0/no/off to disable. */\n enabled?: boolean\n /** The service name to report. Defaults to OTEL_SERVICE_NAME or \"iii-node\". */\n serviceName?: string\n /** The service version to report. Defaults to SERVICE_VERSION env var or \"unknown\". */\n serviceVersion?: string\n /** The service namespace to report. Defaults to SERVICE_NAMESPACE env var. */\n serviceNamespace?: string\n /** The service instance ID to report. Defaults to SERVICE_INSTANCE_ID env var or auto-generated UUID. */\n serviceInstanceId?: string\n /** III Engine WebSocket URL. Defaults to III_URL or \"ws://localhost:49134\". */\n engineWsUrl?: string\n /** OpenTelemetry instrumentations to register (e.g., PrismaInstrumentation). */\n instrumentations?: Instrumentation[]\n /** Whether OpenTelemetry metrics export is enabled. Defaults to true. Set to false or OTEL_METRICS_ENABLED=false/0/no/off to disable. */\n metricsEnabled?: boolean\n /** Metrics export interval in milliseconds. Defaults to 60000 (60 seconds). */\n metricsExportIntervalMs?: number\n /**\n * Span processor flush delay in milliseconds. Defaults to 100ms. This is how\n * long an ended span waits in the batch buffer before it is flushed to the\n * engine, the OpenTelemetry default of 5000ms is what makes traces appear\n * seconds after the action. Env override: OTEL_SPANS_FLUSH_INTERVAL_MS.\n */\n spansFlushIntervalMs?: number\n /** Log processor flush delay in milliseconds. Defaults to 100ms. Env override: OTEL_LOGS_FLUSH_INTERVAL_MS. */\n logsFlushIntervalMs?: number\n /** Maximum number of log records exported per batch. Defaults to 1. */\n logsBatchSize?: number\n /** Whether to auto-instrument globalThis.fetch calls. Defaults to true. Works on Node.js, Bun, and Deno. Set to false to disable. */\n fetchInstrumentationEnabled?: boolean\n /** Optional reconnection configuration for the WebSocket connection. */\n reconnectionConfig?: Partial<ReconnectionConfig>\n}\n\n/** Default configuration values for OpenTelemetry initialization. */\nexport const DEFAULT_OTEL_CONFIG = {\n enabled: true,\n serviceName: 'iii-node',\n serviceVersion: 'unknown',\n engineWsUrl: 'ws://localhost:49134',\n metricsEnabled: true,\n metricsExportIntervalMs: 60000,\n spansFlushIntervalMs: 100,\n logsFlushIntervalMs: 100,\n logsBatchSize: 1,\n fetchInstrumentationEnabled: true,\n} as const satisfies Partial<OtelConfig>\n\n/** Parse a boolean environment variable, recognizing 'false', '0', 'no', 'off' as false. */\nexport function parseBoolEnv(value: string | undefined, defaultValue: boolean): boolean {\n if (value === undefined) return defaultValue\n const lower = value.toLowerCase()\n return lower !== 'false' && lower !== '0' && lower !== 'no' && lower !== 'off'\n}\n","/**\n * Shared WebSocket connection for OpenTelemetry exporters.\n */\n\nimport { WebSocket } from 'ws'\nimport { type ConnectionState, type ReconnectionConfig, DEFAULT_RECONNECTION_CONFIG } from './types'\n\n/**\n * Shared WebSocket connection for all OTEL exporters (traces, metrics, logs).\n * Uses a single connection with message prefixes to identify signal type.\n */\nexport class SharedEngineConnection {\n private static readonly MAX_PENDING_MESSAGES = 1000\n private ws: WebSocket | null = null\n private wsUrl: string\n private connecting = false\n private shuttingDown = false\n private pendingMessages: Array<{ frame: Buffer; callback?: (err?: Error) => void }> = []\n private reconnectAttempt = 0\n private reconnectTimeout: NodeJS.Timeout | null = null\n private config: ReconnectionConfig\n private state: ConnectionState = 'disconnected'\n private onConnectedCallbacks: Array<() => void> = []\n private onFailedCallbacks: Array<() => void> = []\n\n constructor(wsUrl: string, config: Partial<ReconnectionConfig> = {}) {\n this.wsUrl = wsUrl\n this.config = { ...DEFAULT_RECONNECTION_CONFIG, ...config }\n this.connect()\n }\n\n private connect(): void {\n if (this.connecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {\n return\n }\n\n this.connecting = true\n this.state = 'connecting'\n\n try {\n // 10s handshake cap, parity with iii-sdk / Rust SDK (MOT-3857/MOT-3968)\n this.ws = new WebSocket(this.wsUrl, { handshakeTimeout: 10000 })\n\n this.ws.on('open', () => {\n this.connecting = false\n this.state = 'connected'\n console.log(`[OTel] Connected to engine at ${this.wsUrl}`)\n\n // Reset reconnection state\n if (this.reconnectAttempt > 0) {\n console.log('[OTel] Successfully reconnected')\n }\n this.reconnectAttempt = 0\n\n // Clear any pending reconnect timer to prevent race conditions\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // Flush pending messages\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n for (const { frame, callback } of pending) {\n this.ws?.send(frame, err => callback?.(err))\n }\n\n // Notify callbacks\n for (const cb of this.onConnectedCallbacks) {\n cb()\n }\n })\n\n this.ws.on('close', () => {\n this.connecting = false\n this.ws = null\n\n // Skip reconnection if we're shutting down intentionally\n if (this.shuttingDown) {\n this.state = 'disconnected'\n console.log('[OTel] Connection closed during shutdown')\n return\n }\n\n this.state = 'disconnected'\n console.log('[OTel] Disconnected from engine, will reconnect...')\n this.scheduleReconnect()\n })\n\n this.ws.on('error', err => {\n this.connecting = false\n\n // Skip error handling if we're shutting down intentionally\n if (this.shuttingDown) {\n return\n }\n\n console.error('[OTel] WebSocket error:', err.message)\n })\n } catch (err) {\n this.connecting = false\n console.error('[OTel] Connection failed:', err)\n this.scheduleReconnect()\n }\n }\n\n private scheduleReconnect(): void {\n if (this.config.maxRetries !== -1 && this.reconnectAttempt >= this.config.maxRetries) {\n this.state = 'failed'\n console.error(`[OTel] Max retries (${this.config.maxRetries}) reached, giving up`)\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const failedError = new Error('Connection failed after max retries')\n for (const { callback } of pending) {\n callback?.(failedError)\n }\n\n // Notify failed callbacks so exporters can drain their own queues\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n return\n }\n\n if (this.reconnectTimeout) {\n return // Already scheduled\n }\n\n const exponentialDelay =\n this.config.initialDelayMs * this.config.backoffMultiplier ** this.reconnectAttempt\n const cappedDelay = Math.min(exponentialDelay, this.config.maxDelayMs)\n const jitter = cappedDelay * this.config.jitterFactor * (2 * Math.random() - 1)\n const delay = Math.max(0, Math.floor(cappedDelay + jitter))\n\n this.state = 'reconnecting'\n console.log(`[OTel] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt + 1})...`)\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null\n this.reconnectAttempt++\n this.connect()\n }, delay)\n }\n\n /**\n * Send a message with a signal prefix.\n */\n send(prefix: string, data: Uint8Array, callback?: (err?: Error) => void): void {\n const prefixBytes = Buffer.from(prefix, 'utf-8')\n const frame = Buffer.concat([prefixBytes, Buffer.from(data)])\n\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(frame, callback)\n } else {\n // Queue for later with bounded size to prevent memory exhaustion\n if (this.pendingMessages.length >= SharedEngineConnection.MAX_PENDING_MESSAGES) {\n console.warn('[OTel] Pending message queue full, dropping oldest message')\n const dropped = this.pendingMessages.shift()\n dropped?.callback?.(new Error('Message dropped due to queue overflow'))\n }\n this.pendingMessages.push({ frame, callback })\n this.connect()\n }\n }\n\n /**\n * Register a callback to be called when connected.\n */\n onConnected(callback: () => void): void {\n this.onConnectedCallbacks.push(callback)\n if (this.state === 'connected') {\n callback()\n }\n }\n\n /**\n * Register a callback to be called when the connection enters the failed\n * terminal state (max retries reached). Exporters use this to drain their\n * own pending queues so in-flight forceFlush() calls do not hang.\n */\n onFailed(callback: () => void): void {\n this.onFailedCallbacks.push(callback)\n if (this.state === 'failed') {\n try {\n callback()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n\n /**\n * Get the current connection state.\n */\n getState(): ConnectionState {\n return this.state\n }\n\n /**\n * Whether the connection is shutting down. While shutting down, exporters\n * fail-fast instead of queueing when there is no live connection, so a final\n * forceFlush() can't hang waiting for a reconnect that will never happen.\n */\n isShuttingDown(): boolean {\n return this.shuttingDown\n }\n\n /**\n * Begin shutdown: stop reconnecting and stop accepting new queued exports,\n * while leaving an open connection in place so buffered telemetry can still\n * be flushed. Call before flushing, then call shutdown() to close fully.\n */\n beginShutdown(): void {\n if (this.shuttingDown) {\n return\n }\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // With no live connection there's nothing to flush to, so fail queued work\n // now instead of leaving callbacks unresolved for the flush below to wait on\n if (this.state !== 'connected') {\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n }\n\n /**\n * Shutdown the connection.\n */\n async shutdown(): Promise<void> {\n // Set shutdown flag to prevent reconnection attempts\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n this.onConnectedCallbacks = []\n this.onFailedCallbacks = []\n this.state = 'disconnected'\n }\n}\n","/**\n * Span exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'\nimport { JsonTraceSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_TRACES } from './types'\n\n/**\n * Span exporter using the shared WebSocket connection.\n */\nexport class EngineSpanExporter implements SpanExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n spans: ReadableSpan[]\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { spans, resultCallback } of pending) {\n this.sendExport(spans, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued spans')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(spans: ReadableSpan[], resultCallback?: (result: ExportResult) => void): void {\n try {\n const serialized = JsonTraceSerializer.serializeRequest(spans)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_TRACES, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send spans:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting spans:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping spans`),\n })\n return\n }\n if (this.pendingExports.length >= EngineSpanExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Spans export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ spans, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(spans, resultCallback)\n }\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(spans, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op, spans are sent immediately\n }\n}\n","/**\n * Metrics exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics'\nimport { JsonMetricsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_METRICS } from './types'\n\n/**\n * Metrics exporter using the shared WebSocket connection.\n */\nexport class EngineMetricsExporter implements PushMetricExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n metrics: ResourceMetrics\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { metrics, resultCallback } of pending) {\n this.sendExport(metrics, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued metrics')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(\n metricsData: ResourceMetrics,\n resultCallback?: (result: ExportResult) => void,\n ): void {\n try {\n const serialized = JsonMetricsSerializer.serializeRequest(metricsData)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_METRICS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send metrics:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting metrics:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(\n metricsData: ResourceMetrics,\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping metrics`),\n })\n return\n }\n if (this.pendingExports.length >= EngineMetricsExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Metrics export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ metrics: metricsData, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(metricsData, resultCallback)\n }\n\n export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {\n this.doExport(metrics, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op\n }\n}\n","/**\n * Log exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { LogRecordExporter, ReadableLogRecord } from '@opentelemetry/sdk-logs'\nimport { JsonLogsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_LOGS } from './types'\n\n/**\n * Log exporter using the shared WebSocket connection.\n */\nexport class EngineLogExporter implements LogRecordExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n logs: ReadableLogRecord[]\n callback: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { logs, callback } of pending) {\n this.doExport(logs, callback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued logs')\n for (const { callback } of pending) {\n callback({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private doExport(\n logs: ReadableLogRecord[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping logs`),\n })\n return\n }\n if (this.pendingExports.length >= EngineLogExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.callback({\n code: ExportResultCode.FAILED,\n error: new Error('Logs export queue full'),\n })\n console.warn('[OTel] Logs export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ logs, callback: resultCallback })\n return\n }\n\n try {\n const serialized = JsonLogsSerializer.serializeRequest(logs)\n if (!serialized) {\n resultCallback({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_LOGS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send logs:', err.message)\n resultCallback({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting logs:', err)\n resultCallback({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(logs, resultCallback)\n }\n\n async forceFlush(): Promise<void> {}\n\n async shutdown(): Promise<void> {\n for (const { callback } of this.pendingExports) {\n callback({ code: ExportResultCode.FAILED, error: new Error('Exporter shutdown') })\n }\n this.pendingExports = []\n }\n}\n","/**\n * Trace context and baggage propagation utilities.\n */\n\nimport { trace, context, propagation, type Context } from '@opentelemetry/api'\n\n/**\n * Extract the current trace ID from the active span context.\n */\nexport function currentTraceId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.traceId && spanContext.traceId !== '00000000000000000000000000000000') {\n return spanContext.traceId\n }\n }\n return undefined\n}\n\n/**\n * Extract the current span ID from the active span context.\n */\nexport function currentSpanId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.spanId && spanContext.spanId !== '0000000000000000') {\n return spanContext.spanId\n }\n }\n return undefined\n}\n\n/**\n * Inject the current trace context into a W3C traceparent header string.\n */\nexport function injectTraceparent(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.traceparent\n}\n\n/**\n * Extract a trace context from a W3C traceparent header string.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n */\nexport function extractTraceparent(traceparent: string): Context {\n const carrier: Record<string, string> = { traceparent }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Inject the current baggage into a W3C baggage header string.\n */\nexport function injectBaggage(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.baggage\n}\n\n/**\n * Extract baggage from a W3C baggage header string.\n *\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractBaggage(baggage: string): Context {\n const carrier: Record<string, string> = { baggage }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Extract both trace context and baggage from their respective headers.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractContext(traceparent?: string, baggage?: string): Context {\n const carrier: Record<string, string> = {}\n if (traceparent) {\n carrier.traceparent = traceparent\n }\n if (baggage) {\n carrier.baggage = baggage\n }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Get a baggage entry from the current context.\n *\n * @param key - Baggage entry key to read.\n */\nexport function getBaggageEntry(key: string): string | undefined {\n const bag = propagation.getBaggage(context.active())\n return bag?.getEntry(key)?.value\n}\n\n/**\n * Set a baggage entry in the current context.\n *\n * @param key - Baggage entry key to set.\n * @param value - Baggage entry value to set.\n */\nexport function setBaggageEntry(key: string, value: string): Context {\n let bag = propagation.getBaggage(context.active()) ?? propagation.createBaggage()\n bag = bag.setEntry(key, { value })\n return propagation.setBaggage(context.active(), bag)\n}\n\n/**\n * Remove a baggage entry from the current context.\n *\n * @param key - Baggage entry key to remove.\n */\nexport function removeBaggageEntry(key: string): Context {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return context.active()\n }\n const newBag = bag.removeEntry(key)\n return propagation.setBaggage(context.active(), newBag)\n}\n\n/**\n * Get all baggage entries from the current context.\n */\nexport function getAllBaggage(): Record<string, string> {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return {}\n }\n const entries: Record<string, string> = {}\n for (const [key, entry] of bag.getAllEntries()) {\n entries[key] = entry.value\n }\n return entries\n}\n","/**\n * Global fetch auto-instrumentation for the III Node SDK.\n *\n * Patches globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n * Works on all runtimes (Bun, Node.js, Deno) unlike UndiciInstrumentation\n * which only works when fetch is backed by Node.js's undici.\n */\n\nimport { type Tracer, SpanKind, SpanStatusCode, context, propagation } from '@opentelemetry/api'\n\nconst textEncoder = new TextEncoder()\n\nfunction getBodyByteSize(body: unknown): number | undefined {\n if (body == null) return undefined\n if (typeof body === 'string') return textEncoder.encode(body).byteLength\n if (body instanceof ArrayBuffer) return body.byteLength\n if (ArrayBuffer.isView(body)) return body.byteLength\n if (body instanceof Blob) return body.size\n if (body instanceof URLSearchParams) return new TextEncoder().encode(body.toString()).byteLength\n return undefined\n}\n\nconst SAFE_REQUEST_HEADERS = ['content-type', 'accept'] as const\nconst SAFE_RESPONSE_HEADERS = ['content-type'] as const\n\nlet originalFetch: typeof globalThis.fetch | null = null\n\n/**\n * Substring patterns from `OTEL_FETCH_IGNORE_URLS` (comma-separated). A fetch\n * whose URL contains any pattern is executed WITHOUT creating a span, use it\n * to drop noisy/high-frequency calls (health checks, polling, internal\n * endpoints) that would otherwise flood traces.\n */\nconst FETCH_IGNORE_URL_PATTERNS: string[] = (process.env.OTEL_FETCH_IGNORE_URLS ?? '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n\nfunction shouldIgnoreFetchUrl(url: string): boolean {\n return FETCH_IGNORE_URL_PATTERNS.some(pattern => url.includes(pattern))\n}\n\n/**\n * Patch globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n *\n * @param tracer - Tracer used to create the client span for each request.\n */\nexport function patchGlobalFetch(tracer: Tracer): void {\n if (originalFetch) return\n\n originalFetch = globalThis.fetch\n const capturedFetch = originalFetch\n\n globalThis.fetch = async (\n input: string | URL | Request,\n init?: RequestInit,\n ): Promise<Response> => {\n const url = input instanceof Request ? input.url : String(input)\n\n // Skip tracing entirely for ignored URLs (no span, no context injection).\n if (shouldIgnoreFetchUrl(url)) {\n return capturedFetch(input, init)\n }\n\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n\n let host: string | undefined\n let scheme: string | undefined\n let path: string | undefined\n let port: number | undefined\n let query: string | undefined\n try {\n const parsed = new URL(url)\n host = parsed.hostname\n scheme = parsed.protocol.replace(':', '')\n path = parsed.pathname\n port = parsed.port ? parseInt(parsed.port, 10) : undefined\n query = parsed.search ? parsed.search.slice(1) : undefined\n } catch {\n // relative URL or invalid, skip host/scheme/path attributes\n }\n\n const spanAttributes: Record<string, string | number> = {\n 'http.request.method': method,\n 'url.full': url,\n }\n if (host) spanAttributes['server.address'] = host\n if (scheme) {\n spanAttributes['url.scheme'] = scheme\n spanAttributes['network.protocol.name'] = 'http'\n }\n if (path) spanAttributes['url.path'] = path\n if (port) spanAttributes['server.port'] = port\n if (query) spanAttributes['url.query'] = query\n\n const spanName = path ? `${method} ${path}` : method\n\n return tracer.startActiveSpan(\n spanName,\n { kind: SpanKind.CLIENT, attributes: spanAttributes },\n context.active(),\n async span => {\n try {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n for (const [key, value] of Object.entries(carrier)) {\n headers.set(key, value)\n }\n\n for (const name of SAFE_REQUEST_HEADERS) {\n const value = headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.request.header.${name}`, value)\n }\n }\n\n const requestBody = init?.body ?? (input instanceof Request ? input.body : undefined)\n const requestBodySize = getBodyByteSize(requestBody)\n if (requestBodySize !== undefined) {\n span.setAttribute('http.request.body.size', requestBodySize)\n }\n\n const response = await capturedFetch(input, { ...init, headers })\n\n span.setAttribute('http.response.status_code', response.status)\n\n const contentLength = response.headers.get('content-length')\n if (contentLength !== null) {\n const size = parseInt(contentLength, 10)\n if (!Number.isNaN(size)) {\n span.setAttribute('http.response.body.size', size)\n }\n }\n\n for (const name of SAFE_RESPONSE_HEADERS) {\n const value = response.headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.response.header.${name}`, value)\n }\n }\n\n if (response.status >= 400) {\n span.setAttribute('error.type', String(response.status))\n span.setStatus({ code: SpanStatusCode.ERROR })\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n return response\n } catch (error) {\n span.setAttribute('error.type', (error as Error).name ?? 'Error')\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n },\n )\n }\n}\n\n/**\n * Restore globalThis.fetch to its original implementation.\n */\nexport function unpatchGlobalFetch(): void {\n if (originalFetch) {\n globalThis.fetch = originalFetch\n originalFetch = null\n }\n}\n","/**\n * Parse a numeric environment variable with optional minimum bound.\n *\n * An empty or whitespace-only string is treated as unset: `Number('')` is 0,\n * so without this check a variable set-but-blank (common in .env files) would\n * silently resolve to 0 instead of falling through to the default.\n */\nexport function parseNumberEnv(value: string | undefined, minimum: number = 0): number | undefined {\n if (value === undefined || value.trim() === '') return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed < minimum) return undefined\n return parsed\n}\n\n/**\n * Parse an integer environment variable with optional minimum bound.\n */\nexport function parseIntegerEnv(\n value: string | undefined,\n minimum: number = 0,\n): number | undefined {\n const parsed = parseNumberEnv(value, minimum)\n if (parsed === undefined || !Number.isInteger(parsed)) return undefined\n return parsed\n}\n\n/**\n * Resolve a batch-processor flush delay: explicit config wins, then the\n * III-specific env var, then the III default.\n *\n * III SDKs deliberately expose a single OTEL_*_FLUSH_INTERVAL_MS knob and do\n * NOT honor the standard OTel OTEL_BSP_SCHEDULE_DELAY / OTEL_BLRP_SCHEDULE_DELAY\n * vars, for cross-SDK consistency (the Node, Python, and Rust SDKs all resolve\n * the same way). Passing an explicit `scheduledDelayMillis` to the processor\n * already makes the OTel SDK ignore those standard vars regardless.\n */\nexport function resolveFlushIntervalMs(\n configValue: number | undefined,\n envValue: string | undefined,\n defaultValue: number,\n): number {\n return configValue ?? parseNumberEnv(envValue, 0) ?? defaultValue\n}\n","/** High-level span operations so consumers don't need `@opentelemetry/api`. */\n\nimport { SpanStatusCode, trace, type AttributeValue, type Attributes } from '@opentelemetry/api'\n\n/** Returns `false` when there is no active span or the sampler dropped it. */\nexport function currentSpanIsRecording(): boolean {\n const span = trace.getActiveSpan()\n return span ? span.isRecording() : false\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param key - Attribute key to set on the active span.\n * @param value - Attribute value to set.\n */\nexport function setCurrentSpanAttribute(key: string, value: AttributeValue): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.setAttribute(key, value)\n}\n\n/**\n * No-op when there is no active span.\n *\n * @param message - Error message to set as the span's error status.\n */\nexport function setCurrentSpanError(message: string): void {\n const span = trace.getActiveSpan()\n if (!span) return\n span.setStatus({ code: SpanStatusCode.ERROR, message })\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param name - Name of the event to add to the active span.\n * @param attrs - Optional attributes to attach to the event.\n */\nexport function recordSpanEvent(name: string, attrs?: Attributes): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.addEvent(name, attrs)\n}\n","/** Payload redaction + truncation for invocation event capture. */\n\nexport const REDACTED_PLACEHOLDER = '[REDACTED]'\nconst TRUNCATION_MARKER = '...\"[TRUNCATED]\"'\n\n/**\n * Resolve the payload byte cap from the environment, returning undefined when\n * unset.\n */\nexport function resolveMaxBytesFromEnv(): number | null {\n const raw = process.env.III_TRACE_PAYLOAD_MAX_BYTES\n if (raw === undefined) return null\n const trimmed = raw.trim()\n if (trimmed === '' || trimmed.toLowerCase() === 'unlimited') return null\n // parseInt accepts partial parses like \"8192mb\" → 8192; Python int()\n // and Rust parse::<usize>() reject those. Match the strict semantics.\n if (!/^\\d+$/.test(trimmed)) return null\n const parsed = Number(trimmed)\n if (parsed <= 0) return null\n return parsed\n}\n\nconst SENSITIVE_FRAGMENTS = [\n 'api_key',\n 'apikey',\n 'api-key',\n 'password',\n 'secret',\n 'credential',\n 'authorization',\n 'auth_token',\n 'access_token',\n 'refresh_token',\n 'bearer',\n 'private_key',\n 'client_secret',\n]\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase()\n if (SENSITIVE_FRAGMENTS.some((fragment) => lower.includes(fragment))) return true\n // `token` alone is too common a substring; require whole-key or suffix match.\n return lower === 'token' || lower.endsWith('_token') || lower.endsWith('-token')\n}\n\n/**\n * Recursively redact values of sensitive keys. Returns a new value.\n *\n * @param value - The value to recursively redact.\n */\nexport function redact(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (Array.isArray(value)) return value.map(redact)\n if (typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = isSensitiveKey(k) ? REDACTED_PLACEHOLDER : redact(v)\n }\n return out\n }\n return value\n}\n\n/**\n * Redact then serialize to JSON, optionally capped at `maxBytes`.\n *\n * @param value - The value to redact and serialize.\n * @param maxBytes - Maximum serialized size in bytes; null leaves it uncapped.\n */\nexport function redactAndTruncate(\n value: unknown,\n maxBytes: number | null = null,\n): { json: string; truncated: boolean } {\n const redacted = redact(value)\n let serialized: string\n try {\n serialized = JSON.stringify(redacted) ?? 'null'\n } catch {\n serialized = 'null'\n }\n\n if (maxBytes === null || maxBytes === undefined || maxBytes <= 0) {\n return { json: serialized, truncated: false }\n }\n\n const byteLen = Buffer.byteLength(serialized, 'utf8')\n if (byteLen <= maxBytes) {\n return { json: serialized, truncated: false }\n }\n\n const markerLen = Buffer.byteLength(TRUNCATION_MARKER, 'utf8')\n // When maxBytes is smaller than the marker itself, emit only a\n // truncated marker so the result never exceeds the cap.\n if (maxBytes <= markerLen) {\n return { json: TRUNCATION_MARKER.slice(0, maxBytes), truncated: true }\n }\n\n const cap = maxBytes - markerLen\n const buf = Buffer.from(serialized, 'utf8')\n let cut = Math.min(cap, buf.length)\n // Walk back to a UTF-8 boundary so we don't emit half-codepoints.\n while (cut > 0 && (buf[cut] & 0xc0) === 0x80) {\n cut -= 1\n }\n const truncated = buf.subarray(0, cut).toString('utf8') + TRUNCATION_MARKER\n return { json: truncated, truncated: true }\n}\n","/**\n * OpenTelemetry initialization for the III Node SDK.\n *\n * This module provides trace, metrics, and log export to the III Engine\n * via a shared WebSocket connection using OTLP JSON format.\n */\n\nimport { Resource } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'\nimport { randomUUID } from 'node:crypto'\nimport {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n metrics,\n type Span,\n type Context,\n type Tracer,\n type Meter,\n} from '@opentelemetry/api'\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'\nimport { BaggageSpanProcessor } from './baggage-span-processor'\nimport { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'\nimport { registerInstrumentations } from '@opentelemetry/instrumentation'\nimport { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'\nimport { type Logger, SeverityNumber } from '@opentelemetry/api-logs'\n\nimport {\n type OtelConfig,\n DEFAULT_OTEL_CONFIG,\n parseBoolEnv,\n ATTR_SERVICE_VERSION,\n ATTR_SERVICE_NAMESPACE,\n ATTR_SERVICE_INSTANCE_ID,\n} from './types'\nimport { SharedEngineConnection } from './connection'\nimport { EngineSpanExporter, EngineMetricsExporter, EngineLogExporter } from './exporters'\nimport { extractTraceparent } from './context'\nimport { patchGlobalFetch, unpatchGlobalFetch } from './fetch-instrumentation'\nimport { parseIntegerEnv, resolveFlushIntervalMs } from './utils'\n\n// Re-export everything from submodules\nexport * from './types'\nexport * from './context'\nexport { BaggageSpanProcessor } from './baggage-span-processor'\nexport {\n currentSpanIsRecording,\n recordSpanEvent,\n setCurrentSpanAttribute,\n setCurrentSpanError,\n} from './span-ops'\nexport {\n REDACTED_PLACEHOLDER,\n redact,\n redactAndTruncate,\n resolveMaxBytesFromEnv,\n} from './payload'\n\n/**\n * Normalize an engine WebSocket URL into the dedicated OTEL endpoint.\n * The engine exposes `/otel` for telemetry-only WS connections; routing\n * there keeps this socket out of the worker registry (otherwise it shows\n * up as a ghost null-metadata worker).\n */\nfunction appendOtelPath(base: string): string {\n const url = new URL(base)\n const path = url.pathname.replace(/\\/+$/, '')\n url.pathname = path.endsWith('/otel') ? path : `${path}/otel`\n return url.toString()\n}\n\n// Module-level state\nlet sharedConnection: SharedEngineConnection | null = null\nlet tracerProvider: NodeTracerProvider | null = null\nlet meterProvider: MeterProvider | null = null\nlet loggerProvider: LoggerProvider | null = null\nlet tracer: Tracer | null = null\nlet meter: Meter | null = null\nlet logger: Logger | null = null\nlet serviceName: string = 'iii-node-iii'\n\n/**\n * Initialize OpenTelemetry with the given configuration.\n * This should be called once at application startup.\n *\n * @param config - OpenTelemetry configuration; env vars fill in unset fields.\n */\nexport function initOtel(config: OtelConfig = {}): void {\n const enabled = config.enabled ?? parseBoolEnv(process.env.OTEL_ENABLED, DEFAULT_OTEL_CONFIG.enabled)\n\n if (!enabled) {\n console.debug(\n '[OTel] OpenTelemetry is disabled. To enable, remove OTEL_ENABLED=false or set enabled: true in config.',\n )\n return\n }\n\n // Configure service identity\n serviceName = config.serviceName ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_OTEL_CONFIG.serviceName\n const serviceVersion = config.serviceVersion ?? process.env.SERVICE_VERSION ?? DEFAULT_OTEL_CONFIG.serviceVersion\n const serviceNamespace = config.serviceNamespace ?? process.env.SERVICE_NAMESPACE\n const serviceInstanceId = config.serviceInstanceId ?? process.env.SERVICE_INSTANCE_ID ?? randomUUID()\n const engineWsUrl = config.engineWsUrl ?? process.env.III_URL ?? DEFAULT_OTEL_CONFIG.engineWsUrl\n\n // Build resource attributes\n const resourceAttributes: Record<string, string> = {\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n [ATTR_SERVICE_INSTANCE_ID]: serviceInstanceId,\n }\n if (serviceNamespace) {\n resourceAttributes[ATTR_SERVICE_NAMESPACE] = serviceNamespace\n }\n const resource = new Resource(resourceAttributes)\n\n // Create shared WebSocket connection.\n // OTEL always connects to the engine's dedicated `/otel` endpoint so\n // the telemetry socket doesn't get registered in `worker_registry` as\n // a ghost null-metadata worker alongside the real worker.\n sharedConnection = new SharedEngineConnection(appendOtelPath(engineWsUrl), config.reconnectionConfig)\n\n // BaggageSpanProcessor must register first: onStart fires in\n // registration order, so baggage entries are materialized as span\n // attributes before the batch exporter reads them.\n const spanExporter = new EngineSpanExporter(sharedConnection)\n // Without an explicit scheduledDelayMillis, BatchSpanProcessor inherits the\n // OpenTelemetry default of 5000ms, so an ended span sits in the buffer up to\n // 5s before it is flushed to the engine, the dominant reason traces show up\n // seconds after the action that produced them. Mirror the logs path\n // (BatchLogRecordProcessor below) with a small flush delay. maxExportBatchSize\n // stays at the OTel default so a burst of spans from one turn still coalesces\n // into a single frame rather than one frame per span.\n const spansScheduledDelayMillis = resolveFlushIntervalMs(\n config.spansFlushIntervalMs,\n process.env.OTEL_SPANS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.spansFlushIntervalMs,\n )\n tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [\n new BaggageSpanProcessor(),\n new BatchSpanProcessor(spanExporter, { scheduledDelayMillis: spansScheduledDelayMillis }),\n ],\n })\n\n // Register W3C Trace Context and Baggage propagators\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n }),\n )\n\n tracerProvider.register()\n tracer = trace.getTracer(serviceName)\n\n console.debug(`[OTel] Traces initialized: engine=${engineWsUrl}, service=${serviceName}`)\n\n // Initialize metrics (enabled by default, opt-out via config or env)\n const metricsEnabled =\n config.metricsEnabled ?? parseBoolEnv(process.env.OTEL_METRICS_ENABLED, DEFAULT_OTEL_CONFIG.metricsEnabled)\n\n if (metricsEnabled) {\n const metricsExporter = new EngineMetricsExporter(sharedConnection)\n const exportIntervalMs = config.metricsExportIntervalMs ?? DEFAULT_OTEL_CONFIG.metricsExportIntervalMs\n\n const metricReader = new PeriodicExportingMetricReader({\n exporter: metricsExporter,\n exportIntervalMillis: exportIntervalMs,\n })\n\n meterProvider = new MeterProvider({\n resource,\n readers: [metricReader],\n })\n\n metrics.setGlobalMeterProvider(meterProvider)\n meter = meterProvider.getMeter(serviceName)\n\n console.debug(`[OTel] Metrics initialized: interval=${exportIntervalMs}ms`)\n }\n\n // Register user-provided instrumentations AFTER providers are set up\n const instrumentations = [...(config.instrumentations ?? [])]\n if (instrumentations.length > 0) {\n registerInstrumentations({\n instrumentations,\n tracerProvider,\n meterProvider: meterProvider ?? undefined,\n })\n console.debug(`[OTel] Instrumentations registered: ${instrumentations.length} total`)\n }\n\n // Patch global fetch for runtime-agnostic HTTP client tracing (works on Bun, Node.js, Deno)\n const fetchEnabled = config.fetchInstrumentationEnabled ?? DEFAULT_OTEL_CONFIG.fetchInstrumentationEnabled\n\n if (fetchEnabled) {\n patchGlobalFetch(tracer)\n console.debug('[OTel] Global fetch instrumentation enabled')\n }\n\n // Initialize logs (always enabled when OTEL is enabled)\n const logExporter = new EngineLogExporter(sharedConnection)\n const logsScheduledDelayMillis = resolveFlushIntervalMs(\n config.logsFlushIntervalMs,\n process.env.OTEL_LOGS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.logsFlushIntervalMs,\n )\n const logsMaxExportBatchSize =\n config.logsBatchSize ?? parseIntegerEnv(process.env.OTEL_LOGS_BATCH_SIZE, 1) ?? DEFAULT_OTEL_CONFIG.logsBatchSize\n\n loggerProvider = new LoggerProvider({ resource })\n loggerProvider.addLogRecordProcessor(\n new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: logsScheduledDelayMillis,\n maxExportBatchSize: logsMaxExportBatchSize,\n }),\n )\n logger = loggerProvider.getLogger(serviceName)\n\n console.debug(`[OTel] Logs initialized: delay=${logsScheduledDelayMillis}ms, batch=${logsMaxExportBatchSize}`)\n}\n\n/**\n * Shut down OpenTelemetry, best-effort flushing any pending data before\n * teardown.\n */\nexport async function shutdownOtel(): Promise<void> {\n // Stop reconnecting/queuing before flushing so a final forceFlush() can't hang on a dead engine\n sharedConnection?.beginShutdown()\n\n // Flushing is best-effort on shutdown: when the engine is gone the exporters\n // fail their pending exports, which rejects forceFlush()/shutdown(). Swallow\n // those so a dropped final flush can't crash or block teardown.\n const settle = (p: Promise<unknown>) => p.catch(() => {})\n\n if (tracerProvider) {\n await settle(tracerProvider.forceFlush())\n await settle(tracerProvider.shutdown())\n tracerProvider = null\n }\n\n if (meterProvider) {\n await settle(meterProvider.forceFlush())\n await settle(meterProvider.shutdown())\n meterProvider = null\n }\n\n if (loggerProvider) {\n await settle(loggerProvider.forceFlush())\n await settle(loggerProvider.shutdown())\n loggerProvider = null\n }\n\n if (sharedConnection) {\n await sharedConnection.shutdown()\n sharedConnection = null\n }\n\n unpatchGlobalFetch()\n\n tracer = null\n meter = null\n logger = null\n}\n\n/**\n * Force-flush all OTel providers without tearing them down.\n *\n * Counterpart to {@link shutdownOtel}. Use before short-lived process exits\n * where you want pending spans/metrics/logs delivered but plan to keep using\n * OTel afterwards.\n */\nexport async function flushOtel(): Promise<void> {\n await Promise.all(\n [\n tracerProvider?.forceFlush(),\n meterProvider?.forceFlush(),\n loggerProvider?.forceFlush(),\n ].filter(Boolean),\n )\n}\n\n/**\n * Get the OpenTelemetry tracer instance.\n */\nexport function getTracer(): Tracer | null {\n return tracer\n}\n\n/**\n * Get the OpenTelemetry meter instance.\n */\nexport function getMeter(): Meter | null {\n return meter\n}\n\n/**\n * Get the OpenTelemetry logger instance.\n */\nexport function getLogger(): Logger | null {\n return logger\n}\n\n/**\n * Start a new span with the given name and run the callback within it.\n *\n * @param name - Name of the span to create.\n * @param options - Span options: `kind` sets the span kind, `traceparent` sets the parent context from a W3C traceparent header.\n * @param fn - Callback run inside the active span; its result is returned.\n */\nexport async function withSpan<T>(\n name: string,\n options: { kind?: SpanKind; traceparent?: string },\n fn: (span: Span) => Promise<T>,\n): Promise<T> {\n if (!tracer) {\n // Execute without span context when tracer is not initialized\n // Provide a no-op span to avoid runtime errors if fn calls span methods\n const noopSpan: Span = {\n spanContext: () => ({ traceId: '', spanId: '', traceFlags: 0 }),\n setAttribute: () => noopSpan,\n setAttributes: () => noopSpan,\n addEvent: () => noopSpan,\n addLink: () => noopSpan,\n setStatus: () => noopSpan,\n updateName: () => noopSpan,\n end: () => {},\n isRecording: () => false,\n recordException: () => {},\n addLinks: () => noopSpan,\n }\n return fn(noopSpan)\n }\n\n const parentContext = options.traceparent ? extractTraceparent(options.traceparent) : context.active()\n\n return tracer.startActiveSpan(name, { kind: options.kind ?? SpanKind.INTERNAL }, parentContext, async (span) => {\n try {\n const result = await fn(span)\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (error) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n// Re-export OTEL types for convenience\nexport { SpanKind, SpanStatusCode, SeverityNumber, type Span, type Context, type Tracer, type Meter, type Logger as OtelApiLogger }\n"],"mappings":"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"}
@@ -101,7 +101,7 @@ var SharedEngineConnection = class SharedEngineConnection {
101
101
  this.connecting = true;
102
102
  this.state = "connecting";
103
103
  try {
104
- this.ws = new WebSocket(this.wsUrl);
104
+ this.ws = new WebSocket(this.wsUrl, { handshakeTimeout: 1e4 });
105
105
  this.ws.on("open", () => {
106
106
  this.connecting = false;
107
107
  this.state = "connected";
@@ -1163,4 +1163,4 @@ async function withSpan(name, options, fn) {
1163
1163
 
1164
1164
  //#endregion
1165
1165
  export { BaggageSpanProcessor as A, extractTraceparent as C, injectTraceparent as D, injectBaggage as E, removeBaggageEntry as O, extractContext as S, getBaggageEntry as T, patchGlobalFetch as _, getTracer as a, currentTraceId as b, withSpan as c, redactAndTruncate as d, resolveMaxBytesFromEnv as f, setCurrentSpanError as g, setCurrentSpanAttribute as h, getMeter as i, setBaggageEntry as k, REDACTED_PLACEHOLDER as l, recordSpanEvent as m, flushOtel as n, initOtel as o, currentSpanIsRecording as p, getLogger as r, shutdownOtel as s, SeverityNumber$1 as t, redact as u, unpatchGlobalFetch as v, getAllBaggage as w, extractBaggage as x, currentSpanId as y };
1166
- //# sourceMappingURL=telemetry-system-AxDF-K2R.mjs.map
1166
+ //# sourceMappingURL=telemetry-system-Pyz9irBj.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry-system-Pyz9irBj.mjs","names":["SpanKind","SpanStatusCode"],"sources":["../src/observability/telemetry-system/baggage-span-processor.ts","../src/observability/telemetry-system/types.ts","../src/observability/telemetry-system/connection.ts","../src/observability/telemetry-system/span-exporter.ts","../src/observability/telemetry-system/metrics-exporter.ts","../src/observability/telemetry-system/log-exporter.ts","../src/observability/telemetry-system/context.ts","../src/observability/telemetry-system/fetch-instrumentation.ts","../src/observability/telemetry-system/utils.ts","../src/observability/telemetry-system/span-ops.ts","../src/observability/telemetry-system/payload.ts","../src/observability/telemetry-system/index.ts"],"sourcesContent":["// Baggage -> span attribute processor.\n//\n// Copies EVERY baggage entry onto every span started in its scope,\n// unconditionally — the same contract as the upstream OTel contrib\n// BaggageSpanProcessor. There is deliberately no key filtering here: a\n// filtering policy baked into worker binaries has to be kept in lockstep\n// across every SDK language and every deployed worker, and a stale binary\n// silently drops newer keys. Which attributes *mean* something (e.g. the\n// `iii.tag.*` trace-tag namespace, `iii.session.*`) is a query-side\n// convention owned by the engine's traces API, where it can evolve without\n// touching workers.\n\nimport type { Context } from '@opentelemetry/api'\nimport { propagation } from '@opentelemetry/api'\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base'\n\n/**\n * OpenTelemetry span processor that copies OTel baggage entries onto each\n * started span as attributes.\n */\nexport class BaggageSpanProcessor implements SpanProcessor {\n onStart(span: Span, parentContext: Context): void {\n // NoOp guard: skip allocation when sampler drops the span.\n if (!span.isRecording()) {\n return\n }\n\n const baggage = propagation.getBaggage(parentContext)\n if (!baggage) {\n return\n }\n\n for (const [key, entry] of baggage.getAllEntries()) {\n span.setAttribute(key, entry.value)\n }\n }\n\n onEnd(_span: ReadableSpan): void {\n /* no-op */\n }\n\n async shutdown(): Promise<void> {\n /* no-op */\n }\n\n async forceFlush(): Promise<void> {\n /* no-op */\n }\n}\n","/**\n * Types, interfaces, and constants for the OpenTelemetry module.\n */\n\nimport type { Instrumentation } from '@opentelemetry/instrumentation'\n\n// Semantic convention constants for compatibility across versions\nexport const ATTR_SERVICE_VERSION = 'service.version'\nexport const ATTR_SERVICE_NAMESPACE = 'service.namespace'\nexport const ATTR_SERVICE_INSTANCE_ID = 'service.instance.id'\n\n/** Magic prefixes for binary frames over WebSocket */\nexport const PREFIX_TRACES = 'OTLP'\nexport const PREFIX_METRICS = 'MTRC'\nexport const PREFIX_LOGS = 'LOGS'\n\n/** Connection state for the shared WebSocket */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface ReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_RECONNECTION_CONFIG: ReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Configuration for OpenTelemetry initialization. */\nexport interface OtelConfig {\n /** Whether OpenTelemetry export is enabled. Defaults to true. Set to false or OTEL_ENABLED=false/0/no/off to disable. */\n enabled?: boolean\n /** The service name to report. Defaults to OTEL_SERVICE_NAME or \"iii-node\". */\n serviceName?: string\n /** The service version to report. Defaults to SERVICE_VERSION env var or \"unknown\". */\n serviceVersion?: string\n /** The service namespace to report. Defaults to SERVICE_NAMESPACE env var. */\n serviceNamespace?: string\n /** The service instance ID to report. Defaults to SERVICE_INSTANCE_ID env var or auto-generated UUID. */\n serviceInstanceId?: string\n /** III Engine WebSocket URL. Defaults to III_URL or \"ws://localhost:49134\". */\n engineWsUrl?: string\n /** OpenTelemetry instrumentations to register (e.g., PrismaInstrumentation). */\n instrumentations?: Instrumentation[]\n /** Whether OpenTelemetry metrics export is enabled. Defaults to true. Set to false or OTEL_METRICS_ENABLED=false/0/no/off to disable. */\n metricsEnabled?: boolean\n /** Metrics export interval in milliseconds. Defaults to 60000 (60 seconds). */\n metricsExportIntervalMs?: number\n /**\n * Span processor flush delay in milliseconds. Defaults to 100ms. This is how\n * long an ended span waits in the batch buffer before it is flushed to the\n * engine, the OpenTelemetry default of 5000ms is what makes traces appear\n * seconds after the action. Env override: OTEL_SPANS_FLUSH_INTERVAL_MS.\n */\n spansFlushIntervalMs?: number\n /** Log processor flush delay in milliseconds. Defaults to 100ms. Env override: OTEL_LOGS_FLUSH_INTERVAL_MS. */\n logsFlushIntervalMs?: number\n /** Maximum number of log records exported per batch. Defaults to 1. */\n logsBatchSize?: number\n /** Whether to auto-instrument globalThis.fetch calls. Defaults to true. Works on Node.js, Bun, and Deno. Set to false to disable. */\n fetchInstrumentationEnabled?: boolean\n /** Optional reconnection configuration for the WebSocket connection. */\n reconnectionConfig?: Partial<ReconnectionConfig>\n}\n\n/** Default configuration values for OpenTelemetry initialization. */\nexport const DEFAULT_OTEL_CONFIG = {\n enabled: true,\n serviceName: 'iii-node',\n serviceVersion: 'unknown',\n engineWsUrl: 'ws://localhost:49134',\n metricsEnabled: true,\n metricsExportIntervalMs: 60000,\n spansFlushIntervalMs: 100,\n logsFlushIntervalMs: 100,\n logsBatchSize: 1,\n fetchInstrumentationEnabled: true,\n} as const satisfies Partial<OtelConfig>\n\n/** Parse a boolean environment variable, recognizing 'false', '0', 'no', 'off' as false. */\nexport function parseBoolEnv(value: string | undefined, defaultValue: boolean): boolean {\n if (value === undefined) return defaultValue\n const lower = value.toLowerCase()\n return lower !== 'false' && lower !== '0' && lower !== 'no' && lower !== 'off'\n}\n","/**\n * Shared WebSocket connection for OpenTelemetry exporters.\n */\n\nimport { WebSocket } from 'ws'\nimport { type ConnectionState, type ReconnectionConfig, DEFAULT_RECONNECTION_CONFIG } from './types'\n\n/**\n * Shared WebSocket connection for all OTEL exporters (traces, metrics, logs).\n * Uses a single connection with message prefixes to identify signal type.\n */\nexport class SharedEngineConnection {\n private static readonly MAX_PENDING_MESSAGES = 1000\n private ws: WebSocket | null = null\n private wsUrl: string\n private connecting = false\n private shuttingDown = false\n private pendingMessages: Array<{ frame: Buffer; callback?: (err?: Error) => void }> = []\n private reconnectAttempt = 0\n private reconnectTimeout: NodeJS.Timeout | null = null\n private config: ReconnectionConfig\n private state: ConnectionState = 'disconnected'\n private onConnectedCallbacks: Array<() => void> = []\n private onFailedCallbacks: Array<() => void> = []\n\n constructor(wsUrl: string, config: Partial<ReconnectionConfig> = {}) {\n this.wsUrl = wsUrl\n this.config = { ...DEFAULT_RECONNECTION_CONFIG, ...config }\n this.connect()\n }\n\n private connect(): void {\n if (this.connecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {\n return\n }\n\n this.connecting = true\n this.state = 'connecting'\n\n try {\n // 10s handshake cap, parity with iii-sdk / Rust SDK (MOT-3857/MOT-3968)\n this.ws = new WebSocket(this.wsUrl, { handshakeTimeout: 10000 })\n\n this.ws.on('open', () => {\n this.connecting = false\n this.state = 'connected'\n console.log(`[OTel] Connected to engine at ${this.wsUrl}`)\n\n // Reset reconnection state\n if (this.reconnectAttempt > 0) {\n console.log('[OTel] Successfully reconnected')\n }\n this.reconnectAttempt = 0\n\n // Clear any pending reconnect timer to prevent race conditions\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // Flush pending messages\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n for (const { frame, callback } of pending) {\n this.ws?.send(frame, err => callback?.(err))\n }\n\n // Notify callbacks\n for (const cb of this.onConnectedCallbacks) {\n cb()\n }\n })\n\n this.ws.on('close', () => {\n this.connecting = false\n this.ws = null\n\n // Skip reconnection if we're shutting down intentionally\n if (this.shuttingDown) {\n this.state = 'disconnected'\n console.log('[OTel] Connection closed during shutdown')\n return\n }\n\n this.state = 'disconnected'\n console.log('[OTel] Disconnected from engine, will reconnect...')\n this.scheduleReconnect()\n })\n\n this.ws.on('error', err => {\n this.connecting = false\n\n // Skip error handling if we're shutting down intentionally\n if (this.shuttingDown) {\n return\n }\n\n console.error('[OTel] WebSocket error:', err.message)\n })\n } catch (err) {\n this.connecting = false\n console.error('[OTel] Connection failed:', err)\n this.scheduleReconnect()\n }\n }\n\n private scheduleReconnect(): void {\n if (this.config.maxRetries !== -1 && this.reconnectAttempt >= this.config.maxRetries) {\n this.state = 'failed'\n console.error(`[OTel] Max retries (${this.config.maxRetries}) reached, giving up`)\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const failedError = new Error('Connection failed after max retries')\n for (const { callback } of pending) {\n callback?.(failedError)\n }\n\n // Notify failed callbacks so exporters can drain their own queues\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n return\n }\n\n if (this.reconnectTimeout) {\n return // Already scheduled\n }\n\n const exponentialDelay =\n this.config.initialDelayMs * this.config.backoffMultiplier ** this.reconnectAttempt\n const cappedDelay = Math.min(exponentialDelay, this.config.maxDelayMs)\n const jitter = cappedDelay * this.config.jitterFactor * (2 * Math.random() - 1)\n const delay = Math.max(0, Math.floor(cappedDelay + jitter))\n\n this.state = 'reconnecting'\n console.log(`[OTel] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt + 1})...`)\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null\n this.reconnectAttempt++\n this.connect()\n }, delay)\n }\n\n /**\n * Send a message with a signal prefix.\n */\n send(prefix: string, data: Uint8Array, callback?: (err?: Error) => void): void {\n const prefixBytes = Buffer.from(prefix, 'utf-8')\n const frame = Buffer.concat([prefixBytes, Buffer.from(data)])\n\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(frame, callback)\n } else {\n // Queue for later with bounded size to prevent memory exhaustion\n if (this.pendingMessages.length >= SharedEngineConnection.MAX_PENDING_MESSAGES) {\n console.warn('[OTel] Pending message queue full, dropping oldest message')\n const dropped = this.pendingMessages.shift()\n dropped?.callback?.(new Error('Message dropped due to queue overflow'))\n }\n this.pendingMessages.push({ frame, callback })\n this.connect()\n }\n }\n\n /**\n * Register a callback to be called when connected.\n */\n onConnected(callback: () => void): void {\n this.onConnectedCallbacks.push(callback)\n if (this.state === 'connected') {\n callback()\n }\n }\n\n /**\n * Register a callback to be called when the connection enters the failed\n * terminal state (max retries reached). Exporters use this to drain their\n * own pending queues so in-flight forceFlush() calls do not hang.\n */\n onFailed(callback: () => void): void {\n this.onFailedCallbacks.push(callback)\n if (this.state === 'failed') {\n try {\n callback()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n\n /**\n * Get the current connection state.\n */\n getState(): ConnectionState {\n return this.state\n }\n\n /**\n * Whether the connection is shutting down. While shutting down, exporters\n * fail-fast instead of queueing when there is no live connection, so a final\n * forceFlush() can't hang waiting for a reconnect that will never happen.\n */\n isShuttingDown(): boolean {\n return this.shuttingDown\n }\n\n /**\n * Begin shutdown: stop reconnecting and stop accepting new queued exports,\n * while leaving an open connection in place so buffered telemetry can still\n * be flushed. Call before flushing, then call shutdown() to close fully.\n */\n beginShutdown(): void {\n if (this.shuttingDown) {\n return\n }\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // With no live connection there's nothing to flush to, so fail queued work\n // now instead of leaving callbacks unresolved for the flush below to wait on\n if (this.state !== 'connected') {\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n }\n\n /**\n * Shutdown the connection.\n */\n async shutdown(): Promise<void> {\n // Set shutdown flag to prevent reconnection attempts\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n this.onConnectedCallbacks = []\n this.onFailedCallbacks = []\n this.state = 'disconnected'\n }\n}\n","/**\n * Span exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'\nimport { JsonTraceSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_TRACES } from './types'\n\n/**\n * Span exporter using the shared WebSocket connection.\n */\nexport class EngineSpanExporter implements SpanExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n spans: ReadableSpan[]\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { spans, resultCallback } of pending) {\n this.sendExport(spans, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued spans')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(spans: ReadableSpan[], resultCallback?: (result: ExportResult) => void): void {\n try {\n const serialized = JsonTraceSerializer.serializeRequest(spans)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_TRACES, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send spans:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting spans:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping spans`),\n })\n return\n }\n if (this.pendingExports.length >= EngineSpanExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Spans export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ spans, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(spans, resultCallback)\n }\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(spans, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op, spans are sent immediately\n }\n}\n","/**\n * Metrics exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics'\nimport { JsonMetricsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_METRICS } from './types'\n\n/**\n * Metrics exporter using the shared WebSocket connection.\n */\nexport class EngineMetricsExporter implements PushMetricExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n metrics: ResourceMetrics\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { metrics, resultCallback } of pending) {\n this.sendExport(metrics, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued metrics')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(\n metricsData: ResourceMetrics,\n resultCallback?: (result: ExportResult) => void,\n ): void {\n try {\n const serialized = JsonMetricsSerializer.serializeRequest(metricsData)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_METRICS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send metrics:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting metrics:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(\n metricsData: ResourceMetrics,\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping metrics`),\n })\n return\n }\n if (this.pendingExports.length >= EngineMetricsExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Metrics export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ metrics: metricsData, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(metricsData, resultCallback)\n }\n\n export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {\n this.doExport(metrics, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op\n }\n}\n","/**\n * Log exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { LogRecordExporter, ReadableLogRecord } from '@opentelemetry/sdk-logs'\nimport { JsonLogsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_LOGS } from './types'\n\n/**\n * Log exporter using the shared WebSocket connection.\n */\nexport class EngineLogExporter implements LogRecordExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n logs: ReadableLogRecord[]\n callback: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { logs, callback } of pending) {\n this.doExport(logs, callback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued logs')\n for (const { callback } of pending) {\n callback({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private doExport(\n logs: ReadableLogRecord[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping logs`),\n })\n return\n }\n if (this.pendingExports.length >= EngineLogExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.callback({\n code: ExportResultCode.FAILED,\n error: new Error('Logs export queue full'),\n })\n console.warn('[OTel] Logs export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ logs, callback: resultCallback })\n return\n }\n\n try {\n const serialized = JsonLogsSerializer.serializeRequest(logs)\n if (!serialized) {\n resultCallback({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_LOGS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send logs:', err.message)\n resultCallback({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting logs:', err)\n resultCallback({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(logs, resultCallback)\n }\n\n async forceFlush(): Promise<void> {}\n\n async shutdown(): Promise<void> {\n for (const { callback } of this.pendingExports) {\n callback({ code: ExportResultCode.FAILED, error: new Error('Exporter shutdown') })\n }\n this.pendingExports = []\n }\n}\n","/**\n * Trace context and baggage propagation utilities.\n */\n\nimport { trace, context, propagation, type Context } from '@opentelemetry/api'\n\n/**\n * Extract the current trace ID from the active span context.\n */\nexport function currentTraceId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.traceId && spanContext.traceId !== '00000000000000000000000000000000') {\n return spanContext.traceId\n }\n }\n return undefined\n}\n\n/**\n * Extract the current span ID from the active span context.\n */\nexport function currentSpanId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.spanId && spanContext.spanId !== '0000000000000000') {\n return spanContext.spanId\n }\n }\n return undefined\n}\n\n/**\n * Inject the current trace context into a W3C traceparent header string.\n */\nexport function injectTraceparent(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.traceparent\n}\n\n/**\n * Extract a trace context from a W3C traceparent header string.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n */\nexport function extractTraceparent(traceparent: string): Context {\n const carrier: Record<string, string> = { traceparent }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Inject the current baggage into a W3C baggage header string.\n */\nexport function injectBaggage(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.baggage\n}\n\n/**\n * Extract baggage from a W3C baggage header string.\n *\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractBaggage(baggage: string): Context {\n const carrier: Record<string, string> = { baggage }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Extract both trace context and baggage from their respective headers.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractContext(traceparent?: string, baggage?: string): Context {\n const carrier: Record<string, string> = {}\n if (traceparent) {\n carrier.traceparent = traceparent\n }\n if (baggage) {\n carrier.baggage = baggage\n }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Get a baggage entry from the current context.\n *\n * @param key - Baggage entry key to read.\n */\nexport function getBaggageEntry(key: string): string | undefined {\n const bag = propagation.getBaggage(context.active())\n return bag?.getEntry(key)?.value\n}\n\n/**\n * Set a baggage entry in the current context.\n *\n * @param key - Baggage entry key to set.\n * @param value - Baggage entry value to set.\n */\nexport function setBaggageEntry(key: string, value: string): Context {\n let bag = propagation.getBaggage(context.active()) ?? propagation.createBaggage()\n bag = bag.setEntry(key, { value })\n return propagation.setBaggage(context.active(), bag)\n}\n\n/**\n * Remove a baggage entry from the current context.\n *\n * @param key - Baggage entry key to remove.\n */\nexport function removeBaggageEntry(key: string): Context {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return context.active()\n }\n const newBag = bag.removeEntry(key)\n return propagation.setBaggage(context.active(), newBag)\n}\n\n/**\n * Get all baggage entries from the current context.\n */\nexport function getAllBaggage(): Record<string, string> {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return {}\n }\n const entries: Record<string, string> = {}\n for (const [key, entry] of bag.getAllEntries()) {\n entries[key] = entry.value\n }\n return entries\n}\n","/**\n * Global fetch auto-instrumentation for the III Node SDK.\n *\n * Patches globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n * Works on all runtimes (Bun, Node.js, Deno) unlike UndiciInstrumentation\n * which only works when fetch is backed by Node.js's undici.\n */\n\nimport { type Tracer, SpanKind, SpanStatusCode, context, propagation } from '@opentelemetry/api'\n\nconst textEncoder = new TextEncoder()\n\nfunction getBodyByteSize(body: unknown): number | undefined {\n if (body == null) return undefined\n if (typeof body === 'string') return textEncoder.encode(body).byteLength\n if (body instanceof ArrayBuffer) return body.byteLength\n if (ArrayBuffer.isView(body)) return body.byteLength\n if (body instanceof Blob) return body.size\n if (body instanceof URLSearchParams) return new TextEncoder().encode(body.toString()).byteLength\n return undefined\n}\n\nconst SAFE_REQUEST_HEADERS = ['content-type', 'accept'] as const\nconst SAFE_RESPONSE_HEADERS = ['content-type'] as const\n\nlet originalFetch: typeof globalThis.fetch | null = null\n\n/**\n * Substring patterns from `OTEL_FETCH_IGNORE_URLS` (comma-separated). A fetch\n * whose URL contains any pattern is executed WITHOUT creating a span, use it\n * to drop noisy/high-frequency calls (health checks, polling, internal\n * endpoints) that would otherwise flood traces.\n */\nconst FETCH_IGNORE_URL_PATTERNS: string[] = (process.env.OTEL_FETCH_IGNORE_URLS ?? '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n\nfunction shouldIgnoreFetchUrl(url: string): boolean {\n return FETCH_IGNORE_URL_PATTERNS.some(pattern => url.includes(pattern))\n}\n\n/**\n * Patch globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n *\n * @param tracer - Tracer used to create the client span for each request.\n */\nexport function patchGlobalFetch(tracer: Tracer): void {\n if (originalFetch) return\n\n originalFetch = globalThis.fetch\n const capturedFetch = originalFetch\n\n globalThis.fetch = async (\n input: string | URL | Request,\n init?: RequestInit,\n ): Promise<Response> => {\n const url = input instanceof Request ? input.url : String(input)\n\n // Skip tracing entirely for ignored URLs (no span, no context injection).\n if (shouldIgnoreFetchUrl(url)) {\n return capturedFetch(input, init)\n }\n\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n\n let host: string | undefined\n let scheme: string | undefined\n let path: string | undefined\n let port: number | undefined\n let query: string | undefined\n try {\n const parsed = new URL(url)\n host = parsed.hostname\n scheme = parsed.protocol.replace(':', '')\n path = parsed.pathname\n port = parsed.port ? parseInt(parsed.port, 10) : undefined\n query = parsed.search ? parsed.search.slice(1) : undefined\n } catch {\n // relative URL or invalid, skip host/scheme/path attributes\n }\n\n const spanAttributes: Record<string, string | number> = {\n 'http.request.method': method,\n 'url.full': url,\n }\n if (host) spanAttributes['server.address'] = host\n if (scheme) {\n spanAttributes['url.scheme'] = scheme\n spanAttributes['network.protocol.name'] = 'http'\n }\n if (path) spanAttributes['url.path'] = path\n if (port) spanAttributes['server.port'] = port\n if (query) spanAttributes['url.query'] = query\n\n const spanName = path ? `${method} ${path}` : method\n\n return tracer.startActiveSpan(\n spanName,\n { kind: SpanKind.CLIENT, attributes: spanAttributes },\n context.active(),\n async span => {\n try {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n for (const [key, value] of Object.entries(carrier)) {\n headers.set(key, value)\n }\n\n for (const name of SAFE_REQUEST_HEADERS) {\n const value = headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.request.header.${name}`, value)\n }\n }\n\n const requestBody = init?.body ?? (input instanceof Request ? input.body : undefined)\n const requestBodySize = getBodyByteSize(requestBody)\n if (requestBodySize !== undefined) {\n span.setAttribute('http.request.body.size', requestBodySize)\n }\n\n const response = await capturedFetch(input, { ...init, headers })\n\n span.setAttribute('http.response.status_code', response.status)\n\n const contentLength = response.headers.get('content-length')\n if (contentLength !== null) {\n const size = parseInt(contentLength, 10)\n if (!Number.isNaN(size)) {\n span.setAttribute('http.response.body.size', size)\n }\n }\n\n for (const name of SAFE_RESPONSE_HEADERS) {\n const value = response.headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.response.header.${name}`, value)\n }\n }\n\n if (response.status >= 400) {\n span.setAttribute('error.type', String(response.status))\n span.setStatus({ code: SpanStatusCode.ERROR })\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n return response\n } catch (error) {\n span.setAttribute('error.type', (error as Error).name ?? 'Error')\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n },\n )\n }\n}\n\n/**\n * Restore globalThis.fetch to its original implementation.\n */\nexport function unpatchGlobalFetch(): void {\n if (originalFetch) {\n globalThis.fetch = originalFetch\n originalFetch = null\n }\n}\n","/**\n * Parse a numeric environment variable with optional minimum bound.\n *\n * An empty or whitespace-only string is treated as unset: `Number('')` is 0,\n * so without this check a variable set-but-blank (common in .env files) would\n * silently resolve to 0 instead of falling through to the default.\n */\nexport function parseNumberEnv(value: string | undefined, minimum: number = 0): number | undefined {\n if (value === undefined || value.trim() === '') return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed < minimum) return undefined\n return parsed\n}\n\n/**\n * Parse an integer environment variable with optional minimum bound.\n */\nexport function parseIntegerEnv(\n value: string | undefined,\n minimum: number = 0,\n): number | undefined {\n const parsed = parseNumberEnv(value, minimum)\n if (parsed === undefined || !Number.isInteger(parsed)) return undefined\n return parsed\n}\n\n/**\n * Resolve a batch-processor flush delay: explicit config wins, then the\n * III-specific env var, then the III default.\n *\n * III SDKs deliberately expose a single OTEL_*_FLUSH_INTERVAL_MS knob and do\n * NOT honor the standard OTel OTEL_BSP_SCHEDULE_DELAY / OTEL_BLRP_SCHEDULE_DELAY\n * vars, for cross-SDK consistency (the Node, Python, and Rust SDKs all resolve\n * the same way). Passing an explicit `scheduledDelayMillis` to the processor\n * already makes the OTel SDK ignore those standard vars regardless.\n */\nexport function resolveFlushIntervalMs(\n configValue: number | undefined,\n envValue: string | undefined,\n defaultValue: number,\n): number {\n return configValue ?? parseNumberEnv(envValue, 0) ?? defaultValue\n}\n","/** High-level span operations so consumers don't need `@opentelemetry/api`. */\n\nimport { SpanStatusCode, trace, type AttributeValue, type Attributes } from '@opentelemetry/api'\n\n/** Returns `false` when there is no active span or the sampler dropped it. */\nexport function currentSpanIsRecording(): boolean {\n const span = trace.getActiveSpan()\n return span ? span.isRecording() : false\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param key - Attribute key to set on the active span.\n * @param value - Attribute value to set.\n */\nexport function setCurrentSpanAttribute(key: string, value: AttributeValue): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.setAttribute(key, value)\n}\n\n/**\n * No-op when there is no active span.\n *\n * @param message - Error message to set as the span's error status.\n */\nexport function setCurrentSpanError(message: string): void {\n const span = trace.getActiveSpan()\n if (!span) return\n span.setStatus({ code: SpanStatusCode.ERROR, message })\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param name - Name of the event to add to the active span.\n * @param attrs - Optional attributes to attach to the event.\n */\nexport function recordSpanEvent(name: string, attrs?: Attributes): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.addEvent(name, attrs)\n}\n","/** Payload redaction + truncation for invocation event capture. */\n\nexport const REDACTED_PLACEHOLDER = '[REDACTED]'\nconst TRUNCATION_MARKER = '...\"[TRUNCATED]\"'\n\n/**\n * Resolve the payload byte cap from the environment, returning undefined when\n * unset.\n */\nexport function resolveMaxBytesFromEnv(): number | null {\n const raw = process.env.III_TRACE_PAYLOAD_MAX_BYTES\n if (raw === undefined) return null\n const trimmed = raw.trim()\n if (trimmed === '' || trimmed.toLowerCase() === 'unlimited') return null\n // parseInt accepts partial parses like \"8192mb\" → 8192; Python int()\n // and Rust parse::<usize>() reject those. Match the strict semantics.\n if (!/^\\d+$/.test(trimmed)) return null\n const parsed = Number(trimmed)\n if (parsed <= 0) return null\n return parsed\n}\n\nconst SENSITIVE_FRAGMENTS = [\n 'api_key',\n 'apikey',\n 'api-key',\n 'password',\n 'secret',\n 'credential',\n 'authorization',\n 'auth_token',\n 'access_token',\n 'refresh_token',\n 'bearer',\n 'private_key',\n 'client_secret',\n]\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase()\n if (SENSITIVE_FRAGMENTS.some((fragment) => lower.includes(fragment))) return true\n // `token` alone is too common a substring; require whole-key or suffix match.\n return lower === 'token' || lower.endsWith('_token') || lower.endsWith('-token')\n}\n\n/**\n * Recursively redact values of sensitive keys. Returns a new value.\n *\n * @param value - The value to recursively redact.\n */\nexport function redact(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (Array.isArray(value)) return value.map(redact)\n if (typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = isSensitiveKey(k) ? REDACTED_PLACEHOLDER : redact(v)\n }\n return out\n }\n return value\n}\n\n/**\n * Redact then serialize to JSON, optionally capped at `maxBytes`.\n *\n * @param value - The value to redact and serialize.\n * @param maxBytes - Maximum serialized size in bytes; null leaves it uncapped.\n */\nexport function redactAndTruncate(\n value: unknown,\n maxBytes: number | null = null,\n): { json: string; truncated: boolean } {\n const redacted = redact(value)\n let serialized: string\n try {\n serialized = JSON.stringify(redacted) ?? 'null'\n } catch {\n serialized = 'null'\n }\n\n if (maxBytes === null || maxBytes === undefined || maxBytes <= 0) {\n return { json: serialized, truncated: false }\n }\n\n const byteLen = Buffer.byteLength(serialized, 'utf8')\n if (byteLen <= maxBytes) {\n return { json: serialized, truncated: false }\n }\n\n const markerLen = Buffer.byteLength(TRUNCATION_MARKER, 'utf8')\n // When maxBytes is smaller than the marker itself, emit only a\n // truncated marker so the result never exceeds the cap.\n if (maxBytes <= markerLen) {\n return { json: TRUNCATION_MARKER.slice(0, maxBytes), truncated: true }\n }\n\n const cap = maxBytes - markerLen\n const buf = Buffer.from(serialized, 'utf8')\n let cut = Math.min(cap, buf.length)\n // Walk back to a UTF-8 boundary so we don't emit half-codepoints.\n while (cut > 0 && (buf[cut] & 0xc0) === 0x80) {\n cut -= 1\n }\n const truncated = buf.subarray(0, cut).toString('utf8') + TRUNCATION_MARKER\n return { json: truncated, truncated: true }\n}\n","/**\n * OpenTelemetry initialization for the III Node SDK.\n *\n * This module provides trace, metrics, and log export to the III Engine\n * via a shared WebSocket connection using OTLP JSON format.\n */\n\nimport { Resource } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'\nimport { randomUUID } from 'node:crypto'\nimport {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n metrics,\n type Span,\n type Context,\n type Tracer,\n type Meter,\n} from '@opentelemetry/api'\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'\nimport { BaggageSpanProcessor } from './baggage-span-processor'\nimport { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'\nimport { registerInstrumentations } from '@opentelemetry/instrumentation'\nimport { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'\nimport { type Logger, SeverityNumber } from '@opentelemetry/api-logs'\n\nimport {\n type OtelConfig,\n DEFAULT_OTEL_CONFIG,\n parseBoolEnv,\n ATTR_SERVICE_VERSION,\n ATTR_SERVICE_NAMESPACE,\n ATTR_SERVICE_INSTANCE_ID,\n} from './types'\nimport { SharedEngineConnection } from './connection'\nimport { EngineSpanExporter, EngineMetricsExporter, EngineLogExporter } from './exporters'\nimport { extractTraceparent } from './context'\nimport { patchGlobalFetch, unpatchGlobalFetch } from './fetch-instrumentation'\nimport { parseIntegerEnv, resolveFlushIntervalMs } from './utils'\n\n// Re-export everything from submodules\nexport * from './types'\nexport * from './context'\nexport { BaggageSpanProcessor } from './baggage-span-processor'\nexport {\n currentSpanIsRecording,\n recordSpanEvent,\n setCurrentSpanAttribute,\n setCurrentSpanError,\n} from './span-ops'\nexport {\n REDACTED_PLACEHOLDER,\n redact,\n redactAndTruncate,\n resolveMaxBytesFromEnv,\n} from './payload'\n\n/**\n * Normalize an engine WebSocket URL into the dedicated OTEL endpoint.\n * The engine exposes `/otel` for telemetry-only WS connections; routing\n * there keeps this socket out of the worker registry (otherwise it shows\n * up as a ghost null-metadata worker).\n */\nfunction appendOtelPath(base: string): string {\n const url = new URL(base)\n const path = url.pathname.replace(/\\/+$/, '')\n url.pathname = path.endsWith('/otel') ? path : `${path}/otel`\n return url.toString()\n}\n\n// Module-level state\nlet sharedConnection: SharedEngineConnection | null = null\nlet tracerProvider: NodeTracerProvider | null = null\nlet meterProvider: MeterProvider | null = null\nlet loggerProvider: LoggerProvider | null = null\nlet tracer: Tracer | null = null\nlet meter: Meter | null = null\nlet logger: Logger | null = null\nlet serviceName: string = 'iii-node-iii'\n\n/**\n * Initialize OpenTelemetry with the given configuration.\n * This should be called once at application startup.\n *\n * @param config - OpenTelemetry configuration; env vars fill in unset fields.\n */\nexport function initOtel(config: OtelConfig = {}): void {\n const enabled = config.enabled ?? parseBoolEnv(process.env.OTEL_ENABLED, DEFAULT_OTEL_CONFIG.enabled)\n\n if (!enabled) {\n console.debug(\n '[OTel] OpenTelemetry is disabled. To enable, remove OTEL_ENABLED=false or set enabled: true in config.',\n )\n return\n }\n\n // Configure service identity\n serviceName = config.serviceName ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_OTEL_CONFIG.serviceName\n const serviceVersion = config.serviceVersion ?? process.env.SERVICE_VERSION ?? DEFAULT_OTEL_CONFIG.serviceVersion\n const serviceNamespace = config.serviceNamespace ?? process.env.SERVICE_NAMESPACE\n const serviceInstanceId = config.serviceInstanceId ?? process.env.SERVICE_INSTANCE_ID ?? randomUUID()\n const engineWsUrl = config.engineWsUrl ?? process.env.III_URL ?? DEFAULT_OTEL_CONFIG.engineWsUrl\n\n // Build resource attributes\n const resourceAttributes: Record<string, string> = {\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n [ATTR_SERVICE_INSTANCE_ID]: serviceInstanceId,\n }\n if (serviceNamespace) {\n resourceAttributes[ATTR_SERVICE_NAMESPACE] = serviceNamespace\n }\n const resource = new Resource(resourceAttributes)\n\n // Create shared WebSocket connection.\n // OTEL always connects to the engine's dedicated `/otel` endpoint so\n // the telemetry socket doesn't get registered in `worker_registry` as\n // a ghost null-metadata worker alongside the real worker.\n sharedConnection = new SharedEngineConnection(appendOtelPath(engineWsUrl), config.reconnectionConfig)\n\n // BaggageSpanProcessor must register first: onStart fires in\n // registration order, so baggage entries are materialized as span\n // attributes before the batch exporter reads them.\n const spanExporter = new EngineSpanExporter(sharedConnection)\n // Without an explicit scheduledDelayMillis, BatchSpanProcessor inherits the\n // OpenTelemetry default of 5000ms, so an ended span sits in the buffer up to\n // 5s before it is flushed to the engine, the dominant reason traces show up\n // seconds after the action that produced them. Mirror the logs path\n // (BatchLogRecordProcessor below) with a small flush delay. maxExportBatchSize\n // stays at the OTel default so a burst of spans from one turn still coalesces\n // into a single frame rather than one frame per span.\n const spansScheduledDelayMillis = resolveFlushIntervalMs(\n config.spansFlushIntervalMs,\n process.env.OTEL_SPANS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.spansFlushIntervalMs,\n )\n tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [\n new BaggageSpanProcessor(),\n new BatchSpanProcessor(spanExporter, { scheduledDelayMillis: spansScheduledDelayMillis }),\n ],\n })\n\n // Register W3C Trace Context and Baggage propagators\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n }),\n )\n\n tracerProvider.register()\n tracer = trace.getTracer(serviceName)\n\n console.debug(`[OTel] Traces initialized: engine=${engineWsUrl}, service=${serviceName}`)\n\n // Initialize metrics (enabled by default, opt-out via config or env)\n const metricsEnabled =\n config.metricsEnabled ?? parseBoolEnv(process.env.OTEL_METRICS_ENABLED, DEFAULT_OTEL_CONFIG.metricsEnabled)\n\n if (metricsEnabled) {\n const metricsExporter = new EngineMetricsExporter(sharedConnection)\n const exportIntervalMs = config.metricsExportIntervalMs ?? DEFAULT_OTEL_CONFIG.metricsExportIntervalMs\n\n const metricReader = new PeriodicExportingMetricReader({\n exporter: metricsExporter,\n exportIntervalMillis: exportIntervalMs,\n })\n\n meterProvider = new MeterProvider({\n resource,\n readers: [metricReader],\n })\n\n metrics.setGlobalMeterProvider(meterProvider)\n meter = meterProvider.getMeter(serviceName)\n\n console.debug(`[OTel] Metrics initialized: interval=${exportIntervalMs}ms`)\n }\n\n // Register user-provided instrumentations AFTER providers are set up\n const instrumentations = [...(config.instrumentations ?? [])]\n if (instrumentations.length > 0) {\n registerInstrumentations({\n instrumentations,\n tracerProvider,\n meterProvider: meterProvider ?? undefined,\n })\n console.debug(`[OTel] Instrumentations registered: ${instrumentations.length} total`)\n }\n\n // Patch global fetch for runtime-agnostic HTTP client tracing (works on Bun, Node.js, Deno)\n const fetchEnabled = config.fetchInstrumentationEnabled ?? DEFAULT_OTEL_CONFIG.fetchInstrumentationEnabled\n\n if (fetchEnabled) {\n patchGlobalFetch(tracer)\n console.debug('[OTel] Global fetch instrumentation enabled')\n }\n\n // Initialize logs (always enabled when OTEL is enabled)\n const logExporter = new EngineLogExporter(sharedConnection)\n const logsScheduledDelayMillis = resolveFlushIntervalMs(\n config.logsFlushIntervalMs,\n process.env.OTEL_LOGS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.logsFlushIntervalMs,\n )\n const logsMaxExportBatchSize =\n config.logsBatchSize ?? parseIntegerEnv(process.env.OTEL_LOGS_BATCH_SIZE, 1) ?? DEFAULT_OTEL_CONFIG.logsBatchSize\n\n loggerProvider = new LoggerProvider({ resource })\n loggerProvider.addLogRecordProcessor(\n new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: logsScheduledDelayMillis,\n maxExportBatchSize: logsMaxExportBatchSize,\n }),\n )\n logger = loggerProvider.getLogger(serviceName)\n\n console.debug(`[OTel] Logs initialized: delay=${logsScheduledDelayMillis}ms, batch=${logsMaxExportBatchSize}`)\n}\n\n/**\n * Shut down OpenTelemetry, best-effort flushing any pending data before\n * teardown.\n */\nexport async function shutdownOtel(): Promise<void> {\n // Stop reconnecting/queuing before flushing so a final forceFlush() can't hang on a dead engine\n sharedConnection?.beginShutdown()\n\n // Flushing is best-effort on shutdown: when the engine is gone the exporters\n // fail their pending exports, which rejects forceFlush()/shutdown(). Swallow\n // those so a dropped final flush can't crash or block teardown.\n const settle = (p: Promise<unknown>) => p.catch(() => {})\n\n if (tracerProvider) {\n await settle(tracerProvider.forceFlush())\n await settle(tracerProvider.shutdown())\n tracerProvider = null\n }\n\n if (meterProvider) {\n await settle(meterProvider.forceFlush())\n await settle(meterProvider.shutdown())\n meterProvider = null\n }\n\n if (loggerProvider) {\n await settle(loggerProvider.forceFlush())\n await settle(loggerProvider.shutdown())\n loggerProvider = null\n }\n\n if (sharedConnection) {\n await sharedConnection.shutdown()\n sharedConnection = null\n }\n\n unpatchGlobalFetch()\n\n tracer = null\n meter = null\n logger = null\n}\n\n/**\n * Force-flush all OTel providers without tearing them down.\n *\n * Counterpart to {@link shutdownOtel}. Use before short-lived process exits\n * where you want pending spans/metrics/logs delivered but plan to keep using\n * OTel afterwards.\n */\nexport async function flushOtel(): Promise<void> {\n await Promise.all(\n [\n tracerProvider?.forceFlush(),\n meterProvider?.forceFlush(),\n loggerProvider?.forceFlush(),\n ].filter(Boolean),\n )\n}\n\n/**\n * Get the OpenTelemetry tracer instance.\n */\nexport function getTracer(): Tracer | null {\n return tracer\n}\n\n/**\n * Get the OpenTelemetry meter instance.\n */\nexport function getMeter(): Meter | null {\n return meter\n}\n\n/**\n * Get the OpenTelemetry logger instance.\n */\nexport function getLogger(): Logger | null {\n return logger\n}\n\n/**\n * Start a new span with the given name and run the callback within it.\n *\n * @param name - Name of the span to create.\n * @param options - Span options: `kind` sets the span kind, `traceparent` sets the parent context from a W3C traceparent header.\n * @param fn - Callback run inside the active span; its result is returned.\n */\nexport async function withSpan<T>(\n name: string,\n options: { kind?: SpanKind; traceparent?: string },\n fn: (span: Span) => Promise<T>,\n): Promise<T> {\n if (!tracer) {\n // Execute without span context when tracer is not initialized\n // Provide a no-op span to avoid runtime errors if fn calls span methods\n const noopSpan: Span = {\n spanContext: () => ({ traceId: '', spanId: '', traceFlags: 0 }),\n setAttribute: () => noopSpan,\n setAttributes: () => noopSpan,\n addEvent: () => noopSpan,\n addLink: () => noopSpan,\n setStatus: () => noopSpan,\n updateName: () => noopSpan,\n end: () => {},\n isRecording: () => false,\n recordException: () => {},\n addLinks: () => noopSpan,\n }\n return fn(noopSpan)\n }\n\n const parentContext = options.traceparent ? extractTraceparent(options.traceparent) : context.active()\n\n return tracer.startActiveSpan(name, { kind: options.kind ?? SpanKind.INTERNAL }, parentContext, async (span) => {\n try {\n const result = await fn(span)\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (error) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n// Re-export OTEL types for convenience\nexport { SpanKind, SpanStatusCode, SeverityNumber, type Span, type Context, type Tracer, type Meter, type Logger as OtelApiLogger }\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iii-dev/helpers",
3
- "version": "0.21.8-next.1",
3
+ "version": "0.21.8-next.3",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1 +0,0 @@
1
- {"version":3,"file":"telemetry-system-AxDF-K2R.mjs","names":["SpanKind","SpanStatusCode"],"sources":["../src/observability/telemetry-system/baggage-span-processor.ts","../src/observability/telemetry-system/types.ts","../src/observability/telemetry-system/connection.ts","../src/observability/telemetry-system/span-exporter.ts","../src/observability/telemetry-system/metrics-exporter.ts","../src/observability/telemetry-system/log-exporter.ts","../src/observability/telemetry-system/context.ts","../src/observability/telemetry-system/fetch-instrumentation.ts","../src/observability/telemetry-system/utils.ts","../src/observability/telemetry-system/span-ops.ts","../src/observability/telemetry-system/payload.ts","../src/observability/telemetry-system/index.ts"],"sourcesContent":["// Baggage -> span attribute processor.\n//\n// Copies EVERY baggage entry onto every span started in its scope,\n// unconditionally — the same contract as the upstream OTel contrib\n// BaggageSpanProcessor. There is deliberately no key filtering here: a\n// filtering policy baked into worker binaries has to be kept in lockstep\n// across every SDK language and every deployed worker, and a stale binary\n// silently drops newer keys. Which attributes *mean* something (e.g. the\n// `iii.tag.*` trace-tag namespace, `iii.session.*`) is a query-side\n// convention owned by the engine's traces API, where it can evolve without\n// touching workers.\n\nimport type { Context } from '@opentelemetry/api'\nimport { propagation } from '@opentelemetry/api'\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base'\n\n/**\n * OpenTelemetry span processor that copies OTel baggage entries onto each\n * started span as attributes.\n */\nexport class BaggageSpanProcessor implements SpanProcessor {\n onStart(span: Span, parentContext: Context): void {\n // NoOp guard: skip allocation when sampler drops the span.\n if (!span.isRecording()) {\n return\n }\n\n const baggage = propagation.getBaggage(parentContext)\n if (!baggage) {\n return\n }\n\n for (const [key, entry] of baggage.getAllEntries()) {\n span.setAttribute(key, entry.value)\n }\n }\n\n onEnd(_span: ReadableSpan): void {\n /* no-op */\n }\n\n async shutdown(): Promise<void> {\n /* no-op */\n }\n\n async forceFlush(): Promise<void> {\n /* no-op */\n }\n}\n","/**\n * Types, interfaces, and constants for the OpenTelemetry module.\n */\n\nimport type { Instrumentation } from '@opentelemetry/instrumentation'\n\n// Semantic convention constants for compatibility across versions\nexport const ATTR_SERVICE_VERSION = 'service.version'\nexport const ATTR_SERVICE_NAMESPACE = 'service.namespace'\nexport const ATTR_SERVICE_INSTANCE_ID = 'service.instance.id'\n\n/** Magic prefixes for binary frames over WebSocket */\nexport const PREFIX_TRACES = 'OTLP'\nexport const PREFIX_METRICS = 'MTRC'\nexport const PREFIX_LOGS = 'LOGS'\n\n/** Connection state for the shared WebSocket */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface ReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_RECONNECTION_CONFIG: ReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Configuration for OpenTelemetry initialization. */\nexport interface OtelConfig {\n /** Whether OpenTelemetry export is enabled. Defaults to true. Set to false or OTEL_ENABLED=false/0/no/off to disable. */\n enabled?: boolean\n /** The service name to report. Defaults to OTEL_SERVICE_NAME or \"iii-node\". */\n serviceName?: string\n /** The service version to report. Defaults to SERVICE_VERSION env var or \"unknown\". */\n serviceVersion?: string\n /** The service namespace to report. Defaults to SERVICE_NAMESPACE env var. */\n serviceNamespace?: string\n /** The service instance ID to report. Defaults to SERVICE_INSTANCE_ID env var or auto-generated UUID. */\n serviceInstanceId?: string\n /** III Engine WebSocket URL. Defaults to III_URL or \"ws://localhost:49134\". */\n engineWsUrl?: string\n /** OpenTelemetry instrumentations to register (e.g., PrismaInstrumentation). */\n instrumentations?: Instrumentation[]\n /** Whether OpenTelemetry metrics export is enabled. Defaults to true. Set to false or OTEL_METRICS_ENABLED=false/0/no/off to disable. */\n metricsEnabled?: boolean\n /** Metrics export interval in milliseconds. Defaults to 60000 (60 seconds). */\n metricsExportIntervalMs?: number\n /**\n * Span processor flush delay in milliseconds. Defaults to 100ms. This is how\n * long an ended span waits in the batch buffer before it is flushed to the\n * engine, the OpenTelemetry default of 5000ms is what makes traces appear\n * seconds after the action. Env override: OTEL_SPANS_FLUSH_INTERVAL_MS.\n */\n spansFlushIntervalMs?: number\n /** Log processor flush delay in milliseconds. Defaults to 100ms. Env override: OTEL_LOGS_FLUSH_INTERVAL_MS. */\n logsFlushIntervalMs?: number\n /** Maximum number of log records exported per batch. Defaults to 1. */\n logsBatchSize?: number\n /** Whether to auto-instrument globalThis.fetch calls. Defaults to true. Works on Node.js, Bun, and Deno. Set to false to disable. */\n fetchInstrumentationEnabled?: boolean\n /** Optional reconnection configuration for the WebSocket connection. */\n reconnectionConfig?: Partial<ReconnectionConfig>\n}\n\n/** Default configuration values for OpenTelemetry initialization. */\nexport const DEFAULT_OTEL_CONFIG = {\n enabled: true,\n serviceName: 'iii-node',\n serviceVersion: 'unknown',\n engineWsUrl: 'ws://localhost:49134',\n metricsEnabled: true,\n metricsExportIntervalMs: 60000,\n spansFlushIntervalMs: 100,\n logsFlushIntervalMs: 100,\n logsBatchSize: 1,\n fetchInstrumentationEnabled: true,\n} as const satisfies Partial<OtelConfig>\n\n/** Parse a boolean environment variable, recognizing 'false', '0', 'no', 'off' as false. */\nexport function parseBoolEnv(value: string | undefined, defaultValue: boolean): boolean {\n if (value === undefined) return defaultValue\n const lower = value.toLowerCase()\n return lower !== 'false' && lower !== '0' && lower !== 'no' && lower !== 'off'\n}\n","/**\n * Shared WebSocket connection for OpenTelemetry exporters.\n */\n\nimport { WebSocket } from 'ws'\nimport { type ConnectionState, type ReconnectionConfig, DEFAULT_RECONNECTION_CONFIG } from './types'\n\n/**\n * Shared WebSocket connection for all OTEL exporters (traces, metrics, logs).\n * Uses a single connection with message prefixes to identify signal type.\n */\nexport class SharedEngineConnection {\n private static readonly MAX_PENDING_MESSAGES = 1000\n private ws: WebSocket | null = null\n private wsUrl: string\n private connecting = false\n private shuttingDown = false\n private pendingMessages: Array<{ frame: Buffer; callback?: (err?: Error) => void }> = []\n private reconnectAttempt = 0\n private reconnectTimeout: NodeJS.Timeout | null = null\n private config: ReconnectionConfig\n private state: ConnectionState = 'disconnected'\n private onConnectedCallbacks: Array<() => void> = []\n private onFailedCallbacks: Array<() => void> = []\n\n constructor(wsUrl: string, config: Partial<ReconnectionConfig> = {}) {\n this.wsUrl = wsUrl\n this.config = { ...DEFAULT_RECONNECTION_CONFIG, ...config }\n this.connect()\n }\n\n private connect(): void {\n if (this.connecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {\n return\n }\n\n this.connecting = true\n this.state = 'connecting'\n\n try {\n this.ws = new WebSocket(this.wsUrl)\n\n this.ws.on('open', () => {\n this.connecting = false\n this.state = 'connected'\n console.log(`[OTel] Connected to engine at ${this.wsUrl}`)\n\n // Reset reconnection state\n if (this.reconnectAttempt > 0) {\n console.log('[OTel] Successfully reconnected')\n }\n this.reconnectAttempt = 0\n\n // Clear any pending reconnect timer to prevent race conditions\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // Flush pending messages\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n for (const { frame, callback } of pending) {\n this.ws?.send(frame, err => callback?.(err))\n }\n\n // Notify callbacks\n for (const cb of this.onConnectedCallbacks) {\n cb()\n }\n })\n\n this.ws.on('close', () => {\n this.connecting = false\n this.ws = null\n\n // Skip reconnection if we're shutting down intentionally\n if (this.shuttingDown) {\n this.state = 'disconnected'\n console.log('[OTel] Connection closed during shutdown')\n return\n }\n\n this.state = 'disconnected'\n console.log('[OTel] Disconnected from engine, will reconnect...')\n this.scheduleReconnect()\n })\n\n this.ws.on('error', err => {\n this.connecting = false\n\n // Skip error handling if we're shutting down intentionally\n if (this.shuttingDown) {\n return\n }\n\n console.error('[OTel] WebSocket error:', err.message)\n })\n } catch (err) {\n this.connecting = false\n console.error('[OTel] Connection failed:', err)\n this.scheduleReconnect()\n }\n }\n\n private scheduleReconnect(): void {\n if (this.config.maxRetries !== -1 && this.reconnectAttempt >= this.config.maxRetries) {\n this.state = 'failed'\n console.error(`[OTel] Max retries (${this.config.maxRetries}) reached, giving up`)\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const failedError = new Error('Connection failed after max retries')\n for (const { callback } of pending) {\n callback?.(failedError)\n }\n\n // Notify failed callbacks so exporters can drain their own queues\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n return\n }\n\n if (this.reconnectTimeout) {\n return // Already scheduled\n }\n\n const exponentialDelay =\n this.config.initialDelayMs * this.config.backoffMultiplier ** this.reconnectAttempt\n const cappedDelay = Math.min(exponentialDelay, this.config.maxDelayMs)\n const jitter = cappedDelay * this.config.jitterFactor * (2 * Math.random() - 1)\n const delay = Math.max(0, Math.floor(cappedDelay + jitter))\n\n this.state = 'reconnecting'\n console.log(`[OTel] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt + 1})...`)\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null\n this.reconnectAttempt++\n this.connect()\n }, delay)\n }\n\n /**\n * Send a message with a signal prefix.\n */\n send(prefix: string, data: Uint8Array, callback?: (err?: Error) => void): void {\n const prefixBytes = Buffer.from(prefix, 'utf-8')\n const frame = Buffer.concat([prefixBytes, Buffer.from(data)])\n\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(frame, callback)\n } else {\n // Queue for later with bounded size to prevent memory exhaustion\n if (this.pendingMessages.length >= SharedEngineConnection.MAX_PENDING_MESSAGES) {\n console.warn('[OTel] Pending message queue full, dropping oldest message')\n const dropped = this.pendingMessages.shift()\n dropped?.callback?.(new Error('Message dropped due to queue overflow'))\n }\n this.pendingMessages.push({ frame, callback })\n this.connect()\n }\n }\n\n /**\n * Register a callback to be called when connected.\n */\n onConnected(callback: () => void): void {\n this.onConnectedCallbacks.push(callback)\n if (this.state === 'connected') {\n callback()\n }\n }\n\n /**\n * Register a callback to be called when the connection enters the failed\n * terminal state (max retries reached). Exporters use this to drain their\n * own pending queues so in-flight forceFlush() calls do not hang.\n */\n onFailed(callback: () => void): void {\n this.onFailedCallbacks.push(callback)\n if (this.state === 'failed') {\n try {\n callback()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n\n /**\n * Get the current connection state.\n */\n getState(): ConnectionState {\n return this.state\n }\n\n /**\n * Whether the connection is shutting down. While shutting down, exporters\n * fail-fast instead of queueing when there is no live connection, so a final\n * forceFlush() can't hang waiting for a reconnect that will never happen.\n */\n isShuttingDown(): boolean {\n return this.shuttingDown\n }\n\n /**\n * Begin shutdown: stop reconnecting and stop accepting new queued exports,\n * while leaving an open connection in place so buffered telemetry can still\n * be flushed. Call before flushing, then call shutdown() to close fully.\n */\n beginShutdown(): void {\n if (this.shuttingDown) {\n return\n }\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // With no live connection there's nothing to flush to, so fail queued work\n // now instead of leaving callbacks unresolved for the flush below to wait on\n if (this.state !== 'connected') {\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n }\n\n /**\n * Shutdown the connection.\n */\n async shutdown(): Promise<void> {\n // Set shutdown flag to prevent reconnection attempts\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n this.onConnectedCallbacks = []\n this.onFailedCallbacks = []\n this.state = 'disconnected'\n }\n}\n","/**\n * Span exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'\nimport { JsonTraceSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_TRACES } from './types'\n\n/**\n * Span exporter using the shared WebSocket connection.\n */\nexport class EngineSpanExporter implements SpanExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n spans: ReadableSpan[]\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { spans, resultCallback } of pending) {\n this.sendExport(spans, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued spans')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(spans: ReadableSpan[], resultCallback?: (result: ExportResult) => void): void {\n try {\n const serialized = JsonTraceSerializer.serializeRequest(spans)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_TRACES, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send spans:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting spans:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping spans`),\n })\n return\n }\n if (this.pendingExports.length >= EngineSpanExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Spans export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ spans, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(spans, resultCallback)\n }\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(spans, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op, spans are sent immediately\n }\n}\n","/**\n * Metrics exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics'\nimport { JsonMetricsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_METRICS } from './types'\n\n/**\n * Metrics exporter using the shared WebSocket connection.\n */\nexport class EngineMetricsExporter implements PushMetricExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n metrics: ResourceMetrics\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { metrics, resultCallback } of pending) {\n this.sendExport(metrics, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued metrics')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(\n metricsData: ResourceMetrics,\n resultCallback?: (result: ExportResult) => void,\n ): void {\n try {\n const serialized = JsonMetricsSerializer.serializeRequest(metricsData)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_METRICS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send metrics:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting metrics:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(\n metricsData: ResourceMetrics,\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping metrics`),\n })\n return\n }\n if (this.pendingExports.length >= EngineMetricsExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Metrics export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ metrics: metricsData, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(metricsData, resultCallback)\n }\n\n export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {\n this.doExport(metrics, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op\n }\n}\n","/**\n * Log exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { LogRecordExporter, ReadableLogRecord } from '@opentelemetry/sdk-logs'\nimport { JsonLogsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_LOGS } from './types'\n\n/**\n * Log exporter using the shared WebSocket connection.\n */\nexport class EngineLogExporter implements LogRecordExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n logs: ReadableLogRecord[]\n callback: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { logs, callback } of pending) {\n this.doExport(logs, callback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued logs')\n for (const { callback } of pending) {\n callback({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private doExport(\n logs: ReadableLogRecord[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping logs`),\n })\n return\n }\n if (this.pendingExports.length >= EngineLogExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.callback({\n code: ExportResultCode.FAILED,\n error: new Error('Logs export queue full'),\n })\n console.warn('[OTel] Logs export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ logs, callback: resultCallback })\n return\n }\n\n try {\n const serialized = JsonLogsSerializer.serializeRequest(logs)\n if (!serialized) {\n resultCallback({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_LOGS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send logs:', err.message)\n resultCallback({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting logs:', err)\n resultCallback({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(logs, resultCallback)\n }\n\n async forceFlush(): Promise<void> {}\n\n async shutdown(): Promise<void> {\n for (const { callback } of this.pendingExports) {\n callback({ code: ExportResultCode.FAILED, error: new Error('Exporter shutdown') })\n }\n this.pendingExports = []\n }\n}\n","/**\n * Trace context and baggage propagation utilities.\n */\n\nimport { trace, context, propagation, type Context } from '@opentelemetry/api'\n\n/**\n * Extract the current trace ID from the active span context.\n */\nexport function currentTraceId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.traceId && spanContext.traceId !== '00000000000000000000000000000000') {\n return spanContext.traceId\n }\n }\n return undefined\n}\n\n/**\n * Extract the current span ID from the active span context.\n */\nexport function currentSpanId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.spanId && spanContext.spanId !== '0000000000000000') {\n return spanContext.spanId\n }\n }\n return undefined\n}\n\n/**\n * Inject the current trace context into a W3C traceparent header string.\n */\nexport function injectTraceparent(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.traceparent\n}\n\n/**\n * Extract a trace context from a W3C traceparent header string.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n */\nexport function extractTraceparent(traceparent: string): Context {\n const carrier: Record<string, string> = { traceparent }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Inject the current baggage into a W3C baggage header string.\n */\nexport function injectBaggage(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.baggage\n}\n\n/**\n * Extract baggage from a W3C baggage header string.\n *\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractBaggage(baggage: string): Context {\n const carrier: Record<string, string> = { baggage }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Extract both trace context and baggage from their respective headers.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractContext(traceparent?: string, baggage?: string): Context {\n const carrier: Record<string, string> = {}\n if (traceparent) {\n carrier.traceparent = traceparent\n }\n if (baggage) {\n carrier.baggage = baggage\n }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Get a baggage entry from the current context.\n *\n * @param key - Baggage entry key to read.\n */\nexport function getBaggageEntry(key: string): string | undefined {\n const bag = propagation.getBaggage(context.active())\n return bag?.getEntry(key)?.value\n}\n\n/**\n * Set a baggage entry in the current context.\n *\n * @param key - Baggage entry key to set.\n * @param value - Baggage entry value to set.\n */\nexport function setBaggageEntry(key: string, value: string): Context {\n let bag = propagation.getBaggage(context.active()) ?? propagation.createBaggage()\n bag = bag.setEntry(key, { value })\n return propagation.setBaggage(context.active(), bag)\n}\n\n/**\n * Remove a baggage entry from the current context.\n *\n * @param key - Baggage entry key to remove.\n */\nexport function removeBaggageEntry(key: string): Context {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return context.active()\n }\n const newBag = bag.removeEntry(key)\n return propagation.setBaggage(context.active(), newBag)\n}\n\n/**\n * Get all baggage entries from the current context.\n */\nexport function getAllBaggage(): Record<string, string> {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return {}\n }\n const entries: Record<string, string> = {}\n for (const [key, entry] of bag.getAllEntries()) {\n entries[key] = entry.value\n }\n return entries\n}\n","/**\n * Global fetch auto-instrumentation for the III Node SDK.\n *\n * Patches globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n * Works on all runtimes (Bun, Node.js, Deno) unlike UndiciInstrumentation\n * which only works when fetch is backed by Node.js's undici.\n */\n\nimport { type Tracer, SpanKind, SpanStatusCode, context, propagation } from '@opentelemetry/api'\n\nconst textEncoder = new TextEncoder()\n\nfunction getBodyByteSize(body: unknown): number | undefined {\n if (body == null) return undefined\n if (typeof body === 'string') return textEncoder.encode(body).byteLength\n if (body instanceof ArrayBuffer) return body.byteLength\n if (ArrayBuffer.isView(body)) return body.byteLength\n if (body instanceof Blob) return body.size\n if (body instanceof URLSearchParams) return new TextEncoder().encode(body.toString()).byteLength\n return undefined\n}\n\nconst SAFE_REQUEST_HEADERS = ['content-type', 'accept'] as const\nconst SAFE_RESPONSE_HEADERS = ['content-type'] as const\n\nlet originalFetch: typeof globalThis.fetch | null = null\n\n/**\n * Substring patterns from `OTEL_FETCH_IGNORE_URLS` (comma-separated). A fetch\n * whose URL contains any pattern is executed WITHOUT creating a span, use it\n * to drop noisy/high-frequency calls (health checks, polling, internal\n * endpoints) that would otherwise flood traces.\n */\nconst FETCH_IGNORE_URL_PATTERNS: string[] = (process.env.OTEL_FETCH_IGNORE_URLS ?? '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n\nfunction shouldIgnoreFetchUrl(url: string): boolean {\n return FETCH_IGNORE_URL_PATTERNS.some(pattern => url.includes(pattern))\n}\n\n/**\n * Patch globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n *\n * @param tracer - Tracer used to create the client span for each request.\n */\nexport function patchGlobalFetch(tracer: Tracer): void {\n if (originalFetch) return\n\n originalFetch = globalThis.fetch\n const capturedFetch = originalFetch\n\n globalThis.fetch = async (\n input: string | URL | Request,\n init?: RequestInit,\n ): Promise<Response> => {\n const url = input instanceof Request ? input.url : String(input)\n\n // Skip tracing entirely for ignored URLs (no span, no context injection).\n if (shouldIgnoreFetchUrl(url)) {\n return capturedFetch(input, init)\n }\n\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n\n let host: string | undefined\n let scheme: string | undefined\n let path: string | undefined\n let port: number | undefined\n let query: string | undefined\n try {\n const parsed = new URL(url)\n host = parsed.hostname\n scheme = parsed.protocol.replace(':', '')\n path = parsed.pathname\n port = parsed.port ? parseInt(parsed.port, 10) : undefined\n query = parsed.search ? parsed.search.slice(1) : undefined\n } catch {\n // relative URL or invalid, skip host/scheme/path attributes\n }\n\n const spanAttributes: Record<string, string | number> = {\n 'http.request.method': method,\n 'url.full': url,\n }\n if (host) spanAttributes['server.address'] = host\n if (scheme) {\n spanAttributes['url.scheme'] = scheme\n spanAttributes['network.protocol.name'] = 'http'\n }\n if (path) spanAttributes['url.path'] = path\n if (port) spanAttributes['server.port'] = port\n if (query) spanAttributes['url.query'] = query\n\n const spanName = path ? `${method} ${path}` : method\n\n return tracer.startActiveSpan(\n spanName,\n { kind: SpanKind.CLIENT, attributes: spanAttributes },\n context.active(),\n async span => {\n try {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n for (const [key, value] of Object.entries(carrier)) {\n headers.set(key, value)\n }\n\n for (const name of SAFE_REQUEST_HEADERS) {\n const value = headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.request.header.${name}`, value)\n }\n }\n\n const requestBody = init?.body ?? (input instanceof Request ? input.body : undefined)\n const requestBodySize = getBodyByteSize(requestBody)\n if (requestBodySize !== undefined) {\n span.setAttribute('http.request.body.size', requestBodySize)\n }\n\n const response = await capturedFetch(input, { ...init, headers })\n\n span.setAttribute('http.response.status_code', response.status)\n\n const contentLength = response.headers.get('content-length')\n if (contentLength !== null) {\n const size = parseInt(contentLength, 10)\n if (!Number.isNaN(size)) {\n span.setAttribute('http.response.body.size', size)\n }\n }\n\n for (const name of SAFE_RESPONSE_HEADERS) {\n const value = response.headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.response.header.${name}`, value)\n }\n }\n\n if (response.status >= 400) {\n span.setAttribute('error.type', String(response.status))\n span.setStatus({ code: SpanStatusCode.ERROR })\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n return response\n } catch (error) {\n span.setAttribute('error.type', (error as Error).name ?? 'Error')\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n },\n )\n }\n}\n\n/**\n * Restore globalThis.fetch to its original implementation.\n */\nexport function unpatchGlobalFetch(): void {\n if (originalFetch) {\n globalThis.fetch = originalFetch\n originalFetch = null\n }\n}\n","/**\n * Parse a numeric environment variable with optional minimum bound.\n *\n * An empty or whitespace-only string is treated as unset: `Number('')` is 0,\n * so without this check a variable set-but-blank (common in .env files) would\n * silently resolve to 0 instead of falling through to the default.\n */\nexport function parseNumberEnv(value: string | undefined, minimum: number = 0): number | undefined {\n if (value === undefined || value.trim() === '') return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed < minimum) return undefined\n return parsed\n}\n\n/**\n * Parse an integer environment variable with optional minimum bound.\n */\nexport function parseIntegerEnv(\n value: string | undefined,\n minimum: number = 0,\n): number | undefined {\n const parsed = parseNumberEnv(value, minimum)\n if (parsed === undefined || !Number.isInteger(parsed)) return undefined\n return parsed\n}\n\n/**\n * Resolve a batch-processor flush delay: explicit config wins, then the\n * III-specific env var, then the III default.\n *\n * III SDKs deliberately expose a single OTEL_*_FLUSH_INTERVAL_MS knob and do\n * NOT honor the standard OTel OTEL_BSP_SCHEDULE_DELAY / OTEL_BLRP_SCHEDULE_DELAY\n * vars, for cross-SDK consistency (the Node, Python, and Rust SDKs all resolve\n * the same way). Passing an explicit `scheduledDelayMillis` to the processor\n * already makes the OTel SDK ignore those standard vars regardless.\n */\nexport function resolveFlushIntervalMs(\n configValue: number | undefined,\n envValue: string | undefined,\n defaultValue: number,\n): number {\n return configValue ?? parseNumberEnv(envValue, 0) ?? defaultValue\n}\n","/** High-level span operations so consumers don't need `@opentelemetry/api`. */\n\nimport { SpanStatusCode, trace, type AttributeValue, type Attributes } from '@opentelemetry/api'\n\n/** Returns `false` when there is no active span or the sampler dropped it. */\nexport function currentSpanIsRecording(): boolean {\n const span = trace.getActiveSpan()\n return span ? span.isRecording() : false\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param key - Attribute key to set on the active span.\n * @param value - Attribute value to set.\n */\nexport function setCurrentSpanAttribute(key: string, value: AttributeValue): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.setAttribute(key, value)\n}\n\n/**\n * No-op when there is no active span.\n *\n * @param message - Error message to set as the span's error status.\n */\nexport function setCurrentSpanError(message: string): void {\n const span = trace.getActiveSpan()\n if (!span) return\n span.setStatus({ code: SpanStatusCode.ERROR, message })\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param name - Name of the event to add to the active span.\n * @param attrs - Optional attributes to attach to the event.\n */\nexport function recordSpanEvent(name: string, attrs?: Attributes): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.addEvent(name, attrs)\n}\n","/** Payload redaction + truncation for invocation event capture. */\n\nexport const REDACTED_PLACEHOLDER = '[REDACTED]'\nconst TRUNCATION_MARKER = '...\"[TRUNCATED]\"'\n\n/**\n * Resolve the payload byte cap from the environment, returning undefined when\n * unset.\n */\nexport function resolveMaxBytesFromEnv(): number | null {\n const raw = process.env.III_TRACE_PAYLOAD_MAX_BYTES\n if (raw === undefined) return null\n const trimmed = raw.trim()\n if (trimmed === '' || trimmed.toLowerCase() === 'unlimited') return null\n // parseInt accepts partial parses like \"8192mb\" → 8192; Python int()\n // and Rust parse::<usize>() reject those. Match the strict semantics.\n if (!/^\\d+$/.test(trimmed)) return null\n const parsed = Number(trimmed)\n if (parsed <= 0) return null\n return parsed\n}\n\nconst SENSITIVE_FRAGMENTS = [\n 'api_key',\n 'apikey',\n 'api-key',\n 'password',\n 'secret',\n 'credential',\n 'authorization',\n 'auth_token',\n 'access_token',\n 'refresh_token',\n 'bearer',\n 'private_key',\n 'client_secret',\n]\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase()\n if (SENSITIVE_FRAGMENTS.some((fragment) => lower.includes(fragment))) return true\n // `token` alone is too common a substring; require whole-key or suffix match.\n return lower === 'token' || lower.endsWith('_token') || lower.endsWith('-token')\n}\n\n/**\n * Recursively redact values of sensitive keys. Returns a new value.\n *\n * @param value - The value to recursively redact.\n */\nexport function redact(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (Array.isArray(value)) return value.map(redact)\n if (typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = isSensitiveKey(k) ? REDACTED_PLACEHOLDER : redact(v)\n }\n return out\n }\n return value\n}\n\n/**\n * Redact then serialize to JSON, optionally capped at `maxBytes`.\n *\n * @param value - The value to redact and serialize.\n * @param maxBytes - Maximum serialized size in bytes; null leaves it uncapped.\n */\nexport function redactAndTruncate(\n value: unknown,\n maxBytes: number | null = null,\n): { json: string; truncated: boolean } {\n const redacted = redact(value)\n let serialized: string\n try {\n serialized = JSON.stringify(redacted) ?? 'null'\n } catch {\n serialized = 'null'\n }\n\n if (maxBytes === null || maxBytes === undefined || maxBytes <= 0) {\n return { json: serialized, truncated: false }\n }\n\n const byteLen = Buffer.byteLength(serialized, 'utf8')\n if (byteLen <= maxBytes) {\n return { json: serialized, truncated: false }\n }\n\n const markerLen = Buffer.byteLength(TRUNCATION_MARKER, 'utf8')\n // When maxBytes is smaller than the marker itself, emit only a\n // truncated marker so the result never exceeds the cap.\n if (maxBytes <= markerLen) {\n return { json: TRUNCATION_MARKER.slice(0, maxBytes), truncated: true }\n }\n\n const cap = maxBytes - markerLen\n const buf = Buffer.from(serialized, 'utf8')\n let cut = Math.min(cap, buf.length)\n // Walk back to a UTF-8 boundary so we don't emit half-codepoints.\n while (cut > 0 && (buf[cut] & 0xc0) === 0x80) {\n cut -= 1\n }\n const truncated = buf.subarray(0, cut).toString('utf8') + TRUNCATION_MARKER\n return { json: truncated, truncated: true }\n}\n","/**\n * OpenTelemetry initialization for the III Node SDK.\n *\n * This module provides trace, metrics, and log export to the III Engine\n * via a shared WebSocket connection using OTLP JSON format.\n */\n\nimport { Resource } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'\nimport { randomUUID } from 'node:crypto'\nimport {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n metrics,\n type Span,\n type Context,\n type Tracer,\n type Meter,\n} from '@opentelemetry/api'\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'\nimport { BaggageSpanProcessor } from './baggage-span-processor'\nimport { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'\nimport { registerInstrumentations } from '@opentelemetry/instrumentation'\nimport { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'\nimport { type Logger, SeverityNumber } from '@opentelemetry/api-logs'\n\nimport {\n type OtelConfig,\n DEFAULT_OTEL_CONFIG,\n parseBoolEnv,\n ATTR_SERVICE_VERSION,\n ATTR_SERVICE_NAMESPACE,\n ATTR_SERVICE_INSTANCE_ID,\n} from './types'\nimport { SharedEngineConnection } from './connection'\nimport { EngineSpanExporter, EngineMetricsExporter, EngineLogExporter } from './exporters'\nimport { extractTraceparent } from './context'\nimport { patchGlobalFetch, unpatchGlobalFetch } from './fetch-instrumentation'\nimport { parseIntegerEnv, resolveFlushIntervalMs } from './utils'\n\n// Re-export everything from submodules\nexport * from './types'\nexport * from './context'\nexport { BaggageSpanProcessor } from './baggage-span-processor'\nexport {\n currentSpanIsRecording,\n recordSpanEvent,\n setCurrentSpanAttribute,\n setCurrentSpanError,\n} from './span-ops'\nexport {\n REDACTED_PLACEHOLDER,\n redact,\n redactAndTruncate,\n resolveMaxBytesFromEnv,\n} from './payload'\n\n/**\n * Normalize an engine WebSocket URL into the dedicated OTEL endpoint.\n * The engine exposes `/otel` for telemetry-only WS connections; routing\n * there keeps this socket out of the worker registry (otherwise it shows\n * up as a ghost null-metadata worker).\n */\nfunction appendOtelPath(base: string): string {\n const url = new URL(base)\n const path = url.pathname.replace(/\\/+$/, '')\n url.pathname = path.endsWith('/otel') ? path : `${path}/otel`\n return url.toString()\n}\n\n// Module-level state\nlet sharedConnection: SharedEngineConnection | null = null\nlet tracerProvider: NodeTracerProvider | null = null\nlet meterProvider: MeterProvider | null = null\nlet loggerProvider: LoggerProvider | null = null\nlet tracer: Tracer | null = null\nlet meter: Meter | null = null\nlet logger: Logger | null = null\nlet serviceName: string = 'iii-node-iii'\n\n/**\n * Initialize OpenTelemetry with the given configuration.\n * This should be called once at application startup.\n *\n * @param config - OpenTelemetry configuration; env vars fill in unset fields.\n */\nexport function initOtel(config: OtelConfig = {}): void {\n const enabled = config.enabled ?? parseBoolEnv(process.env.OTEL_ENABLED, DEFAULT_OTEL_CONFIG.enabled)\n\n if (!enabled) {\n console.debug(\n '[OTel] OpenTelemetry is disabled. To enable, remove OTEL_ENABLED=false or set enabled: true in config.',\n )\n return\n }\n\n // Configure service identity\n serviceName = config.serviceName ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_OTEL_CONFIG.serviceName\n const serviceVersion = config.serviceVersion ?? process.env.SERVICE_VERSION ?? DEFAULT_OTEL_CONFIG.serviceVersion\n const serviceNamespace = config.serviceNamespace ?? process.env.SERVICE_NAMESPACE\n const serviceInstanceId = config.serviceInstanceId ?? process.env.SERVICE_INSTANCE_ID ?? randomUUID()\n const engineWsUrl = config.engineWsUrl ?? process.env.III_URL ?? DEFAULT_OTEL_CONFIG.engineWsUrl\n\n // Build resource attributes\n const resourceAttributes: Record<string, string> = {\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n [ATTR_SERVICE_INSTANCE_ID]: serviceInstanceId,\n }\n if (serviceNamespace) {\n resourceAttributes[ATTR_SERVICE_NAMESPACE] = serviceNamespace\n }\n const resource = new Resource(resourceAttributes)\n\n // Create shared WebSocket connection.\n // OTEL always connects to the engine's dedicated `/otel` endpoint so\n // the telemetry socket doesn't get registered in `worker_registry` as\n // a ghost null-metadata worker alongside the real worker.\n sharedConnection = new SharedEngineConnection(appendOtelPath(engineWsUrl), config.reconnectionConfig)\n\n // BaggageSpanProcessor must register first: onStart fires in\n // registration order, so baggage entries are materialized as span\n // attributes before the batch exporter reads them.\n const spanExporter = new EngineSpanExporter(sharedConnection)\n // Without an explicit scheduledDelayMillis, BatchSpanProcessor inherits the\n // OpenTelemetry default of 5000ms, so an ended span sits in the buffer up to\n // 5s before it is flushed to the engine, the dominant reason traces show up\n // seconds after the action that produced them. Mirror the logs path\n // (BatchLogRecordProcessor below) with a small flush delay. maxExportBatchSize\n // stays at the OTel default so a burst of spans from one turn still coalesces\n // into a single frame rather than one frame per span.\n const spansScheduledDelayMillis = resolveFlushIntervalMs(\n config.spansFlushIntervalMs,\n process.env.OTEL_SPANS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.spansFlushIntervalMs,\n )\n tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [\n new BaggageSpanProcessor(),\n new BatchSpanProcessor(spanExporter, { scheduledDelayMillis: spansScheduledDelayMillis }),\n ],\n })\n\n // Register W3C Trace Context and Baggage propagators\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n }),\n )\n\n tracerProvider.register()\n tracer = trace.getTracer(serviceName)\n\n console.debug(`[OTel] Traces initialized: engine=${engineWsUrl}, service=${serviceName}`)\n\n // Initialize metrics (enabled by default, opt-out via config or env)\n const metricsEnabled =\n config.metricsEnabled ?? parseBoolEnv(process.env.OTEL_METRICS_ENABLED, DEFAULT_OTEL_CONFIG.metricsEnabled)\n\n if (metricsEnabled) {\n const metricsExporter = new EngineMetricsExporter(sharedConnection)\n const exportIntervalMs = config.metricsExportIntervalMs ?? DEFAULT_OTEL_CONFIG.metricsExportIntervalMs\n\n const metricReader = new PeriodicExportingMetricReader({\n exporter: metricsExporter,\n exportIntervalMillis: exportIntervalMs,\n })\n\n meterProvider = new MeterProvider({\n resource,\n readers: [metricReader],\n })\n\n metrics.setGlobalMeterProvider(meterProvider)\n meter = meterProvider.getMeter(serviceName)\n\n console.debug(`[OTel] Metrics initialized: interval=${exportIntervalMs}ms`)\n }\n\n // Register user-provided instrumentations AFTER providers are set up\n const instrumentations = [...(config.instrumentations ?? [])]\n if (instrumentations.length > 0) {\n registerInstrumentations({\n instrumentations,\n tracerProvider,\n meterProvider: meterProvider ?? undefined,\n })\n console.debug(`[OTel] Instrumentations registered: ${instrumentations.length} total`)\n }\n\n // Patch global fetch for runtime-agnostic HTTP client tracing (works on Bun, Node.js, Deno)\n const fetchEnabled = config.fetchInstrumentationEnabled ?? DEFAULT_OTEL_CONFIG.fetchInstrumentationEnabled\n\n if (fetchEnabled) {\n patchGlobalFetch(tracer)\n console.debug('[OTel] Global fetch instrumentation enabled')\n }\n\n // Initialize logs (always enabled when OTEL is enabled)\n const logExporter = new EngineLogExporter(sharedConnection)\n const logsScheduledDelayMillis = resolveFlushIntervalMs(\n config.logsFlushIntervalMs,\n process.env.OTEL_LOGS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.logsFlushIntervalMs,\n )\n const logsMaxExportBatchSize =\n config.logsBatchSize ?? parseIntegerEnv(process.env.OTEL_LOGS_BATCH_SIZE, 1) ?? DEFAULT_OTEL_CONFIG.logsBatchSize\n\n loggerProvider = new LoggerProvider({ resource })\n loggerProvider.addLogRecordProcessor(\n new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: logsScheduledDelayMillis,\n maxExportBatchSize: logsMaxExportBatchSize,\n }),\n )\n logger = loggerProvider.getLogger(serviceName)\n\n console.debug(`[OTel] Logs initialized: delay=${logsScheduledDelayMillis}ms, batch=${logsMaxExportBatchSize}`)\n}\n\n/**\n * Shut down OpenTelemetry, best-effort flushing any pending data before\n * teardown.\n */\nexport async function shutdownOtel(): Promise<void> {\n // Stop reconnecting/queuing before flushing so a final forceFlush() can't hang on a dead engine\n sharedConnection?.beginShutdown()\n\n // Flushing is best-effort on shutdown: when the engine is gone the exporters\n // fail their pending exports, which rejects forceFlush()/shutdown(). Swallow\n // those so a dropped final flush can't crash or block teardown.\n const settle = (p: Promise<unknown>) => p.catch(() => {})\n\n if (tracerProvider) {\n await settle(tracerProvider.forceFlush())\n await settle(tracerProvider.shutdown())\n tracerProvider = null\n }\n\n if (meterProvider) {\n await settle(meterProvider.forceFlush())\n await settle(meterProvider.shutdown())\n meterProvider = null\n }\n\n if (loggerProvider) {\n await settle(loggerProvider.forceFlush())\n await settle(loggerProvider.shutdown())\n loggerProvider = null\n }\n\n if (sharedConnection) {\n await sharedConnection.shutdown()\n sharedConnection = null\n }\n\n unpatchGlobalFetch()\n\n tracer = null\n meter = null\n logger = null\n}\n\n/**\n * Force-flush all OTel providers without tearing them down.\n *\n * Counterpart to {@link shutdownOtel}. Use before short-lived process exits\n * where you want pending spans/metrics/logs delivered but plan to keep using\n * OTel afterwards.\n */\nexport async function flushOtel(): Promise<void> {\n await Promise.all(\n [\n tracerProvider?.forceFlush(),\n meterProvider?.forceFlush(),\n loggerProvider?.forceFlush(),\n ].filter(Boolean),\n )\n}\n\n/**\n * Get the OpenTelemetry tracer instance.\n */\nexport function getTracer(): Tracer | null {\n return tracer\n}\n\n/**\n * Get the OpenTelemetry meter instance.\n */\nexport function getMeter(): Meter | null {\n return meter\n}\n\n/**\n * Get the OpenTelemetry logger instance.\n */\nexport function getLogger(): Logger | null {\n return logger\n}\n\n/**\n * Start a new span with the given name and run the callback within it.\n *\n * @param name - Name of the span to create.\n * @param options - Span options: `kind` sets the span kind, `traceparent` sets the parent context from a W3C traceparent header.\n * @param fn - Callback run inside the active span; its result is returned.\n */\nexport async function withSpan<T>(\n name: string,\n options: { kind?: SpanKind; traceparent?: string },\n fn: (span: Span) => Promise<T>,\n): Promise<T> {\n if (!tracer) {\n // Execute without span context when tracer is not initialized\n // Provide a no-op span to avoid runtime errors if fn calls span methods\n const noopSpan: Span = {\n spanContext: () => ({ traceId: '', spanId: '', traceFlags: 0 }),\n setAttribute: () => noopSpan,\n setAttributes: () => noopSpan,\n addEvent: () => noopSpan,\n addLink: () => noopSpan,\n setStatus: () => noopSpan,\n updateName: () => noopSpan,\n end: () => {},\n isRecording: () => false,\n recordException: () => {},\n addLinks: () => noopSpan,\n }\n return fn(noopSpan)\n }\n\n const parentContext = options.traceparent ? extractTraceparent(options.traceparent) : context.active()\n\n return tracer.startActiveSpan(name, { kind: options.kind ?? SpanKind.INTERNAL }, parentContext, async (span) => {\n try {\n const result = await fn(span)\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (error) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n// Re-export OTEL types for convenience\nexport { SpanKind, SpanStatusCode, SeverityNumber, type Span, type Context, type Tracer, type Meter, type Logger as OtelApiLogger }\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,IAAa,uBAAb,MAA2D;CACzD,QAAQ,MAAY,eAA8B;AAEhD,MAAI,CAAC,KAAK,aAAa,CACrB;EAGF,MAAM,UAAU,YAAY,WAAW,cAAc;AACrD,MAAI,CAAC,QACH;AAGF,OAAK,MAAM,CAAC,KAAK,UAAU,QAAQ,eAAe,CAChD,MAAK,aAAa,KAAK,MAAM,MAAM;;CAIvC,MAAM,OAA2B;CAIjC,MAAM,WAA0B;CAIhC,MAAM,aAA4B;;;;;ACtCpC,MAAa,uBAAuB;AACpC,MAAa,yBAAyB;AACtC,MAAa,2BAA2B;;AAGxC,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;AAC9B,MAAa,cAAc;;AAoB3B,MAAa,8BAAkD;CAC7D,gBAAgB;CAChB,YAAY;CACZ,mBAAmB;CACnB,cAAc;CACd,YAAY;CACb;;AAwCD,MAAa,sBAAsB;CACjC,SAAS;CACT,aAAa;CACb,gBAAgB;CAChB,aAAa;CACb,gBAAgB;CAChB,yBAAyB;CACzB,sBAAsB;CACtB,qBAAqB;CACrB,eAAe;CACf,6BAA6B;CAC9B;;AAGD,SAAgB,aAAa,OAA2B,cAAgC;AACtF,KAAI,UAAU,OAAW,QAAO;CAChC,MAAM,QAAQ,MAAM,aAAa;AACjC,QAAO,UAAU,WAAW,UAAU,OAAO,UAAU,QAAQ,UAAU;;;;;;;;;;;;ACtF3E,IAAa,yBAAb,MAAa,uBAAuB;CAClC,OAAwB,uBAAuB;CAC/C,AAAQ,KAAuB;CAC/B,AAAQ;CACR,AAAQ,aAAa;CACrB,AAAQ,eAAe;CACvB,AAAQ,kBAA8E,EAAE;CACxF,AAAQ,mBAAmB;CAC3B,AAAQ,mBAA0C;CAClD,AAAQ;CACR,AAAQ,QAAyB;CACjC,AAAQ,uBAA0C,EAAE;CACpD,AAAQ,oBAAuC,EAAE;CAEjD,YAAY,OAAe,SAAsC,EAAE,EAAE;AACnE,OAAK,QAAQ;AACb,OAAK,SAAS;GAAE,GAAG;GAA6B,GAAG;GAAQ;AAC3D,OAAK,SAAS;;CAGhB,AAAQ,UAAgB;AACtB,MAAI,KAAK,cAAe,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,KAClE;AAGF,OAAK,aAAa;AAClB,OAAK,QAAQ;AAEb,MAAI;AACF,QAAK,KAAK,IAAI,UAAU,KAAK,MAAM;AAEnC,QAAK,GAAG,GAAG,cAAc;AACvB,SAAK,aAAa;AAClB,SAAK,QAAQ;AACb,YAAQ,IAAI,iCAAiC,KAAK,QAAQ;AAG1D,QAAI,KAAK,mBAAmB,EAC1B,SAAQ,IAAI,kCAAkC;AAEhD,SAAK,mBAAmB;AAGxB,QAAI,KAAK,kBAAkB;AACzB,kBAAa,KAAK,iBAAiB;AACnC,UAAK,mBAAmB;;IAI1B,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;AAC3E,SAAK,MAAM,EAAE,OAAO,cAAc,QAChC,MAAK,IAAI,KAAK,QAAO,QAAO,WAAW,IAAI,CAAC;AAI9C,SAAK,MAAM,MAAM,KAAK,qBACpB,KAAI;KAEN;AAEF,QAAK,GAAG,GAAG,eAAe;AACxB,SAAK,aAAa;AAClB,SAAK,KAAK;AAGV,QAAI,KAAK,cAAc;AACrB,UAAK,QAAQ;AACb,aAAQ,IAAI,2CAA2C;AACvD;;AAGF,SAAK,QAAQ;AACb,YAAQ,IAAI,qDAAqD;AACjE,SAAK,mBAAmB;KACxB;AAEF,QAAK,GAAG,GAAG,UAAS,QAAO;AACzB,SAAK,aAAa;AAGlB,QAAI,KAAK,aACP;AAGF,YAAQ,MAAM,2BAA2B,IAAI,QAAQ;KACrD;WACK,KAAK;AACZ,QAAK,aAAa;AAClB,WAAQ,MAAM,6BAA6B,IAAI;AAC/C,QAAK,mBAAmB;;;CAI5B,AAAQ,oBAA0B;AAChC,MAAI,KAAK,OAAO,eAAe,MAAM,KAAK,oBAAoB,KAAK,OAAO,YAAY;AACpF,QAAK,QAAQ;AACb,WAAQ,MAAM,uBAAuB,KAAK,OAAO,WAAW,sBAAsB;GAGlF,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;GAC3E,MAAM,8BAAc,IAAI,MAAM,sCAAsC;AACpE,QAAK,MAAM,EAAE,cAAc,QACzB,YAAW,YAAY;AAIzB,QAAK,MAAM,MAAM,KAAK,kBACpB,KAAI;AACF,QAAI;YACG,KAAK;AACZ,YAAQ,MAAM,mCAAmC,IAAI;;AAGzD;;AAGF,MAAI,KAAK,iBACP;EAGF,MAAM,mBACJ,KAAK,OAAO,iBAAiB,KAAK,OAAO,qBAAqB,KAAK;EACrE,MAAM,cAAc,KAAK,IAAI,kBAAkB,KAAK,OAAO,WAAW;EACtE,MAAM,SAAS,cAAc,KAAK,OAAO,gBAAgB,IAAI,KAAK,QAAQ,GAAG;EAC7E,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,OAAO,CAAC;AAE3D,OAAK,QAAQ;AACb,UAAQ,IAAI,0BAA0B,MAAM,cAAc,KAAK,mBAAmB,EAAE,MAAM;AAE1F,OAAK,mBAAmB,iBAAiB;AACvC,QAAK,mBAAmB;AACxB,QAAK;AACL,QAAK,SAAS;KACb,MAAM;;;;;CAMX,KAAK,QAAgB,MAAkB,UAAwC;EAC7E,MAAM,cAAc,OAAO,KAAK,QAAQ,QAAQ;EAChD,MAAM,QAAQ,OAAO,OAAO,CAAC,aAAa,OAAO,KAAK,KAAK,CAAC,CAAC;AAE7D,MAAI,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,KAC9C,MAAK,GAAG,KAAK,OAAO,SAAS;OACxB;AAEL,OAAI,KAAK,gBAAgB,UAAU,uBAAuB,sBAAsB;AAC9E,YAAQ,KAAK,6DAA6D;AAE1E,IADgB,KAAK,gBAAgB,OAAO,EACnC,2BAAW,IAAI,MAAM,wCAAwC,CAAC;;AAEzE,QAAK,gBAAgB,KAAK;IAAE;IAAO;IAAU,CAAC;AAC9C,QAAK,SAAS;;;;;;CAOlB,YAAY,UAA4B;AACtC,OAAK,qBAAqB,KAAK,SAAS;AACxC,MAAI,KAAK,UAAU,YACjB,WAAU;;;;;;;CASd,SAAS,UAA4B;AACnC,OAAK,kBAAkB,KAAK,SAAS;AACrC,MAAI,KAAK,UAAU,SACjB,KAAI;AACF,aAAU;WACH,KAAK;AACZ,WAAQ,MAAM,mCAAmC,IAAI;;;;;;CAQ3D,WAA4B;AAC1B,SAAO,KAAK;;;;;;;CAQd,iBAA0B;AACxB,SAAO,KAAK;;;;;;;CAQd,gBAAsB;AACpB,MAAI,KAAK,aACP;AAEF,OAAK,eAAe;AAEpB,MAAI,KAAK,kBAAkB;AACzB,gBAAa,KAAK,iBAAiB;AACnC,QAAK,mBAAmB;;AAK1B,MAAI,KAAK,UAAU,aAAa;GAC9B,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;GAC3E,MAAM,gCAAgB,IAAI,MAAM,mDAAmD;AACnF,QAAK,MAAM,EAAE,cAAc,QACzB,YAAW,cAAc;AAG3B,QAAK,MAAM,MAAM,KAAK,kBACpB,KAAI;AACF,QAAI;YACG,KAAK;AACZ,YAAQ,MAAM,mCAAmC,IAAI;;;;;;;CAS7D,MAAM,WAA0B;AAE9B,OAAK,eAAe;AAEpB,MAAI,KAAK,kBAAkB;AACzB,gBAAa,KAAK,iBAAiB;AACnC,QAAK,mBAAmB;;AAG1B,MAAI,KAAK,IAAI;AACX,QAAK,GAAG,OAAO;AACf,QAAK,KAAK;;EAIZ,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;EAC3E,MAAM,gCAAgB,IAAI,MAAM,mDAAmD;AACnF,OAAK,MAAM,EAAE,cAAc,QACzB,YAAW,cAAc;AAE3B,OAAK,uBAAuB,EAAE;AAC9B,OAAK,oBAAoB,EAAE;AAC3B,OAAK,QAAQ;;;;;;;;;;;;AChQjB,IAAa,qBAAb,MAAa,mBAA2C;CACtD,OAAwB,sBAAsB;CAC9C,AAAQ;CACR,AAAQ,iBAGH,EAAE;CAEP,YAAY,YAAoC;AAC9C,OAAK,aAAa;AAClB,OAAK,WAAW,kBAAkB,KAAK,cAAc,CAAC;AACtD,OAAK,WAAW,eAAe,KAAK,aAAa,CAAC;;CAGpD,AAAQ,eAAqB;EAC3B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;AACzE,OAAK,MAAM,EAAE,OAAO,oBAAoB,QACtC,MAAK,WAAW,OAAO,eAAe;;CAI1C,AAAQ,cAAoB;EAC1B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,wBAAQ,IAAI,MAAM,2CAA2C;AACnE,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAM,iBAAiB;GAAQ;GAAO,CAAC;;CAI9D,AAAQ,WAAW,OAAuB,gBAAuD;AAC/F,MAAI;GACF,MAAM,aAAa,oBAAoB,iBAAiB,MAAM;AAC9D,OAAI,CAAC,YAAY;AACf,qBAAiB,EAAE,MAAM,iBAAiB,SAAS,CAAC;AACpD;;AAGF,QAAK,WAAW,KAAK,eAAe,aAAY,QAAO;AACrD,QAAI,KAAK;AACP,aAAQ,MAAM,gCAAgC,IAAI,QAAQ;AAC1D,sBAAiB;MAAE,MAAM,iBAAiB;MAAQ,OAAO;MAAK,CAAC;UAE/D,kBAAiB,EAAE,MAAM,iBAAiB,SAAS,CAAC;KAEtD;WACK,KAAK;AACZ,WAAQ,MAAM,iCAAiC,IAAI;AACnD,oBAAiB;IAAE,MAAM,iBAAiB;IAAQ,OAAO;IAAc,CAAC;;;CAI5E,AAAQ,SAAS,OAAuB,gBAAsD;EAC5F,MAAM,QAAQ,KAAK,WAAW,UAAU;AACxC,MAAI,UAAU,aAAa;AAEzB,OAAI,UAAU,YAAY,KAAK,WAAW,gBAAgB,EAAE;IAC1D,MAAM,SAAS,UAAU,WAAW,WAAW;AAC/C,mBAAe;KACb,MAAM,iBAAiB;KACvB,uBAAO,IAAI,MAAM,cAAc,OAAO,kBAAkB;KACzD,CAAC;AACF;;AAEF,OAAI,KAAK,eAAe,UAAU,mBAAmB,qBAAqB;AAExE,IADgB,KAAK,eAAe,OAAO,EAClC,iBAAiB;KACxB,MAAM,iBAAiB;KACvB,uBAAO,IAAI,MAAM,iBAAiB;KACnC,CAAC;AACF,YAAQ,KAAK,uDAAuD;;AAEtE,QAAK,eAAe,KAAK;IAAE;IAAO;IAAgB,CAAC;AAEnD;;AAGF,OAAK,WAAW,OAAO,eAAe;;CAGxC,OAAO,OAAuB,gBAAsD;AAClF,OAAK,SAAS,OAAO,eAAe;;CAGtC,MAAM,WAA0B;EAC9B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,gCAAgB,IAAI,MAAM,4CAA4C;AAC5E,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAM,iBAAiB;GAAQ,OAAO;GAAe,CAAC;;CAI7E,MAAM,aAA4B;;;;;;;;;;;AC3FpC,IAAa,wBAAb,MAAa,sBAAoD;CAC/D,OAAwB,sBAAsB;CAC9C,AAAQ;CACR,AAAQ,iBAGH,EAAE;CAEP,YAAY,YAAoC;AAC9C,OAAK,aAAa;AAClB,OAAK,WAAW,kBAAkB,KAAK,cAAc,CAAC;AACtD,OAAK,WAAW,eAAe,KAAK,aAAa,CAAC;;CAGpD,AAAQ,eAAqB;EAC3B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;AACzE,OAAK,MAAM,EAAE,SAAS,oBAAoB,QACxC,MAAK,WAAW,SAAS,eAAe;;CAI5C,AAAQ,cAAoB;EAC1B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,wBAAQ,IAAI,MAAM,6CAA6C;AACrE,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAM,iBAAiB;GAAQ;GAAO,CAAC;;CAI9D,AAAQ,WACN,aACA,gBACM;AACN,MAAI;GACF,MAAM,aAAa,sBAAsB,iBAAiB,YAAY;AACtE,OAAI,CAAC,YAAY;AACf,qBAAiB,EAAE,MAAM,iBAAiB,SAAS,CAAC;AACpD;;AAGF,QAAK,WAAW,KAAK,gBAAgB,aAAY,QAAO;AACtD,QAAI,KAAK;AACP,aAAQ,MAAM,kCAAkC,IAAI,QAAQ;AAC5D,sBAAiB;MAAE,MAAM,iBAAiB;MAAQ,OAAO;MAAK,CAAC;UAE/D,kBAAiB,EAAE,MAAM,iBAAiB,SAAS,CAAC;KAEtD;WACK,KAAK;AACZ,WAAQ,MAAM,mCAAmC,IAAI;AACrD,oBAAiB;IAAE,MAAM,iBAAiB;IAAQ,OAAO;IAAc,CAAC;;;CAI5E,AAAQ,SACN,aACA,gBACM;EACN,MAAM,QAAQ,KAAK,WAAW,UAAU;AACxC,MAAI,UAAU,aAAa;AAEzB,OAAI,UAAU,YAAY,KAAK,WAAW,gBAAgB,EAAE;IAC1D,MAAM,SAAS,UAAU,WAAW,WAAW;AAC/C,mBAAe;KACb,MAAM,iBAAiB;KACvB,uBAAO,IAAI,MAAM,cAAc,OAAO,oBAAoB;KAC3D,CAAC;AACF;;AAEF,OAAI,KAAK,eAAe,UAAU,sBAAsB,qBAAqB;AAE3E,IADgB,KAAK,eAAe,OAAO,EAClC,iBAAiB;KACxB,MAAM,iBAAiB;KACvB,uBAAO,IAAI,MAAM,iBAAiB;KACnC,CAAC;AACF,YAAQ,KAAK,yDAAyD;;AAExE,QAAK,eAAe,KAAK;IAAE,SAAS;IAAa;IAAgB,CAAC;AAElE;;AAGF,OAAK,WAAW,aAAa,eAAe;;CAG9C,OAAO,SAA0B,gBAAsD;AACrF,OAAK,SAAS,SAAS,eAAe;;CAGxC,MAAM,WAA0B;EAC9B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,gCAAgB,IAAI,MAAM,4CAA4C;AAC5E,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAM,iBAAiB;GAAQ,OAAO;GAAe,CAAC;;CAI7E,MAAM,aAA4B;;;;;;;;;;;ACjGpC,IAAa,oBAAb,MAAa,kBAA+C;CAC1D,OAAwB,sBAAsB;CAC9C,AAAQ;CACR,AAAQ,iBAGH,EAAE;CAEP,YAAY,YAAoC;AAC9C,OAAK,aAAa;AAClB,OAAK,WAAW,kBAAkB,KAAK,cAAc,CAAC;AACtD,OAAK,WAAW,eAAe,KAAK,aAAa,CAAC;;CAGpD,AAAQ,eAAqB;EAC3B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;AACzE,OAAK,MAAM,EAAE,MAAM,cAAc,QAC/B,MAAK,SAAS,MAAM,SAAS;;CAIjC,AAAQ,cAAoB;EAC1B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,wBAAQ,IAAI,MAAM,0CAA0C;AAClE,OAAK,MAAM,EAAE,cAAc,QACzB,UAAS;GAAE,MAAM,iBAAiB;GAAQ;GAAO,CAAC;;CAItD,AAAQ,SACN,MACA,gBACM;EACN,MAAM,QAAQ,KAAK,WAAW,UAAU;AACxC,MAAI,UAAU,aAAa;AAEzB,OAAI,UAAU,YAAY,KAAK,WAAW,gBAAgB,EAAE;IAC1D,MAAM,SAAS,UAAU,WAAW,WAAW;AAC/C,mBAAe;KACb,MAAM,iBAAiB;KACvB,uBAAO,IAAI,MAAM,cAAc,OAAO,iBAAiB;KACxD,CAAC;AACF;;AAEF,OAAI,KAAK,eAAe,UAAU,kBAAkB,qBAAqB;AAEvE,IADgB,KAAK,eAAe,OAAO,EAClC,SAAS;KAChB,MAAM,iBAAiB;KACvB,uBAAO,IAAI,MAAM,yBAAyB;KAC3C,CAAC;AACF,YAAQ,KAAK,sDAAsD;;AAErE,QAAK,eAAe,KAAK;IAAE;IAAM,UAAU;IAAgB,CAAC;AAC5D;;AAGF,MAAI;GACF,MAAM,aAAa,mBAAmB,iBAAiB,KAAK;AAC5D,OAAI,CAAC,YAAY;AACf,mBAAe,EAAE,MAAM,iBAAiB,SAAS,CAAC;AAClD;;AAGF,QAAK,WAAW,KAAK,aAAa,aAAY,QAAO;AACnD,QAAI,KAAK;AACP,aAAQ,MAAM,+BAA+B,IAAI,QAAQ;AACzD,oBAAe;MAAE,MAAM,iBAAiB;MAAQ,OAAO;MAAK,CAAC;UAE7D,gBAAe,EAAE,MAAM,iBAAiB,SAAS,CAAC;KAEpD;WACK,KAAK;AACZ,WAAQ,MAAM,gCAAgC,IAAI;AAClD,kBAAe;IAAE,MAAM,iBAAiB;IAAQ,OAAO;IAAc,CAAC;;;CAI1E,OAAO,MAA2B,gBAAsD;AACtF,OAAK,SAAS,MAAM,eAAe;;CAGrC,MAAM,aAA4B;CAElC,MAAM,WAA0B;AAC9B,OAAK,MAAM,EAAE,cAAc,KAAK,eAC9B,UAAS;GAAE,MAAM,iBAAiB;GAAQ,uBAAO,IAAI,MAAM,oBAAoB;GAAE,CAAC;AAEpF,OAAK,iBAAiB,EAAE;;;;;;;;;;;;AC5F5B,SAAgB,iBAAqC;CACnD,MAAM,OAAO,MAAM,eAAe;AAClC,KAAI,MAAM;EACR,MAAM,cAAc,KAAK,aAAa;AACtC,MAAI,YAAY,WAAW,YAAY,YAAY,mCACjD,QAAO,YAAY;;;;;;AASzB,SAAgB,gBAAoC;CAClD,MAAM,OAAO,MAAM,eAAe;AAClC,KAAI,MAAM;EACR,MAAM,cAAc,KAAK,aAAa;AACtC,MAAI,YAAY,UAAU,YAAY,WAAW,mBAC/C,QAAO,YAAY;;;;;;AASzB,SAAgB,oBAAwC;CACtD,MAAM,UAAkC,EAAE;AAC1C,aAAY,OAAO,QAAQ,QAAQ,EAAE,QAAQ;AAC7C,QAAO,QAAQ;;;;;;;AAQjB,SAAgB,mBAAmB,aAA8B;CAC/D,MAAM,UAAkC,EAAE,aAAa;AACvD,QAAO,YAAY,QAAQ,QAAQ,QAAQ,EAAE,QAAQ;;;;;AAMvD,SAAgB,gBAAoC;CAClD,MAAM,UAAkC,EAAE;AAC1C,aAAY,OAAO,QAAQ,QAAQ,EAAE,QAAQ;AAC7C,QAAO,QAAQ;;;;;;;AAQjB,SAAgB,eAAe,SAA0B;CACvD,MAAM,UAAkC,EAAE,SAAS;AACnD,QAAO,YAAY,QAAQ,QAAQ,QAAQ,EAAE,QAAQ;;;;;;;;AASvD,SAAgB,eAAe,aAAsB,SAA2B;CAC9E,MAAM,UAAkC,EAAE;AAC1C,KAAI,YACF,SAAQ,cAAc;AAExB,KAAI,QACF,SAAQ,UAAU;AAEpB,QAAO,YAAY,QAAQ,QAAQ,QAAQ,EAAE,QAAQ;;;;;;;AAQvD,SAAgB,gBAAgB,KAAiC;AAE/D,QADY,YAAY,WAAW,QAAQ,QAAQ,CAAC,EACxC,SAAS,IAAI,EAAE;;;;;;;;AAS7B,SAAgB,gBAAgB,KAAa,OAAwB;CACnE,IAAI,MAAM,YAAY,WAAW,QAAQ,QAAQ,CAAC,IAAI,YAAY,eAAe;AACjF,OAAM,IAAI,SAAS,KAAK,EAAE,OAAO,CAAC;AAClC,QAAO,YAAY,WAAW,QAAQ,QAAQ,EAAE,IAAI;;;;;;;AAQtD,SAAgB,mBAAmB,KAAsB;CACvD,MAAM,MAAM,YAAY,WAAW,QAAQ,QAAQ,CAAC;AACpD,KAAI,CAAC,IACH,QAAO,QAAQ,QAAQ;CAEzB,MAAM,SAAS,IAAI,YAAY,IAAI;AACnC,QAAO,YAAY,WAAW,QAAQ,QAAQ,EAAE,OAAO;;;;;AAMzD,SAAgB,gBAAwC;CACtD,MAAM,MAAM,YAAY,WAAW,QAAQ,QAAQ,CAAC;AACpD,KAAI,CAAC,IACH,QAAO,EAAE;CAEX,MAAM,UAAkC,EAAE;AAC1C,MAAK,MAAM,CAAC,KAAK,UAAU,IAAI,eAAe,CAC5C,SAAQ,OAAO,MAAM;AAEvB,QAAO;;;;;;;;;;;;AC/HT,MAAM,cAAc,IAAI,aAAa;AAErC,SAAS,gBAAgB,MAAmC;AAC1D,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,OAAO,SAAS,SAAU,QAAO,YAAY,OAAO,KAAK,CAAC;AAC9D,KAAI,gBAAgB,YAAa,QAAO,KAAK;AAC7C,KAAI,YAAY,OAAO,KAAK,CAAE,QAAO,KAAK;AAC1C,KAAI,gBAAgB,KAAM,QAAO,KAAK;AACtC,KAAI,gBAAgB,gBAAiB,QAAO,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC;;AAIxF,MAAM,uBAAuB,CAAC,gBAAgB,SAAS;AACvD,MAAM,wBAAwB,CAAC,eAAe;AAE9C,IAAI,gBAAgD;;;;;;;AAQpD,MAAM,6BAAuC,QAAQ,IAAI,0BAA0B,IAChF,MAAM,IAAI,CACV,KAAI,MAAK,EAAE,MAAM,CAAC,CAClB,OAAO,QAAQ;AAElB,SAAS,qBAAqB,KAAsB;AAClD,QAAO,0BAA0B,MAAK,YAAW,IAAI,SAAS,QAAQ,CAAC;;;;;;;AAQzE,SAAgB,iBAAiB,QAAsB;AACrD,KAAI,cAAe;AAEnB,iBAAgB,WAAW;CAC3B,MAAM,gBAAgB;AAEtB,YAAW,QAAQ,OACjB,OACA,SACsB;EACtB,MAAM,MAAM,iBAAiB,UAAU,MAAM,MAAM,OAAO,MAAM;AAGhE,MAAI,qBAAqB,IAAI,CAC3B,QAAO,cAAc,OAAO,KAAK;EAGnC,MAAM,UAAU,MAAM,WAAW,iBAAiB,UAAU,MAAM,SAAS,QAAQ,aAAa;EAEhG,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;AACJ,MAAI;GACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,UAAO,OAAO;AACd,YAAS,OAAO,SAAS,QAAQ,KAAK,GAAG;AACzC,UAAO,OAAO;AACd,UAAO,OAAO,OAAO,SAAS,OAAO,MAAM,GAAG,GAAG;AACjD,WAAQ,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE,GAAG;UAC3C;EAIR,MAAM,iBAAkD;GACtD,uBAAuB;GACvB,YAAY;GACb;AACD,MAAI,KAAM,gBAAe,oBAAoB;AAC7C,MAAI,QAAQ;AACV,kBAAe,gBAAgB;AAC/B,kBAAe,2BAA2B;;AAE5C,MAAI,KAAM,gBAAe,cAAc;AACvC,MAAI,KAAM,gBAAe,iBAAiB;AAC1C,MAAI,MAAO,gBAAe,eAAe;EAEzC,MAAM,WAAW,OAAO,GAAG,OAAO,GAAG,SAAS;AAE9C,SAAO,OAAO,gBACZ,UACA;GAAE,MAAM,SAAS;GAAQ,YAAY;GAAgB,EACrD,QAAQ,QAAQ,EAChB,OAAM,SAAQ;AACZ,OAAI;IACF,MAAM,UAAkC,EAAE;AAC1C,gBAAY,OAAO,QAAQ,QAAQ,EAAE,QAAQ;IAE7C,MAAM,UAAU,IAAI,QAClB,MAAM,YAAY,iBAAiB,UAAU,MAAM,UAAU,QAC9D;AACD,SAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,SAAQ,IAAI,KAAK,MAAM;AAGzB,SAAK,MAAM,QAAQ,sBAAsB;KACvC,MAAM,QAAQ,QAAQ,IAAI,KAAK;AAC/B,SAAI,UAAU,KACZ,MAAK,aAAa,uBAAuB,QAAQ,MAAM;;IAK3D,MAAM,kBAAkB,gBADJ,MAAM,SAAS,iBAAiB,UAAU,MAAM,OAAO,QACvB;AACpD,QAAI,oBAAoB,OACtB,MAAK,aAAa,0BAA0B,gBAAgB;IAG9D,MAAM,WAAW,MAAM,cAAc,OAAO;KAAE,GAAG;KAAM;KAAS,CAAC;AAEjE,SAAK,aAAa,6BAA6B,SAAS,OAAO;IAE/D,MAAM,gBAAgB,SAAS,QAAQ,IAAI,iBAAiB;AAC5D,QAAI,kBAAkB,MAAM;KAC1B,MAAM,OAAO,SAAS,eAAe,GAAG;AACxC,SAAI,CAAC,OAAO,MAAM,KAAK,CACrB,MAAK,aAAa,2BAA2B,KAAK;;AAItD,SAAK,MAAM,QAAQ,uBAAuB;KACxC,MAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK;AACxC,SAAI,UAAU,KACZ,MAAK,aAAa,wBAAwB,QAAQ,MAAM;;AAI5D,QAAI,SAAS,UAAU,KAAK;AAC1B,UAAK,aAAa,cAAc,OAAO,SAAS,OAAO,CAAC;AACxD,UAAK,UAAU,EAAE,MAAM,eAAe,OAAO,CAAC;UAE9C,MAAK,UAAU,EAAE,MAAM,eAAe,IAAI,CAAC;AAG7C,WAAO;YACA,OAAO;AACd,SAAK,aAAa,cAAe,MAAgB,QAAQ,QAAQ;AACjE,SAAK,UAAU;KAAE,MAAM,eAAe;KAAO,SAAU,MAAgB;KAAS,CAAC;AACjF,SAAK,gBAAgB,MAAe;AACpC,UAAM;aACE;AACR,SAAK,KAAK;;IAGf;;;;;;AAOL,SAAgB,qBAA2B;AACzC,KAAI,eAAe;AACjB,aAAW,QAAQ;AACnB,kBAAgB;;;;;;;;;;;;;ACrKpB,SAAgB,eAAe,OAA2B,UAAkB,GAAuB;AACjG,KAAI,UAAU,UAAa,MAAM,MAAM,KAAK,GAAI,QAAO;CACvD,MAAM,SAAS,OAAO,MAAM;AAC5B,KAAI,CAAC,OAAO,SAAS,OAAO,IAAI,SAAS,QAAS,QAAO;AACzD,QAAO;;;;;AAMT,SAAgB,gBACd,OACA,UAAkB,GACE;CACpB,MAAM,SAAS,eAAe,OAAO,QAAQ;AAC7C,KAAI,WAAW,UAAa,CAAC,OAAO,UAAU,OAAO,CAAE,QAAO;AAC9D,QAAO;;;;;;;;;;;;AAaT,SAAgB,uBACd,aACA,UACA,cACQ;AACR,QAAO,eAAe,eAAe,UAAU,EAAE,IAAI;;;;;;;ACpCvD,SAAgB,yBAAkC;CAChD,MAAM,OAAO,MAAM,eAAe;AAClC,QAAO,OAAO,KAAK,aAAa,GAAG;;;;;;;;AASrC,SAAgB,wBAAwB,KAAa,OAA6B;CAChF,MAAM,OAAO,MAAM,eAAe;AAClC,KAAI,CAAC,QAAQ,CAAC,KAAK,aAAa,CAAE;AAClC,MAAK,aAAa,KAAK,MAAM;;;;;;;AAQ/B,SAAgB,oBAAoB,SAAuB;CACzD,MAAM,OAAO,MAAM,eAAe;AAClC,KAAI,CAAC,KAAM;AACX,MAAK,UAAU;EAAE,MAAM,eAAe;EAAO;EAAS,CAAC;;;;;;;;AASzD,SAAgB,gBAAgB,MAAc,OAA0B;CACtE,MAAM,OAAO,MAAM,eAAe;AAClC,KAAI,CAAC,QAAQ,CAAC,KAAK,aAAa,CAAE;AAClC,MAAK,SAAS,MAAM,MAAM;;;;;;ACxC5B,MAAa,uBAAuB;AACpC,MAAM,oBAAoB;;;;;AAM1B,SAAgB,yBAAwC;CACtD,MAAM,MAAM,QAAQ,IAAI;AACxB,KAAI,QAAQ,OAAW,QAAO;CAC9B,MAAM,UAAU,IAAI,MAAM;AAC1B,KAAI,YAAY,MAAM,QAAQ,aAAa,KAAK,YAAa,QAAO;AAGpE,KAAI,CAAC,QAAQ,KAAK,QAAQ,CAAE,QAAO;CACnC,MAAM,SAAS,OAAO,QAAQ;AAC9B,KAAI,UAAU,EAAG,QAAO;AACxB,QAAO;;AAGT,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,eAAe,KAAsB;CAC5C,MAAM,QAAQ,IAAI,aAAa;AAC/B,KAAI,oBAAoB,MAAM,aAAa,MAAM,SAAS,SAAS,CAAC,CAAE,QAAO;AAE7E,QAAO,UAAU,WAAW,MAAM,SAAS,SAAS,IAAI,MAAM,SAAS,SAAS;;;;;;;AAQlF,SAAgB,OAAO,OAAyB;AAC9C,KAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,IAAI,OAAO;AAClD,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,MAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAiC,CACnE,KAAI,KAAK,eAAe,EAAE,GAAG,uBAAuB,OAAO,EAAE;AAE/D,SAAO;;AAET,QAAO;;;;;;;;AAST,SAAgB,kBACd,OACA,WAA0B,MACY;CACtC,MAAM,WAAW,OAAO,MAAM;CAC9B,IAAI;AACJ,KAAI;AACF,eAAa,KAAK,UAAU,SAAS,IAAI;SACnC;AACN,eAAa;;AAGf,KAAI,aAAa,QAAQ,aAAa,UAAa,YAAY,EAC7D,QAAO;EAAE,MAAM;EAAY,WAAW;EAAO;AAI/C,KADgB,OAAO,WAAW,YAAY,OAAO,IACtC,SACb,QAAO;EAAE,MAAM;EAAY,WAAW;EAAO;CAG/C,MAAM,YAAY,OAAO,WAAW,mBAAmB,OAAO;AAG9D,KAAI,YAAY,UACd,QAAO;EAAE,MAAM,kBAAkB,MAAM,GAAG,SAAS;EAAE,WAAW;EAAM;CAGxE,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,OAAO,KAAK,YAAY,OAAO;CAC3C,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO;AAEnC,QAAO,MAAM,MAAM,IAAI,OAAO,SAAU,IACtC,QAAO;AAGT,QAAO;EAAE,MADS,IAAI,SAAS,GAAG,IAAI,CAAC,SAAS,OAAO,GAAG;EAChC,WAAW;EAAM;;;;;;;;;;;;;;;;;ACrC7C,SAAS,eAAe,MAAsB;CAC5C,MAAM,MAAM,IAAI,IAAI,KAAK;CACzB,MAAM,OAAO,IAAI,SAAS,QAAQ,QAAQ,GAAG;AAC7C,KAAI,WAAW,KAAK,SAAS,QAAQ,GAAG,OAAO,GAAG,KAAK;AACvD,QAAO,IAAI,UAAU;;AAIvB,IAAI,mBAAkD;AACtD,IAAI,iBAA4C;AAChD,IAAI,gBAAsC;AAC1C,IAAI,iBAAwC;AAC5C,IAAI,SAAwB;AAC5B,IAAI,QAAsB;AAC1B,IAAI,SAAwB;AAC5B,IAAI,cAAsB;;;;;;;AAQ1B,SAAgB,SAAS,SAAqB,EAAE,EAAQ;AAGtD,KAAI,EAFY,OAAO,WAAW,aAAa,QAAQ,IAAI,cAAc,oBAAoB,QAAQ,GAEvF;AACZ,UAAQ,MACN,yGACD;AACD;;AAIF,eAAc,OAAO,eAAe,QAAQ,IAAI,qBAAqB,oBAAoB;CACzF,MAAM,iBAAiB,OAAO,kBAAkB,QAAQ,IAAI,mBAAmB,oBAAoB;CACnG,MAAM,mBAAmB,OAAO,oBAAoB,QAAQ,IAAI;CAChE,MAAM,oBAAoB,OAAO,qBAAqB,QAAQ,IAAI,uBAAuB,YAAY;CACrG,MAAM,cAAc,OAAO,eAAe,QAAQ,IAAI,WAAW,oBAAoB;CAGrF,MAAM,qBAA6C;GAChD,oBAAoB;GACpB,uBAAuB;GACvB,2BAA2B;EAC7B;AACD,KAAI,iBACF,oBAAmB,0BAA0B;CAE/C,MAAM,WAAW,IAAI,SAAS,mBAAmB;AAMjD,oBAAmB,IAAI,uBAAuB,eAAe,YAAY,EAAE,OAAO,mBAAmB;CAKrG,MAAM,eAAe,IAAI,mBAAmB,iBAAiB;CAQ7D,MAAM,4BAA4B,uBAChC,OAAO,sBACP,QAAQ,IAAI,8BACZ,oBAAoB,qBACrB;AACD,kBAAiB,IAAI,mBAAmB;EACtC;EACA,gBAAgB,CACd,IAAI,sBAAsB,EAC1B,IAAI,mBAAmB,cAAc,EAAE,sBAAsB,2BAA2B,CAAC,CAC1F;EACF,CAAC;AAGF,aAAY,oBACV,IAAI,oBAAoB,EACtB,aAAa,CAAC,IAAI,2BAA2B,EAAE,IAAI,sBAAsB,CAAC,EAC3E,CAAC,CACH;AAED,gBAAe,UAAU;AACzB,UAAS,MAAM,UAAU,YAAY;AAErC,SAAQ,MAAM,qCAAqC,YAAY,YAAY,cAAc;AAMzF,KAFE,OAAO,kBAAkB,aAAa,QAAQ,IAAI,sBAAsB,oBAAoB,eAAe,EAEzF;EAClB,MAAM,kBAAkB,IAAI,sBAAsB,iBAAiB;EACnE,MAAM,mBAAmB,OAAO,2BAA2B,oBAAoB;AAO/E,kBAAgB,IAAI,cAAc;GAChC;GACA,SAAS,CAPU,IAAI,8BAA8B;IACrD,UAAU;IACV,sBAAsB;IACvB,CAAC,CAIuB;GACxB,CAAC;AAEF,UAAQ,uBAAuB,cAAc;AAC7C,UAAQ,cAAc,SAAS,YAAY;AAE3C,UAAQ,MAAM,wCAAwC,iBAAiB,IAAI;;CAI7E,MAAM,mBAAmB,CAAC,GAAI,OAAO,oBAAoB,EAAE,CAAE;AAC7D,KAAI,iBAAiB,SAAS,GAAG;AAC/B,2BAAyB;GACvB;GACA;GACA,eAAe,iBAAiB;GACjC,CAAC;AACF,UAAQ,MAAM,uCAAuC,iBAAiB,OAAO,QAAQ;;AAMvF,KAFqB,OAAO,+BAA+B,oBAAoB,6BAE7D;AAChB,mBAAiB,OAAO;AACxB,UAAQ,MAAM,8CAA8C;;CAI9D,MAAM,cAAc,IAAI,kBAAkB,iBAAiB;CAC3D,MAAM,2BAA2B,uBAC/B,OAAO,qBACP,QAAQ,IAAI,6BACZ,oBAAoB,oBACrB;CACD,MAAM,yBACJ,OAAO,iBAAiB,gBAAgB,QAAQ,IAAI,sBAAsB,EAAE,IAAI,oBAAoB;AAEtG,kBAAiB,IAAI,eAAe,EAAE,UAAU,CAAC;AACjD,gBAAe,sBACb,IAAI,wBAAwB,aAAa;EACvC,sBAAsB;EACtB,oBAAoB;EACrB,CAAC,CACH;AACD,UAAS,eAAe,UAAU,YAAY;AAE9C,SAAQ,MAAM,kCAAkC,yBAAyB,YAAY,yBAAyB;;;;;;AAOhH,eAAsB,eAA8B;AAElD,mBAAkB,eAAe;CAKjC,MAAM,UAAU,MAAwB,EAAE,YAAY,GAAG;AAEzD,KAAI,gBAAgB;AAClB,QAAM,OAAO,eAAe,YAAY,CAAC;AACzC,QAAM,OAAO,eAAe,UAAU,CAAC;AACvC,mBAAiB;;AAGnB,KAAI,eAAe;AACjB,QAAM,OAAO,cAAc,YAAY,CAAC;AACxC,QAAM,OAAO,cAAc,UAAU,CAAC;AACtC,kBAAgB;;AAGlB,KAAI,gBAAgB;AAClB,QAAM,OAAO,eAAe,YAAY,CAAC;AACzC,QAAM,OAAO,eAAe,UAAU,CAAC;AACvC,mBAAiB;;AAGnB,KAAI,kBAAkB;AACpB,QAAM,iBAAiB,UAAU;AACjC,qBAAmB;;AAGrB,qBAAoB;AAEpB,UAAS;AACT,SAAQ;AACR,UAAS;;;;;;;;;AAUX,eAAsB,YAA2B;AAC/C,OAAM,QAAQ,IACZ;EACE,gBAAgB,YAAY;EAC5B,eAAe,YAAY;EAC3B,gBAAgB,YAAY;EAC7B,CAAC,OAAO,QAAQ,CAClB;;;;;AAMH,SAAgB,YAA2B;AACzC,QAAO;;;;;AAMT,SAAgB,WAAyB;AACvC,QAAO;;;;;AAMT,SAAgB,YAA2B;AACzC,QAAO;;;;;;;;;AAUT,eAAsB,SACpB,MACA,SACA,IACY;AACZ,KAAI,CAAC,QAAQ;EAGX,MAAM,WAAiB;GACrB,oBAAoB;IAAE,SAAS;IAAI,QAAQ;IAAI,YAAY;IAAG;GAC9D,oBAAoB;GACpB,qBAAqB;GACrB,gBAAgB;GAChB,eAAe;GACf,iBAAiB;GACjB,kBAAkB;GAClB,WAAW;GACX,mBAAmB;GACnB,uBAAuB;GACvB,gBAAgB;GACjB;AACD,SAAO,GAAG,SAAS;;CAGrB,MAAM,gBAAgB,QAAQ,cAAc,mBAAmB,QAAQ,YAAY,GAAG,QAAQ,QAAQ;AAEtG,QAAO,OAAO,gBAAgB,MAAM,EAAE,MAAM,QAAQ,QAAQA,WAAS,UAAU,EAAE,eAAe,OAAO,SAAS;AAC9G,MAAI;GACF,MAAM,SAAS,MAAM,GAAG,KAAK;AAC7B,QAAK,UAAU,EAAE,MAAMC,iBAAe,IAAI,CAAC;AAC3C,UAAO;WACA,OAAO;AACd,QAAK,UAAU;IAAE,MAAMA,iBAAe;IAAO,SAAU,MAAgB;IAAS,CAAC;AACjF,QAAK,gBAAgB,MAAe;AACpC,SAAM;YACE;AACR,QAAK,KAAK;;GAEZ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"telemetry-system-Dd45rFx-.cjs","names":["propagation","WebSocket","ExportResultCode","JsonTraceSerializer","ExportResultCode","JsonMetricsSerializer","ExportResultCode","JsonLogsSerializer","trace","context","propagation","SpanKind","context","SpanStatusCode","trace","SpanStatusCode","ATTR_SERVICE_NAME","Resource","NodeTracerProvider","BatchSpanProcessor","CompositePropagator","W3CTraceContextPropagator","W3CBaggagePropagator","trace","MeterProvider","PeriodicExportingMetricReader","LoggerProvider","BatchLogRecordProcessor","context","SpanKind","SpanStatusCode"],"sources":["../src/observability/telemetry-system/baggage-span-processor.ts","../src/observability/telemetry-system/types.ts","../src/observability/telemetry-system/connection.ts","../src/observability/telemetry-system/span-exporter.ts","../src/observability/telemetry-system/metrics-exporter.ts","../src/observability/telemetry-system/log-exporter.ts","../src/observability/telemetry-system/context.ts","../src/observability/telemetry-system/fetch-instrumentation.ts","../src/observability/telemetry-system/utils.ts","../src/observability/telemetry-system/span-ops.ts","../src/observability/telemetry-system/payload.ts","../src/observability/telemetry-system/index.ts"],"sourcesContent":["// Baggage -> span attribute processor.\n//\n// Copies EVERY baggage entry onto every span started in its scope,\n// unconditionally — the same contract as the upstream OTel contrib\n// BaggageSpanProcessor. There is deliberately no key filtering here: a\n// filtering policy baked into worker binaries has to be kept in lockstep\n// across every SDK language and every deployed worker, and a stale binary\n// silently drops newer keys. Which attributes *mean* something (e.g. the\n// `iii.tag.*` trace-tag namespace, `iii.session.*`) is a query-side\n// convention owned by the engine's traces API, where it can evolve without\n// touching workers.\n\nimport type { Context } from '@opentelemetry/api'\nimport { propagation } from '@opentelemetry/api'\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base'\n\n/**\n * OpenTelemetry span processor that copies OTel baggage entries onto each\n * started span as attributes.\n */\nexport class BaggageSpanProcessor implements SpanProcessor {\n onStart(span: Span, parentContext: Context): void {\n // NoOp guard: skip allocation when sampler drops the span.\n if (!span.isRecording()) {\n return\n }\n\n const baggage = propagation.getBaggage(parentContext)\n if (!baggage) {\n return\n }\n\n for (const [key, entry] of baggage.getAllEntries()) {\n span.setAttribute(key, entry.value)\n }\n }\n\n onEnd(_span: ReadableSpan): void {\n /* no-op */\n }\n\n async shutdown(): Promise<void> {\n /* no-op */\n }\n\n async forceFlush(): Promise<void> {\n /* no-op */\n }\n}\n","/**\n * Types, interfaces, and constants for the OpenTelemetry module.\n */\n\nimport type { Instrumentation } from '@opentelemetry/instrumentation'\n\n// Semantic convention constants for compatibility across versions\nexport const ATTR_SERVICE_VERSION = 'service.version'\nexport const ATTR_SERVICE_NAMESPACE = 'service.namespace'\nexport const ATTR_SERVICE_INSTANCE_ID = 'service.instance.id'\n\n/** Magic prefixes for binary frames over WebSocket */\nexport const PREFIX_TRACES = 'OTLP'\nexport const PREFIX_METRICS = 'MTRC'\nexport const PREFIX_LOGS = 'LOGS'\n\n/** Connection state for the shared WebSocket */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'failed'\n\n/** Configuration for WebSocket reconnection behavior */\nexport interface ReconnectionConfig {\n /** Starting delay in milliseconds (default: 1000ms) */\n initialDelayMs: number\n /** Maximum delay cap in milliseconds (default: 30000ms) */\n maxDelayMs: number\n /** Exponential backoff multiplier (default: 2) */\n backoffMultiplier: number\n /** Random jitter factor 0-1 (default: 0.3) */\n jitterFactor: number\n /** Maximum retry attempts, -1 for infinite (default: -1) */\n maxRetries: number\n}\n\n/** Default reconnection configuration */\nexport const DEFAULT_RECONNECTION_CONFIG: ReconnectionConfig = {\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n backoffMultiplier: 2,\n jitterFactor: 0.3,\n maxRetries: -1,\n}\n\n/** Configuration for OpenTelemetry initialization. */\nexport interface OtelConfig {\n /** Whether OpenTelemetry export is enabled. Defaults to true. Set to false or OTEL_ENABLED=false/0/no/off to disable. */\n enabled?: boolean\n /** The service name to report. Defaults to OTEL_SERVICE_NAME or \"iii-node\". */\n serviceName?: string\n /** The service version to report. Defaults to SERVICE_VERSION env var or \"unknown\". */\n serviceVersion?: string\n /** The service namespace to report. Defaults to SERVICE_NAMESPACE env var. */\n serviceNamespace?: string\n /** The service instance ID to report. Defaults to SERVICE_INSTANCE_ID env var or auto-generated UUID. */\n serviceInstanceId?: string\n /** III Engine WebSocket URL. Defaults to III_URL or \"ws://localhost:49134\". */\n engineWsUrl?: string\n /** OpenTelemetry instrumentations to register (e.g., PrismaInstrumentation). */\n instrumentations?: Instrumentation[]\n /** Whether OpenTelemetry metrics export is enabled. Defaults to true. Set to false or OTEL_METRICS_ENABLED=false/0/no/off to disable. */\n metricsEnabled?: boolean\n /** Metrics export interval in milliseconds. Defaults to 60000 (60 seconds). */\n metricsExportIntervalMs?: number\n /**\n * Span processor flush delay in milliseconds. Defaults to 100ms. This is how\n * long an ended span waits in the batch buffer before it is flushed to the\n * engine, the OpenTelemetry default of 5000ms is what makes traces appear\n * seconds after the action. Env override: OTEL_SPANS_FLUSH_INTERVAL_MS.\n */\n spansFlushIntervalMs?: number\n /** Log processor flush delay in milliseconds. Defaults to 100ms. Env override: OTEL_LOGS_FLUSH_INTERVAL_MS. */\n logsFlushIntervalMs?: number\n /** Maximum number of log records exported per batch. Defaults to 1. */\n logsBatchSize?: number\n /** Whether to auto-instrument globalThis.fetch calls. Defaults to true. Works on Node.js, Bun, and Deno. Set to false to disable. */\n fetchInstrumentationEnabled?: boolean\n /** Optional reconnection configuration for the WebSocket connection. */\n reconnectionConfig?: Partial<ReconnectionConfig>\n}\n\n/** Default configuration values for OpenTelemetry initialization. */\nexport const DEFAULT_OTEL_CONFIG = {\n enabled: true,\n serviceName: 'iii-node',\n serviceVersion: 'unknown',\n engineWsUrl: 'ws://localhost:49134',\n metricsEnabled: true,\n metricsExportIntervalMs: 60000,\n spansFlushIntervalMs: 100,\n logsFlushIntervalMs: 100,\n logsBatchSize: 1,\n fetchInstrumentationEnabled: true,\n} as const satisfies Partial<OtelConfig>\n\n/** Parse a boolean environment variable, recognizing 'false', '0', 'no', 'off' as false. */\nexport function parseBoolEnv(value: string | undefined, defaultValue: boolean): boolean {\n if (value === undefined) return defaultValue\n const lower = value.toLowerCase()\n return lower !== 'false' && lower !== '0' && lower !== 'no' && lower !== 'off'\n}\n","/**\n * Shared WebSocket connection for OpenTelemetry exporters.\n */\n\nimport { WebSocket } from 'ws'\nimport { type ConnectionState, type ReconnectionConfig, DEFAULT_RECONNECTION_CONFIG } from './types'\n\n/**\n * Shared WebSocket connection for all OTEL exporters (traces, metrics, logs).\n * Uses a single connection with message prefixes to identify signal type.\n */\nexport class SharedEngineConnection {\n private static readonly MAX_PENDING_MESSAGES = 1000\n private ws: WebSocket | null = null\n private wsUrl: string\n private connecting = false\n private shuttingDown = false\n private pendingMessages: Array<{ frame: Buffer; callback?: (err?: Error) => void }> = []\n private reconnectAttempt = 0\n private reconnectTimeout: NodeJS.Timeout | null = null\n private config: ReconnectionConfig\n private state: ConnectionState = 'disconnected'\n private onConnectedCallbacks: Array<() => void> = []\n private onFailedCallbacks: Array<() => void> = []\n\n constructor(wsUrl: string, config: Partial<ReconnectionConfig> = {}) {\n this.wsUrl = wsUrl\n this.config = { ...DEFAULT_RECONNECTION_CONFIG, ...config }\n this.connect()\n }\n\n private connect(): void {\n if (this.connecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {\n return\n }\n\n this.connecting = true\n this.state = 'connecting'\n\n try {\n this.ws = new WebSocket(this.wsUrl)\n\n this.ws.on('open', () => {\n this.connecting = false\n this.state = 'connected'\n console.log(`[OTel] Connected to engine at ${this.wsUrl}`)\n\n // Reset reconnection state\n if (this.reconnectAttempt > 0) {\n console.log('[OTel] Successfully reconnected')\n }\n this.reconnectAttempt = 0\n\n // Clear any pending reconnect timer to prevent race conditions\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // Flush pending messages\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n for (const { frame, callback } of pending) {\n this.ws?.send(frame, err => callback?.(err))\n }\n\n // Notify callbacks\n for (const cb of this.onConnectedCallbacks) {\n cb()\n }\n })\n\n this.ws.on('close', () => {\n this.connecting = false\n this.ws = null\n\n // Skip reconnection if we're shutting down intentionally\n if (this.shuttingDown) {\n this.state = 'disconnected'\n console.log('[OTel] Connection closed during shutdown')\n return\n }\n\n this.state = 'disconnected'\n console.log('[OTel] Disconnected from engine, will reconnect...')\n this.scheduleReconnect()\n })\n\n this.ws.on('error', err => {\n this.connecting = false\n\n // Skip error handling if we're shutting down intentionally\n if (this.shuttingDown) {\n return\n }\n\n console.error('[OTel] WebSocket error:', err.message)\n })\n } catch (err) {\n this.connecting = false\n console.error('[OTel] Connection failed:', err)\n this.scheduleReconnect()\n }\n }\n\n private scheduleReconnect(): void {\n if (this.config.maxRetries !== -1 && this.reconnectAttempt >= this.config.maxRetries) {\n this.state = 'failed'\n console.error(`[OTel] Max retries (${this.config.maxRetries}) reached, giving up`)\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const failedError = new Error('Connection failed after max retries')\n for (const { callback } of pending) {\n callback?.(failedError)\n }\n\n // Notify failed callbacks so exporters can drain their own queues\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n return\n }\n\n if (this.reconnectTimeout) {\n return // Already scheduled\n }\n\n const exponentialDelay =\n this.config.initialDelayMs * this.config.backoffMultiplier ** this.reconnectAttempt\n const cappedDelay = Math.min(exponentialDelay, this.config.maxDelayMs)\n const jitter = cappedDelay * this.config.jitterFactor * (2 * Math.random() - 1)\n const delay = Math.max(0, Math.floor(cappedDelay + jitter))\n\n this.state = 'reconnecting'\n console.log(`[OTel] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt + 1})...`)\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null\n this.reconnectAttempt++\n this.connect()\n }, delay)\n }\n\n /**\n * Send a message with a signal prefix.\n */\n send(prefix: string, data: Uint8Array, callback?: (err?: Error) => void): void {\n const prefixBytes = Buffer.from(prefix, 'utf-8')\n const frame = Buffer.concat([prefixBytes, Buffer.from(data)])\n\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(frame, callback)\n } else {\n // Queue for later with bounded size to prevent memory exhaustion\n if (this.pendingMessages.length >= SharedEngineConnection.MAX_PENDING_MESSAGES) {\n console.warn('[OTel] Pending message queue full, dropping oldest message')\n const dropped = this.pendingMessages.shift()\n dropped?.callback?.(new Error('Message dropped due to queue overflow'))\n }\n this.pendingMessages.push({ frame, callback })\n this.connect()\n }\n }\n\n /**\n * Register a callback to be called when connected.\n */\n onConnected(callback: () => void): void {\n this.onConnectedCallbacks.push(callback)\n if (this.state === 'connected') {\n callback()\n }\n }\n\n /**\n * Register a callback to be called when the connection enters the failed\n * terminal state (max retries reached). Exporters use this to drain their\n * own pending queues so in-flight forceFlush() calls do not hang.\n */\n onFailed(callback: () => void): void {\n this.onFailedCallbacks.push(callback)\n if (this.state === 'failed') {\n try {\n callback()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n\n /**\n * Get the current connection state.\n */\n getState(): ConnectionState {\n return this.state\n }\n\n /**\n * Whether the connection is shutting down. While shutting down, exporters\n * fail-fast instead of queueing when there is no live connection, so a final\n * forceFlush() can't hang waiting for a reconnect that will never happen.\n */\n isShuttingDown(): boolean {\n return this.shuttingDown\n }\n\n /**\n * Begin shutdown: stop reconnecting and stop accepting new queued exports,\n * while leaving an open connection in place so buffered telemetry can still\n * be flushed. Call before flushing, then call shutdown() to close fully.\n */\n beginShutdown(): void {\n if (this.shuttingDown) {\n return\n }\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n // With no live connection there's nothing to flush to, so fail queued work\n // now instead of leaving callbacks unresolved for the flush below to wait on\n if (this.state !== 'connected') {\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n\n for (const cb of this.onFailedCallbacks) {\n try {\n cb()\n } catch (err) {\n console.error('[OTel] onFailed callback threw:', err)\n }\n }\n }\n }\n\n /**\n * Shutdown the connection.\n */\n async shutdown(): Promise<void> {\n // Set shutdown flag to prevent reconnection attempts\n this.shuttingDown = true\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout)\n this.reconnectTimeout = null\n }\n\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n\n // Notify pending message callbacks that they won't be delivered\n const pending = this.pendingMessages.splice(0, this.pendingMessages.length)\n const shutdownError = new Error('Connection shutdown before message could be sent')\n for (const { callback } of pending) {\n callback?.(shutdownError)\n }\n this.onConnectedCallbacks = []\n this.onFailedCallbacks = []\n this.state = 'disconnected'\n }\n}\n","/**\n * Span exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'\nimport { JsonTraceSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_TRACES } from './types'\n\n/**\n * Span exporter using the shared WebSocket connection.\n */\nexport class EngineSpanExporter implements SpanExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n spans: ReadableSpan[]\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { spans, resultCallback } of pending) {\n this.sendExport(spans, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued spans')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(spans: ReadableSpan[], resultCallback?: (result: ExportResult) => void): void {\n try {\n const serialized = JsonTraceSerializer.serializeRequest(spans)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_TRACES, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send spans:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting spans:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping spans`),\n })\n return\n }\n if (this.pendingExports.length >= EngineSpanExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Spans export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ spans, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(spans, resultCallback)\n }\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(spans, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op, spans are sent immediately\n }\n}\n","/**\n * Metrics exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics'\nimport { JsonMetricsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_METRICS } from './types'\n\n/**\n * Metrics exporter using the shared WebSocket connection.\n */\nexport class EngineMetricsExporter implements PushMetricExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n metrics: ResourceMetrics\n resultCallback?: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { metrics, resultCallback } of pending) {\n this.sendExport(metrics, resultCallback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued metrics')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private sendExport(\n metricsData: ResourceMetrics,\n resultCallback?: (result: ExportResult) => void,\n ): void {\n try {\n const serialized = JsonMetricsSerializer.serializeRequest(metricsData)\n if (!serialized) {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_METRICS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send metrics:', err.message)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback?.({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting metrics:', err)\n resultCallback?.({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n private doExport(\n metricsData: ResourceMetrics,\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping metrics`),\n })\n return\n }\n if (this.pendingExports.length >= EngineMetricsExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.resultCallback?.({\n code: ExportResultCode.FAILED,\n error: new Error('Queue overflow'),\n })\n console.warn('[OTel] Metrics export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ metrics: metricsData, resultCallback })\n // Don't call resultCallback here - it will be called when actually sent or on shutdown\n return\n }\n\n this.sendExport(metricsData, resultCallback)\n }\n\n export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {\n this.doExport(metrics, resultCallback)\n }\n\n async shutdown(): Promise<void> {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const shutdownError = new Error('Exporter shutdown before export completed')\n for (const { resultCallback } of pending) {\n resultCallback?.({ code: ExportResultCode.FAILED, error: shutdownError })\n }\n }\n\n async forceFlush(): Promise<void> {\n // No-op\n }\n}\n","/**\n * Log exporter for the III Engine.\n */\n\nimport { ExportResultCode, type ExportResult } from '@opentelemetry/core'\nimport type { LogRecordExporter, ReadableLogRecord } from '@opentelemetry/sdk-logs'\nimport { JsonLogsSerializer } from '@opentelemetry/otlp-transformer'\n\nimport type { SharedEngineConnection } from './connection'\nimport { PREFIX_LOGS } from './types'\n\n/**\n * Log exporter using the shared WebSocket connection.\n */\nexport class EngineLogExporter implements LogRecordExporter {\n private static readonly MAX_PENDING_EXPORTS = 100\n private connection: SharedEngineConnection\n private pendingExports: Array<{\n logs: ReadableLogRecord[]\n callback: (result: ExportResult) => void\n }> = []\n\n constructor(connection: SharedEngineConnection) {\n this.connection = connection\n this.connection.onConnected(() => this.flushPending())\n this.connection.onFailed(() => this.failPending())\n }\n\n private flushPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n for (const { logs, callback } of pending) {\n this.doExport(logs, callback)\n }\n }\n\n private failPending(): void {\n const pending = this.pendingExports.splice(0, this.pendingExports.length)\n const error = new Error('Connection failed: dropping queued logs')\n for (const { callback } of pending) {\n callback({ code: ExportResultCode.FAILED, error })\n }\n }\n\n private doExport(\n logs: ReadableLogRecord[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n const state = this.connection.getState()\n if (state !== 'connected') {\n // Drop instead of queue when there's no prospect of delivery (failed, or shutting down)\n if (state === 'failed' || this.connection.isShuttingDown()) {\n const reason = state === 'failed' ? 'failed' : 'shut down'\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`Connection ${reason}: dropping logs`),\n })\n return\n }\n if (this.pendingExports.length >= EngineLogExporter.MAX_PENDING_EXPORTS) {\n const dropped = this.pendingExports.shift()\n dropped?.callback({\n code: ExportResultCode.FAILED,\n error: new Error('Logs export queue full'),\n })\n console.warn('[OTel] Logs export queue full, dropped oldest entry')\n }\n this.pendingExports.push({ logs, callback: resultCallback })\n return\n }\n\n try {\n const serialized = JsonLogsSerializer.serializeRequest(logs)\n if (!serialized) {\n resultCallback({ code: ExportResultCode.SUCCESS })\n return\n }\n\n this.connection.send(PREFIX_LOGS, serialized, err => {\n if (err) {\n console.error('[OTel] Failed to send logs:', err.message)\n resultCallback({ code: ExportResultCode.FAILED, error: err })\n } else {\n resultCallback({ code: ExportResultCode.SUCCESS })\n }\n })\n } catch (err) {\n console.error('[OTel] Error exporting logs:', err)\n resultCallback({ code: ExportResultCode.FAILED, error: err as Error })\n }\n }\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {\n this.doExport(logs, resultCallback)\n }\n\n async forceFlush(): Promise<void> {}\n\n async shutdown(): Promise<void> {\n for (const { callback } of this.pendingExports) {\n callback({ code: ExportResultCode.FAILED, error: new Error('Exporter shutdown') })\n }\n this.pendingExports = []\n }\n}\n","/**\n * Trace context and baggage propagation utilities.\n */\n\nimport { trace, context, propagation, type Context } from '@opentelemetry/api'\n\n/**\n * Extract the current trace ID from the active span context.\n */\nexport function currentTraceId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.traceId && spanContext.traceId !== '00000000000000000000000000000000') {\n return spanContext.traceId\n }\n }\n return undefined\n}\n\n/**\n * Extract the current span ID from the active span context.\n */\nexport function currentSpanId(): string | undefined {\n const span = trace.getActiveSpan()\n if (span) {\n const spanContext = span.spanContext()\n if (spanContext.spanId && spanContext.spanId !== '0000000000000000') {\n return spanContext.spanId\n }\n }\n return undefined\n}\n\n/**\n * Inject the current trace context into a W3C traceparent header string.\n */\nexport function injectTraceparent(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.traceparent\n}\n\n/**\n * Extract a trace context from a W3C traceparent header string.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n */\nexport function extractTraceparent(traceparent: string): Context {\n const carrier: Record<string, string> = { traceparent }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Inject the current baggage into a W3C baggage header string.\n */\nexport function injectBaggage(): string | undefined {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n return carrier.baggage\n}\n\n/**\n * Extract baggage from a W3C baggage header string.\n *\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractBaggage(baggage: string): Context {\n const carrier: Record<string, string> = { baggage }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Extract both trace context and baggage from their respective headers.\n *\n * @param traceparent - W3C `traceparent` header value to parse.\n * @param baggage - W3C `baggage` header value to parse.\n */\nexport function extractContext(traceparent?: string, baggage?: string): Context {\n const carrier: Record<string, string> = {}\n if (traceparent) {\n carrier.traceparent = traceparent\n }\n if (baggage) {\n carrier.baggage = baggage\n }\n return propagation.extract(context.active(), carrier)\n}\n\n/**\n * Get a baggage entry from the current context.\n *\n * @param key - Baggage entry key to read.\n */\nexport function getBaggageEntry(key: string): string | undefined {\n const bag = propagation.getBaggage(context.active())\n return bag?.getEntry(key)?.value\n}\n\n/**\n * Set a baggage entry in the current context.\n *\n * @param key - Baggage entry key to set.\n * @param value - Baggage entry value to set.\n */\nexport function setBaggageEntry(key: string, value: string): Context {\n let bag = propagation.getBaggage(context.active()) ?? propagation.createBaggage()\n bag = bag.setEntry(key, { value })\n return propagation.setBaggage(context.active(), bag)\n}\n\n/**\n * Remove a baggage entry from the current context.\n *\n * @param key - Baggage entry key to remove.\n */\nexport function removeBaggageEntry(key: string): Context {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return context.active()\n }\n const newBag = bag.removeEntry(key)\n return propagation.setBaggage(context.active(), newBag)\n}\n\n/**\n * Get all baggage entries from the current context.\n */\nexport function getAllBaggage(): Record<string, string> {\n const bag = propagation.getBaggage(context.active())\n if (!bag) {\n return {}\n }\n const entries: Record<string, string> = {}\n for (const [key, entry] of bag.getAllEntries()) {\n entries[key] = entry.value\n }\n return entries\n}\n","/**\n * Global fetch auto-instrumentation for the III Node SDK.\n *\n * Patches globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n * Works on all runtimes (Bun, Node.js, Deno) unlike UndiciInstrumentation\n * which only works when fetch is backed by Node.js's undici.\n */\n\nimport { type Tracer, SpanKind, SpanStatusCode, context, propagation } from '@opentelemetry/api'\n\nconst textEncoder = new TextEncoder()\n\nfunction getBodyByteSize(body: unknown): number | undefined {\n if (body == null) return undefined\n if (typeof body === 'string') return textEncoder.encode(body).byteLength\n if (body instanceof ArrayBuffer) return body.byteLength\n if (ArrayBuffer.isView(body)) return body.byteLength\n if (body instanceof Blob) return body.size\n if (body instanceof URLSearchParams) return new TextEncoder().encode(body.toString()).byteLength\n return undefined\n}\n\nconst SAFE_REQUEST_HEADERS = ['content-type', 'accept'] as const\nconst SAFE_RESPONSE_HEADERS = ['content-type'] as const\n\nlet originalFetch: typeof globalThis.fetch | null = null\n\n/**\n * Substring patterns from `OTEL_FETCH_IGNORE_URLS` (comma-separated). A fetch\n * whose URL contains any pattern is executed WITHOUT creating a span, use it\n * to drop noisy/high-frequency calls (health checks, polling, internal\n * endpoints) that would otherwise flood traces.\n */\nconst FETCH_IGNORE_URL_PATTERNS: string[] = (process.env.OTEL_FETCH_IGNORE_URLS ?? '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n\nfunction shouldIgnoreFetchUrl(url: string): boolean {\n return FETCH_IGNORE_URL_PATTERNS.some(pattern => url.includes(pattern))\n}\n\n/**\n * Patch globalThis.fetch to create OTel CLIENT spans for every HTTP request.\n *\n * @param tracer - Tracer used to create the client span for each request.\n */\nexport function patchGlobalFetch(tracer: Tracer): void {\n if (originalFetch) return\n\n originalFetch = globalThis.fetch\n const capturedFetch = originalFetch\n\n globalThis.fetch = async (\n input: string | URL | Request,\n init?: RequestInit,\n ): Promise<Response> => {\n const url = input instanceof Request ? input.url : String(input)\n\n // Skip tracing entirely for ignored URLs (no span, no context injection).\n if (shouldIgnoreFetchUrl(url)) {\n return capturedFetch(input, init)\n }\n\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n\n let host: string | undefined\n let scheme: string | undefined\n let path: string | undefined\n let port: number | undefined\n let query: string | undefined\n try {\n const parsed = new URL(url)\n host = parsed.hostname\n scheme = parsed.protocol.replace(':', '')\n path = parsed.pathname\n port = parsed.port ? parseInt(parsed.port, 10) : undefined\n query = parsed.search ? parsed.search.slice(1) : undefined\n } catch {\n // relative URL or invalid, skip host/scheme/path attributes\n }\n\n const spanAttributes: Record<string, string | number> = {\n 'http.request.method': method,\n 'url.full': url,\n }\n if (host) spanAttributes['server.address'] = host\n if (scheme) {\n spanAttributes['url.scheme'] = scheme\n spanAttributes['network.protocol.name'] = 'http'\n }\n if (path) spanAttributes['url.path'] = path\n if (port) spanAttributes['server.port'] = port\n if (query) spanAttributes['url.query'] = query\n\n const spanName = path ? `${method} ${path}` : method\n\n return tracer.startActiveSpan(\n spanName,\n { kind: SpanKind.CLIENT, attributes: spanAttributes },\n context.active(),\n async span => {\n try {\n const carrier: Record<string, string> = {}\n propagation.inject(context.active(), carrier)\n\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n for (const [key, value] of Object.entries(carrier)) {\n headers.set(key, value)\n }\n\n for (const name of SAFE_REQUEST_HEADERS) {\n const value = headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.request.header.${name}`, value)\n }\n }\n\n const requestBody = init?.body ?? (input instanceof Request ? input.body : undefined)\n const requestBodySize = getBodyByteSize(requestBody)\n if (requestBodySize !== undefined) {\n span.setAttribute('http.request.body.size', requestBodySize)\n }\n\n const response = await capturedFetch(input, { ...init, headers })\n\n span.setAttribute('http.response.status_code', response.status)\n\n const contentLength = response.headers.get('content-length')\n if (contentLength !== null) {\n const size = parseInt(contentLength, 10)\n if (!Number.isNaN(size)) {\n span.setAttribute('http.response.body.size', size)\n }\n }\n\n for (const name of SAFE_RESPONSE_HEADERS) {\n const value = response.headers.get(name)\n if (value !== null) {\n span.setAttribute(`http.response.header.${name}`, value)\n }\n }\n\n if (response.status >= 400) {\n span.setAttribute('error.type', String(response.status))\n span.setStatus({ code: SpanStatusCode.ERROR })\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n return response\n } catch (error) {\n span.setAttribute('error.type', (error as Error).name ?? 'Error')\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n },\n )\n }\n}\n\n/**\n * Restore globalThis.fetch to its original implementation.\n */\nexport function unpatchGlobalFetch(): void {\n if (originalFetch) {\n globalThis.fetch = originalFetch\n originalFetch = null\n }\n}\n","/**\n * Parse a numeric environment variable with optional minimum bound.\n *\n * An empty or whitespace-only string is treated as unset: `Number('')` is 0,\n * so without this check a variable set-but-blank (common in .env files) would\n * silently resolve to 0 instead of falling through to the default.\n */\nexport function parseNumberEnv(value: string | undefined, minimum: number = 0): number | undefined {\n if (value === undefined || value.trim() === '') return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed < minimum) return undefined\n return parsed\n}\n\n/**\n * Parse an integer environment variable with optional minimum bound.\n */\nexport function parseIntegerEnv(\n value: string | undefined,\n minimum: number = 0,\n): number | undefined {\n const parsed = parseNumberEnv(value, minimum)\n if (parsed === undefined || !Number.isInteger(parsed)) return undefined\n return parsed\n}\n\n/**\n * Resolve a batch-processor flush delay: explicit config wins, then the\n * III-specific env var, then the III default.\n *\n * III SDKs deliberately expose a single OTEL_*_FLUSH_INTERVAL_MS knob and do\n * NOT honor the standard OTel OTEL_BSP_SCHEDULE_DELAY / OTEL_BLRP_SCHEDULE_DELAY\n * vars, for cross-SDK consistency (the Node, Python, and Rust SDKs all resolve\n * the same way). Passing an explicit `scheduledDelayMillis` to the processor\n * already makes the OTel SDK ignore those standard vars regardless.\n */\nexport function resolveFlushIntervalMs(\n configValue: number | undefined,\n envValue: string | undefined,\n defaultValue: number,\n): number {\n return configValue ?? parseNumberEnv(envValue, 0) ?? defaultValue\n}\n","/** High-level span operations so consumers don't need `@opentelemetry/api`. */\n\nimport { SpanStatusCode, trace, type AttributeValue, type Attributes } from '@opentelemetry/api'\n\n/** Returns `false` when there is no active span or the sampler dropped it. */\nexport function currentSpanIsRecording(): boolean {\n const span = trace.getActiveSpan()\n return span ? span.isRecording() : false\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param key - Attribute key to set on the active span.\n * @param value - Attribute value to set.\n */\nexport function setCurrentSpanAttribute(key: string, value: AttributeValue): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.setAttribute(key, value)\n}\n\n/**\n * No-op when there is no active span.\n *\n * @param message - Error message to set as the span's error status.\n */\nexport function setCurrentSpanError(message: string): void {\n const span = trace.getActiveSpan()\n if (!span) return\n span.setStatus({ code: SpanStatusCode.ERROR, message })\n}\n\n/**\n * No-op when the current span is not recording.\n *\n * @param name - Name of the event to add to the active span.\n * @param attrs - Optional attributes to attach to the event.\n */\nexport function recordSpanEvent(name: string, attrs?: Attributes): void {\n const span = trace.getActiveSpan()\n if (!span || !span.isRecording()) return\n span.addEvent(name, attrs)\n}\n","/** Payload redaction + truncation for invocation event capture. */\n\nexport const REDACTED_PLACEHOLDER = '[REDACTED]'\nconst TRUNCATION_MARKER = '...\"[TRUNCATED]\"'\n\n/**\n * Resolve the payload byte cap from the environment, returning undefined when\n * unset.\n */\nexport function resolveMaxBytesFromEnv(): number | null {\n const raw = process.env.III_TRACE_PAYLOAD_MAX_BYTES\n if (raw === undefined) return null\n const trimmed = raw.trim()\n if (trimmed === '' || trimmed.toLowerCase() === 'unlimited') return null\n // parseInt accepts partial parses like \"8192mb\" → 8192; Python int()\n // and Rust parse::<usize>() reject those. Match the strict semantics.\n if (!/^\\d+$/.test(trimmed)) return null\n const parsed = Number(trimmed)\n if (parsed <= 0) return null\n return parsed\n}\n\nconst SENSITIVE_FRAGMENTS = [\n 'api_key',\n 'apikey',\n 'api-key',\n 'password',\n 'secret',\n 'credential',\n 'authorization',\n 'auth_token',\n 'access_token',\n 'refresh_token',\n 'bearer',\n 'private_key',\n 'client_secret',\n]\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase()\n if (SENSITIVE_FRAGMENTS.some((fragment) => lower.includes(fragment))) return true\n // `token` alone is too common a substring; require whole-key or suffix match.\n return lower === 'token' || lower.endsWith('_token') || lower.endsWith('-token')\n}\n\n/**\n * Recursively redact values of sensitive keys. Returns a new value.\n *\n * @param value - The value to recursively redact.\n */\nexport function redact(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (Array.isArray(value)) return value.map(redact)\n if (typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = isSensitiveKey(k) ? REDACTED_PLACEHOLDER : redact(v)\n }\n return out\n }\n return value\n}\n\n/**\n * Redact then serialize to JSON, optionally capped at `maxBytes`.\n *\n * @param value - The value to redact and serialize.\n * @param maxBytes - Maximum serialized size in bytes; null leaves it uncapped.\n */\nexport function redactAndTruncate(\n value: unknown,\n maxBytes: number | null = null,\n): { json: string; truncated: boolean } {\n const redacted = redact(value)\n let serialized: string\n try {\n serialized = JSON.stringify(redacted) ?? 'null'\n } catch {\n serialized = 'null'\n }\n\n if (maxBytes === null || maxBytes === undefined || maxBytes <= 0) {\n return { json: serialized, truncated: false }\n }\n\n const byteLen = Buffer.byteLength(serialized, 'utf8')\n if (byteLen <= maxBytes) {\n return { json: serialized, truncated: false }\n }\n\n const markerLen = Buffer.byteLength(TRUNCATION_MARKER, 'utf8')\n // When maxBytes is smaller than the marker itself, emit only a\n // truncated marker so the result never exceeds the cap.\n if (maxBytes <= markerLen) {\n return { json: TRUNCATION_MARKER.slice(0, maxBytes), truncated: true }\n }\n\n const cap = maxBytes - markerLen\n const buf = Buffer.from(serialized, 'utf8')\n let cut = Math.min(cap, buf.length)\n // Walk back to a UTF-8 boundary so we don't emit half-codepoints.\n while (cut > 0 && (buf[cut] & 0xc0) === 0x80) {\n cut -= 1\n }\n const truncated = buf.subarray(0, cut).toString('utf8') + TRUNCATION_MARKER\n return { json: truncated, truncated: true }\n}\n","/**\n * OpenTelemetry initialization for the III Node SDK.\n *\n * This module provides trace, metrics, and log export to the III Engine\n * via a shared WebSocket connection using OTLP JSON format.\n */\n\nimport { Resource } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'\nimport { randomUUID } from 'node:crypto'\nimport {\n trace,\n context,\n propagation,\n SpanKind,\n SpanStatusCode,\n metrics,\n type Span,\n type Context,\n type Tracer,\n type Meter,\n} from '@opentelemetry/api'\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'\nimport { BaggageSpanProcessor } from './baggage-span-processor'\nimport { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'\nimport { registerInstrumentations } from '@opentelemetry/instrumentation'\nimport { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs'\nimport { type Logger, SeverityNumber } from '@opentelemetry/api-logs'\n\nimport {\n type OtelConfig,\n DEFAULT_OTEL_CONFIG,\n parseBoolEnv,\n ATTR_SERVICE_VERSION,\n ATTR_SERVICE_NAMESPACE,\n ATTR_SERVICE_INSTANCE_ID,\n} from './types'\nimport { SharedEngineConnection } from './connection'\nimport { EngineSpanExporter, EngineMetricsExporter, EngineLogExporter } from './exporters'\nimport { extractTraceparent } from './context'\nimport { patchGlobalFetch, unpatchGlobalFetch } from './fetch-instrumentation'\nimport { parseIntegerEnv, resolveFlushIntervalMs } from './utils'\n\n// Re-export everything from submodules\nexport * from './types'\nexport * from './context'\nexport { BaggageSpanProcessor } from './baggage-span-processor'\nexport {\n currentSpanIsRecording,\n recordSpanEvent,\n setCurrentSpanAttribute,\n setCurrentSpanError,\n} from './span-ops'\nexport {\n REDACTED_PLACEHOLDER,\n redact,\n redactAndTruncate,\n resolveMaxBytesFromEnv,\n} from './payload'\n\n/**\n * Normalize an engine WebSocket URL into the dedicated OTEL endpoint.\n * The engine exposes `/otel` for telemetry-only WS connections; routing\n * there keeps this socket out of the worker registry (otherwise it shows\n * up as a ghost null-metadata worker).\n */\nfunction appendOtelPath(base: string): string {\n const url = new URL(base)\n const path = url.pathname.replace(/\\/+$/, '')\n url.pathname = path.endsWith('/otel') ? path : `${path}/otel`\n return url.toString()\n}\n\n// Module-level state\nlet sharedConnection: SharedEngineConnection | null = null\nlet tracerProvider: NodeTracerProvider | null = null\nlet meterProvider: MeterProvider | null = null\nlet loggerProvider: LoggerProvider | null = null\nlet tracer: Tracer | null = null\nlet meter: Meter | null = null\nlet logger: Logger | null = null\nlet serviceName: string = 'iii-node-iii'\n\n/**\n * Initialize OpenTelemetry with the given configuration.\n * This should be called once at application startup.\n *\n * @param config - OpenTelemetry configuration; env vars fill in unset fields.\n */\nexport function initOtel(config: OtelConfig = {}): void {\n const enabled = config.enabled ?? parseBoolEnv(process.env.OTEL_ENABLED, DEFAULT_OTEL_CONFIG.enabled)\n\n if (!enabled) {\n console.debug(\n '[OTel] OpenTelemetry is disabled. To enable, remove OTEL_ENABLED=false or set enabled: true in config.',\n )\n return\n }\n\n // Configure service identity\n serviceName = config.serviceName ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_OTEL_CONFIG.serviceName\n const serviceVersion = config.serviceVersion ?? process.env.SERVICE_VERSION ?? DEFAULT_OTEL_CONFIG.serviceVersion\n const serviceNamespace = config.serviceNamespace ?? process.env.SERVICE_NAMESPACE\n const serviceInstanceId = config.serviceInstanceId ?? process.env.SERVICE_INSTANCE_ID ?? randomUUID()\n const engineWsUrl = config.engineWsUrl ?? process.env.III_URL ?? DEFAULT_OTEL_CONFIG.engineWsUrl\n\n // Build resource attributes\n const resourceAttributes: Record<string, string> = {\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n [ATTR_SERVICE_INSTANCE_ID]: serviceInstanceId,\n }\n if (serviceNamespace) {\n resourceAttributes[ATTR_SERVICE_NAMESPACE] = serviceNamespace\n }\n const resource = new Resource(resourceAttributes)\n\n // Create shared WebSocket connection.\n // OTEL always connects to the engine's dedicated `/otel` endpoint so\n // the telemetry socket doesn't get registered in `worker_registry` as\n // a ghost null-metadata worker alongside the real worker.\n sharedConnection = new SharedEngineConnection(appendOtelPath(engineWsUrl), config.reconnectionConfig)\n\n // BaggageSpanProcessor must register first: onStart fires in\n // registration order, so baggage entries are materialized as span\n // attributes before the batch exporter reads them.\n const spanExporter = new EngineSpanExporter(sharedConnection)\n // Without an explicit scheduledDelayMillis, BatchSpanProcessor inherits the\n // OpenTelemetry default of 5000ms, so an ended span sits in the buffer up to\n // 5s before it is flushed to the engine, the dominant reason traces show up\n // seconds after the action that produced them. Mirror the logs path\n // (BatchLogRecordProcessor below) with a small flush delay. maxExportBatchSize\n // stays at the OTel default so a burst of spans from one turn still coalesces\n // into a single frame rather than one frame per span.\n const spansScheduledDelayMillis = resolveFlushIntervalMs(\n config.spansFlushIntervalMs,\n process.env.OTEL_SPANS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.spansFlushIntervalMs,\n )\n tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [\n new BaggageSpanProcessor(),\n new BatchSpanProcessor(spanExporter, { scheduledDelayMillis: spansScheduledDelayMillis }),\n ],\n })\n\n // Register W3C Trace Context and Baggage propagators\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n }),\n )\n\n tracerProvider.register()\n tracer = trace.getTracer(serviceName)\n\n console.debug(`[OTel] Traces initialized: engine=${engineWsUrl}, service=${serviceName}`)\n\n // Initialize metrics (enabled by default, opt-out via config or env)\n const metricsEnabled =\n config.metricsEnabled ?? parseBoolEnv(process.env.OTEL_METRICS_ENABLED, DEFAULT_OTEL_CONFIG.metricsEnabled)\n\n if (metricsEnabled) {\n const metricsExporter = new EngineMetricsExporter(sharedConnection)\n const exportIntervalMs = config.metricsExportIntervalMs ?? DEFAULT_OTEL_CONFIG.metricsExportIntervalMs\n\n const metricReader = new PeriodicExportingMetricReader({\n exporter: metricsExporter,\n exportIntervalMillis: exportIntervalMs,\n })\n\n meterProvider = new MeterProvider({\n resource,\n readers: [metricReader],\n })\n\n metrics.setGlobalMeterProvider(meterProvider)\n meter = meterProvider.getMeter(serviceName)\n\n console.debug(`[OTel] Metrics initialized: interval=${exportIntervalMs}ms`)\n }\n\n // Register user-provided instrumentations AFTER providers are set up\n const instrumentations = [...(config.instrumentations ?? [])]\n if (instrumentations.length > 0) {\n registerInstrumentations({\n instrumentations,\n tracerProvider,\n meterProvider: meterProvider ?? undefined,\n })\n console.debug(`[OTel] Instrumentations registered: ${instrumentations.length} total`)\n }\n\n // Patch global fetch for runtime-agnostic HTTP client tracing (works on Bun, Node.js, Deno)\n const fetchEnabled = config.fetchInstrumentationEnabled ?? DEFAULT_OTEL_CONFIG.fetchInstrumentationEnabled\n\n if (fetchEnabled) {\n patchGlobalFetch(tracer)\n console.debug('[OTel] Global fetch instrumentation enabled')\n }\n\n // Initialize logs (always enabled when OTEL is enabled)\n const logExporter = new EngineLogExporter(sharedConnection)\n const logsScheduledDelayMillis = resolveFlushIntervalMs(\n config.logsFlushIntervalMs,\n process.env.OTEL_LOGS_FLUSH_INTERVAL_MS,\n DEFAULT_OTEL_CONFIG.logsFlushIntervalMs,\n )\n const logsMaxExportBatchSize =\n config.logsBatchSize ?? parseIntegerEnv(process.env.OTEL_LOGS_BATCH_SIZE, 1) ?? DEFAULT_OTEL_CONFIG.logsBatchSize\n\n loggerProvider = new LoggerProvider({ resource })\n loggerProvider.addLogRecordProcessor(\n new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: logsScheduledDelayMillis,\n maxExportBatchSize: logsMaxExportBatchSize,\n }),\n )\n logger = loggerProvider.getLogger(serviceName)\n\n console.debug(`[OTel] Logs initialized: delay=${logsScheduledDelayMillis}ms, batch=${logsMaxExportBatchSize}`)\n}\n\n/**\n * Shut down OpenTelemetry, best-effort flushing any pending data before\n * teardown.\n */\nexport async function shutdownOtel(): Promise<void> {\n // Stop reconnecting/queuing before flushing so a final forceFlush() can't hang on a dead engine\n sharedConnection?.beginShutdown()\n\n // Flushing is best-effort on shutdown: when the engine is gone the exporters\n // fail their pending exports, which rejects forceFlush()/shutdown(). Swallow\n // those so a dropped final flush can't crash or block teardown.\n const settle = (p: Promise<unknown>) => p.catch(() => {})\n\n if (tracerProvider) {\n await settle(tracerProvider.forceFlush())\n await settle(tracerProvider.shutdown())\n tracerProvider = null\n }\n\n if (meterProvider) {\n await settle(meterProvider.forceFlush())\n await settle(meterProvider.shutdown())\n meterProvider = null\n }\n\n if (loggerProvider) {\n await settle(loggerProvider.forceFlush())\n await settle(loggerProvider.shutdown())\n loggerProvider = null\n }\n\n if (sharedConnection) {\n await sharedConnection.shutdown()\n sharedConnection = null\n }\n\n unpatchGlobalFetch()\n\n tracer = null\n meter = null\n logger = null\n}\n\n/**\n * Force-flush all OTel providers without tearing them down.\n *\n * Counterpart to {@link shutdownOtel}. Use before short-lived process exits\n * where you want pending spans/metrics/logs delivered but plan to keep using\n * OTel afterwards.\n */\nexport async function flushOtel(): Promise<void> {\n await Promise.all(\n [\n tracerProvider?.forceFlush(),\n meterProvider?.forceFlush(),\n loggerProvider?.forceFlush(),\n ].filter(Boolean),\n )\n}\n\n/**\n * Get the OpenTelemetry tracer instance.\n */\nexport function getTracer(): Tracer | null {\n return tracer\n}\n\n/**\n * Get the OpenTelemetry meter instance.\n */\nexport function getMeter(): Meter | null {\n return meter\n}\n\n/**\n * Get the OpenTelemetry logger instance.\n */\nexport function getLogger(): Logger | null {\n return logger\n}\n\n/**\n * Start a new span with the given name and run the callback within it.\n *\n * @param name - Name of the span to create.\n * @param options - Span options: `kind` sets the span kind, `traceparent` sets the parent context from a W3C traceparent header.\n * @param fn - Callback run inside the active span; its result is returned.\n */\nexport async function withSpan<T>(\n name: string,\n options: { kind?: SpanKind; traceparent?: string },\n fn: (span: Span) => Promise<T>,\n): Promise<T> {\n if (!tracer) {\n // Execute without span context when tracer is not initialized\n // Provide a no-op span to avoid runtime errors if fn calls span methods\n const noopSpan: Span = {\n spanContext: () => ({ traceId: '', spanId: '', traceFlags: 0 }),\n setAttribute: () => noopSpan,\n setAttributes: () => noopSpan,\n addEvent: () => noopSpan,\n addLink: () => noopSpan,\n setStatus: () => noopSpan,\n updateName: () => noopSpan,\n end: () => {},\n isRecording: () => false,\n recordException: () => {},\n addLinks: () => noopSpan,\n }\n return fn(noopSpan)\n }\n\n const parentContext = options.traceparent ? extractTraceparent(options.traceparent) : context.active()\n\n return tracer.startActiveSpan(name, { kind: options.kind ?? SpanKind.INTERNAL }, parentContext, async (span) => {\n try {\n const result = await fn(span)\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (error) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error).message })\n span.recordException(error as Error)\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n// Re-export OTEL types for convenience\nexport { SpanKind, SpanStatusCode, SeverityNumber, type Span, type Context, type Tracer, type Meter, type Logger as OtelApiLogger }\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,IAAa,uBAAb,MAA2D;CACzD,QAAQ,MAAY,eAA8B;AAEhD,MAAI,CAAC,KAAK,aAAa,CACrB;EAGF,MAAM,UAAUA,+BAAY,WAAW,cAAc;AACrD,MAAI,CAAC,QACH;AAGF,OAAK,MAAM,CAAC,KAAK,UAAU,QAAQ,eAAe,CAChD,MAAK,aAAa,KAAK,MAAM,MAAM;;CAIvC,MAAM,OAA2B;CAIjC,MAAM,WAA0B;CAIhC,MAAM,aAA4B;;;;;ACtCpC,MAAa,uBAAuB;AACpC,MAAa,yBAAyB;AACtC,MAAa,2BAA2B;;AAGxC,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;AAC9B,MAAa,cAAc;;AAoB3B,MAAa,8BAAkD;CAC7D,gBAAgB;CAChB,YAAY;CACZ,mBAAmB;CACnB,cAAc;CACd,YAAY;CACb;;AAwCD,MAAa,sBAAsB;CACjC,SAAS;CACT,aAAa;CACb,gBAAgB;CAChB,aAAa;CACb,gBAAgB;CAChB,yBAAyB;CACzB,sBAAsB;CACtB,qBAAqB;CACrB,eAAe;CACf,6BAA6B;CAC9B;;AAGD,SAAgB,aAAa,OAA2B,cAAgC;AACtF,KAAI,UAAU,OAAW,QAAO;CAChC,MAAM,QAAQ,MAAM,aAAa;AACjC,QAAO,UAAU,WAAW,UAAU,OAAO,UAAU,QAAQ,UAAU;;;;;;;;;;;;ACtF3E,IAAa,yBAAb,MAAa,uBAAuB;CAClC,OAAwB,uBAAuB;CAC/C,AAAQ,KAAuB;CAC/B,AAAQ;CACR,AAAQ,aAAa;CACrB,AAAQ,eAAe;CACvB,AAAQ,kBAA8E,EAAE;CACxF,AAAQ,mBAAmB;CAC3B,AAAQ,mBAA0C;CAClD,AAAQ;CACR,AAAQ,QAAyB;CACjC,AAAQ,uBAA0C,EAAE;CACpD,AAAQ,oBAAuC,EAAE;CAEjD,YAAY,OAAe,SAAsC,EAAE,EAAE;AACnE,OAAK,QAAQ;AACb,OAAK,SAAS;GAAE,GAAG;GAA6B,GAAG;GAAQ;AAC3D,OAAK,SAAS;;CAGhB,AAAQ,UAAgB;AACtB,MAAI,KAAK,cAAe,KAAK,MAAM,KAAK,GAAG,eAAeC,aAAU,KAClE;AAGF,OAAK,aAAa;AAClB,OAAK,QAAQ;AAEb,MAAI;AACF,QAAK,KAAK,IAAIA,aAAU,KAAK,MAAM;AAEnC,QAAK,GAAG,GAAG,cAAc;AACvB,SAAK,aAAa;AAClB,SAAK,QAAQ;AACb,YAAQ,IAAI,iCAAiC,KAAK,QAAQ;AAG1D,QAAI,KAAK,mBAAmB,EAC1B,SAAQ,IAAI,kCAAkC;AAEhD,SAAK,mBAAmB;AAGxB,QAAI,KAAK,kBAAkB;AACzB,kBAAa,KAAK,iBAAiB;AACnC,UAAK,mBAAmB;;IAI1B,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;AAC3E,SAAK,MAAM,EAAE,OAAO,cAAc,QAChC,MAAK,IAAI,KAAK,QAAO,QAAO,WAAW,IAAI,CAAC;AAI9C,SAAK,MAAM,MAAM,KAAK,qBACpB,KAAI;KAEN;AAEF,QAAK,GAAG,GAAG,eAAe;AACxB,SAAK,aAAa;AAClB,SAAK,KAAK;AAGV,QAAI,KAAK,cAAc;AACrB,UAAK,QAAQ;AACb,aAAQ,IAAI,2CAA2C;AACvD;;AAGF,SAAK,QAAQ;AACb,YAAQ,IAAI,qDAAqD;AACjE,SAAK,mBAAmB;KACxB;AAEF,QAAK,GAAG,GAAG,UAAS,QAAO;AACzB,SAAK,aAAa;AAGlB,QAAI,KAAK,aACP;AAGF,YAAQ,MAAM,2BAA2B,IAAI,QAAQ;KACrD;WACK,KAAK;AACZ,QAAK,aAAa;AAClB,WAAQ,MAAM,6BAA6B,IAAI;AAC/C,QAAK,mBAAmB;;;CAI5B,AAAQ,oBAA0B;AAChC,MAAI,KAAK,OAAO,eAAe,MAAM,KAAK,oBAAoB,KAAK,OAAO,YAAY;AACpF,QAAK,QAAQ;AACb,WAAQ,MAAM,uBAAuB,KAAK,OAAO,WAAW,sBAAsB;GAGlF,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;GAC3E,MAAM,8BAAc,IAAI,MAAM,sCAAsC;AACpE,QAAK,MAAM,EAAE,cAAc,QACzB,YAAW,YAAY;AAIzB,QAAK,MAAM,MAAM,KAAK,kBACpB,KAAI;AACF,QAAI;YACG,KAAK;AACZ,YAAQ,MAAM,mCAAmC,IAAI;;AAGzD;;AAGF,MAAI,KAAK,iBACP;EAGF,MAAM,mBACJ,KAAK,OAAO,iBAAiB,KAAK,OAAO,qBAAqB,KAAK;EACrE,MAAM,cAAc,KAAK,IAAI,kBAAkB,KAAK,OAAO,WAAW;EACtE,MAAM,SAAS,cAAc,KAAK,OAAO,gBAAgB,IAAI,KAAK,QAAQ,GAAG;EAC7E,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,OAAO,CAAC;AAE3D,OAAK,QAAQ;AACb,UAAQ,IAAI,0BAA0B,MAAM,cAAc,KAAK,mBAAmB,EAAE,MAAM;AAE1F,OAAK,mBAAmB,iBAAiB;AACvC,QAAK,mBAAmB;AACxB,QAAK;AACL,QAAK,SAAS;KACb,MAAM;;;;;CAMX,KAAK,QAAgB,MAAkB,UAAwC;EAC7E,MAAM,cAAc,OAAO,KAAK,QAAQ,QAAQ;EAChD,MAAM,QAAQ,OAAO,OAAO,CAAC,aAAa,OAAO,KAAK,KAAK,CAAC,CAAC;AAE7D,MAAI,KAAK,MAAM,KAAK,GAAG,eAAeA,aAAU,KAC9C,MAAK,GAAG,KAAK,OAAO,SAAS;OACxB;AAEL,OAAI,KAAK,gBAAgB,UAAU,uBAAuB,sBAAsB;AAC9E,YAAQ,KAAK,6DAA6D;AAE1E,IADgB,KAAK,gBAAgB,OAAO,EACnC,2BAAW,IAAI,MAAM,wCAAwC,CAAC;;AAEzE,QAAK,gBAAgB,KAAK;IAAE;IAAO;IAAU,CAAC;AAC9C,QAAK,SAAS;;;;;;CAOlB,YAAY,UAA4B;AACtC,OAAK,qBAAqB,KAAK,SAAS;AACxC,MAAI,KAAK,UAAU,YACjB,WAAU;;;;;;;CASd,SAAS,UAA4B;AACnC,OAAK,kBAAkB,KAAK,SAAS;AACrC,MAAI,KAAK,UAAU,SACjB,KAAI;AACF,aAAU;WACH,KAAK;AACZ,WAAQ,MAAM,mCAAmC,IAAI;;;;;;CAQ3D,WAA4B;AAC1B,SAAO,KAAK;;;;;;;CAQd,iBAA0B;AACxB,SAAO,KAAK;;;;;;;CAQd,gBAAsB;AACpB,MAAI,KAAK,aACP;AAEF,OAAK,eAAe;AAEpB,MAAI,KAAK,kBAAkB;AACzB,gBAAa,KAAK,iBAAiB;AACnC,QAAK,mBAAmB;;AAK1B,MAAI,KAAK,UAAU,aAAa;GAC9B,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;GAC3E,MAAM,gCAAgB,IAAI,MAAM,mDAAmD;AACnF,QAAK,MAAM,EAAE,cAAc,QACzB,YAAW,cAAc;AAG3B,QAAK,MAAM,MAAM,KAAK,kBACpB,KAAI;AACF,QAAI;YACG,KAAK;AACZ,YAAQ,MAAM,mCAAmC,IAAI;;;;;;;CAS7D,MAAM,WAA0B;AAE9B,OAAK,eAAe;AAEpB,MAAI,KAAK,kBAAkB;AACzB,gBAAa,KAAK,iBAAiB;AACnC,QAAK,mBAAmB;;AAG1B,MAAI,KAAK,IAAI;AACX,QAAK,GAAG,OAAO;AACf,QAAK,KAAK;;EAIZ,MAAM,UAAU,KAAK,gBAAgB,OAAO,GAAG,KAAK,gBAAgB,OAAO;EAC3E,MAAM,gCAAgB,IAAI,MAAM,mDAAmD;AACnF,OAAK,MAAM,EAAE,cAAc,QACzB,YAAW,cAAc;AAE3B,OAAK,uBAAuB,EAAE;AAC9B,OAAK,oBAAoB,EAAE;AAC3B,OAAK,QAAQ;;;;;;;;;;;;AChQjB,IAAa,qBAAb,MAAa,mBAA2C;CACtD,OAAwB,sBAAsB;CAC9C,AAAQ;CACR,AAAQ,iBAGH,EAAE;CAEP,YAAY,YAAoC;AAC9C,OAAK,aAAa;AAClB,OAAK,WAAW,kBAAkB,KAAK,cAAc,CAAC;AACtD,OAAK,WAAW,eAAe,KAAK,aAAa,CAAC;;CAGpD,AAAQ,eAAqB;EAC3B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;AACzE,OAAK,MAAM,EAAE,OAAO,oBAAoB,QACtC,MAAK,WAAW,OAAO,eAAe;;CAI1C,AAAQ,cAAoB;EAC1B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,wBAAQ,IAAI,MAAM,2CAA2C;AACnE,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAMC,qCAAiB;GAAQ;GAAO,CAAC;;CAI9D,AAAQ,WAAW,OAAuB,gBAAuD;AAC/F,MAAI;GACF,MAAM,aAAaC,oDAAoB,iBAAiB,MAAM;AAC9D,OAAI,CAAC,YAAY;AACf,qBAAiB,EAAE,MAAMD,qCAAiB,SAAS,CAAC;AACpD;;AAGF,QAAK,WAAW,KAAK,eAAe,aAAY,QAAO;AACrD,QAAI,KAAK;AACP,aAAQ,MAAM,gCAAgC,IAAI,QAAQ;AAC1D,sBAAiB;MAAE,MAAMA,qCAAiB;MAAQ,OAAO;MAAK,CAAC;UAE/D,kBAAiB,EAAE,MAAMA,qCAAiB,SAAS,CAAC;KAEtD;WACK,KAAK;AACZ,WAAQ,MAAM,iCAAiC,IAAI;AACnD,oBAAiB;IAAE,MAAMA,qCAAiB;IAAQ,OAAO;IAAc,CAAC;;;CAI5E,AAAQ,SAAS,OAAuB,gBAAsD;EAC5F,MAAM,QAAQ,KAAK,WAAW,UAAU;AACxC,MAAI,UAAU,aAAa;AAEzB,OAAI,UAAU,YAAY,KAAK,WAAW,gBAAgB,EAAE;IAC1D,MAAM,SAAS,UAAU,WAAW,WAAW;AAC/C,mBAAe;KACb,MAAMA,qCAAiB;KACvB,uBAAO,IAAI,MAAM,cAAc,OAAO,kBAAkB;KACzD,CAAC;AACF;;AAEF,OAAI,KAAK,eAAe,UAAU,mBAAmB,qBAAqB;AAExE,IADgB,KAAK,eAAe,OAAO,EAClC,iBAAiB;KACxB,MAAMA,qCAAiB;KACvB,uBAAO,IAAI,MAAM,iBAAiB;KACnC,CAAC;AACF,YAAQ,KAAK,uDAAuD;;AAEtE,QAAK,eAAe,KAAK;IAAE;IAAO;IAAgB,CAAC;AAEnD;;AAGF,OAAK,WAAW,OAAO,eAAe;;CAGxC,OAAO,OAAuB,gBAAsD;AAClF,OAAK,SAAS,OAAO,eAAe;;CAGtC,MAAM,WAA0B;EAC9B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,gCAAgB,IAAI,MAAM,4CAA4C;AAC5E,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAMA,qCAAiB;GAAQ,OAAO;GAAe,CAAC;;CAI7E,MAAM,aAA4B;;;;;;;;;;;AC3FpC,IAAa,wBAAb,MAAa,sBAAoD;CAC/D,OAAwB,sBAAsB;CAC9C,AAAQ;CACR,AAAQ,iBAGH,EAAE;CAEP,YAAY,YAAoC;AAC9C,OAAK,aAAa;AAClB,OAAK,WAAW,kBAAkB,KAAK,cAAc,CAAC;AACtD,OAAK,WAAW,eAAe,KAAK,aAAa,CAAC;;CAGpD,AAAQ,eAAqB;EAC3B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;AACzE,OAAK,MAAM,EAAE,SAAS,oBAAoB,QACxC,MAAK,WAAW,SAAS,eAAe;;CAI5C,AAAQ,cAAoB;EAC1B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,wBAAQ,IAAI,MAAM,6CAA6C;AACrE,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAME,qCAAiB;GAAQ;GAAO,CAAC;;CAI9D,AAAQ,WACN,aACA,gBACM;AACN,MAAI;GACF,MAAM,aAAaC,sDAAsB,iBAAiB,YAAY;AACtE,OAAI,CAAC,YAAY;AACf,qBAAiB,EAAE,MAAMD,qCAAiB,SAAS,CAAC;AACpD;;AAGF,QAAK,WAAW,KAAK,gBAAgB,aAAY,QAAO;AACtD,QAAI,KAAK;AACP,aAAQ,MAAM,kCAAkC,IAAI,QAAQ;AAC5D,sBAAiB;MAAE,MAAMA,qCAAiB;MAAQ,OAAO;MAAK,CAAC;UAE/D,kBAAiB,EAAE,MAAMA,qCAAiB,SAAS,CAAC;KAEtD;WACK,KAAK;AACZ,WAAQ,MAAM,mCAAmC,IAAI;AACrD,oBAAiB;IAAE,MAAMA,qCAAiB;IAAQ,OAAO;IAAc,CAAC;;;CAI5E,AAAQ,SACN,aACA,gBACM;EACN,MAAM,QAAQ,KAAK,WAAW,UAAU;AACxC,MAAI,UAAU,aAAa;AAEzB,OAAI,UAAU,YAAY,KAAK,WAAW,gBAAgB,EAAE;IAC1D,MAAM,SAAS,UAAU,WAAW,WAAW;AAC/C,mBAAe;KACb,MAAMA,qCAAiB;KACvB,uBAAO,IAAI,MAAM,cAAc,OAAO,oBAAoB;KAC3D,CAAC;AACF;;AAEF,OAAI,KAAK,eAAe,UAAU,sBAAsB,qBAAqB;AAE3E,IADgB,KAAK,eAAe,OAAO,EAClC,iBAAiB;KACxB,MAAMA,qCAAiB;KACvB,uBAAO,IAAI,MAAM,iBAAiB;KACnC,CAAC;AACF,YAAQ,KAAK,yDAAyD;;AAExE,QAAK,eAAe,KAAK;IAAE,SAAS;IAAa;IAAgB,CAAC;AAElE;;AAGF,OAAK,WAAW,aAAa,eAAe;;CAG9C,OAAO,SAA0B,gBAAsD;AACrF,OAAK,SAAS,SAAS,eAAe;;CAGxC,MAAM,WAA0B;EAC9B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,gCAAgB,IAAI,MAAM,4CAA4C;AAC5E,OAAK,MAAM,EAAE,oBAAoB,QAC/B,kBAAiB;GAAE,MAAMA,qCAAiB;GAAQ,OAAO;GAAe,CAAC;;CAI7E,MAAM,aAA4B;;;;;;;;;;;ACjGpC,IAAa,oBAAb,MAAa,kBAA+C;CAC1D,OAAwB,sBAAsB;CAC9C,AAAQ;CACR,AAAQ,iBAGH,EAAE;CAEP,YAAY,YAAoC;AAC9C,OAAK,aAAa;AAClB,OAAK,WAAW,kBAAkB,KAAK,cAAc,CAAC;AACtD,OAAK,WAAW,eAAe,KAAK,aAAa,CAAC;;CAGpD,AAAQ,eAAqB;EAC3B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;AACzE,OAAK,MAAM,EAAE,MAAM,cAAc,QAC/B,MAAK,SAAS,MAAM,SAAS;;CAIjC,AAAQ,cAAoB;EAC1B,MAAM,UAAU,KAAK,eAAe,OAAO,GAAG,KAAK,eAAe,OAAO;EACzE,MAAM,wBAAQ,IAAI,MAAM,0CAA0C;AAClE,OAAK,MAAM,EAAE,cAAc,QACzB,UAAS;GAAE,MAAME,qCAAiB;GAAQ;GAAO,CAAC;;CAItD,AAAQ,SACN,MACA,gBACM;EACN,MAAM,QAAQ,KAAK,WAAW,UAAU;AACxC,MAAI,UAAU,aAAa;AAEzB,OAAI,UAAU,YAAY,KAAK,WAAW,gBAAgB,EAAE;IAC1D,MAAM,SAAS,UAAU,WAAW,WAAW;AAC/C,mBAAe;KACb,MAAMA,qCAAiB;KACvB,uBAAO,IAAI,MAAM,cAAc,OAAO,iBAAiB;KACxD,CAAC;AACF;;AAEF,OAAI,KAAK,eAAe,UAAU,kBAAkB,qBAAqB;AAEvE,IADgB,KAAK,eAAe,OAAO,EAClC,SAAS;KAChB,MAAMA,qCAAiB;KACvB,uBAAO,IAAI,MAAM,yBAAyB;KAC3C,CAAC;AACF,YAAQ,KAAK,sDAAsD;;AAErE,QAAK,eAAe,KAAK;IAAE;IAAM,UAAU;IAAgB,CAAC;AAC5D;;AAGF,MAAI;GACF,MAAM,aAAaC,mDAAmB,iBAAiB,KAAK;AAC5D,OAAI,CAAC,YAAY;AACf,mBAAe,EAAE,MAAMD,qCAAiB,SAAS,CAAC;AAClD;;AAGF,QAAK,WAAW,KAAK,aAAa,aAAY,QAAO;AACnD,QAAI,KAAK;AACP,aAAQ,MAAM,+BAA+B,IAAI,QAAQ;AACzD,oBAAe;MAAE,MAAMA,qCAAiB;MAAQ,OAAO;MAAK,CAAC;UAE7D,gBAAe,EAAE,MAAMA,qCAAiB,SAAS,CAAC;KAEpD;WACK,KAAK;AACZ,WAAQ,MAAM,gCAAgC,IAAI;AAClD,kBAAe;IAAE,MAAMA,qCAAiB;IAAQ,OAAO;IAAc,CAAC;;;CAI1E,OAAO,MAA2B,gBAAsD;AACtF,OAAK,SAAS,MAAM,eAAe;;CAGrC,MAAM,aAA4B;CAElC,MAAM,WAA0B;AAC9B,OAAK,MAAM,EAAE,cAAc,KAAK,eAC9B,UAAS;GAAE,MAAMA,qCAAiB;GAAQ,uBAAO,IAAI,MAAM,oBAAoB;GAAE,CAAC;AAEpF,OAAK,iBAAiB,EAAE;;;;;;;;;;;;AC5F5B,SAAgB,iBAAqC;CACnD,MAAM,OAAOE,yBAAM,eAAe;AAClC,KAAI,MAAM;EACR,MAAM,cAAc,KAAK,aAAa;AACtC,MAAI,YAAY,WAAW,YAAY,YAAY,mCACjD,QAAO,YAAY;;;;;;AASzB,SAAgB,gBAAoC;CAClD,MAAM,OAAOA,yBAAM,eAAe;AAClC,KAAI,MAAM;EACR,MAAM,cAAc,KAAK,aAAa;AACtC,MAAI,YAAY,UAAU,YAAY,WAAW,mBAC/C,QAAO,YAAY;;;;;;AASzB,SAAgB,oBAAwC;CACtD,MAAM,UAAkC,EAAE;AAC1C,gCAAY,OAAOC,2BAAQ,QAAQ,EAAE,QAAQ;AAC7C,QAAO,QAAQ;;;;;;;AAQjB,SAAgB,mBAAmB,aAA8B;CAC/D,MAAM,UAAkC,EAAE,aAAa;AACvD,QAAOC,+BAAY,QAAQD,2BAAQ,QAAQ,EAAE,QAAQ;;;;;AAMvD,SAAgB,gBAAoC;CAClD,MAAM,UAAkC,EAAE;AAC1C,gCAAY,OAAOA,2BAAQ,QAAQ,EAAE,QAAQ;AAC7C,QAAO,QAAQ;;;;;;;AAQjB,SAAgB,eAAe,SAA0B;CACvD,MAAM,UAAkC,EAAE,SAAS;AACnD,QAAOC,+BAAY,QAAQD,2BAAQ,QAAQ,EAAE,QAAQ;;;;;;;;AASvD,SAAgB,eAAe,aAAsB,SAA2B;CAC9E,MAAM,UAAkC,EAAE;AAC1C,KAAI,YACF,SAAQ,cAAc;AAExB,KAAI,QACF,SAAQ,UAAU;AAEpB,QAAOC,+BAAY,QAAQD,2BAAQ,QAAQ,EAAE,QAAQ;;;;;;;AAQvD,SAAgB,gBAAgB,KAAiC;AAE/D,QADYC,+BAAY,WAAWD,2BAAQ,QAAQ,CAAC,EACxC,SAAS,IAAI,EAAE;;;;;;;;AAS7B,SAAgB,gBAAgB,KAAa,OAAwB;CACnE,IAAI,MAAMC,+BAAY,WAAWD,2BAAQ,QAAQ,CAAC,IAAIC,+BAAY,eAAe;AACjF,OAAM,IAAI,SAAS,KAAK,EAAE,OAAO,CAAC;AAClC,QAAOA,+BAAY,WAAWD,2BAAQ,QAAQ,EAAE,IAAI;;;;;;;AAQtD,SAAgB,mBAAmB,KAAsB;CACvD,MAAM,MAAMC,+BAAY,WAAWD,2BAAQ,QAAQ,CAAC;AACpD,KAAI,CAAC,IACH,QAAOA,2BAAQ,QAAQ;CAEzB,MAAM,SAAS,IAAI,YAAY,IAAI;AACnC,QAAOC,+BAAY,WAAWD,2BAAQ,QAAQ,EAAE,OAAO;;;;;AAMzD,SAAgB,gBAAwC;CACtD,MAAM,MAAMC,+BAAY,WAAWD,2BAAQ,QAAQ,CAAC;AACpD,KAAI,CAAC,IACH,QAAO,EAAE;CAEX,MAAM,UAAkC,EAAE;AAC1C,MAAK,MAAM,CAAC,KAAK,UAAU,IAAI,eAAe,CAC5C,SAAQ,OAAO,MAAM;AAEvB,QAAO;;;;;;;;;;;;AC/HT,MAAM,cAAc,IAAI,aAAa;AAErC,SAAS,gBAAgB,MAAmC;AAC1D,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,OAAO,SAAS,SAAU,QAAO,YAAY,OAAO,KAAK,CAAC;AAC9D,KAAI,gBAAgB,YAAa,QAAO,KAAK;AAC7C,KAAI,YAAY,OAAO,KAAK,CAAE,QAAO,KAAK;AAC1C,KAAI,gBAAgB,KAAM,QAAO,KAAK;AACtC,KAAI,gBAAgB,gBAAiB,QAAO,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC;;AAIxF,MAAM,uBAAuB,CAAC,gBAAgB,SAAS;AACvD,MAAM,wBAAwB,CAAC,eAAe;AAE9C,IAAI,gBAAgD;;;;;;;AAQpD,MAAM,6BAAuC,QAAQ,IAAI,0BAA0B,IAChF,MAAM,IAAI,CACV,KAAI,MAAK,EAAE,MAAM,CAAC,CAClB,OAAO,QAAQ;AAElB,SAAS,qBAAqB,KAAsB;AAClD,QAAO,0BAA0B,MAAK,YAAW,IAAI,SAAS,QAAQ,CAAC;;;;;;;AAQzE,SAAgB,iBAAiB,QAAsB;AACrD,KAAI,cAAe;AAEnB,iBAAgB,WAAW;CAC3B,MAAM,gBAAgB;AAEtB,YAAW,QAAQ,OACjB,OACA,SACsB;EACtB,MAAM,MAAM,iBAAiB,UAAU,MAAM,MAAM,OAAO,MAAM;AAGhE,MAAI,qBAAqB,IAAI,CAC3B,QAAO,cAAc,OAAO,KAAK;EAGnC,MAAM,UAAU,MAAM,WAAW,iBAAiB,UAAU,MAAM,SAAS,QAAQ,aAAa;EAEhG,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;AACJ,MAAI;GACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,UAAO,OAAO;AACd,YAAS,OAAO,SAAS,QAAQ,KAAK,GAAG;AACzC,UAAO,OAAO;AACd,UAAO,OAAO,OAAO,SAAS,OAAO,MAAM,GAAG,GAAG;AACjD,WAAQ,OAAO,SAAS,OAAO,OAAO,MAAM,EAAE,GAAG;UAC3C;EAIR,MAAM,iBAAkD;GACtD,uBAAuB;GACvB,YAAY;GACb;AACD,MAAI,KAAM,gBAAe,oBAAoB;AAC7C,MAAI,QAAQ;AACV,kBAAe,gBAAgB;AAC/B,kBAAe,2BAA2B;;AAE5C,MAAI,KAAM,gBAAe,cAAc;AACvC,MAAI,KAAM,gBAAe,iBAAiB;AAC1C,MAAI,MAAO,gBAAe,eAAe;EAEzC,MAAM,WAAW,OAAO,GAAG,OAAO,GAAG,SAAS;AAE9C,SAAO,OAAO,gBACZ,UACA;GAAE,MAAME,4BAAS;GAAQ,YAAY;GAAgB,EACrDC,2BAAQ,QAAQ,EAChB,OAAM,SAAQ;AACZ,OAAI;IACF,MAAM,UAAkC,EAAE;AAC1C,mCAAY,OAAOA,2BAAQ,QAAQ,EAAE,QAAQ;IAE7C,MAAM,UAAU,IAAI,QAClB,MAAM,YAAY,iBAAiB,UAAU,MAAM,UAAU,QAC9D;AACD,SAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,SAAQ,IAAI,KAAK,MAAM;AAGzB,SAAK,MAAM,QAAQ,sBAAsB;KACvC,MAAM,QAAQ,QAAQ,IAAI,KAAK;AAC/B,SAAI,UAAU,KACZ,MAAK,aAAa,uBAAuB,QAAQ,MAAM;;IAK3D,MAAM,kBAAkB,gBADJ,MAAM,SAAS,iBAAiB,UAAU,MAAM,OAAO,QACvB;AACpD,QAAI,oBAAoB,OACtB,MAAK,aAAa,0BAA0B,gBAAgB;IAG9D,MAAM,WAAW,MAAM,cAAc,OAAO;KAAE,GAAG;KAAM;KAAS,CAAC;AAEjE,SAAK,aAAa,6BAA6B,SAAS,OAAO;IAE/D,MAAM,gBAAgB,SAAS,QAAQ,IAAI,iBAAiB;AAC5D,QAAI,kBAAkB,MAAM;KAC1B,MAAM,OAAO,SAAS,eAAe,GAAG;AACxC,SAAI,CAAC,OAAO,MAAM,KAAK,CACrB,MAAK,aAAa,2BAA2B,KAAK;;AAItD,SAAK,MAAM,QAAQ,uBAAuB;KACxC,MAAM,QAAQ,SAAS,QAAQ,IAAI,KAAK;AACxC,SAAI,UAAU,KACZ,MAAK,aAAa,wBAAwB,QAAQ,MAAM;;AAI5D,QAAI,SAAS,UAAU,KAAK;AAC1B,UAAK,aAAa,cAAc,OAAO,SAAS,OAAO,CAAC;AACxD,UAAK,UAAU,EAAE,MAAMC,kCAAe,OAAO,CAAC;UAE9C,MAAK,UAAU,EAAE,MAAMA,kCAAe,IAAI,CAAC;AAG7C,WAAO;YACA,OAAO;AACd,SAAK,aAAa,cAAe,MAAgB,QAAQ,QAAQ;AACjE,SAAK,UAAU;KAAE,MAAMA,kCAAe;KAAO,SAAU,MAAgB;KAAS,CAAC;AACjF,SAAK,gBAAgB,MAAe;AACpC,UAAM;aACE;AACR,SAAK,KAAK;;IAGf;;;;;;AAOL,SAAgB,qBAA2B;AACzC,KAAI,eAAe;AACjB,aAAW,QAAQ;AACnB,kBAAgB;;;;;;;;;;;;;ACrKpB,SAAgB,eAAe,OAA2B,UAAkB,GAAuB;AACjG,KAAI,UAAU,UAAa,MAAM,MAAM,KAAK,GAAI,QAAO;CACvD,MAAM,SAAS,OAAO,MAAM;AAC5B,KAAI,CAAC,OAAO,SAAS,OAAO,IAAI,SAAS,QAAS,QAAO;AACzD,QAAO;;;;;AAMT,SAAgB,gBACd,OACA,UAAkB,GACE;CACpB,MAAM,SAAS,eAAe,OAAO,QAAQ;AAC7C,KAAI,WAAW,UAAa,CAAC,OAAO,UAAU,OAAO,CAAE,QAAO;AAC9D,QAAO;;;;;;;;;;;;AAaT,SAAgB,uBACd,aACA,UACA,cACQ;AACR,QAAO,eAAe,eAAe,UAAU,EAAE,IAAI;;;;;;;ACpCvD,SAAgB,yBAAkC;CAChD,MAAM,OAAOC,yBAAM,eAAe;AAClC,QAAO,OAAO,KAAK,aAAa,GAAG;;;;;;;;AASrC,SAAgB,wBAAwB,KAAa,OAA6B;CAChF,MAAM,OAAOA,yBAAM,eAAe;AAClC,KAAI,CAAC,QAAQ,CAAC,KAAK,aAAa,CAAE;AAClC,MAAK,aAAa,KAAK,MAAM;;;;;;;AAQ/B,SAAgB,oBAAoB,SAAuB;CACzD,MAAM,OAAOA,yBAAM,eAAe;AAClC,KAAI,CAAC,KAAM;AACX,MAAK,UAAU;EAAE,MAAMC,kCAAe;EAAO;EAAS,CAAC;;;;;;;;AASzD,SAAgB,gBAAgB,MAAc,OAA0B;CACtE,MAAM,OAAOD,yBAAM,eAAe;AAClC,KAAI,CAAC,QAAQ,CAAC,KAAK,aAAa,CAAE;AAClC,MAAK,SAAS,MAAM,MAAM;;;;;;ACxC5B,MAAa,uBAAuB;AACpC,MAAM,oBAAoB;;;;;AAM1B,SAAgB,yBAAwC;CACtD,MAAM,MAAM,QAAQ,IAAI;AACxB,KAAI,QAAQ,OAAW,QAAO;CAC9B,MAAM,UAAU,IAAI,MAAM;AAC1B,KAAI,YAAY,MAAM,QAAQ,aAAa,KAAK,YAAa,QAAO;AAGpE,KAAI,CAAC,QAAQ,KAAK,QAAQ,CAAE,QAAO;CACnC,MAAM,SAAS,OAAO,QAAQ;AAC9B,KAAI,UAAU,EAAG,QAAO;AACxB,QAAO;;AAGT,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,eAAe,KAAsB;CAC5C,MAAM,QAAQ,IAAI,aAAa;AAC/B,KAAI,oBAAoB,MAAM,aAAa,MAAM,SAAS,SAAS,CAAC,CAAE,QAAO;AAE7E,QAAO,UAAU,WAAW,MAAM,SAAS,SAAS,IAAI,MAAM,SAAS,SAAS;;;;;;;AAQlF,SAAgB,OAAO,OAAyB;AAC9C,KAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,IAAI,OAAO;AAClD,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,MAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAiC,CACnE,KAAI,KAAK,eAAe,EAAE,GAAG,uBAAuB,OAAO,EAAE;AAE/D,SAAO;;AAET,QAAO;;;;;;;;AAST,SAAgB,kBACd,OACA,WAA0B,MACY;CACtC,MAAM,WAAW,OAAO,MAAM;CAC9B,IAAI;AACJ,KAAI;AACF,eAAa,KAAK,UAAU,SAAS,IAAI;SACnC;AACN,eAAa;;AAGf,KAAI,aAAa,QAAQ,aAAa,UAAa,YAAY,EAC7D,QAAO;EAAE,MAAM;EAAY,WAAW;EAAO;AAI/C,KADgB,OAAO,WAAW,YAAY,OAAO,IACtC,SACb,QAAO;EAAE,MAAM;EAAY,WAAW;EAAO;CAG/C,MAAM,YAAY,OAAO,WAAW,mBAAmB,OAAO;AAG9D,KAAI,YAAY,UACd,QAAO;EAAE,MAAM,kBAAkB,MAAM,GAAG,SAAS;EAAE,WAAW;EAAM;CAGxE,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,OAAO,KAAK,YAAY,OAAO;CAC3C,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO;AAEnC,QAAO,MAAM,MAAM,IAAI,OAAO,SAAU,IACtC,QAAO;AAGT,QAAO;EAAE,MADS,IAAI,SAAS,GAAG,IAAI,CAAC,SAAS,OAAO,GAAG;EAChC,WAAW;EAAM;;;;;;;;;;;;;;;;;ACrC7C,SAAS,eAAe,MAAsB;CAC5C,MAAM,MAAM,IAAI,IAAI,KAAK;CACzB,MAAM,OAAO,IAAI,SAAS,QAAQ,QAAQ,GAAG;AAC7C,KAAI,WAAW,KAAK,SAAS,QAAQ,GAAG,OAAO,GAAG,KAAK;AACvD,QAAO,IAAI,UAAU;;AAIvB,IAAI,mBAAkD;AACtD,IAAI,iBAA4C;AAChD,IAAI,gBAAsC;AAC1C,IAAI,iBAAwC;AAC5C,IAAI,SAAwB;AAC5B,IAAI,QAAsB;AAC1B,IAAI,SAAwB;AAC5B,IAAI,cAAsB;;;;;;;AAQ1B,SAAgB,SAAS,SAAqB,EAAE,EAAQ;AAGtD,KAAI,EAFY,OAAO,WAAW,aAAa,QAAQ,IAAI,cAAc,oBAAoB,QAAQ,GAEvF;AACZ,UAAQ,MACN,yGACD;AACD;;AAIF,eAAc,OAAO,eAAe,QAAQ,IAAI,qBAAqB,oBAAoB;CACzF,MAAM,iBAAiB,OAAO,kBAAkB,QAAQ,IAAI,mBAAmB,oBAAoB;CACnG,MAAM,mBAAmB,OAAO,oBAAoB,QAAQ,IAAI;CAChE,MAAM,oBAAoB,OAAO,qBAAqB,QAAQ,IAAI,oDAAmC;CACrG,MAAM,cAAc,OAAO,eAAe,QAAQ,IAAI,WAAW,oBAAoB;CAGrF,MAAM,qBAA6C;GAChDE,wDAAoB;GACpB,uBAAuB;GACvB,2BAA2B;EAC7B;AACD,KAAI,iBACF,oBAAmB,0BAA0B;CAE/C,MAAM,WAAW,IAAIC,kCAAS,mBAAmB;AAMjD,oBAAmB,IAAI,uBAAuB,eAAe,YAAY,EAAE,OAAO,mBAAmB;CAKrG,MAAM,eAAe,IAAI,mBAAmB,iBAAiB;CAQ7D,MAAM,4BAA4B,uBAChC,OAAO,sBACP,QAAQ,IAAI,8BACZ,oBAAoB,qBACrB;AACD,kBAAiB,IAAIC,iDAAmB;EACtC;EACA,gBAAgB,CACd,IAAI,sBAAsB,EAC1B,IAAIC,iDAAmB,cAAc,EAAE,sBAAsB,2BAA2B,CAAC,CAC1F;EACF,CAAC;AAGF,gCAAY,oBACV,IAAIC,wCAAoB,EACtB,aAAa,CAAC,IAAIC,+CAA2B,EAAE,IAAIC,0CAAsB,CAAC,EAC3E,CAAC,CACH;AAED,gBAAe,UAAU;AACzB,UAASC,yBAAM,UAAU,YAAY;AAErC,SAAQ,MAAM,qCAAqC,YAAY,YAAY,cAAc;AAMzF,KAFE,OAAO,kBAAkB,aAAa,QAAQ,IAAI,sBAAsB,oBAAoB,eAAe,EAEzF;EAClB,MAAM,kBAAkB,IAAI,sBAAsB,iBAAiB;EACnE,MAAM,mBAAmB,OAAO,2BAA2B,oBAAoB;AAO/E,kBAAgB,IAAIC,yCAAc;GAChC;GACA,SAAS,CAPU,IAAIC,yDAA8B;IACrD,UAAU;IACV,sBAAsB;IACvB,CAAC,CAIuB;GACxB,CAAC;AAEF,6BAAQ,uBAAuB,cAAc;AAC7C,UAAQ,cAAc,SAAS,YAAY;AAE3C,UAAQ,MAAM,wCAAwC,iBAAiB,IAAI;;CAI7E,MAAM,mBAAmB,CAAC,GAAI,OAAO,oBAAoB,EAAE,CAAE;AAC7D,KAAI,iBAAiB,SAAS,GAAG;AAC/B,+DAAyB;GACvB;GACA;GACA,eAAe,iBAAiB;GACjC,CAAC;AACF,UAAQ,MAAM,uCAAuC,iBAAiB,OAAO,QAAQ;;AAMvF,KAFqB,OAAO,+BAA+B,oBAAoB,6BAE7D;AAChB,mBAAiB,OAAO;AACxB,UAAQ,MAAM,8CAA8C;;CAI9D,MAAM,cAAc,IAAI,kBAAkB,iBAAiB;CAC3D,MAAM,2BAA2B,uBAC/B,OAAO,qBACP,QAAQ,IAAI,6BACZ,oBAAoB,oBACrB;CACD,MAAM,yBACJ,OAAO,iBAAiB,gBAAgB,QAAQ,IAAI,sBAAsB,EAAE,IAAI,oBAAoB;AAEtG,kBAAiB,IAAIC,uCAAe,EAAE,UAAU,CAAC;AACjD,gBAAe,sBACb,IAAIC,gDAAwB,aAAa;EACvC,sBAAsB;EACtB,oBAAoB;EACrB,CAAC,CACH;AACD,UAAS,eAAe,UAAU,YAAY;AAE9C,SAAQ,MAAM,kCAAkC,yBAAyB,YAAY,yBAAyB;;;;;;AAOhH,eAAsB,eAA8B;AAElD,mBAAkB,eAAe;CAKjC,MAAM,UAAU,MAAwB,EAAE,YAAY,GAAG;AAEzD,KAAI,gBAAgB;AAClB,QAAM,OAAO,eAAe,YAAY,CAAC;AACzC,QAAM,OAAO,eAAe,UAAU,CAAC;AACvC,mBAAiB;;AAGnB,KAAI,eAAe;AACjB,QAAM,OAAO,cAAc,YAAY,CAAC;AACxC,QAAM,OAAO,cAAc,UAAU,CAAC;AACtC,kBAAgB;;AAGlB,KAAI,gBAAgB;AAClB,QAAM,OAAO,eAAe,YAAY,CAAC;AACzC,QAAM,OAAO,eAAe,UAAU,CAAC;AACvC,mBAAiB;;AAGnB,KAAI,kBAAkB;AACpB,QAAM,iBAAiB,UAAU;AACjC,qBAAmB;;AAGrB,qBAAoB;AAEpB,UAAS;AACT,SAAQ;AACR,UAAS;;;;;;;;;AAUX,eAAsB,YAA2B;AAC/C,OAAM,QAAQ,IACZ;EACE,gBAAgB,YAAY;EAC5B,eAAe,YAAY;EAC3B,gBAAgB,YAAY;EAC7B,CAAC,OAAO,QAAQ,CAClB;;;;;AAMH,SAAgB,YAA2B;AACzC,QAAO;;;;;AAMT,SAAgB,WAAyB;AACvC,QAAO;;;;;AAMT,SAAgB,YAA2B;AACzC,QAAO;;;;;;;;;AAUT,eAAsB,SACpB,MACA,SACA,IACY;AACZ,KAAI,CAAC,QAAQ;EAGX,MAAM,WAAiB;GACrB,oBAAoB;IAAE,SAAS;IAAI,QAAQ;IAAI,YAAY;IAAG;GAC9D,oBAAoB;GACpB,qBAAqB;GACrB,gBAAgB;GAChB,eAAe;GACf,iBAAiB;GACjB,kBAAkB;GAClB,WAAW;GACX,mBAAmB;GACnB,uBAAuB;GACvB,gBAAgB;GACjB;AACD,SAAO,GAAG,SAAS;;CAGrB,MAAM,gBAAgB,QAAQ,cAAc,mBAAmB,QAAQ,YAAY,GAAGC,2BAAQ,QAAQ;AAEtG,QAAO,OAAO,gBAAgB,MAAM,EAAE,MAAM,QAAQ,QAAQC,4BAAS,UAAU,EAAE,eAAe,OAAO,SAAS;AAC9G,MAAI;GACF,MAAM,SAAS,MAAM,GAAG,KAAK;AAC7B,QAAK,UAAU,EAAE,MAAMC,kCAAe,IAAI,CAAC;AAC3C,UAAO;WACA,OAAO;AACd,QAAK,UAAU;IAAE,MAAMA,kCAAe;IAAO,SAAU,MAAgB;IAAS,CAAC;AACjF,QAAK,gBAAgB,MAAe;AACpC,SAAM;YACE;AACR,QAAK,KAAK;;GAEZ"}