autotel-devtools 5.0.1 → 6.0.0

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.
@@ -105,6 +105,11 @@ var DevtoolsSpanExporter = class {
105
105
  timestamp: event.time[0] * 1e3 + event.time[1] / 1e6,
106
106
  attributes: event.attributes ? Object.fromEntries(Object.entries(event.attributes)) : void 0
107
107
  }));
108
+ const links = span.links.map((link) => ({
109
+ traceId: link.context.traceId,
110
+ spanId: link.context.spanId,
111
+ attributes: link.attributes ? Object.fromEntries(Object.entries(link.attributes)) : void 0
112
+ }));
108
113
  return {
109
114
  traceId: spanContext.traceId,
110
115
  spanId: spanContext.spanId,
@@ -119,9 +124,15 @@ var DevtoolsSpanExporter = class {
119
124
  code: status,
120
125
  message: span.status.message
121
126
  },
122
- events: events.length > 0 ? events : void 0
127
+ events: events.length > 0 ? events : void 0,
128
+ links: links.length > 0 ? links : void 0,
129
+ scope: this.convertScope(span)
123
130
  };
124
131
  }
132
+ convertScope(span) {
133
+ const s = span.instrumentationScope ?? span.instrumentationLibrary;
134
+ return s?.name ? { name: s.name, version: s.version || void 0 } : void 0;
135
+ }
125
136
  /**
126
137
  * Convert OpenTelemetry SpanKind to string
127
138
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/exporter.ts"],"names":[],"mappings":"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","file":"exporter.cjs","sourcesContent":["/**\n * OpenTelemetry SpanExporter that streams spans to DevtoolsServer\n */\n\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport type { DevtoolsServer } from './server';\nimport type { TraceData, SpanData } from './types';\n\nexport class DevtoolsSpanExporter implements SpanExporter {\n private server: DevtoolsServer;\n private serviceName: string;\n\n constructor(server: DevtoolsServer, serviceName: string = 'unknown-service') {\n this.server = server;\n this.serviceName = serviceName;\n }\n\n /**\n * Export spans to the WebSocket server\n */\n async export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): Promise<void> {\n // Immediately call the callback to unblock the span processor\n // Then process the spans asynchronously\n resultCallback({ code: 0 as ExportResultCode });\n\n // Process spans asynchronously without blocking\n Promise.resolve().then(() => {\n try {\n console.log(`[Autotel Exporter] Exporting ${spans.length} span(s)`);\n\n // Group spans by trace ID\n const traceMap = new Map<string, ReadableSpan[]>();\n\n for (const span of spans) {\n const traceId = span.spanContext().traceId;\n if (!traceMap.has(traceId)) {\n traceMap.set(traceId, []);\n }\n traceMap.get(traceId)!.push(span);\n }\n\n // Convert each trace and send to server\n for (const [traceId, traceSpans] of traceMap) {\n const trace = this.convertToTraceData(traceId, traceSpans);\n console.log(\n `[Autotel Exporter] Adding trace ${traceId.slice(0, 16)} with ${traceSpans.length} spans`,\n );\n this.server.addTrace(trace);\n }\n } catch (error) {\n console.error('[Autotel Exporter] Export error:', error);\n }\n });\n }\n\n /**\n * Shutdown the exporter\n */\n async shutdown(): Promise<void> {\n // Nothing to clean up\n }\n\n /**\n * Force flush any buffered spans\n */\n async forceFlush(): Promise<void> {\n // Nothing to flush\n }\n\n /**\n * Convert OpenTelemetry spans to TraceData\n */\n private convertToTraceData(\n traceId: string,\n spans: ReadableSpan[],\n ): TraceData {\n // Convert spans\n const spanData: SpanData[] = spans.map((span) => this.convertSpan(span));\n\n // Find root span (no parent)\n const rootSpan = spanData.find((s) => !s.parentSpanId) || spanData[0];\n\n // Sort spans by start time\n spanData.sort((a, b) => a.startTime - b.startTime);\n\n const startTime = Math.min(...spanData.map((s) => s.startTime));\n const endTime = Math.max(...spanData.map((s) => s.endTime));\n\n // Determine overall status (ERROR if any span errored)\n const hasError = spanData.some((s) => s.status.code === 'ERROR');\n const status = hasError ? 'ERROR' : 'OK';\n\n return {\n traceId,\n correlationId: traceId.slice(0, 16), // First 16 chars\n rootSpan,\n spans: spanData,\n startTime,\n endTime,\n duration: endTime - startTime,\n status: status as 'OK' | 'ERROR' | 'UNSET',\n service: this.serviceName,\n };\n }\n\n /**\n * Convert OpenTelemetry span to SpanData\n */\n private convertSpan(span: ReadableSpan): SpanData {\n const spanContext = span.spanContext();\n const startTime = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;\n const endTime = span.endTime[0] * 1000 + span.endTime[1] / 1_000_000;\n\n // Convert attributes\n const attributes: Record<string, any> = {};\n for (const [key, value] of Object.entries(span.attributes)) {\n attributes[key] = value;\n }\n\n // Convert status\n const statusCode = span.status.code;\n let status: 'OK' | 'ERROR' | 'UNSET';\n switch (statusCode) {\n case 0: {\n status = 'UNSET';\n break;\n }\n case 1: {\n status = 'OK';\n break;\n }\n case 2: {\n status = 'ERROR';\n break;\n }\n default: {\n status = 'UNSET';\n }\n }\n\n // Convert events\n const events = span.events.map((event) => ({\n name: event.name,\n timestamp: event.time[0] * 1000 + event.time[1] / 1_000_000,\n attributes: event.attributes\n ? Object.fromEntries(Object.entries(event.attributes))\n : undefined,\n }));\n\n return {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n parentSpanId: (span as any).parentSpanId,\n name: span.name,\n kind: this.convertSpanKind(span.kind),\n startTime,\n endTime,\n duration: endTime - startTime,\n attributes,\n status: {\n code: status,\n message: span.status.message,\n },\n events: events.length > 0 ? events : undefined,\n };\n }\n\n /**\n * Convert OpenTelemetry SpanKind to string\n */\n private convertSpanKind(\n kind: number,\n ): 'INTERNAL' | 'SERVER' | 'CLIENT' | 'PRODUCER' | 'CONSUMER' {\n switch (kind) {\n case 0: {\n return 'INTERNAL';\n }\n case 1: {\n return 'SERVER';\n }\n case 2: {\n return 'CLIENT';\n }\n case 3: {\n return 'PRODUCER';\n }\n case 4: {\n return 'CONSUMER';\n }\n default: {\n return 'INTERNAL';\n }\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/server/exporter.ts"],"names":[],"mappings":"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","file":"exporter.cjs","sourcesContent":["/**\n * OpenTelemetry SpanExporter that streams spans to DevtoolsServer\n */\n\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport type { DevtoolsServer } from './server';\nimport type { TraceData, SpanData } from './types';\n\nexport class DevtoolsSpanExporter implements SpanExporter {\n private server: DevtoolsServer;\n private serviceName: string;\n\n constructor(server: DevtoolsServer, serviceName: string = 'unknown-service') {\n this.server = server;\n this.serviceName = serviceName;\n }\n\n /**\n * Export spans to the WebSocket server\n */\n async export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): Promise<void> {\n // Immediately call the callback to unblock the span processor\n // Then process the spans asynchronously\n resultCallback({ code: 0 as ExportResultCode });\n\n // Process spans asynchronously without blocking\n Promise.resolve().then(() => {\n try {\n console.log(`[Autotel Exporter] Exporting ${spans.length} span(s)`);\n\n // Group spans by trace ID\n const traceMap = new Map<string, ReadableSpan[]>();\n\n for (const span of spans) {\n const traceId = span.spanContext().traceId;\n if (!traceMap.has(traceId)) {\n traceMap.set(traceId, []);\n }\n traceMap.get(traceId)!.push(span);\n }\n\n // Convert each trace and send to server\n for (const [traceId, traceSpans] of traceMap) {\n const trace = this.convertToTraceData(traceId, traceSpans);\n console.log(\n `[Autotel Exporter] Adding trace ${traceId.slice(0, 16)} with ${traceSpans.length} spans`,\n );\n this.server.addTrace(trace);\n }\n } catch (error) {\n console.error('[Autotel Exporter] Export error:', error);\n }\n });\n }\n\n /**\n * Shutdown the exporter\n */\n async shutdown(): Promise<void> {\n // Nothing to clean up\n }\n\n /**\n * Force flush any buffered spans\n */\n async forceFlush(): Promise<void> {\n // Nothing to flush\n }\n\n /**\n * Convert OpenTelemetry spans to TraceData\n */\n private convertToTraceData(\n traceId: string,\n spans: ReadableSpan[],\n ): TraceData {\n // Convert spans\n const spanData: SpanData[] = spans.map((span) => this.convertSpan(span));\n\n // Find root span (no parent)\n const rootSpan = spanData.find((s) => !s.parentSpanId) || spanData[0];\n\n // Sort spans by start time\n spanData.sort((a, b) => a.startTime - b.startTime);\n\n const startTime = Math.min(...spanData.map((s) => s.startTime));\n const endTime = Math.max(...spanData.map((s) => s.endTime));\n\n // Determine overall status (ERROR if any span errored)\n const hasError = spanData.some((s) => s.status.code === 'ERROR');\n const status = hasError ? 'ERROR' : 'OK';\n\n return {\n traceId,\n correlationId: traceId.slice(0, 16), // First 16 chars\n rootSpan,\n spans: spanData,\n startTime,\n endTime,\n duration: endTime - startTime,\n status: status as 'OK' | 'ERROR' | 'UNSET',\n service: this.serviceName,\n };\n }\n\n /**\n * Convert OpenTelemetry span to SpanData\n */\n private convertSpan(span: ReadableSpan): SpanData {\n const spanContext = span.spanContext();\n const startTime = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;\n const endTime = span.endTime[0] * 1000 + span.endTime[1] / 1_000_000;\n\n // Convert attributes\n const attributes: Record<string, any> = {};\n for (const [key, value] of Object.entries(span.attributes)) {\n attributes[key] = value;\n }\n\n // Convert status\n const statusCode = span.status.code;\n let status: 'OK' | 'ERROR' | 'UNSET';\n switch (statusCode) {\n case 0: {\n status = 'UNSET';\n break;\n }\n case 1: {\n status = 'OK';\n break;\n }\n case 2: {\n status = 'ERROR';\n break;\n }\n default: {\n status = 'UNSET';\n }\n }\n\n // Convert events\n const events = span.events.map((event) => ({\n name: event.name,\n timestamp: event.time[0] * 1000 + event.time[1] / 1_000_000,\n attributes: event.attributes\n ? Object.fromEntries(Object.entries(event.attributes))\n : undefined,\n }));\n\n // Convert links\n const links = span.links.map((link) => ({\n traceId: link.context.traceId,\n spanId: link.context.spanId,\n attributes: link.attributes\n ? Object.fromEntries(Object.entries(link.attributes))\n : undefined,\n }));\n\n return {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n parentSpanId: (span as any).parentSpanId,\n name: span.name,\n kind: this.convertSpanKind(span.kind),\n startTime,\n endTime,\n duration: endTime - startTime,\n attributes,\n status: {\n code: status,\n message: span.status.message,\n },\n events: events.length > 0 ? events : undefined,\n links: links.length > 0 ? links : undefined,\n scope: this.convertScope(span),\n };\n }\n\n private convertScope(span: ReadableSpan): SpanData['scope'] {\n const s =\n (span as any).instrumentationScope ??\n (span as any).instrumentationLibrary;\n return s?.name ? { name: s.name, version: s.version || undefined } : undefined;\n }\n\n /**\n * Convert OpenTelemetry SpanKind to string\n */\n private convertSpanKind(\n kind: number,\n ): 'INTERNAL' | 'SERVER' | 'CLIENT' | 'PRODUCER' | 'CONSUMER' {\n switch (kind) {\n case 0: {\n return 'INTERNAL';\n }\n case 1: {\n return 'SERVER';\n }\n case 2: {\n return 'CLIENT';\n }\n case 3: {\n return 'PRODUCER';\n }\n case 4: {\n return 'CONSUMER';\n }\n default: {\n return 'INTERNAL';\n }\n }\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
1
  import '@opentelemetry/sdk-trace-base';
2
2
  import '@opentelemetry/core';
3
- export { a as DevtoolsSpanExporter } from '../exporter-qIQPDw29.cjs';
3
+ export { a as DevtoolsSpanExporter } from '../exporter-DjLkU621.cjs';
4
4
  import 'node:http';
@@ -1,4 +1,4 @@
1
1
  import '@opentelemetry/sdk-trace-base';
2
2
  import '@opentelemetry/core';
3
- export { a as DevtoolsSpanExporter } from '../exporter-qIQPDw29.js';
3
+ export { a as DevtoolsSpanExporter } from '../exporter-DjLkU621.js';
4
4
  import 'node:http';
@@ -103,6 +103,11 @@ var DevtoolsSpanExporter = class {
103
103
  timestamp: event.time[0] * 1e3 + event.time[1] / 1e6,
104
104
  attributes: event.attributes ? Object.fromEntries(Object.entries(event.attributes)) : void 0
105
105
  }));
106
+ const links = span.links.map((link) => ({
107
+ traceId: link.context.traceId,
108
+ spanId: link.context.spanId,
109
+ attributes: link.attributes ? Object.fromEntries(Object.entries(link.attributes)) : void 0
110
+ }));
106
111
  return {
107
112
  traceId: spanContext.traceId,
108
113
  spanId: spanContext.spanId,
@@ -117,9 +122,15 @@ var DevtoolsSpanExporter = class {
117
122
  code: status,
118
123
  message: span.status.message
119
124
  },
120
- events: events.length > 0 ? events : void 0
125
+ events: events.length > 0 ? events : void 0,
126
+ links: links.length > 0 ? links : void 0,
127
+ scope: this.convertScope(span)
121
128
  };
122
129
  }
130
+ convertScope(span) {
131
+ const s = span.instrumentationScope ?? span.instrumentationLibrary;
132
+ return s?.name ? { name: s.name, version: s.version || void 0 } : void 0;
133
+ }
123
134
  /**
124
135
  * Convert OpenTelemetry SpanKind to string
125
136
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/exporter.ts"],"names":[],"mappings":"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","file":"exporter.js","sourcesContent":["/**\n * OpenTelemetry SpanExporter that streams spans to DevtoolsServer\n */\n\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport type { DevtoolsServer } from './server';\nimport type { TraceData, SpanData } from './types';\n\nexport class DevtoolsSpanExporter implements SpanExporter {\n private server: DevtoolsServer;\n private serviceName: string;\n\n constructor(server: DevtoolsServer, serviceName: string = 'unknown-service') {\n this.server = server;\n this.serviceName = serviceName;\n }\n\n /**\n * Export spans to the WebSocket server\n */\n async export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): Promise<void> {\n // Immediately call the callback to unblock the span processor\n // Then process the spans asynchronously\n resultCallback({ code: 0 as ExportResultCode });\n\n // Process spans asynchronously without blocking\n Promise.resolve().then(() => {\n try {\n console.log(`[Autotel Exporter] Exporting ${spans.length} span(s)`);\n\n // Group spans by trace ID\n const traceMap = new Map<string, ReadableSpan[]>();\n\n for (const span of spans) {\n const traceId = span.spanContext().traceId;\n if (!traceMap.has(traceId)) {\n traceMap.set(traceId, []);\n }\n traceMap.get(traceId)!.push(span);\n }\n\n // Convert each trace and send to server\n for (const [traceId, traceSpans] of traceMap) {\n const trace = this.convertToTraceData(traceId, traceSpans);\n console.log(\n `[Autotel Exporter] Adding trace ${traceId.slice(0, 16)} with ${traceSpans.length} spans`,\n );\n this.server.addTrace(trace);\n }\n } catch (error) {\n console.error('[Autotel Exporter] Export error:', error);\n }\n });\n }\n\n /**\n * Shutdown the exporter\n */\n async shutdown(): Promise<void> {\n // Nothing to clean up\n }\n\n /**\n * Force flush any buffered spans\n */\n async forceFlush(): Promise<void> {\n // Nothing to flush\n }\n\n /**\n * Convert OpenTelemetry spans to TraceData\n */\n private convertToTraceData(\n traceId: string,\n spans: ReadableSpan[],\n ): TraceData {\n // Convert spans\n const spanData: SpanData[] = spans.map((span) => this.convertSpan(span));\n\n // Find root span (no parent)\n const rootSpan = spanData.find((s) => !s.parentSpanId) || spanData[0];\n\n // Sort spans by start time\n spanData.sort((a, b) => a.startTime - b.startTime);\n\n const startTime = Math.min(...spanData.map((s) => s.startTime));\n const endTime = Math.max(...spanData.map((s) => s.endTime));\n\n // Determine overall status (ERROR if any span errored)\n const hasError = spanData.some((s) => s.status.code === 'ERROR');\n const status = hasError ? 'ERROR' : 'OK';\n\n return {\n traceId,\n correlationId: traceId.slice(0, 16), // First 16 chars\n rootSpan,\n spans: spanData,\n startTime,\n endTime,\n duration: endTime - startTime,\n status: status as 'OK' | 'ERROR' | 'UNSET',\n service: this.serviceName,\n };\n }\n\n /**\n * Convert OpenTelemetry span to SpanData\n */\n private convertSpan(span: ReadableSpan): SpanData {\n const spanContext = span.spanContext();\n const startTime = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;\n const endTime = span.endTime[0] * 1000 + span.endTime[1] / 1_000_000;\n\n // Convert attributes\n const attributes: Record<string, any> = {};\n for (const [key, value] of Object.entries(span.attributes)) {\n attributes[key] = value;\n }\n\n // Convert status\n const statusCode = span.status.code;\n let status: 'OK' | 'ERROR' | 'UNSET';\n switch (statusCode) {\n case 0: {\n status = 'UNSET';\n break;\n }\n case 1: {\n status = 'OK';\n break;\n }\n case 2: {\n status = 'ERROR';\n break;\n }\n default: {\n status = 'UNSET';\n }\n }\n\n // Convert events\n const events = span.events.map((event) => ({\n name: event.name,\n timestamp: event.time[0] * 1000 + event.time[1] / 1_000_000,\n attributes: event.attributes\n ? Object.fromEntries(Object.entries(event.attributes))\n : undefined,\n }));\n\n return {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n parentSpanId: (span as any).parentSpanId,\n name: span.name,\n kind: this.convertSpanKind(span.kind),\n startTime,\n endTime,\n duration: endTime - startTime,\n attributes,\n status: {\n code: status,\n message: span.status.message,\n },\n events: events.length > 0 ? events : undefined,\n };\n }\n\n /**\n * Convert OpenTelemetry SpanKind to string\n */\n private convertSpanKind(\n kind: number,\n ): 'INTERNAL' | 'SERVER' | 'CLIENT' | 'PRODUCER' | 'CONSUMER' {\n switch (kind) {\n case 0: {\n return 'INTERNAL';\n }\n case 1: {\n return 'SERVER';\n }\n case 2: {\n return 'CLIENT';\n }\n case 3: {\n return 'PRODUCER';\n }\n case 4: {\n return 'CONSUMER';\n }\n default: {\n return 'INTERNAL';\n }\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/server/exporter.ts"],"names":[],"mappings":"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","file":"exporter.js","sourcesContent":["/**\n * OpenTelemetry SpanExporter that streams spans to DevtoolsServer\n */\n\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport type { DevtoolsServer } from './server';\nimport type { TraceData, SpanData } from './types';\n\nexport class DevtoolsSpanExporter implements SpanExporter {\n private server: DevtoolsServer;\n private serviceName: string;\n\n constructor(server: DevtoolsServer, serviceName: string = 'unknown-service') {\n this.server = server;\n this.serviceName = serviceName;\n }\n\n /**\n * Export spans to the WebSocket server\n */\n async export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): Promise<void> {\n // Immediately call the callback to unblock the span processor\n // Then process the spans asynchronously\n resultCallback({ code: 0 as ExportResultCode });\n\n // Process spans asynchronously without blocking\n Promise.resolve().then(() => {\n try {\n console.log(`[Autotel Exporter] Exporting ${spans.length} span(s)`);\n\n // Group spans by trace ID\n const traceMap = new Map<string, ReadableSpan[]>();\n\n for (const span of spans) {\n const traceId = span.spanContext().traceId;\n if (!traceMap.has(traceId)) {\n traceMap.set(traceId, []);\n }\n traceMap.get(traceId)!.push(span);\n }\n\n // Convert each trace and send to server\n for (const [traceId, traceSpans] of traceMap) {\n const trace = this.convertToTraceData(traceId, traceSpans);\n console.log(\n `[Autotel Exporter] Adding trace ${traceId.slice(0, 16)} with ${traceSpans.length} spans`,\n );\n this.server.addTrace(trace);\n }\n } catch (error) {\n console.error('[Autotel Exporter] Export error:', error);\n }\n });\n }\n\n /**\n * Shutdown the exporter\n */\n async shutdown(): Promise<void> {\n // Nothing to clean up\n }\n\n /**\n * Force flush any buffered spans\n */\n async forceFlush(): Promise<void> {\n // Nothing to flush\n }\n\n /**\n * Convert OpenTelemetry spans to TraceData\n */\n private convertToTraceData(\n traceId: string,\n spans: ReadableSpan[],\n ): TraceData {\n // Convert spans\n const spanData: SpanData[] = spans.map((span) => this.convertSpan(span));\n\n // Find root span (no parent)\n const rootSpan = spanData.find((s) => !s.parentSpanId) || spanData[0];\n\n // Sort spans by start time\n spanData.sort((a, b) => a.startTime - b.startTime);\n\n const startTime = Math.min(...spanData.map((s) => s.startTime));\n const endTime = Math.max(...spanData.map((s) => s.endTime));\n\n // Determine overall status (ERROR if any span errored)\n const hasError = spanData.some((s) => s.status.code === 'ERROR');\n const status = hasError ? 'ERROR' : 'OK';\n\n return {\n traceId,\n correlationId: traceId.slice(0, 16), // First 16 chars\n rootSpan,\n spans: spanData,\n startTime,\n endTime,\n duration: endTime - startTime,\n status: status as 'OK' | 'ERROR' | 'UNSET',\n service: this.serviceName,\n };\n }\n\n /**\n * Convert OpenTelemetry span to SpanData\n */\n private convertSpan(span: ReadableSpan): SpanData {\n const spanContext = span.spanContext();\n const startTime = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;\n const endTime = span.endTime[0] * 1000 + span.endTime[1] / 1_000_000;\n\n // Convert attributes\n const attributes: Record<string, any> = {};\n for (const [key, value] of Object.entries(span.attributes)) {\n attributes[key] = value;\n }\n\n // Convert status\n const statusCode = span.status.code;\n let status: 'OK' | 'ERROR' | 'UNSET';\n switch (statusCode) {\n case 0: {\n status = 'UNSET';\n break;\n }\n case 1: {\n status = 'OK';\n break;\n }\n case 2: {\n status = 'ERROR';\n break;\n }\n default: {\n status = 'UNSET';\n }\n }\n\n // Convert events\n const events = span.events.map((event) => ({\n name: event.name,\n timestamp: event.time[0] * 1000 + event.time[1] / 1_000_000,\n attributes: event.attributes\n ? Object.fromEntries(Object.entries(event.attributes))\n : undefined,\n }));\n\n // Convert links\n const links = span.links.map((link) => ({\n traceId: link.context.traceId,\n spanId: link.context.spanId,\n attributes: link.attributes\n ? Object.fromEntries(Object.entries(link.attributes))\n : undefined,\n }));\n\n return {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n parentSpanId: (span as any).parentSpanId,\n name: span.name,\n kind: this.convertSpanKind(span.kind),\n startTime,\n endTime,\n duration: endTime - startTime,\n attributes,\n status: {\n code: status,\n message: span.status.message,\n },\n events: events.length > 0 ? events : undefined,\n links: links.length > 0 ? links : undefined,\n scope: this.convertScope(span),\n };\n }\n\n private convertScope(span: ReadableSpan): SpanData['scope'] {\n const s =\n (span as any).instrumentationScope ??\n (span as any).instrumentationLibrary;\n return s?.name ? { name: s.name, version: s.version || undefined } : undefined;\n }\n\n /**\n * Convert OpenTelemetry SpanKind to string\n */\n private convertSpanKind(\n kind: number,\n ): 'INTERNAL' | 'SERVER' | 'CLIENT' | 'PRODUCER' | 'CONSUMER' {\n switch (kind) {\n case 0: {\n return 'INTERNAL';\n }\n case 1: {\n return 'SERVER';\n }\n case 2: {\n return 'CLIENT';\n }\n case 3: {\n return 'PRODUCER';\n }\n case 4: {\n return 'CONSUMER';\n }\n default: {\n return 'INTERNAL';\n }\n }\n }\n}\n"]}
@@ -9,25 +9,9 @@ var url = require('url');
9
9
  var protobuf = require('protobufjs');
10
10
 
11
11
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
12
- function _interopNamespace(e) {
13
- if (e && e.__esModule) return e;
14
- var n = Object.create(null);
15
- if (e) {
16
- Object.keys(e).forEach(function (k) {
17
- if (k !== 'default') {
18
- var d = Object.getOwnPropertyDescriptor(e, k);
19
- Object.defineProperty(n, k, d.get ? d : {
20
- enumerable: true,
21
- get: function () { return e[k]; }
22
- });
23
- }
24
- });
25
- }
26
- n.default = e;
27
- return Object.freeze(n);
28
- }
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
29
13
 
30
- var protobuf__namespace = /*#__PURE__*/_interopNamespace(protobuf);
14
+ var protobuf__default = /*#__PURE__*/_interopDefault(protobuf);
31
15
 
32
16
  // src/server/server.ts
33
17
 
@@ -391,10 +375,12 @@ var DevtoolsServer = class {
391
375
  limits;
392
376
  verbose;
393
377
  _port;
378
+ onData;
394
379
  constructor(options = {}) {
395
380
  this.limits = resolveTelemetryLimits(options);
396
381
  this.verbose = options.verbose ?? false;
397
382
  this._port = options.port ?? 4318;
383
+ this.onData = options.onData;
398
384
  this.httpServer = options.server ?? http.createServer();
399
385
  this.wss = new ws.WebSocketServer({ server: this.httpServer, path: options.path ?? "/ws" });
400
386
  this.wss.on("connection", (ws) => {
@@ -488,6 +474,12 @@ var DevtoolsServer = class {
488
474
  client.send(msg);
489
475
  }
490
476
  }
477
+ if (this.onData) {
478
+ try {
479
+ this.onData(data);
480
+ } catch {
481
+ }
482
+ }
491
483
  }
492
484
  log(message) {
493
485
  if (this.verbose) console.log(`[autotel-devtools] ${message}`);
@@ -605,6 +597,11 @@ var DevtoolsSpanExporter = class {
605
597
  timestamp: event.time[0] * 1e3 + event.time[1] / 1e6,
606
598
  attributes: event.attributes ? Object.fromEntries(Object.entries(event.attributes)) : void 0
607
599
  }));
600
+ const links = span.links.map((link) => ({
601
+ traceId: link.context.traceId,
602
+ spanId: link.context.spanId,
603
+ attributes: link.attributes ? Object.fromEntries(Object.entries(link.attributes)) : void 0
604
+ }));
608
605
  return {
609
606
  traceId: spanContext.traceId,
610
607
  spanId: spanContext.spanId,
@@ -619,9 +616,15 @@ var DevtoolsSpanExporter = class {
619
616
  code: status,
620
617
  message: span.status.message
621
618
  },
622
- events: events.length > 0 ? events : void 0
619
+ events: events.length > 0 ? events : void 0,
620
+ links: links.length > 0 ? links : void 0,
621
+ scope: this.convertScope(span)
623
622
  };
624
623
  }
624
+ convertScope(span) {
625
+ const s = span.instrumentationScope ?? span.instrumentationLibrary;
626
+ return s?.name ? { name: s.name, version: s.version || void 0 } : void 0;
627
+ }
625
628
  /**
626
629
  * Convert OpenTelemetry SpanKind to string
627
630
  */
@@ -990,7 +993,10 @@ function flattenAttributes(attrs) {
990
993
  }
991
994
  function nanoToMs(nano) {
992
995
  if (!nano) return 0;
993
- return Number(BigInt(nano) / 1000000n);
996
+ const ns = BigInt(nano);
997
+ const ms = ns / 1000000n;
998
+ const remNs = ns % 1000000n;
999
+ return Number(ms) + Number(remNs) / 1e6;
994
1000
  }
995
1001
  var SPAN_KIND_MAP = {
996
1002
  0: "INTERNAL",
@@ -1028,6 +1034,7 @@ function parseOtlpTraces(payload) {
1028
1034
  const service = String(resourceAttrs["service.name"] || "unknown");
1029
1035
  const scopeSpans = rs.scopeSpans || [];
1030
1036
  for (const ss of scopeSpans) {
1037
+ const scope = ss.scope?.name ? { name: ss.scope.name, version: ss.scope.version || void 0 } : void 0;
1031
1038
  for (const span of ss.spans || []) {
1032
1039
  const traceId = normalizeHexId(span.traceId);
1033
1040
  if (!traceId) continue;
@@ -1052,7 +1059,13 @@ function parseOtlpTraces(payload) {
1052
1059
  name: e.name || "",
1053
1060
  timestamp: nanoToMs(e.timeUnixNano),
1054
1061
  attributes: flattenAttributes(e.attributes)
1055
- }))
1062
+ })),
1063
+ links: (span.links || []).map((l) => ({
1064
+ traceId: normalizeHexId(l.traceId),
1065
+ spanId: normalizeHexId(l.spanId),
1066
+ attributes: flattenAttributes(l.attributes)
1067
+ })),
1068
+ scope
1056
1069
  };
1057
1070
  const existing = traceMap.get(traceId);
1058
1071
  if (existing) {
@@ -1354,9 +1367,9 @@ var TO_OBJECT_OPTIONS = {
1354
1367
  var cachedRoot = null;
1355
1368
  function getRoot() {
1356
1369
  if (cachedRoot) return cachedRoot;
1357
- const root = new protobuf__namespace.Root();
1370
+ const root = new protobuf__default.default.Root();
1358
1371
  for (const source of [COMMON_PROTO, RESOURCE_PROTO, TRACE_PROTO, LOGS_PROTO, METRICS_PROTO]) {
1359
- protobuf__namespace.parse(source, root, { keepCase: false });
1372
+ protobuf__default.default.parse(source, root, { keepCase: false });
1360
1373
  }
1361
1374
  root.resolveAll();
1362
1375
  cachedRoot = root;