autotel-devtools 13.1.1 → 14.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.
Files changed (38) hide show
  1. package/README.md +24 -23
  2. package/dist/cli.cjs.map +1 -1
  3. package/dist/cli.d.cts +1 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/{error-aggregator-C8X-RQRi.d.ts → error-aggregator-BrgYNNoC.d.ts} +2 -3
  7. package/dist/{error-aggregator-7Q2H7htn.d.cts → error-aggregator-bZ-prq97.d.cts} +2 -3
  8. package/dist/{exporter-yqXiHw1Q.d.ts → exporter-BLqTs00O.d.ts} +1 -2
  9. package/dist/{exporter-kXTGDFoH.d.cts → exporter-BSIS3Qgy.d.cts} +1 -2
  10. package/dist/genai/index.cjs.map +1 -1
  11. package/dist/genai/index.d.cts +0 -1
  12. package/dist/genai/index.d.ts +0 -1
  13. package/dist/genai/index.js.map +1 -1
  14. package/dist/http-BUHnkhrC.cjs.map +1 -1
  15. package/dist/http-yIS667nX.js.map +1 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +2 -3
  18. package/dist/index.d.ts +2 -3
  19. package/dist/index.js.map +1 -1
  20. package/dist/listen-DGzVi7DE.cjs.map +1 -1
  21. package/dist/listen-NVMbBWHw.js.map +1 -1
  22. package/dist/resource-utils-B4UVvfnH.js.map +1 -1
  23. package/dist/resource-utils-DjHJB6uc.cjs.map +1 -1
  24. package/dist/server/exporter.cjs.map +1 -1
  25. package/dist/server/exporter.d.cts +1 -1
  26. package/dist/server/exporter.d.ts +1 -1
  27. package/dist/server/exporter.js.map +1 -1
  28. package/dist/server/index.d.cts +2 -3
  29. package/dist/server/index.d.ts +2 -3
  30. package/dist/server/log-exporter.cjs.map +1 -1
  31. package/dist/server/log-exporter.d.cts +0 -1
  32. package/dist/server/log-exporter.d.ts +0 -1
  33. package/dist/server/log-exporter.js.map +1 -1
  34. package/dist/server/remote-exporter.d.cts +0 -1
  35. package/dist/server/remote-exporter.d.ts +0 -1
  36. package/dist/widget.global.js +14 -13
  37. package/package.json +27 -27
  38. package/skills/autotel-devtools/SKILL.md +48 -46
@@ -1 +1 @@
1
- {"version":3,"file":"listen-NVMbBWHw.js","names":[],"sources":["../src/server/listen.ts"],"sourcesContent":["// src/server/listen.ts\nimport { createServer, type Server } from 'node:http'\n\nconst LOOPBACK = new Set(['localhost', '127.0.0.1', '::1'])\n\n/** How many consecutive ports to try before giving up. The default sweeps\n * 4318..4337 — a tight enough window that we don't accidentally squat on\n * something a sibling tool is using, but wide enough that the common case\n * (\"a previous devtools is still running\") succeeds. */\nconst DEFAULT_MAX_PORT_TRIES = 20\n\nexport interface LoopbackListeners {\n /** Resolves once the primary and (attempted) sibling listeners are up.\n * `port` is the port the primary actually bound to — it may differ from\n * the requested port when fallback was needed. */\n ready: Promise<{ addresses: string[]; port: number; warnings: string[] }>\n /** Close the sibling listener (the primary server is owned by the caller). */\n closeSibling: () => Promise<void>\n}\n\n/** Format host:port, bracketing IPv6 literals (e.g. `[::1]:4318`). */\nexport function formatAddress(host: string, port: number): string {\n return host.includes(':') ? `[${host}]:${port}` : `${host}:${port}`\n}\n\n/**\n * Listen on `host:port`, and when `host` is a loopback literal, ALSO listen on\n * the sibling loopback family (IPv4 ⟷ IPv6) so a client reaches the collector\n * whether the OS resolves `localhost` to `127.0.0.1` or `::1`.\n *\n * This kills a notoriously silent footgun: a dev-server proxy targeting\n * `http://localhost:PORT` on macOS resolves `localhost` to `::1`, but a\n * collector bound only to `127.0.0.1` never receives the request — spans\n * vanish with no error. Binding both loopback families makes `localhost` work\n * regardless of resolution order.\n *\n * If `port` is busy (EADDRINUSE), the listener walks forward up to `maxTries`\n * consecutive ports and binds the first one that's free. The resolved port\n * is returned in `ready` so callers can print correct URLs and OTLP\n * endpoints. Each fallback produces a warning.\n *\n * The sibling listener serves the same HTTP routes (via `attachSecondary`);\n * the WebSocket/UI stays on the primary address. If the sibling cannot bind\n * (e.g. no IPv6, or the port is taken on that family), it is reported as a\n * warning rather than a fatal error.\n */\nexport function listenLoopbackDualStack(args: {\n primary: Server\n port: number\n host: string\n attachSecondary: (server: Server) => void\n maxTries?: number\n}): LoopbackListeners {\n const { primary, port, host, attachSecondary, maxTries } = args\n const maxAttempts = Math.max(1, maxTries ?? DEFAULT_MAX_PORT_TRIES)\n let sibling: Server | undefined\n\n const ready = new Promise<{ addresses: string[]; port: number; warnings: string[] }>(\n (resolve, reject) => {\n const addresses: string[] = []\n const warnings: string[] = []\n // Normalise `localhost` to an explicit family so the primary bind is\n // deterministic and we know which sibling family to add.\n const primaryHost = host === 'localhost' ? '127.0.0.1' : host\n\n // The port currently being attempted, and how many we've burned so far.\n // One persistent handler pair owns the whole forward-walk; we just bump\n // `candidate` and re-`listen()` on the same server (the caller owns it\n // and has the WSS/routes attached, so we can't swap in a fresh one).\n let candidate = port\n let attempt = 0\n\n const bindFailed = (atPort: number, msg: string) =>\n reject(\n new Error(`could not bind ${formatAddress(primaryHost, atPort)}: ${msg}`),\n )\n\n // Walk forward from `port` until we find a free port. Anything that\n // isn't EADDRINUSE (EACCES, EAFNOSUPPORT, …) is fatal — it won't fix\n // itself on the next port.\n const onError = (e: NodeJS.ErrnoException) => {\n if (e.code !== 'EADDRINUSE') return bindFailed(candidate, e.message)\n if (++attempt >= maxAttempts) {\n reject(\n new Error(\n `could not bind ${formatAddress(primaryHost, port)}: ${maxAttempts} consecutive ports in use`,\n ),\n )\n return\n }\n candidate++\n listen()\n }\n\n const onListening = () => {\n // Bind succeeded — stop owning the primary's `error` event so a later\n // runtime error doesn't get mistaken for a bind failure.\n primary.removeListener('error', onError)\n if (candidate !== port) {\n warnings.push(`port ${port} was busy; using ${candidate} instead`)\n }\n const addr = primary.address()\n const resolvedPort =\n addr && typeof addr === 'object' ? addr.port : candidate\n addresses.push(formatAddress(primaryHost, resolvedPort))\n\n if (!LOOPBACK.has(host)) {\n resolve({ addresses, port: resolvedPort, warnings })\n return\n }\n\n const siblingHost = primaryHost === '::1' ? '127.0.0.1' : '::1'\n const s = createServer()\n attachSecondary(s)\n\n const onSiblingError = (se: Error) => {\n s.close()\n warnings.push(\n `could not also bind ${formatAddress(siblingHost, resolvedPort)} (${se.message}); ` +\n `clients using the ${siblingHost === '::1' ? 'IPv6' : 'IPv4'} form of \"localhost\" may not connect.`,\n )\n resolve({ addresses, port: resolvedPort, warnings })\n }\n s.once('error', onSiblingError)\n s.listen(resolvedPort, siblingHost, () => {\n s.off('error', onSiblingError)\n sibling = s\n addresses.push(formatAddress(siblingHost, resolvedPort))\n resolve({ addresses, port: resolvedPort, warnings })\n })\n }\n\n const listen = () => {\n try {\n primary.listen(candidate, primaryHost)\n } catch (e) {\n // `candidate` can overflow 65535 when the top port is busy; Node\n // throws a RangeError synchronously instead of emitting 'error'.\n primary.removeListener('error', onError)\n primary.removeListener('listening', onListening)\n bindFailed(candidate, (e as Error).message)\n }\n }\n\n primary.on('error', onError)\n primary.once('listening', onListening)\n listen()\n },\n )\n\n return {\n ready,\n closeSibling: () =>\n new Promise<void>((res) => {\n if (!sibling) return res()\n sibling.close(() => res())\n }),\n }\n}\n"],"mappings":";;;AAGA,MAAM,2BAAW,IAAI,IAAI;CAAC;CAAa;CAAa;AAAK,CAAC;;;;;AAM1D,MAAM,yBAAyB;;AAY/B,SAAgB,cAAc,MAAc,MAAsB;CAChE,OAAO,KAAK,SAAS,GAAG,IAAI,IAAI,KAAK,IAAI,SAAS,GAAG,KAAK,GAAG;AAC/D;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,wBAAwB,MAMlB;CACpB,MAAM,EAAE,SAAS,MAAM,MAAM,iBAAiB,aAAa;CAC3D,MAAM,cAAc,KAAK,IAAI,GAAG,YAAY,sBAAsB;CAClE,IAAI;CA+FJ,OAAO;EACL,WA9FgB,SACf,SAAS,WAAW;GACnB,MAAM,YAAsB,CAAC;GAC7B,MAAM,WAAqB,CAAC;GAG5B,MAAM,cAAc,SAAS,cAAc,cAAc;GAMzD,IAAI,YAAY;GAChB,IAAI,UAAU;GAEd,MAAM,cAAc,QAAgB,QAClC,uBACE,IAAI,MAAM,kBAAkB,cAAc,aAAa,MAAM,EAAE,IAAI,KAAK,CAC1E;GAKF,MAAM,WAAW,MAA6B;IAC5C,IAAI,EAAE,SAAS,cAAc,OAAO,WAAW,WAAW,EAAE,OAAO;IACnE,IAAI,EAAE,WAAW,aAAa;KAC5B,uBACE,IAAI,MACF,kBAAkB,cAAc,aAAa,IAAI,EAAE,IAAI,YAAY,0BACrE,CACF;KACA;IACF;IACA;IACA,OAAO;GACT;GAEA,MAAM,oBAAoB;IAGxB,QAAQ,eAAe,SAAS,OAAO;IACvC,IAAI,cAAc,MAChB,SAAS,KAAK,QAAQ,KAAK,mBAAmB,UAAU,SAAS;IAEnE,MAAM,OAAO,QAAQ,QAAQ;IAC7B,MAAM,eACJ,QAAQ,OAAO,SAAS,WAAW,KAAK,OAAO;IACjD,UAAU,KAAK,cAAc,aAAa,YAAY,CAAC;IAEvD,IAAI,CAAC,SAAS,IAAI,IAAI,GAAG;KACvB,QAAQ;MAAE;MAAW,MAAM;MAAc;KAAS,CAAC;KACnD;IACF;IAEA,MAAM,cAAc,gBAAgB,QAAQ,cAAc;IAC1D,MAAM,IAAI,aAAa;IACvB,gBAAgB,CAAC;IAEjB,MAAM,kBAAkB,OAAc;KACpC,EAAE,MAAM;KACR,SAAS,KACP,uBAAuB,cAAc,aAAa,YAAY,EAAE,IAAI,GAAG,QAAQ,uBACxD,gBAAgB,QAAQ,SAAS,OAAO,sCACjE;KACA,QAAQ;MAAE;MAAW,MAAM;MAAc;KAAS,CAAC;IACrD;IACA,EAAE,KAAK,SAAS,cAAc;IAC9B,EAAE,OAAO,cAAc,mBAAmB;KACxC,EAAE,IAAI,SAAS,cAAc;KAC7B,UAAU;KACV,UAAU,KAAK,cAAc,aAAa,YAAY,CAAC;KACvD,QAAQ;MAAE;MAAW,MAAM;MAAc;KAAS,CAAC;IACrD,CAAC;GACH;GAEA,MAAM,eAAe;IACnB,IAAI;KACF,QAAQ,OAAO,WAAW,WAAW;IACvC,SAAS,GAAG;KAGV,QAAQ,eAAe,SAAS,OAAO;KACvC,QAAQ,eAAe,aAAa,WAAW;KAC/C,WAAW,WAAY,EAAY,OAAO;IAC5C;GACF;GAEA,QAAQ,GAAG,SAAS,OAAO;GAC3B,QAAQ,KAAK,aAAa,WAAW;GACrC,OAAO;EACT,CAII;EACJ,oBACE,IAAI,SAAe,QAAQ;GACzB,IAAI,CAAC,SAAS,OAAO,IAAI;GACzB,QAAQ,YAAY,IAAI,CAAC;EAC3B,CAAC;CACL;AACF"}
1
+ {"version":3,"file":"listen-NVMbBWHw.js","names":[],"sources":["../src/server/listen.ts"],"sourcesContent":["// src/server/listen.ts\nimport { createServer, type Server } from 'node:http';\n\nconst LOOPBACK = new Set(['localhost', '127.0.0.1', '::1']);\n\n/** How many consecutive ports to try before giving up. The default sweeps\n * 4318..4337 — a tight enough window that we don't accidentally squat on\n * something a sibling tool is using, but wide enough that the common case\n * (\"a previous devtools is still running\") succeeds. */\nconst DEFAULT_MAX_PORT_TRIES = 20;\n\nexport interface LoopbackListeners {\n /** Resolves once the primary and (attempted) sibling listeners are up.\n * `port` is the port the primary actually bound to — it may differ from\n * the requested port when fallback was needed. */\n ready: Promise<{ addresses: string[]; port: number; warnings: string[] }>;\n /** Close the sibling listener (the primary server is owned by the caller). */\n closeSibling: () => Promise<void>;\n}\n\n/** Format host:port, bracketing IPv6 literals (e.g. `[::1]:4318`). */\nexport function formatAddress(host: string, port: number): string {\n return host.includes(':') ? `[${host}]:${port}` : `${host}:${port}`;\n}\n\n/**\n * Listen on `host:port`, and when `host` is a loopback literal, ALSO listen on\n * the sibling loopback family (IPv4 ⟷ IPv6) so a client reaches the collector\n * whether the OS resolves `localhost` to `127.0.0.1` or `::1`.\n *\n * This kills a notoriously silent footgun: a dev-server proxy targeting\n * `http://localhost:PORT` on macOS resolves `localhost` to `::1`, but a\n * collector bound only to `127.0.0.1` never receives the request — spans\n * vanish with no error. Binding both loopback families makes `localhost` work\n * regardless of resolution order.\n *\n * If `port` is busy (EADDRINUSE), the listener walks forward up to `maxTries`\n * consecutive ports and binds the first one that's free. The resolved port\n * is returned in `ready` so callers can print correct URLs and OTLP\n * endpoints. Each fallback produces a warning.\n *\n * The sibling listener serves the same HTTP routes (via `attachSecondary`);\n * the WebSocket/UI stays on the primary address. If the sibling cannot bind\n * (e.g. no IPv6, or the port is taken on that family), it is reported as a\n * warning rather than a fatal error.\n */\nexport function listenLoopbackDualStack(args: {\n primary: Server;\n port: number;\n host: string;\n attachSecondary: (server: Server) => void;\n maxTries?: number;\n}): LoopbackListeners {\n const { primary, port, host, attachSecondary, maxTries } = args;\n const maxAttempts = Math.max(1, maxTries ?? DEFAULT_MAX_PORT_TRIES);\n let sibling: Server | undefined;\n\n const ready = new Promise<{\n addresses: string[];\n port: number;\n warnings: string[];\n }>((resolve, reject) => {\n const addresses: string[] = [];\n const warnings: string[] = [];\n // Normalise `localhost` to an explicit family so the primary bind is\n // deterministic and we know which sibling family to add.\n const primaryHost = host === 'localhost' ? '127.0.0.1' : host;\n\n // The port currently being attempted, and how many we've burned so far.\n // One persistent handler pair owns the whole forward-walk; we just bump\n // `candidate` and re-`listen()` on the same server (the caller owns it\n // and has the WSS/routes attached, so we can't swap in a fresh one).\n let candidate = port;\n let attempt = 0;\n\n const bindFailed = (atPort: number, msg: string) =>\n reject(\n new Error(\n `could not bind ${formatAddress(primaryHost, atPort)}: ${msg}`,\n ),\n );\n\n // Walk forward from `port` until we find a free port. Anything that\n // isn't EADDRINUSE (EACCES, EAFNOSUPPORT, …) is fatal — it won't fix\n // itself on the next port.\n const onError = (e: NodeJS.ErrnoException) => {\n if (e.code !== 'EADDRINUSE') return bindFailed(candidate, e.message);\n if (++attempt >= maxAttempts) {\n reject(\n new Error(\n `could not bind ${formatAddress(primaryHost, port)}: ${maxAttempts} consecutive ports in use`,\n ),\n );\n return;\n }\n candidate++;\n listen();\n };\n\n const onListening = () => {\n // Bind succeeded — stop owning the primary's `error` event so a later\n // runtime error doesn't get mistaken for a bind failure.\n primary.removeListener('error', onError);\n if (candidate !== port) {\n warnings.push(`port ${port} was busy; using ${candidate} instead`);\n }\n const addr = primary.address();\n const resolvedPort =\n addr && typeof addr === 'object' ? addr.port : candidate;\n addresses.push(formatAddress(primaryHost, resolvedPort));\n\n if (!LOOPBACK.has(host)) {\n resolve({ addresses, port: resolvedPort, warnings });\n return;\n }\n\n const siblingHost = primaryHost === '::1' ? '127.0.0.1' : '::1';\n const s = createServer();\n attachSecondary(s);\n\n const onSiblingError = (se: Error) => {\n s.close();\n warnings.push(\n `could not also bind ${formatAddress(siblingHost, resolvedPort)} (${se.message}); ` +\n `clients using the ${siblingHost === '::1' ? 'IPv6' : 'IPv4'} form of \"localhost\" may not connect.`,\n );\n resolve({ addresses, port: resolvedPort, warnings });\n };\n s.once('error', onSiblingError);\n s.listen(resolvedPort, siblingHost, () => {\n s.off('error', onSiblingError);\n sibling = s;\n addresses.push(formatAddress(siblingHost, resolvedPort));\n resolve({ addresses, port: resolvedPort, warnings });\n });\n };\n\n const listen = () => {\n try {\n primary.listen(candidate, primaryHost);\n } catch (e) {\n // `candidate` can overflow 65535 when the top port is busy; Node\n // throws a RangeError synchronously instead of emitting 'error'.\n primary.removeListener('error', onError);\n primary.removeListener('listening', onListening);\n bindFailed(candidate, (e as Error).message);\n }\n };\n\n primary.on('error', onError);\n primary.once('listening', onListening);\n listen();\n });\n\n return {\n ready,\n closeSibling: () =>\n new Promise<void>((res) => {\n if (!sibling) return res();\n sibling.close(() => res());\n }),\n };\n}\n"],"mappings":";;;AAGA,MAAM,2BAAW,IAAI,IAAI;CAAC;CAAa;CAAa;AAAK,CAAC;;;;;AAM1D,MAAM,yBAAyB;;AAY/B,SAAgB,cAAc,MAAc,MAAsB;CAChE,OAAO,KAAK,SAAS,GAAG,IAAI,IAAI,KAAK,IAAI,SAAS,GAAG,KAAK,GAAG;AAC/D;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,wBAAwB,MAMlB;CACpB,MAAM,EAAE,SAAS,MAAM,MAAM,iBAAiB,aAAa;CAC3D,MAAM,cAAc,KAAK,IAAI,GAAG,YAAY,sBAAsB;CAClE,IAAI;CAmGJ,OAAO;EACL,WAlGgB,SAId,SAAS,WAAW;GACtB,MAAM,YAAsB,CAAC;GAC7B,MAAM,WAAqB,CAAC;GAG5B,MAAM,cAAc,SAAS,cAAc,cAAc;GAMzD,IAAI,YAAY;GAChB,IAAI,UAAU;GAEd,MAAM,cAAc,QAAgB,QAClC,uBACE,IAAI,MACF,kBAAkB,cAAc,aAAa,MAAM,EAAE,IAAI,KAC3D,CACF;GAKF,MAAM,WAAW,MAA6B;IAC5C,IAAI,EAAE,SAAS,cAAc,OAAO,WAAW,WAAW,EAAE,OAAO;IACnE,IAAI,EAAE,WAAW,aAAa;KAC5B,uBACE,IAAI,MACF,kBAAkB,cAAc,aAAa,IAAI,EAAE,IAAI,YAAY,0BACrE,CACF;KACA;IACF;IACA;IACA,OAAO;GACT;GAEA,MAAM,oBAAoB;IAGxB,QAAQ,eAAe,SAAS,OAAO;IACvC,IAAI,cAAc,MAChB,SAAS,KAAK,QAAQ,KAAK,mBAAmB,UAAU,SAAS;IAEnE,MAAM,OAAO,QAAQ,QAAQ;IAC7B,MAAM,eACJ,QAAQ,OAAO,SAAS,WAAW,KAAK,OAAO;IACjD,UAAU,KAAK,cAAc,aAAa,YAAY,CAAC;IAEvD,IAAI,CAAC,SAAS,IAAI,IAAI,GAAG;KACvB,QAAQ;MAAE;MAAW,MAAM;MAAc;KAAS,CAAC;KACnD;IACF;IAEA,MAAM,cAAc,gBAAgB,QAAQ,cAAc;IAC1D,MAAM,IAAI,aAAa;IACvB,gBAAgB,CAAC;IAEjB,MAAM,kBAAkB,OAAc;KACpC,EAAE,MAAM;KACR,SAAS,KACP,uBAAuB,cAAc,aAAa,YAAY,EAAE,IAAI,GAAG,QAAQ,uBACxD,gBAAgB,QAAQ,SAAS,OAAO,sCACjE;KACA,QAAQ;MAAE;MAAW,MAAM;MAAc;KAAS,CAAC;IACrD;IACA,EAAE,KAAK,SAAS,cAAc;IAC9B,EAAE,OAAO,cAAc,mBAAmB;KACxC,EAAE,IAAI,SAAS,cAAc;KAC7B,UAAU;KACV,UAAU,KAAK,cAAc,aAAa,YAAY,CAAC;KACvD,QAAQ;MAAE;MAAW,MAAM;MAAc;KAAS,CAAC;IACrD,CAAC;GACH;GAEA,MAAM,eAAe;IACnB,IAAI;KACF,QAAQ,OAAO,WAAW,WAAW;IACvC,SAAS,GAAG;KAGV,QAAQ,eAAe,SAAS,OAAO;KACvC,QAAQ,eAAe,aAAa,WAAW;KAC/C,WAAW,WAAY,EAAY,OAAO;IAC5C;GACF;GAEA,QAAQ,GAAG,SAAS,OAAO;GAC3B,QAAQ,KAAK,aAAa,WAAW;GACrC,OAAO;EACT,CAGM;EACJ,oBACE,IAAI,SAAe,QAAQ;GACzB,IAAI,CAAC,SAAS,OAAO,IAAI;GACzB,QAAQ,YAAY,IAAI,CAAC;EAC3B,CAAC;CACL;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"resource-utils-B4UVvfnH.js","names":[],"sources":["../src/server/resource-utils.ts"],"sourcesContent":["export function getResourceName(\n resource: Record<string, unknown> | undefined,\n fallback = 'unknown',\n): string {\n if (!resource) return fallback\n\n const candidates = [\n resource['service.name'],\n resource['service.namespace'],\n resource['deployment.environment.name'],\n resource['host.name'],\n resource['container.name'],\n resource['process.executable.name'],\n ]\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate\n }\n }\n\n return fallback\n}\n"],"mappings":";AAAA,SAAgB,gBACd,UACA,WAAW,WACH;CACR,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,aAAa;EACjB,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;CACX;CAEA,KAAK,MAAM,aAAa,YACtB,IAAI,OAAO,cAAc,YAAY,UAAU,KAAK,CAAC,CAAC,SAAS,GAC7D,OAAO;CAIX,OAAO;AACT"}
1
+ {"version":3,"file":"resource-utils-B4UVvfnH.js","names":[],"sources":["../src/server/resource-utils.ts"],"sourcesContent":["export function getResourceName(\n resource: Record<string, unknown> | undefined,\n fallback = 'unknown',\n): string {\n if (!resource) return fallback;\n\n const candidates = [\n resource['service.name'],\n resource['service.namespace'],\n resource['deployment.environment.name'],\n resource['host.name'],\n resource['container.name'],\n resource['process.executable.name'],\n ];\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate;\n }\n }\n\n return fallback;\n}\n"],"mappings":";AAAA,SAAgB,gBACd,UACA,WAAW,WACH;CACR,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,aAAa;EACjB,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;CACX;CAEA,KAAK,MAAM,aAAa,YACtB,IAAI,OAAO,cAAc,YAAY,UAAU,KAAK,CAAC,CAAC,SAAS,GAC7D,OAAO;CAIX,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"resource-utils-DjHJB6uc.cjs","names":[],"sources":["../src/server/resource-utils.ts"],"sourcesContent":["export function getResourceName(\n resource: Record<string, unknown> | undefined,\n fallback = 'unknown',\n): string {\n if (!resource) return fallback\n\n const candidates = [\n resource['service.name'],\n resource['service.namespace'],\n resource['deployment.environment.name'],\n resource['host.name'],\n resource['container.name'],\n resource['process.executable.name'],\n ]\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate\n }\n }\n\n return fallback\n}\n"],"mappings":";;AAAA,SAAgB,gBACd,UACA,WAAW,WACH;CACR,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,aAAa;EACjB,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;CACX;CAEA,KAAK,MAAM,aAAa,YACtB,IAAI,OAAO,cAAc,YAAY,UAAU,KAAK,CAAC,CAAC,SAAS,GAC7D,OAAO;CAIX,OAAO;AACT"}
1
+ {"version":3,"file":"resource-utils-DjHJB6uc.cjs","names":[],"sources":["../src/server/resource-utils.ts"],"sourcesContent":["export function getResourceName(\n resource: Record<string, unknown> | undefined,\n fallback = 'unknown',\n): string {\n if (!resource) return fallback;\n\n const candidates = [\n resource['service.name'],\n resource['service.namespace'],\n resource['deployment.environment.name'],\n resource['host.name'],\n resource['container.name'],\n resource['process.executable.name'],\n ];\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate;\n }\n }\n\n return fallback;\n}\n"],"mappings":";;AAAA,SAAgB,gBACd,UACA,WAAW,WACH;CACR,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,aAAa;EACjB,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;CACX;CAEA,KAAK,MAAM,aAAa,YACtB,IAAI,OAAO,cAAc,YAAY,UAAU,KAAK,CAAC,CAAC,SAAS,GAC7D,OAAO;CAIX,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"exporter.cjs","names":[],"sources":["../../src/server/exporter.ts"],"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"],"mappings":"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"}
1
+ {"version":3,"file":"exporter.cjs","names":[],"sources":["../../src/server/exporter.ts"],"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\n ? { name: s.name, version: s.version || undefined }\n : 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"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { t as DevtoolsSpanExporter } from "../exporter-kXTGDFoH.cjs";
1
+ import { t as DevtoolsSpanExporter } from "../exporter-BSIS3Qgy.cjs";
2
2
  export { DevtoolsSpanExporter };
@@ -1,2 +1,2 @@
1
- import { t as DevtoolsSpanExporter } from "../exporter-yqXiHw1Q.js";
1
+ import { t as DevtoolsSpanExporter } from "../exporter-BLqTs00O.js";
2
2
  export { DevtoolsSpanExporter };
@@ -1 +1 @@
1
- {"version":3,"file":"exporter.js","names":[],"sources":["../../src/server/exporter.ts"],"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"],"mappings":"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"}
1
+ {"version":3,"file":"exporter.js","names":[],"sources":["../../src/server/exporter.ts"],"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\n ? { name: s.name, version: s.version || undefined }\n : 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"],"mappings":"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"}
@@ -1,10 +1,9 @@
1
- import { a as ErrorGroup, c as MetricData, i as DevtoolsData, l as SpanData, n as DevtoolsServer, o as ErrorOccurrence, r as DevtoolsServerOptions, s as LogData, t as DevtoolsSpanExporter, u as TraceData } from "../exporter-kXTGDFoH.cjs";
1
+ import { a as ErrorGroup, c as MetricData, i as DevtoolsData, l as SpanData, n as DevtoolsServer, o as ErrorOccurrence, r as DevtoolsServerOptions, s as LogData, t as DevtoolsSpanExporter, u as TraceData } from "../exporter-BSIS3Qgy.cjs";
2
2
  import { DevtoolsLogExporter } from "./log-exporter.cjs";
3
3
  import { DevtoolsRemoteExporter, DevtoolsRemoteExporterOptions } from "./remote-exporter.cjs";
4
- import { t as ErrorAggregator } from "../error-aggregator-7Q2H7htn.cjs";
4
+ import { t as ErrorAggregator } from "../error-aggregator-bZ-prq97.cjs";
5
5
  import { Server } from "node:http";
6
6
  import { AgentRawEvent, OtelMetricRecord } from "autotel-agents";
7
-
8
7
  //#region src/server/http.d.ts
9
8
  interface HttpServerOptions {
10
9
  port?: number;
@@ -1,10 +1,9 @@
1
- import { a as ErrorGroup, c as MetricData, i as DevtoolsData, l as SpanData, n as DevtoolsServer, o as ErrorOccurrence, r as DevtoolsServerOptions, s as LogData, t as DevtoolsSpanExporter, u as TraceData } from "../exporter-yqXiHw1Q.js";
1
+ import { a as ErrorGroup, c as MetricData, i as DevtoolsData, l as SpanData, n as DevtoolsServer, o as ErrorOccurrence, r as DevtoolsServerOptions, s as LogData, t as DevtoolsSpanExporter, u as TraceData } from "../exporter-BLqTs00O.js";
2
2
  import { DevtoolsLogExporter } from "./log-exporter.js";
3
3
  import { DevtoolsRemoteExporter, DevtoolsRemoteExporterOptions } from "./remote-exporter.js";
4
- import { t as ErrorAggregator } from "../error-aggregator-C8X-RQRi.js";
4
+ import { t as ErrorAggregator } from "../error-aggregator-BrgYNNoC.js";
5
5
  import { Server } from "node:http";
6
6
  import { AgentRawEvent, OtelMetricRecord } from "autotel-agents";
7
-
8
7
  //#region src/server/http.d.ts
9
8
  interface HttpServerOptions {
10
9
  port?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"log-exporter.cjs","names":["getResourceName","ExportResultCode"],"sources":["../../src/server/log-exporter.ts"],"sourcesContent":["/**\n * Log record exporter that sends OTel logs to a Devtools server HTTP ingest.\n * Use with BatchLogRecordProcessor when you want to view logs in the Autotel widget/extension.\n *\n * @example\n * ```typescript\n * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\n * import { DevtoolsLogExporter } from '@autotel/devtools/server';\n * import { init } from 'autotel';\n *\n * init({\n * service: 'my-app',\n * logRecordProcessors: [\n * new BatchLogRecordProcessor(\n * new DevtoolsLogExporter({ endpoint: 'http://localhost:8082' })\n * ),\n * ],\n * });\n * ```\n */\n\nimport type { ExportResult } from '@opentelemetry/core';\nimport { ExportResultCode } from '@opentelemetry/core';\nimport type { LogRecordExporter } from '@opentelemetry/sdk-logs';\nimport type { ReadableLogRecord } from '@opentelemetry/sdk-logs';\nimport type { LogData } from './types';\nimport { getResourceName } from './resource-utils';\n\nexport interface DevtoolsLogExporterOptions {\n /**\n * Base URL of the Devtools HTTP ingest server\n * e.g. 'http://localhost:8082'\n */\n endpoint: string;\n\n /**\n * API key for authentication (if server requires it)\n */\n apiKey?: string;\n\n /**\n * Request timeout in milliseconds (default: 5000)\n */\n timeout?: number;\n}\n\nconst defaultTimeout = 5000;\n\nfunction hrTimeToMs(hrTime: [number, number]): number {\n return hrTime[0] * 1000 + hrTime[1] / 1e6;\n}\n\nfunction bodyToPayload(body: ReadableLogRecord['body']): string | Record<string, unknown> {\n if (body === undefined) return '';\n if (typeof body === 'string') return body;\n if (typeof body === 'object' && body !== null) return body as Record<string, unknown>;\n return String(body);\n}\n\nfunction recordToLogData(record: ReadableLogRecord, index: number): LogData {\n const id = `log-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 9)}`;\n const timestamp = hrTimeToMs(record.hrTime);\n const body = bodyToPayload(record.body);\n const attributes = record.attributes && Object.keys(record.attributes).length > 0\n ? (record.attributes as Record<string, unknown>)\n : undefined;\n const resource = record.resource?.attributes && Object.keys(record.resource.attributes).length > 0\n ? (record.resource.attributes as Record<string, unknown>)\n : undefined;\n\n const log: LogData = {\n id,\n resourceName: getResourceName(resource),\n severityText: record.severityText,\n severityNumber: record.severityNumber,\n body,\n timestamp,\n attributes,\n resource,\n };\n\n if (record.spanContext) {\n log.traceId = record.spanContext.traceId;\n log.spanId = record.spanContext.spanId;\n }\n\n return log;\n}\n\nexport class DevtoolsLogExporter implements LogRecordExporter {\n private endpoint: string;\n private apiKey: string;\n private timeout: number;\n private isShutdown = false;\n\n constructor(options: DevtoolsLogExporterOptions) {\n this.endpoint = options.endpoint.replace(/\\/$/, '');\n this.apiKey = options.apiKey ?? '';\n this.timeout = options.timeout ?? defaultTimeout;\n }\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {\n if (this.isShutdown || logs.length === 0) {\n resultCallback({ code: ExportResultCode.SUCCESS });\n return;\n }\n\n const payload = { logs: logs.map((r, i) => recordToLogData(r, i)) };\n const url = `${this.endpoint}/ingest/logs`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n .then((res) => {\n clearTimeout(timeoutId);\n if (!res.ok) {\n throw new Error(`Devtools log ingest failed: ${res.status} ${res.statusText}`);\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n })\n .catch((err) => {\n clearTimeout(timeoutId);\n resultCallback({\n code: ExportResultCode.FAILED,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n }\n\n shutdown(): Promise<void> {\n this.isShutdown = true;\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n"],"mappings":";;;;;AA8CA,MAAM,iBAAiB;AAEvB,SAAS,WAAW,QAAkC;CACpD,OAAO,OAAO,KAAK,MAAO,OAAO,KAAK;AACxC;AAEA,SAAS,cAAc,MAAmE;CACxF,IAAI,SAAS,QAAW,OAAO;CAC/B,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO;CACtD,OAAO,OAAO,IAAI;AACpB;AAEA,SAAS,gBAAgB,QAA2B,OAAwB;CAC1E,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE,GAAG,MAAM,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC9E,MAAM,YAAY,WAAW,OAAO,MAAM;CAC1C,MAAM,OAAO,cAAc,OAAO,IAAI;CACtC,MAAM,aAAa,OAAO,cAAc,OAAO,KAAK,OAAO,UAAU,CAAC,CAAC,SAAS,IAC3E,OAAO,aACR;CACJ,MAAM,WAAW,OAAO,UAAU,cAAc,OAAO,KAAK,OAAO,SAAS,UAAU,CAAC,CAAC,SAAS,IAC5F,OAAO,SAAS,aACjB;CAEJ,MAAM,MAAe;EACnB;EACA,cAAcA,uCAAgB,QAAQ;EACtC,cAAc,OAAO;EACrB,gBAAgB,OAAO;EACvB;EACA;EACA;EACA;CACF;CAEA,IAAI,OAAO,aAAa;EACtB,IAAI,UAAU,OAAO,YAAY;EACjC,IAAI,SAAS,OAAO,YAAY;CAClC;CAEA,OAAO;AACT;AAEA,IAAa,sBAAb,MAA8D;CAC5D,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,aAAa;CAErB,YAAY,SAAqC;EAC/C,KAAK,WAAW,QAAQ,SAAS,QAAQ,OAAO,EAAE;EAClD,KAAK,SAAS,QAAQ,UAAU;EAChC,KAAK,UAAU,QAAQ,WAAW;CACpC;CAEA,OAAO,MAA2B,gBAAsD;EACtF,IAAI,KAAK,cAAc,KAAK,WAAW,GAAG;GACxC,eAAe,EAAE,MAAMC,qCAAiB,QAAQ,CAAC;GACjD;EACF;EAEA,MAAM,UAAU,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE;EAClE,MAAM,MAAM,GAAG,KAAK,SAAS;EAC7B,MAAM,UAAkC,EACtC,gBAAgB,mBAClB;EACA,IAAI,KAAK,QACP,QAAQ,mBAAmB,UAAU,KAAK;EAG5C,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,KAAK,OAAO;EAEnE,MAAM,KAAK;GACT,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,WAAW;EACrB,CAAC,CAAC,CACC,MAAM,QAAQ;GACb,aAAa,SAAS;GACtB,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,+BAA+B,IAAI,OAAO,GAAG,IAAI,YAAY;GAE/E,eAAe,EAAE,MAAMA,qCAAiB,QAAQ,CAAC;EACnD,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,aAAa,SAAS;GACtB,eAAe;IACb,MAAMA,qCAAiB;IACvB,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAC3D,CAAC;EACH,CAAC;CACL;CAEA,WAA0B;EACxB,KAAK,aAAa;EAClB,OAAO,QAAQ,QAAQ;CACzB;CAEA,aAA4B;EAC1B,OAAO,QAAQ,QAAQ;CACzB;AACF"}
1
+ {"version":3,"file":"log-exporter.cjs","names":["getResourceName","ExportResultCode"],"sources":["../../src/server/log-exporter.ts"],"sourcesContent":["/**\n * Log record exporter that sends OTel logs to a Devtools server HTTP ingest.\n * Use with BatchLogRecordProcessor when you want to view logs in the Autotel widget/extension.\n *\n * @example\n * ```typescript\n * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\n * import { DevtoolsLogExporter } from '@autotel/devtools/server';\n * import { init } from 'autotel';\n *\n * init({\n * service: 'my-app',\n * logRecordProcessors: [\n * new BatchLogRecordProcessor(\n * new DevtoolsLogExporter({ endpoint: 'http://localhost:8082' })\n * ),\n * ],\n * });\n * ```\n */\n\nimport type { ExportResult } from '@opentelemetry/core';\nimport { ExportResultCode } from '@opentelemetry/core';\nimport type { LogRecordExporter } from '@opentelemetry/sdk-logs';\nimport type { ReadableLogRecord } from '@opentelemetry/sdk-logs';\nimport type { LogData } from './types';\nimport { getResourceName } from './resource-utils';\n\nexport interface DevtoolsLogExporterOptions {\n /**\n * Base URL of the Devtools HTTP ingest server\n * e.g. 'http://localhost:8082'\n */\n endpoint: string;\n\n /**\n * API key for authentication (if server requires it)\n */\n apiKey?: string;\n\n /**\n * Request timeout in milliseconds (default: 5000)\n */\n timeout?: number;\n}\n\nconst defaultTimeout = 5000;\n\nfunction hrTimeToMs(hrTime: [number, number]): number {\n return hrTime[0] * 1000 + hrTime[1] / 1e6;\n}\n\nfunction bodyToPayload(\n body: ReadableLogRecord['body'],\n): string | Record<string, unknown> {\n if (body === undefined) return '';\n if (typeof body === 'string') return body;\n if (typeof body === 'object' && body !== null)\n return body as Record<string, unknown>;\n return String(body);\n}\n\nfunction recordToLogData(record: ReadableLogRecord, index: number): LogData {\n const id = `log-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 9)}`;\n const timestamp = hrTimeToMs(record.hrTime);\n const body = bodyToPayload(record.body);\n const attributes =\n record.attributes && Object.keys(record.attributes).length > 0\n ? (record.attributes as Record<string, unknown>)\n : undefined;\n const resource =\n record.resource?.attributes &&\n Object.keys(record.resource.attributes).length > 0\n ? (record.resource.attributes as Record<string, unknown>)\n : undefined;\n\n const log: LogData = {\n id,\n resourceName: getResourceName(resource),\n severityText: record.severityText,\n severityNumber: record.severityNumber,\n body,\n timestamp,\n attributes,\n resource,\n };\n\n if (record.spanContext) {\n log.traceId = record.spanContext.traceId;\n log.spanId = record.spanContext.spanId;\n }\n\n return log;\n}\n\nexport class DevtoolsLogExporter implements LogRecordExporter {\n private endpoint: string;\n private apiKey: string;\n private timeout: number;\n private isShutdown = false;\n\n constructor(options: DevtoolsLogExporterOptions) {\n this.endpoint = options.endpoint.replace(/\\/$/, '');\n this.apiKey = options.apiKey ?? '';\n this.timeout = options.timeout ?? defaultTimeout;\n }\n\n export(\n logs: ReadableLogRecord[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n if (this.isShutdown || logs.length === 0) {\n resultCallback({ code: ExportResultCode.SUCCESS });\n return;\n }\n\n const payload = { logs: logs.map((r, i) => recordToLogData(r, i)) };\n const url = `${this.endpoint}/ingest/logs`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n .then((res) => {\n clearTimeout(timeoutId);\n if (!res.ok) {\n throw new Error(\n `Devtools log ingest failed: ${res.status} ${res.statusText}`,\n );\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n })\n .catch((err) => {\n clearTimeout(timeoutId);\n resultCallback({\n code: ExportResultCode.FAILED,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n }\n\n shutdown(): Promise<void> {\n this.isShutdown = true;\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n"],"mappings":";;;;;AA8CA,MAAM,iBAAiB;AAEvB,SAAS,WAAW,QAAkC;CACpD,OAAO,OAAO,KAAK,MAAO,OAAO,KAAK;AACxC;AAEA,SAAS,cACP,MACkC;CAClC,IAAI,SAAS,QAAW,OAAO;CAC/B,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC,OAAO;CACT,OAAO,OAAO,IAAI;AACpB;AAEA,SAAS,gBAAgB,QAA2B,OAAwB;CAC1E,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE,GAAG,MAAM,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC9E,MAAM,YAAY,WAAW,OAAO,MAAM;CAC1C,MAAM,OAAO,cAAc,OAAO,IAAI;CACtC,MAAM,aACJ,OAAO,cAAc,OAAO,KAAK,OAAO,UAAU,CAAC,CAAC,SAAS,IACxD,OAAO,aACR;CACN,MAAM,WACJ,OAAO,UAAU,cACjB,OAAO,KAAK,OAAO,SAAS,UAAU,CAAC,CAAC,SAAS,IAC5C,OAAO,SAAS,aACjB;CAEN,MAAM,MAAe;EACnB;EACA,cAAcA,uCAAgB,QAAQ;EACtC,cAAc,OAAO;EACrB,gBAAgB,OAAO;EACvB;EACA;EACA;EACA;CACF;CAEA,IAAI,OAAO,aAAa;EACtB,IAAI,UAAU,OAAO,YAAY;EACjC,IAAI,SAAS,OAAO,YAAY;CAClC;CAEA,OAAO;AACT;AAEA,IAAa,sBAAb,MAA8D;CAC5D,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,aAAa;CAErB,YAAY,SAAqC;EAC/C,KAAK,WAAW,QAAQ,SAAS,QAAQ,OAAO,EAAE;EAClD,KAAK,SAAS,QAAQ,UAAU;EAChC,KAAK,UAAU,QAAQ,WAAW;CACpC;CAEA,OACE,MACA,gBACM;EACN,IAAI,KAAK,cAAc,KAAK,WAAW,GAAG;GACxC,eAAe,EAAE,MAAMC,qCAAiB,QAAQ,CAAC;GACjD;EACF;EAEA,MAAM,UAAU,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE;EAClE,MAAM,MAAM,GAAG,KAAK,SAAS;EAC7B,MAAM,UAAkC,EACtC,gBAAgB,mBAClB;EACA,IAAI,KAAK,QACP,QAAQ,mBAAmB,UAAU,KAAK;EAG5C,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,KAAK,OAAO;EAEnE,MAAM,KAAK;GACT,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,WAAW;EACrB,CAAC,CAAC,CACC,MAAM,QAAQ;GACb,aAAa,SAAS;GACtB,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MACR,+BAA+B,IAAI,OAAO,GAAG,IAAI,YACnD;GAEF,eAAe,EAAE,MAAMA,qCAAiB,QAAQ,CAAC;EACnD,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,aAAa,SAAS;GACtB,eAAe;IACb,MAAMA,qCAAiB;IACvB,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAC3D,CAAC;EACH,CAAC;CACL;CAEA,WAA0B;EACxB,KAAK,aAAa;EAClB,OAAO,QAAQ,QAAQ;CACzB;CAEA,aAA4B;EAC1B,OAAO,QAAQ,QAAQ;CACzB;AACF"}
@@ -1,6 +1,5 @@
1
1
  import { ExportResult } from "@opentelemetry/core";
2
2
  import { LogRecordExporter, ReadableLogRecord } from "@opentelemetry/sdk-logs";
3
-
4
3
  //#region src/server/log-exporter.d.ts
5
4
  interface DevtoolsLogExporterOptions {
6
5
  /**
@@ -1,6 +1,5 @@
1
1
  import { ExportResult } from "@opentelemetry/core";
2
2
  import { LogRecordExporter, ReadableLogRecord } from "@opentelemetry/sdk-logs";
3
-
4
3
  //#region src/server/log-exporter.d.ts
5
4
  interface DevtoolsLogExporterOptions {
6
5
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"log-exporter.js","names":[],"sources":["../../src/server/log-exporter.ts"],"sourcesContent":["/**\n * Log record exporter that sends OTel logs to a Devtools server HTTP ingest.\n * Use with BatchLogRecordProcessor when you want to view logs in the Autotel widget/extension.\n *\n * @example\n * ```typescript\n * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\n * import { DevtoolsLogExporter } from '@autotel/devtools/server';\n * import { init } from 'autotel';\n *\n * init({\n * service: 'my-app',\n * logRecordProcessors: [\n * new BatchLogRecordProcessor(\n * new DevtoolsLogExporter({ endpoint: 'http://localhost:8082' })\n * ),\n * ],\n * });\n * ```\n */\n\nimport type { ExportResult } from '@opentelemetry/core';\nimport { ExportResultCode } from '@opentelemetry/core';\nimport type { LogRecordExporter } from '@opentelemetry/sdk-logs';\nimport type { ReadableLogRecord } from '@opentelemetry/sdk-logs';\nimport type { LogData } from './types';\nimport { getResourceName } from './resource-utils';\n\nexport interface DevtoolsLogExporterOptions {\n /**\n * Base URL of the Devtools HTTP ingest server\n * e.g. 'http://localhost:8082'\n */\n endpoint: string;\n\n /**\n * API key for authentication (if server requires it)\n */\n apiKey?: string;\n\n /**\n * Request timeout in milliseconds (default: 5000)\n */\n timeout?: number;\n}\n\nconst defaultTimeout = 5000;\n\nfunction hrTimeToMs(hrTime: [number, number]): number {\n return hrTime[0] * 1000 + hrTime[1] / 1e6;\n}\n\nfunction bodyToPayload(body: ReadableLogRecord['body']): string | Record<string, unknown> {\n if (body === undefined) return '';\n if (typeof body === 'string') return body;\n if (typeof body === 'object' && body !== null) return body as Record<string, unknown>;\n return String(body);\n}\n\nfunction recordToLogData(record: ReadableLogRecord, index: number): LogData {\n const id = `log-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 9)}`;\n const timestamp = hrTimeToMs(record.hrTime);\n const body = bodyToPayload(record.body);\n const attributes = record.attributes && Object.keys(record.attributes).length > 0\n ? (record.attributes as Record<string, unknown>)\n : undefined;\n const resource = record.resource?.attributes && Object.keys(record.resource.attributes).length > 0\n ? (record.resource.attributes as Record<string, unknown>)\n : undefined;\n\n const log: LogData = {\n id,\n resourceName: getResourceName(resource),\n severityText: record.severityText,\n severityNumber: record.severityNumber,\n body,\n timestamp,\n attributes,\n resource,\n };\n\n if (record.spanContext) {\n log.traceId = record.spanContext.traceId;\n log.spanId = record.spanContext.spanId;\n }\n\n return log;\n}\n\nexport class DevtoolsLogExporter implements LogRecordExporter {\n private endpoint: string;\n private apiKey: string;\n private timeout: number;\n private isShutdown = false;\n\n constructor(options: DevtoolsLogExporterOptions) {\n this.endpoint = options.endpoint.replace(/\\/$/, '');\n this.apiKey = options.apiKey ?? '';\n this.timeout = options.timeout ?? defaultTimeout;\n }\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {\n if (this.isShutdown || logs.length === 0) {\n resultCallback({ code: ExportResultCode.SUCCESS });\n return;\n }\n\n const payload = { logs: logs.map((r, i) => recordToLogData(r, i)) };\n const url = `${this.endpoint}/ingest/logs`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n .then((res) => {\n clearTimeout(timeoutId);\n if (!res.ok) {\n throw new Error(`Devtools log ingest failed: ${res.status} ${res.statusText}`);\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n })\n .catch((err) => {\n clearTimeout(timeoutId);\n resultCallback({\n code: ExportResultCode.FAILED,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n }\n\n shutdown(): Promise<void> {\n this.isShutdown = true;\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n"],"mappings":";;;;AA8CA,MAAM,iBAAiB;AAEvB,SAAS,WAAW,QAAkC;CACpD,OAAO,OAAO,KAAK,MAAO,OAAO,KAAK;AACxC;AAEA,SAAS,cAAc,MAAmE;CACxF,IAAI,SAAS,QAAW,OAAO;CAC/B,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO;CACtD,OAAO,OAAO,IAAI;AACpB;AAEA,SAAS,gBAAgB,QAA2B,OAAwB;CAC1E,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE,GAAG,MAAM,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC9E,MAAM,YAAY,WAAW,OAAO,MAAM;CAC1C,MAAM,OAAO,cAAc,OAAO,IAAI;CACtC,MAAM,aAAa,OAAO,cAAc,OAAO,KAAK,OAAO,UAAU,CAAC,CAAC,SAAS,IAC3E,OAAO,aACR;CACJ,MAAM,WAAW,OAAO,UAAU,cAAc,OAAO,KAAK,OAAO,SAAS,UAAU,CAAC,CAAC,SAAS,IAC5F,OAAO,SAAS,aACjB;CAEJ,MAAM,MAAe;EACnB;EACA,cAAc,gBAAgB,QAAQ;EACtC,cAAc,OAAO;EACrB,gBAAgB,OAAO;EACvB;EACA;EACA;EACA;CACF;CAEA,IAAI,OAAO,aAAa;EACtB,IAAI,UAAU,OAAO,YAAY;EACjC,IAAI,SAAS,OAAO,YAAY;CAClC;CAEA,OAAO;AACT;AAEA,IAAa,sBAAb,MAA8D;CAC5D,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,aAAa;CAErB,YAAY,SAAqC;EAC/C,KAAK,WAAW,QAAQ,SAAS,QAAQ,OAAO,EAAE;EAClD,KAAK,SAAS,QAAQ,UAAU;EAChC,KAAK,UAAU,QAAQ,WAAW;CACpC;CAEA,OAAO,MAA2B,gBAAsD;EACtF,IAAI,KAAK,cAAc,KAAK,WAAW,GAAG;GACxC,eAAe,EAAE,MAAM,iBAAiB,QAAQ,CAAC;GACjD;EACF;EAEA,MAAM,UAAU,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE;EAClE,MAAM,MAAM,GAAG,KAAK,SAAS;EAC7B,MAAM,UAAkC,EACtC,gBAAgB,mBAClB;EACA,IAAI,KAAK,QACP,QAAQ,mBAAmB,UAAU,KAAK;EAG5C,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,KAAK,OAAO;EAEnE,MAAM,KAAK;GACT,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,WAAW;EACrB,CAAC,CAAC,CACC,MAAM,QAAQ;GACb,aAAa,SAAS;GACtB,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,+BAA+B,IAAI,OAAO,GAAG,IAAI,YAAY;GAE/E,eAAe,EAAE,MAAM,iBAAiB,QAAQ,CAAC;EACnD,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,aAAa,SAAS;GACtB,eAAe;IACb,MAAM,iBAAiB;IACvB,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAC3D,CAAC;EACH,CAAC;CACL;CAEA,WAA0B;EACxB,KAAK,aAAa;EAClB,OAAO,QAAQ,QAAQ;CACzB;CAEA,aAA4B;EAC1B,OAAO,QAAQ,QAAQ;CACzB;AACF"}
1
+ {"version":3,"file":"log-exporter.js","names":[],"sources":["../../src/server/log-exporter.ts"],"sourcesContent":["/**\n * Log record exporter that sends OTel logs to a Devtools server HTTP ingest.\n * Use with BatchLogRecordProcessor when you want to view logs in the Autotel widget/extension.\n *\n * @example\n * ```typescript\n * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\n * import { DevtoolsLogExporter } from '@autotel/devtools/server';\n * import { init } from 'autotel';\n *\n * init({\n * service: 'my-app',\n * logRecordProcessors: [\n * new BatchLogRecordProcessor(\n * new DevtoolsLogExporter({ endpoint: 'http://localhost:8082' })\n * ),\n * ],\n * });\n * ```\n */\n\nimport type { ExportResult } from '@opentelemetry/core';\nimport { ExportResultCode } from '@opentelemetry/core';\nimport type { LogRecordExporter } from '@opentelemetry/sdk-logs';\nimport type { ReadableLogRecord } from '@opentelemetry/sdk-logs';\nimport type { LogData } from './types';\nimport { getResourceName } from './resource-utils';\n\nexport interface DevtoolsLogExporterOptions {\n /**\n * Base URL of the Devtools HTTP ingest server\n * e.g. 'http://localhost:8082'\n */\n endpoint: string;\n\n /**\n * API key for authentication (if server requires it)\n */\n apiKey?: string;\n\n /**\n * Request timeout in milliseconds (default: 5000)\n */\n timeout?: number;\n}\n\nconst defaultTimeout = 5000;\n\nfunction hrTimeToMs(hrTime: [number, number]): number {\n return hrTime[0] * 1000 + hrTime[1] / 1e6;\n}\n\nfunction bodyToPayload(\n body: ReadableLogRecord['body'],\n): string | Record<string, unknown> {\n if (body === undefined) return '';\n if (typeof body === 'string') return body;\n if (typeof body === 'object' && body !== null)\n return body as Record<string, unknown>;\n return String(body);\n}\n\nfunction recordToLogData(record: ReadableLogRecord, index: number): LogData {\n const id = `log-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 9)}`;\n const timestamp = hrTimeToMs(record.hrTime);\n const body = bodyToPayload(record.body);\n const attributes =\n record.attributes && Object.keys(record.attributes).length > 0\n ? (record.attributes as Record<string, unknown>)\n : undefined;\n const resource =\n record.resource?.attributes &&\n Object.keys(record.resource.attributes).length > 0\n ? (record.resource.attributes as Record<string, unknown>)\n : undefined;\n\n const log: LogData = {\n id,\n resourceName: getResourceName(resource),\n severityText: record.severityText,\n severityNumber: record.severityNumber,\n body,\n timestamp,\n attributes,\n resource,\n };\n\n if (record.spanContext) {\n log.traceId = record.spanContext.traceId;\n log.spanId = record.spanContext.spanId;\n }\n\n return log;\n}\n\nexport class DevtoolsLogExporter implements LogRecordExporter {\n private endpoint: string;\n private apiKey: string;\n private timeout: number;\n private isShutdown = false;\n\n constructor(options: DevtoolsLogExporterOptions) {\n this.endpoint = options.endpoint.replace(/\\/$/, '');\n this.apiKey = options.apiKey ?? '';\n this.timeout = options.timeout ?? defaultTimeout;\n }\n\n export(\n logs: ReadableLogRecord[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n if (this.isShutdown || logs.length === 0) {\n resultCallback({ code: ExportResultCode.SUCCESS });\n return;\n }\n\n const payload = { logs: logs.map((r, i) => recordToLogData(r, i)) };\n const url = `${this.endpoint}/ingest/logs`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.apiKey) {\n headers['Authorization'] = `Bearer ${this.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n .then((res) => {\n clearTimeout(timeoutId);\n if (!res.ok) {\n throw new Error(\n `Devtools log ingest failed: ${res.status} ${res.statusText}`,\n );\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n })\n .catch((err) => {\n clearTimeout(timeoutId);\n resultCallback({\n code: ExportResultCode.FAILED,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n });\n }\n\n shutdown(): Promise<void> {\n this.isShutdown = true;\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n"],"mappings":";;;;AA8CA,MAAM,iBAAiB;AAEvB,SAAS,WAAW,QAAkC;CACpD,OAAO,OAAO,KAAK,MAAO,OAAO,KAAK;AACxC;AAEA,SAAS,cACP,MACkC;CAClC,IAAI,SAAS,QAAW,OAAO;CAC/B,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC,OAAO;CACT,OAAO,OAAO,IAAI;AACpB;AAEA,SAAS,gBAAgB,QAA2B,OAAwB;CAC1E,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE,GAAG,MAAM,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC9E,MAAM,YAAY,WAAW,OAAO,MAAM;CAC1C,MAAM,OAAO,cAAc,OAAO,IAAI;CACtC,MAAM,aACJ,OAAO,cAAc,OAAO,KAAK,OAAO,UAAU,CAAC,CAAC,SAAS,IACxD,OAAO,aACR;CACN,MAAM,WACJ,OAAO,UAAU,cACjB,OAAO,KAAK,OAAO,SAAS,UAAU,CAAC,CAAC,SAAS,IAC5C,OAAO,SAAS,aACjB;CAEN,MAAM,MAAe;EACnB;EACA,cAAc,gBAAgB,QAAQ;EACtC,cAAc,OAAO;EACrB,gBAAgB,OAAO;EACvB;EACA;EACA;EACA;CACF;CAEA,IAAI,OAAO,aAAa;EACtB,IAAI,UAAU,OAAO,YAAY;EACjC,IAAI,SAAS,OAAO,YAAY;CAClC;CAEA,OAAO;AACT;AAEA,IAAa,sBAAb,MAA8D;CAC5D,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,aAAa;CAErB,YAAY,SAAqC;EAC/C,KAAK,WAAW,QAAQ,SAAS,QAAQ,OAAO,EAAE;EAClD,KAAK,SAAS,QAAQ,UAAU;EAChC,KAAK,UAAU,QAAQ,WAAW;CACpC;CAEA,OACE,MACA,gBACM;EACN,IAAI,KAAK,cAAc,KAAK,WAAW,GAAG;GACxC,eAAe,EAAE,MAAM,iBAAiB,QAAQ,CAAC;GACjD;EACF;EAEA,MAAM,UAAU,EAAE,MAAM,KAAK,KAAK,GAAG,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE;EAClE,MAAM,MAAM,GAAG,KAAK,SAAS;EAC7B,MAAM,UAAkC,EACtC,gBAAgB,mBAClB;EACA,IAAI,KAAK,QACP,QAAQ,mBAAmB,UAAU,KAAK;EAG5C,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,KAAK,OAAO;EAEnE,MAAM,KAAK;GACT,QAAQ;GACR;GACA,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,WAAW;EACrB,CAAC,CAAC,CACC,MAAM,QAAQ;GACb,aAAa,SAAS;GACtB,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MACR,+BAA+B,IAAI,OAAO,GAAG,IAAI,YACnD;GAEF,eAAe,EAAE,MAAM,iBAAiB,QAAQ,CAAC;EACnD,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,aAAa,SAAS;GACtB,eAAe;IACb,MAAM,iBAAiB;IACvB,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAC3D,CAAC;EACH,CAAC;CACL;CAEA,WAA0B;EACxB,KAAK,aAAa;EAClB,OAAO,QAAQ,QAAQ;CACzB;CAEA,aAA4B;EAC1B,OAAO,QAAQ,QAAQ;CACzB;AACF"}
@@ -1,6 +1,5 @@
1
1
  import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
2
2
  import { ExportResult } from "@opentelemetry/core";
3
-
4
3
  //#region src/server/remote-exporter.d.ts
5
4
  interface DevtoolsRemoteExporterOptions {
6
5
  /**
@@ -1,6 +1,5 @@
1
1
  import { ExportResult } from "@opentelemetry/core";
2
2
  import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
3
-
4
3
  //#region src/server/remote-exporter.d.ts
5
4
  interface DevtoolsRemoteExporterOptions {
6
5
  /**