autotel-devtools 8.0.0 → 8.1.1
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 +37 -0
- package/dist/cli.cjs +76 -7
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +76 -7
- package/dist/cli.js.map +1 -1
- package/dist/{error-aggregator-CAk_pt3Z.d.ts → error-aggregator-D0Uu5r38.d.ts} +1 -1
- package/dist/{error-aggregator-CbLiuot4.d.cts → error-aggregator-D1Mr221Y.d.cts} +1 -1
- package/dist/{exporter-DjLkU621.d.cts → exporter-De6p4iAD.d.cts} +6 -0
- package/dist/{exporter-DjLkU621.d.ts → exporter-De6p4iAD.d.ts} +6 -0
- package/dist/genai/index.cjs +7 -2
- package/dist/genai/index.cjs.map +1 -1
- package/dist/genai/index.d.cts +6 -2
- package/dist/genai/index.d.ts +6 -2
- package/dist/genai/index.js +7 -2
- package/dist/genai/index.js.map +1 -1
- package/dist/index.cjs +76 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +76 -6
- package/dist/index.js.map +1 -1
- package/dist/server/exporter.d.cts +1 -1
- package/dist/server/exporter.d.ts +1 -1
- package/dist/server/index.cjs +76 -4
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +30 -5
- package/dist/server/index.d.ts +30 -5
- package/dist/server/index.js +73 -5
- package/dist/server/index.js.map +1 -1
- package/dist/widget.global.js +10 -9
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-
|
|
2
|
-
export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-
|
|
1
|
+
import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-De6p4iAD.cjs';
|
|
2
|
+
export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-De6p4iAD.cjs';
|
|
3
3
|
import { Server } from 'node:http';
|
|
4
4
|
export { DevtoolsLogExporter } from './server/log-exporter.cjs';
|
|
5
5
|
export { DevtoolsRemoteExporter } from './server/remote-exporter.cjs';
|
|
6
|
-
export { E as ErrorAggregator } from './error-aggregator-
|
|
6
|
+
export { E as ErrorAggregator } from './error-aggregator-D1Mr221Y.cjs';
|
|
7
7
|
import '@opentelemetry/sdk-trace-base';
|
|
8
8
|
import '@opentelemetry/core';
|
|
9
9
|
import '@opentelemetry/sdk-logs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-
|
|
2
|
-
export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-
|
|
1
|
+
import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-De6p4iAD.js';
|
|
2
|
+
export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-De6p4iAD.js';
|
|
3
3
|
import { Server } from 'node:http';
|
|
4
4
|
export { DevtoolsLogExporter } from './server/log-exporter.js';
|
|
5
5
|
export { DevtoolsRemoteExporter } from './server/remote-exporter.js';
|
|
6
|
-
export { E as ErrorAggregator } from './error-aggregator-
|
|
6
|
+
export { E as ErrorAggregator } from './error-aggregator-D0Uu5r38.js';
|
|
7
7
|
import '@opentelemetry/sdk-trace-base';
|
|
8
8
|
import '@opentelemetry/core';
|
|
9
9
|
import '@opentelemetry/sdk-logs';
|
package/dist/index.js
CHANGED
|
@@ -348,6 +348,40 @@ function appendManyWithLimit(items, incoming, limit) {
|
|
|
348
348
|
return next.length > limit ? next.slice(next.length - limit) : next;
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
+
// src/server/origin-guard.ts
|
|
352
|
+
var LOOPBACK_IPV6 = /* @__PURE__ */ new Set(["::1", "0:0:0:0:0:0:0:1"]);
|
|
353
|
+
function isLoopbackHostname(hostname) {
|
|
354
|
+
const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
355
|
+
return h === "localhost" || /^127\./.test(h) || LOOPBACK_IPV6.has(h);
|
|
356
|
+
}
|
|
357
|
+
function hostnameFromHostHeader(host) {
|
|
358
|
+
const h = host.trim();
|
|
359
|
+
if (h.startsWith("[")) {
|
|
360
|
+
const end = h.indexOf("]");
|
|
361
|
+
return end > 0 ? h.slice(1, end) : h;
|
|
362
|
+
}
|
|
363
|
+
const colon = h.indexOf(":");
|
|
364
|
+
return colon === -1 ? h : h.slice(0, colon);
|
|
365
|
+
}
|
|
366
|
+
function hostHeaderIsLoopback(host) {
|
|
367
|
+
return isLoopbackHostname(hostnameFromHostHeader(host));
|
|
368
|
+
}
|
|
369
|
+
function originIsLoopback(origin) {
|
|
370
|
+
try {
|
|
371
|
+
return isLoopbackHostname(new URL(origin).hostname);
|
|
372
|
+
} catch {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function allowSensitiveRequest(headers, loopbackOnly) {
|
|
377
|
+
const { origin, host } = headers;
|
|
378
|
+
if (origin && origin.length > 0 && !originIsLoopback(origin)) return false;
|
|
379
|
+
if (loopbackOnly && host && host.length > 0 && !hostHeaderIsLoopback(host)) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
|
|
351
385
|
// src/server/server.ts
|
|
352
386
|
var DevtoolsServer = class {
|
|
353
387
|
wss;
|
|
@@ -367,7 +401,12 @@ var DevtoolsServer = class {
|
|
|
367
401
|
this._port = options.port ?? 4318;
|
|
368
402
|
this.onData = options.onData;
|
|
369
403
|
this.httpServer = options.server ?? createServer();
|
|
370
|
-
|
|
404
|
+
const loopbackOnly = options.host == null || hostHeaderIsLoopback(options.host);
|
|
405
|
+
this.wss = new WebSocketServer({
|
|
406
|
+
server: this.httpServer,
|
|
407
|
+
path: options.path ?? "/ws",
|
|
408
|
+
verifyClient: ({ origin, req }) => allowSensitiveRequest({ origin, host: req.headers.host }, loopbackOnly)
|
|
409
|
+
});
|
|
371
410
|
this.wss.on("error", (err) => {
|
|
372
411
|
if (this.httpServer.listening) throw err;
|
|
373
412
|
});
|
|
@@ -401,6 +440,7 @@ var DevtoolsServer = class {
|
|
|
401
440
|
}
|
|
402
441
|
addTrace(trace) {
|
|
403
442
|
const existing = this.traces.find((t) => t.traceId === trace.traceId);
|
|
443
|
+
const merged = existing ?? trace;
|
|
404
444
|
if (existing) {
|
|
405
445
|
const existingSpanIds = new Set(existing.spans.map((s) => s.spanId));
|
|
406
446
|
for (const span of trace.spans) {
|
|
@@ -412,6 +452,14 @@ var DevtoolsServer = class {
|
|
|
412
452
|
existing.endTime = Math.max(existing.endTime, trace.endTime);
|
|
413
453
|
existing.duration = existing.endTime - existing.startTime;
|
|
414
454
|
if (trace.status === "ERROR") existing.status = "ERROR";
|
|
455
|
+
const root = existing.spans.find((s) => !s.parentSpanId);
|
|
456
|
+
if (root) {
|
|
457
|
+
existing.rootSpan = root;
|
|
458
|
+
const rootService = root.attributes?.["service.name"];
|
|
459
|
+
if (typeof rootService === "string" && rootService.length > 0) {
|
|
460
|
+
existing.service = rootService;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
415
463
|
} else {
|
|
416
464
|
this.traces = appendWithLimit(
|
|
417
465
|
this.traces,
|
|
@@ -420,7 +468,7 @@ var DevtoolsServer = class {
|
|
|
420
468
|
);
|
|
421
469
|
}
|
|
422
470
|
this.errorAggregator.addErrorsFromTrace(trace);
|
|
423
|
-
this.broadcast({ traces: [
|
|
471
|
+
this.broadcast({ traces: [merged], metrics: [], logs: [], errors: this.errorAggregator.getErrorGroups() });
|
|
424
472
|
}
|
|
425
473
|
addTraces(traces) {
|
|
426
474
|
for (const trace of traces) this.addTrace(trace);
|
|
@@ -951,7 +999,8 @@ function findPackageRoot() {
|
|
|
951
999
|
}
|
|
952
1000
|
return dir;
|
|
953
1001
|
}
|
|
954
|
-
var
|
|
1002
|
+
var DEVTOOLS_FAVICON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#0f172a"/><text x="32" y="41" text-anchor="middle" font-size="32">\u{1F6F0}\uFE0F</text></svg>';
|
|
1003
|
+
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><link rel="icon" href="/favicon.svg" type="image/svg+xml"><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>`;
|
|
955
1004
|
var cachedVersion = null;
|
|
956
1005
|
function getVersion() {
|
|
957
1006
|
if (cachedVersion !== null) return cachedVersion;
|
|
@@ -985,8 +1034,10 @@ function getWidgetJs() {
|
|
|
985
1034
|
}
|
|
986
1035
|
return cachedWidgetJs;
|
|
987
1036
|
}
|
|
988
|
-
function attachDevtoolsRoutes(httpServer, devtools) {
|
|
1037
|
+
function attachDevtoolsRoutes(httpServer, devtools, options = {}) {
|
|
1038
|
+
const loopbackOnly = options.loopbackOnly ?? true;
|
|
989
1039
|
httpServer.on("request", async (req, res) => {
|
|
1040
|
+
if (req.headers.upgrade?.toLowerCase() === "websocket") return;
|
|
990
1041
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
991
1042
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
992
1043
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
@@ -1009,6 +1060,15 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1009
1060
|
res.end(js);
|
|
1010
1061
|
return;
|
|
1011
1062
|
}
|
|
1063
|
+
if (req.method === "GET" && (url === "/favicon.svg" || url === "/favicon.ico")) {
|
|
1064
|
+
res.writeHead(200, {
|
|
1065
|
+
"Content-Type": "image/svg+xml; charset=utf-8",
|
|
1066
|
+
"Cache-Control": "public, max-age=86400",
|
|
1067
|
+
"Content-Length": Buffer.byteLength(DEVTOOLS_FAVICON_SVG)
|
|
1068
|
+
});
|
|
1069
|
+
res.end(DEVTOOLS_FAVICON_SVG);
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1012
1072
|
if (req.method === "GET" && url === "/healthz") {
|
|
1013
1073
|
sendJson(res, 200, {
|
|
1014
1074
|
ok: true,
|
|
@@ -1019,11 +1079,19 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
1019
1079
|
return;
|
|
1020
1080
|
}
|
|
1021
1081
|
if (req.method === "GET" && url === "/v1/traces") {
|
|
1082
|
+
if (!allowSensitiveRequest(req.headers, loopbackOnly)) {
|
|
1083
|
+
sendJson(res, 403, { error: "Forbidden" });
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1022
1086
|
const data = devtools.getCurrentData();
|
|
1023
1087
|
sendJson(res, 200, { traces: data.traces, count: data.traces.length });
|
|
1024
1088
|
return;
|
|
1025
1089
|
}
|
|
1026
1090
|
if (req.method === "DELETE" && url === "/v1/traces") {
|
|
1091
|
+
if (!allowSensitiveRequest(req.headers, loopbackOnly)) {
|
|
1092
|
+
sendJson(res, 403, { error: "Forbidden" });
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1027
1095
|
devtools.clearData();
|
|
1028
1096
|
sendJson(res, 200, { cleared: true });
|
|
1029
1097
|
return;
|
|
@@ -1610,21 +1678,23 @@ var DevtoolsRemoteExporter = class {
|
|
|
1610
1678
|
function createDevtools(options = {}) {
|
|
1611
1679
|
const port = options.port ?? 4318;
|
|
1612
1680
|
const host = options.host ?? "127.0.0.1";
|
|
1681
|
+
const loopbackOnly = hostHeaderIsLoopback(host);
|
|
1613
1682
|
const httpServer = createServer();
|
|
1614
1683
|
const wsServer = new DevtoolsServer({
|
|
1615
1684
|
server: httpServer,
|
|
1685
|
+
host,
|
|
1616
1686
|
verbose: options.verbose,
|
|
1617
1687
|
maxHistory: options.maxHistory,
|
|
1618
1688
|
maxTraceCount: options.maxTraceCount,
|
|
1619
1689
|
maxLogCount: options.maxLogCount,
|
|
1620
1690
|
maxMetricCount: options.maxMetricCount
|
|
1621
1691
|
});
|
|
1622
|
-
attachDevtoolsRoutes(httpServer, wsServer);
|
|
1692
|
+
attachDevtoolsRoutes(httpServer, wsServer, { loopbackOnly });
|
|
1623
1693
|
const listeners = listenLoopbackDualStack({
|
|
1624
1694
|
primary: httpServer,
|
|
1625
1695
|
port,
|
|
1626
1696
|
host,
|
|
1627
|
-
attachSecondary: (s) => attachDevtoolsRoutes(s, wsServer)
|
|
1697
|
+
attachSecondary: (s) => attachDevtoolsRoutes(s, wsServer, { loopbackOnly })
|
|
1628
1698
|
});
|
|
1629
1699
|
if (options.verbose) {
|
|
1630
1700
|
listeners.ready.then(({ warnings }) => {
|