autotel-devtools 6.0.1 → 6.1.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.
- package/README.md +19 -0
- package/dist/cli.cjs +66 -4
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +66 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +33 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +33 -4
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +56 -4
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +17 -1
- package/dist/server/index.d.ts +17 -1
- package/dist/server/index.js +55 -5
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.d.cts
CHANGED
|
@@ -24,6 +24,22 @@ declare function parseOtlpLogs(payload: unknown): LogData[];
|
|
|
24
24
|
*/
|
|
25
25
|
declare function isProtobufContentType(contentType?: string): boolean;
|
|
26
26
|
|
|
27
|
+
/** Value of the `x-autotel-devtools` response header and the /healthz `service` field. */
|
|
28
|
+
declare const DEVTOOLS_IDENTITY = "autotel-devtools";
|
|
29
|
+
/** Who is holding a TCP port, as far as we can tell over HTTP:
|
|
30
|
+
* - `autotel-devtools` — another instance of us (benign; the user has two running)
|
|
31
|
+
* - `foreign` — an HTTP server that is NOT us (e.g. an IDE's OTLP collector)
|
|
32
|
+
* - `none` — nothing answered HTTP (refused, timed out, or non-HTTP listener) */
|
|
33
|
+
type PortHolder = 'autotel-devtools' | 'foreign' | 'none';
|
|
34
|
+
/**
|
|
35
|
+
* Probe `host:port` over HTTP and classify what is listening. Used when our
|
|
36
|
+
* requested port is busy: it lets us tell "a stale autotel-devtools is still
|
|
37
|
+
* up" (benign) apart from "a foreign collector owns this port" — the latter is
|
|
38
|
+
* the silent footgun where apps keep exporting OTLP to the busy port and reach
|
|
39
|
+
* the wrong process, so the devtools UI stays empty and the app sees errors.
|
|
40
|
+
*/
|
|
41
|
+
declare function probePortHolder(host: string, port: number, timeoutMs?: number): Promise<PortHolder>;
|
|
42
|
+
|
|
27
43
|
/** Decode an OTLP/protobuf `ExportTraceServiceRequest` into the OTLP/JSON object shape. */
|
|
28
44
|
declare function decodeOtlpTraceRequest(body: Uint8Array): Record<string, unknown>;
|
|
29
45
|
/** Decode an OTLP/protobuf `ExportLogsServiceRequest` into the OTLP/JSON object shape. */
|
|
@@ -48,4 +64,4 @@ declare function appendWithLimit<T>(items: T[], item: T, limit: number): T[];
|
|
|
48
64
|
declare function appendManyWithLimit<T>(items: T[], incoming: T[], limit: number): T[];
|
|
49
65
|
declare function applyTelemetryLimits(data: DevtoolsData, limits: TelemetryLimits): DevtoolsData;
|
|
50
66
|
|
|
51
|
-
export { DevtoolsData, DevtoolsServer, type HttpServerOptions, LogData, type TelemetryLimits, TraceData, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, isProtobufContentType, parseOtlpLogs, parseOtlpTraces, resolveTelemetryLimits };
|
|
67
|
+
export { DEVTOOLS_IDENTITY, DevtoolsData, DevtoolsServer, type HttpServerOptions, LogData, type PortHolder, type TelemetryLimits, TraceData, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, isProtobufContentType, parseOtlpLogs, parseOtlpTraces, probePortHolder, resolveTelemetryLimits };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -24,6 +24,22 @@ declare function parseOtlpLogs(payload: unknown): LogData[];
|
|
|
24
24
|
*/
|
|
25
25
|
declare function isProtobufContentType(contentType?: string): boolean;
|
|
26
26
|
|
|
27
|
+
/** Value of the `x-autotel-devtools` response header and the /healthz `service` field. */
|
|
28
|
+
declare const DEVTOOLS_IDENTITY = "autotel-devtools";
|
|
29
|
+
/** Who is holding a TCP port, as far as we can tell over HTTP:
|
|
30
|
+
* - `autotel-devtools` — another instance of us (benign; the user has two running)
|
|
31
|
+
* - `foreign` — an HTTP server that is NOT us (e.g. an IDE's OTLP collector)
|
|
32
|
+
* - `none` — nothing answered HTTP (refused, timed out, or non-HTTP listener) */
|
|
33
|
+
type PortHolder = 'autotel-devtools' | 'foreign' | 'none';
|
|
34
|
+
/**
|
|
35
|
+
* Probe `host:port` over HTTP and classify what is listening. Used when our
|
|
36
|
+
* requested port is busy: it lets us tell "a stale autotel-devtools is still
|
|
37
|
+
* up" (benign) apart from "a foreign collector owns this port" — the latter is
|
|
38
|
+
* the silent footgun where apps keep exporting OTLP to the busy port and reach
|
|
39
|
+
* the wrong process, so the devtools UI stays empty and the app sees errors.
|
|
40
|
+
*/
|
|
41
|
+
declare function probePortHolder(host: string, port: number, timeoutMs?: number): Promise<PortHolder>;
|
|
42
|
+
|
|
27
43
|
/** Decode an OTLP/protobuf `ExportTraceServiceRequest` into the OTLP/JSON object shape. */
|
|
28
44
|
declare function decodeOtlpTraceRequest(body: Uint8Array): Record<string, unknown>;
|
|
29
45
|
/** Decode an OTLP/protobuf `ExportLogsServiceRequest` into the OTLP/JSON object shape. */
|
|
@@ -48,4 +64,4 @@ declare function appendWithLimit<T>(items: T[], item: T, limit: number): T[];
|
|
|
48
64
|
declare function appendManyWithLimit<T>(items: T[], incoming: T[], limit: number): T[];
|
|
49
65
|
declare function applyTelemetryLimits(data: DevtoolsData, limits: TelemetryLimits): DevtoolsData;
|
|
50
66
|
|
|
51
|
-
export { DevtoolsData, DevtoolsServer, type HttpServerOptions, LogData, type TelemetryLimits, TraceData, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, isProtobufContentType, parseOtlpLogs, parseOtlpTraces, resolveTelemetryLimits };
|
|
67
|
+
export { DEVTOOLS_IDENTITY, DevtoolsData, DevtoolsServer, type HttpServerOptions, LogData, type PortHolder, type TelemetryLimits, TraceData, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, isProtobufContentType, parseOtlpLogs, parseOtlpTraces, probePortHolder, resolveTelemetryLimits };
|
package/dist/server/index.js
CHANGED
|
@@ -1386,7 +1386,38 @@ function decodeOtlpMetricsRequest(body) {
|
|
|
1386
1386
|
return decodeRequest("opentelemetry.proto.metrics.v1.ExportMetricsServiceRequest", body);
|
|
1387
1387
|
}
|
|
1388
1388
|
|
|
1389
|
+
// src/server/identity.ts
|
|
1390
|
+
var DEVTOOLS_IDENTITY = "autotel-devtools";
|
|
1391
|
+
async function probePortHolder(host, port, timeoutMs = 500) {
|
|
1392
|
+
const authority = host.includes(":") ? `[${host}]` : host;
|
|
1393
|
+
const controller = new AbortController();
|
|
1394
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1395
|
+
try {
|
|
1396
|
+
const res = await fetch(`http://${authority}:${port}/healthz`, {
|
|
1397
|
+
signal: controller.signal
|
|
1398
|
+
});
|
|
1399
|
+
if (res.headers.get("x-autotel-devtools")) return "autotel-devtools";
|
|
1400
|
+
try {
|
|
1401
|
+
const body = await res.json();
|
|
1402
|
+
if (body && body.service === DEVTOOLS_IDENTITY) return "autotel-devtools";
|
|
1403
|
+
} catch {
|
|
1404
|
+
}
|
|
1405
|
+
return "foreign";
|
|
1406
|
+
} catch {
|
|
1407
|
+
return "none";
|
|
1408
|
+
} finally {
|
|
1409
|
+
clearTimeout(timer);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1389
1413
|
// src/server/http.ts
|
|
1414
|
+
function sendOtlpError(res, req, e) {
|
|
1415
|
+
sendJson(res, 400, {
|
|
1416
|
+
error: "Invalid OTLP payload",
|
|
1417
|
+
message: e instanceof Error ? e.message : String(e),
|
|
1418
|
+
contentType: req.headers["content-type"] ?? null
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1390
1421
|
var PROTOBUF_DECODERS = {
|
|
1391
1422
|
traces: decodeOtlpTraceRequest,
|
|
1392
1423
|
logs: decodeOtlpLogsRequest,
|
|
@@ -1407,6 +1438,18 @@ function findPackageRoot() {
|
|
|
1407
1438
|
return dir;
|
|
1408
1439
|
}
|
|
1409
1440
|
var FULLPAGE_HTML = `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>autotel-devtools</title><style>*{margin:0;padding:0;box-sizing:border-box}html,body{height:100%;width:100%;overflow:hidden}</style></head><body><script src="/widget.js?mode=fullpage"></script></body></html>`;
|
|
1441
|
+
var cachedVersion = null;
|
|
1442
|
+
function getVersion() {
|
|
1443
|
+
if (cachedVersion !== null) return cachedVersion;
|
|
1444
|
+
let version = "unknown";
|
|
1445
|
+
try {
|
|
1446
|
+
const pkg = JSON.parse(readFileSync(resolve(findPackageRoot(), "package.json"), "utf8"));
|
|
1447
|
+
if (typeof pkg.version === "string") version = pkg.version;
|
|
1448
|
+
} catch {
|
|
1449
|
+
}
|
|
1450
|
+
cachedVersion = version;
|
|
1451
|
+
return version;
|
|
1452
|
+
}
|
|
1410
1453
|
var cachedWidgetJs = null;
|
|
1411
1454
|
function getWidgetJs() {
|
|
1412
1455
|
if (!cachedWidgetJs) {
|
|
@@ -1433,6 +1476,8 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1433
1476
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1434
1477
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
1435
1478
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
1479
|
+
res.setHeader("x-autotel-devtools", getVersion());
|
|
1480
|
+
res.setHeader("Access-Control-Expose-Headers", "x-autotel-devtools");
|
|
1436
1481
|
if (req.method === "OPTIONS") {
|
|
1437
1482
|
res.writeHead(204);
|
|
1438
1483
|
res.end();
|
|
@@ -1451,7 +1496,12 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1451
1496
|
return;
|
|
1452
1497
|
}
|
|
1453
1498
|
if (req.method === "GET" && url === "/healthz") {
|
|
1454
|
-
sendJson(res, 200, {
|
|
1499
|
+
sendJson(res, 200, {
|
|
1500
|
+
ok: true,
|
|
1501
|
+
service: DEVTOOLS_IDENTITY,
|
|
1502
|
+
version: getVersion(),
|
|
1503
|
+
clients: devtools.clientCount
|
|
1504
|
+
});
|
|
1455
1505
|
return;
|
|
1456
1506
|
}
|
|
1457
1507
|
if (req.method === "GET" && url === "/v1/traces") {
|
|
@@ -1471,7 +1521,7 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1471
1521
|
devtools.addTraces(traces);
|
|
1472
1522
|
sendJson(res, 200, { acceptedTraces: traces.length });
|
|
1473
1523
|
} catch (e) {
|
|
1474
|
-
|
|
1524
|
+
sendOtlpError(res, req, e);
|
|
1475
1525
|
}
|
|
1476
1526
|
return;
|
|
1477
1527
|
}
|
|
@@ -1482,7 +1532,7 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1482
1532
|
devtools.addLogs(logs);
|
|
1483
1533
|
sendJson(res, 200, { acceptedLogs: logs.length });
|
|
1484
1534
|
} catch (e) {
|
|
1485
|
-
|
|
1535
|
+
sendOtlpError(res, req, e);
|
|
1486
1536
|
}
|
|
1487
1537
|
return;
|
|
1488
1538
|
}
|
|
@@ -1492,7 +1542,7 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1492
1542
|
const count = countOtlpMetrics(payload);
|
|
1493
1543
|
sendJson(res, 200, { acceptedMetrics: count });
|
|
1494
1544
|
} catch (e) {
|
|
1495
|
-
|
|
1545
|
+
sendOtlpError(res, req, e);
|
|
1496
1546
|
}
|
|
1497
1547
|
return;
|
|
1498
1548
|
}
|
|
@@ -1505,6 +1555,6 @@ function createDevtoolsHttpServer(devtools, _options = {}) {
|
|
|
1505
1555
|
return server;
|
|
1506
1556
|
}
|
|
1507
1557
|
|
|
1508
|
-
export { DevtoolsLogExporter, DevtoolsRemoteExporter, DevtoolsServer, DevtoolsSpanExporter, ErrorAggregator, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, isProtobufContentType, parseOtlpLogs, parseOtlpTraces, resolveTelemetryLimits };
|
|
1558
|
+
export { DEVTOOLS_IDENTITY, DevtoolsLogExporter, DevtoolsRemoteExporter, DevtoolsServer, DevtoolsSpanExporter, ErrorAggregator, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, isProtobufContentType, parseOtlpLogs, parseOtlpTraces, probePortHolder, resolveTelemetryLimits };
|
|
1509
1559
|
//# sourceMappingURL=index.js.map
|
|
1510
1560
|
//# sourceMappingURL=index.js.map
|