@geekmidas/telescope 10.0.0-alpha.14 → 10.0.0-alpha.141

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 (132) hide show
  1. package/README.md +14 -14
  2. package/dist/{MetricsAggregator-BxBLQUPj.d.cts → MetricsAggregator-BJdIvfEv.d.mts} +2 -2
  3. package/dist/MetricsAggregator-BJdIvfEv.d.mts.map +1 -0
  4. package/dist/{MetricsAggregator-j9wmZ0K_.d.mts → MetricsAggregator-CnC3oT5q.d.cts} +2 -2
  5. package/dist/MetricsAggregator-CnC3oT5q.d.cts.map +1 -0
  6. package/dist/{Telescope-BcrWTaar.d.mts → Telescope-BVfDvVvY.d.mts} +3 -3
  7. package/dist/{Telescope-BcrWTaar.d.mts.map → Telescope-BVfDvVvY.d.mts.map} +1 -1
  8. package/dist/{Telescope-DnCMZT7V.d.cts → Telescope-DeqSHfuB.d.cts} +3 -3
  9. package/dist/{Telescope-DnCMZT7V.d.cts.map → Telescope-DeqSHfuB.d.cts.map} +1 -1
  10. package/dist/Telescope.d.cts +1 -1
  11. package/dist/Telescope.d.mts +1 -1
  12. package/dist/adapters/lambda.d.cts +1 -1
  13. package/dist/adapters/lambda.d.cts.map +1 -1
  14. package/dist/adapters/lambda.d.mts +1 -1
  15. package/dist/adapters/lambda.d.mts.map +1 -1
  16. package/dist/adapters/middy.d.cts +1 -1
  17. package/dist/adapters/middy.d.mts +1 -1
  18. package/dist/index.d.cts +3 -3
  19. package/dist/index.d.mts +3 -3
  20. package/dist/instrumentation/hono.cjs +47 -7
  21. package/dist/instrumentation/hono.cjs.map +1 -1
  22. package/dist/instrumentation/hono.d.cts +19 -0
  23. package/dist/instrumentation/hono.d.cts.map +1 -1
  24. package/dist/instrumentation/hono.d.mts +19 -0
  25. package/dist/instrumentation/hono.d.mts.map +1 -1
  26. package/dist/instrumentation/hono.mjs +48 -8
  27. package/dist/instrumentation/hono.mjs.map +1 -1
  28. package/dist/instrumentation/http.cjs +29 -4
  29. package/dist/instrumentation/http.cjs.map +1 -1
  30. package/dist/instrumentation/http.d.cts +18 -2
  31. package/dist/instrumentation/http.d.cts.map +1 -1
  32. package/dist/instrumentation/http.d.mts +18 -2
  33. package/dist/instrumentation/http.d.mts.map +1 -1
  34. package/dist/instrumentation/http.mjs +30 -6
  35. package/dist/instrumentation/http.mjs.map +1 -1
  36. package/dist/instrumentation/index.cjs +9 -0
  37. package/dist/instrumentation/index.d.cts +5 -3
  38. package/dist/instrumentation/index.d.mts +5 -3
  39. package/dist/instrumentation/index.mjs +5 -3
  40. package/dist/instrumentation/middleware.cjs +4 -2
  41. package/dist/instrumentation/middleware.cjs.map +1 -1
  42. package/dist/instrumentation/middleware.d.cts +13 -0
  43. package/dist/instrumentation/middleware.d.cts.map +1 -1
  44. package/dist/instrumentation/middleware.d.mts +13 -0
  45. package/dist/instrumentation/middleware.d.mts.map +1 -1
  46. package/dist/instrumentation/middleware.mjs +5 -3
  47. package/dist/instrumentation/middleware.mjs.map +1 -1
  48. package/dist/instrumentation/otel.d.cts.map +1 -1
  49. package/dist/instrumentation/otel.d.mts.map +1 -1
  50. package/dist/instrumentation/sampler.cjs +54 -0
  51. package/dist/instrumentation/sampler.cjs.map +1 -0
  52. package/dist/instrumentation/sampler.d.cts +38 -0
  53. package/dist/instrumentation/sampler.d.cts.map +1 -0
  54. package/dist/instrumentation/sampler.d.mts +38 -0
  55. package/dist/instrumentation/sampler.d.mts.map +1 -0
  56. package/dist/instrumentation/sampler.mjs +52 -0
  57. package/dist/instrumentation/sampler.mjs.map +1 -0
  58. package/dist/instrumentation/setup.cjs +63 -21
  59. package/dist/instrumentation/setup.cjs.map +1 -1
  60. package/dist/instrumentation/setup.d.cts +59 -3
  61. package/dist/instrumentation/setup.d.cts.map +1 -1
  62. package/dist/instrumentation/setup.d.mts +59 -3
  63. package/dist/instrumentation/setup.d.mts.map +1 -1
  64. package/dist/instrumentation/setup.mjs +64 -23
  65. package/dist/instrumentation/setup.mjs.map +1 -1
  66. package/dist/instrumentation/trust.cjs +116 -0
  67. package/dist/instrumentation/trust.cjs.map +1 -0
  68. package/dist/instrumentation/trust.d.cts +59 -0
  69. package/dist/instrumentation/trust.d.cts.map +1 -0
  70. package/dist/instrumentation/trust.d.mts +59 -0
  71. package/dist/instrumentation/trust.d.mts.map +1 -0
  72. package/dist/instrumentation/trust.mjs +113 -0
  73. package/dist/instrumentation/trust.mjs.map +1 -0
  74. package/dist/logger/console.d.cts +1 -1
  75. package/dist/logger/console.d.cts.map +1 -1
  76. package/dist/logger/console.d.mts +1 -1
  77. package/dist/logger/console.d.mts.map +1 -1
  78. package/dist/logger/pino.d.cts +1 -1
  79. package/dist/logger/pino.d.mts +1 -1
  80. package/dist/metrics/MetricsAggregator.d.cts +1 -1
  81. package/dist/metrics/MetricsAggregator.d.mts +1 -1
  82. package/dist/metrics/index.d.cts +1 -1
  83. package/dist/metrics/index.d.mts +1 -1
  84. package/dist/metrics/storage/InMemoryMetricsStorage.d.cts.map +1 -1
  85. package/dist/metrics/storage/InMemoryMetricsStorage.d.mts.map +1 -1
  86. package/dist/otlp/index.d.cts +1 -1
  87. package/dist/otlp/index.d.mts +1 -1
  88. package/dist/otlp/receiver.d.cts +2 -2
  89. package/dist/otlp/receiver.d.cts.map +1 -1
  90. package/dist/otlp/receiver.d.mts +2 -2
  91. package/dist/otlp/receiver.d.mts.map +1 -1
  92. package/dist/otlp/transformer.d.cts +1 -1
  93. package/dist/otlp/transformer.d.mts +1 -1
  94. package/dist/redact.d.cts +1 -1
  95. package/dist/redact.d.mts +1 -1
  96. package/dist/server/hono.cjs +11 -23
  97. package/dist/server/hono.cjs.map +1 -1
  98. package/dist/server/hono.d.cts +11 -3
  99. package/dist/server/hono.d.cts.map +1 -1
  100. package/dist/server/hono.d.mts +11 -3
  101. package/dist/server/hono.d.mts.map +1 -1
  102. package/dist/server/hono.mjs +11 -23
  103. package/dist/server/hono.mjs.map +1 -1
  104. package/dist/storage/kysely.d.cts +1 -1
  105. package/dist/storage/kysely.d.cts.map +1 -1
  106. package/dist/storage/kysely.d.mts +1 -1
  107. package/dist/storage/kysely.d.mts.map +1 -1
  108. package/dist/storage/memory.d.cts +1 -1
  109. package/dist/storage/memory.d.cts.map +1 -1
  110. package/dist/storage/memory.d.mts +1 -1
  111. package/dist/storage/memory.d.mts.map +1 -1
  112. package/dist/{transformer-DlESim6Q.d.cts → transformer-BtqjAs0b.d.cts} +2 -2
  113. package/dist/{transformer-BBBXCjHP.d.mts.map → transformer-BtqjAs0b.d.cts.map} +1 -1
  114. package/dist/{transformer-BBBXCjHP.d.mts → transformer-DI6t8-YA.d.mts} +2 -2
  115. package/dist/{transformer-DlESim6Q.d.cts.map → transformer-DI6t8-YA.d.mts.map} +1 -1
  116. package/dist/{types-a9Vistj1.d.cts → types-BVujq4zd.d.cts} +2 -2
  117. package/dist/{types-a9Vistj1.d.cts.map → types-BVujq4zd.d.cts.map} +1 -1
  118. package/dist/{types-a9Vistj1.d.mts → types-BVujq4zd.d.mts} +2 -2
  119. package/dist/{types-a9Vistj1.d.mts.map → types-BVujq4zd.d.mts.map} +1 -1
  120. package/dist/types.d.cts +1 -1
  121. package/dist/types.d.mts +1 -1
  122. package/package.json +7 -5
  123. package/dist/MetricsAggregator-BxBLQUPj.d.cts.map +0 -1
  124. package/dist/MetricsAggregator-j9wmZ0K_.d.mts.map +0 -1
  125. package/dist/ui-assets.cjs +0 -32
  126. package/dist/ui-assets.cjs.map +0 -1
  127. package/dist/ui-assets.d.cts +0 -11
  128. package/dist/ui-assets.d.cts.map +0 -1
  129. package/dist/ui-assets.d.mts +0 -11
  130. package/dist/ui-assets.d.mts.map +0 -1
  131. package/dist/ui-assets.mjs +0 -29
  132. package/dist/ui-assets.mjs.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @geekmidas/telescope
2
2
 
3
- Laravel Telescope-style debugging and monitoring for web applications. Capture and inspect HTTP requests, exceptions, and logs in real-time.
3
+ Laravel Telescope-style debugging and monitoring for web applications. Capture HTTP requests, exceptions and logs, and read them back as a JSON API with a WebSocket feed. Headless: there is no dashboard — build whatever UI you want on the JSON.
4
4
 
5
5
  **Framework-agnostic core** with adapters for Hono, AWS Lambda, and more.
6
6
 
@@ -17,7 +17,7 @@ pnpm add @geekmidas/telescope
17
17
  ```typescript
18
18
  import { Hono } from 'hono';
19
19
  import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
20
- import { createMiddleware, createUI } from '@geekmidas/telescope/server/hono';
20
+ import { createApi, createMiddleware } from '@geekmidas/telescope/server/hono';
21
21
 
22
22
  const telescope = new Telescope({
23
23
  storage: new InMemoryStorage(),
@@ -28,8 +28,8 @@ const app = new Hono();
28
28
  // Add middleware to capture requests
29
29
  app.use('*', createMiddleware(telescope));
30
30
 
31
- // Mount the dashboard
32
- app.route('/__telescope', createUI(telescope));
31
+ // Mount the JSON API
32
+ app.route('/__telescope', createApi(telescope));
33
33
 
34
34
  // Your routes
35
35
  app.get('/users', (c) => c.json({ users: [] }));
@@ -37,7 +37,7 @@ app.get('/users', (c) => c.json({ users: [] }));
37
37
  export default app;
38
38
  ```
39
39
 
40
- Visit `http://localhost:3000/__telescope` to view the dashboard.
40
+ Read the data at `http://localhost:3000/__telescope/api/requests` (and `/api/exceptions`, `/api/logs`, …).
41
41
 
42
42
  ### Framework-Agnostic Core
43
43
 
@@ -80,7 +80,7 @@ try {
80
80
  - **Request Recording**: Capture HTTP requests with headers, body, query params, and response
81
81
  - **Exception Tracking**: Record exceptions with stack traces and source context
82
82
  - **Log Aggregation**: Collect application logs with context
83
- - **Real-time Updates**: WebSocket-powered live dashboard
83
+ - **Real-time Updates**: a WebSocket feed of new entries
84
84
  - **Storage Agnostic**: Use in-memory for dev, database for production
85
85
  - **Hono Integration**: First-class middleware and route mounting
86
86
  - **Lambda Integration**: Wrapper and Middy middleware for AWS Lambda with auto-flush
@@ -95,7 +95,7 @@ const telescope = new Telescope({
95
95
  // Optional: Enable/disable telescope (default: true)
96
96
  enabled: true,
97
97
 
98
- // Optional: Dashboard path (default: '/__telescope')
98
+ // Optional: where the JSON API is mounted (default: '/__telescope')
99
99
  path: '/__telescope',
100
100
 
101
101
  // Optional: Record request/response bodies (default: true)
@@ -344,7 +344,7 @@ telescope.destroy();
344
344
  Import from `@geekmidas/telescope/server/hono`:
345
345
 
346
346
  ```typescript
347
- import { createMiddleware, createUI, setupWebSocket, getRequestId } from '@geekmidas/telescope/server/hono';
347
+ import { createApi, createMiddleware, setupWebSocket, getRequestId } from '@geekmidas/telescope/server/hono';
348
348
  ```
349
349
 
350
350
  #### `createMiddleware(telescope)`
@@ -355,12 +355,12 @@ Returns Hono middleware that captures requests and responses.
355
355
  app.use('*', createMiddleware(telescope));
356
356
  ```
357
357
 
358
- #### `createUI(telescope)`
358
+ #### `createApi(telescope)`
359
359
 
360
- Returns a Hono app with dashboard UI and API routes.
360
+ Returns a Hono app serving the JSON API under `/api`.
361
361
 
362
362
  ```typescript
363
- app.route('/__telescope', createUI(telescope));
363
+ app.route('/__telescope', createApi(telescope));
364
364
  ```
365
365
 
366
366
  #### `setupWebSocket(app, telescope, upgradeWebSocket)`
@@ -371,7 +371,7 @@ Set up WebSocket routes for real-time updates.
371
371
  import { createNodeWebSocket } from '@hono/node-ws';
372
372
 
373
373
  const { upgradeWebSocket } = createNodeWebSocket({ app });
374
- setupWebSocket(createUI(telescope), telescope, upgradeWebSocket);
374
+ setupWebSocket(createApi(telescope), telescope, upgradeWebSocket);
375
375
  ```
376
376
 
377
377
  #### `getRequestId(c)`
@@ -542,9 +542,9 @@ const requestLogger = logger.withRequestId('req-abc123');
542
542
  requestLogger.info('Processing request');
543
543
  ```
544
544
 
545
- ## Dashboard API
545
+ ## JSON API
546
546
 
547
- The dashboard UI is served at the configured path. It also exposes a REST API:
547
+ `createApi` serves a read API at the path it is mounted on:
548
548
 
549
549
  | Endpoint | Description |
550
550
  |----------|-------------|
@@ -1,4 +1,4 @@
1
- import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-a9Vistj1.cjs";
1
+ import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-BVujq4zd.mjs";
2
2
  //#region src/metrics/MetricsAggregator.d.ts
3
3
  /**
4
4
  * Configuration for MetricsAggregator
@@ -55,4 +55,4 @@ declare class MetricsAggregator {
55
55
  }
56
56
  //#endregion
57
57
  export { MetricsAggregatorOptions as n, MetricsAggregator as t };
58
- //# sourceMappingURL=MetricsAggregator-BxBLQUPj.d.cts.map
58
+ //# sourceMappingURL=MetricsAggregator-BJdIvfEv.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetricsAggregator-BJdIvfEv.d.mts","names":[],"sources":["../src/metrics/MetricsAggregator.ts"],"mappings":";;;;;UAgBiB;;EAEhB;;EAEA;;EAEA;;cAwBY;UACJ;UACA;UACA;UAEA;EAGR,YAAY,UAAS;;;;EAOrB,OAAO,OAAO;;;;EAiBd,WAAW,UAAS,sBAA2B;;;;EAwD/C,mBAAmB,UAAS,sBAA2B;;;;EAiCvD,sBAAsB,UAAS,sBAA2B;;;;EAwB1D,mBACC,gBACA,cACA,UAAS,sBACP;;;;EAyEH;UAUQ;UAMA;UAuCA;UAuCA;UAsDA;UAmBA;UAgBA;UAMA;UAcA;UAqDA;UAiBA"}
@@ -1,4 +1,4 @@
1
- import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-a9Vistj1.mjs";
1
+ import { f as RequestEntry, g as StatusDistribution, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions } from "./types-BVujq4zd.cjs";
2
2
  //#region src/metrics/MetricsAggregator.d.ts
3
3
  /**
4
4
  * Configuration for MetricsAggregator
@@ -55,4 +55,4 @@ declare class MetricsAggregator {
55
55
  }
56
56
  //#endregion
57
57
  export { MetricsAggregatorOptions as n, MetricsAggregator as t };
58
- //# sourceMappingURL=MetricsAggregator-j9wmZ0K_.d.mts.map
58
+ //# sourceMappingURL=MetricsAggregator-CnC3oT5q.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetricsAggregator-CnC3oT5q.d.cts","names":[],"sources":["../src/metrics/MetricsAggregator.ts"],"mappings":";;;;;UAgBiB;;EAEhB;;EAEA;;EAEA;;cAwBY;UACJ;UACA;UACA;UAEA;EAGR,YAAY,UAAS;;;;EAOrB,OAAO,OAAO;;;;EAiBd,WAAW,UAAS,sBAA2B;;;;EAwD/C,mBAAmB,UAAS,sBAA2B;;;;EAiCvD,sBAAsB,UAAS,sBAA2B;;;;EAwB1D,mBACC,gBACA,cACA,UAAS,sBACP;;;;EAyEH;UAUQ;UAMA;UAuCA;UAuCA;UAsDA;UAmBA;UAgBA;UAMA;UAcA;UAqDA;UAiBA"}
@@ -1,5 +1,5 @@
1
- import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-a9Vistj1.mjs";
2
- import { n as MetricsAggregatorOptions } from "./MetricsAggregator-j9wmZ0K_.mjs";
1
+ import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.mjs";
2
+ import { n as MetricsAggregatorOptions } from "./MetricsAggregator-BJdIvfEv.mjs";
3
3
  //#region src/Telescope.d.ts
4
4
  /**
5
5
  * Framework-agnostic Telescope class for debugging and monitoring applications.
@@ -166,4 +166,4 @@ declare class Telescope {
166
166
  }
167
167
  //#endregion
168
168
  export { Telescope as t };
169
- //# sourceMappingURL=Telescope-BcrWTaar.d.mts.map
169
+ //# sourceMappingURL=Telescope-BVfDvVvY.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Telescope-BcrWTaar.d.mts","names":["_$__types0.TelescopeStats"],"sources":["../src/Telescope.ts"],"mappings":";;;;;;;cA4Ba;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;EAGP,YAAA,SAAS;IAAqB,UAAU;;;;;EAuBnC,cACL,OAAO,KAAK,oCACV;;;;UA+BW;;;;;;;;;;;EAsBR,IACL,SAAS;IACR;IACA;IACA,UAAU;IACV;OAEC;;;;EAsBG,MACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,MACL,iBACA,UAAU,yBACV,qBACE;UAIW;;;;EA4BR,UAAU,OAAO,OAAO,qBAAqB;;;;EA8B7C,YAAY,UAAU,eAAe,QAAQ;;;;EAO7C,WAAW,aAAa,QAAQ;;;;EAOhC,cAAc,UAAU,eAAe,QAAQ;;;;EAO/C,aAAa,aAAa,QAAQ;;;;EAOlC,QAAQ,UAAU,eAAe,QAAQ;;;;EAOzC,YAAQ,QAPyBA;;;;EAkBvC,WAAW,UAAU,sBAAsB;;;;EAO3C,mBAAmB,UAAU,sBAAsB;;;;EAOnD,mBACC,gBACA,cACA,UAAU,sBACR;;;;EAOH,sBAAsB,UAAU,sBAAsB;;;;EAOtD;;;;EAOA,sBAAsB;;;;;;;EAuBtB,sBAAsB;;;;EAoBtB;;;;EAcA,YAAY,IAAI;;;;EAYhB,eAAe,IAAI;;;;EAOnB,UAAU,OAAO;;;;EAkBX,MAAM,WAAW,OAAO;;;;EAO9B;;;;MAeI;;;;MAOA;;;;MAOA;;;;MAOA;;;;EAOJ,aAAa;UAqBL;UAeA;UA2CM"}
1
+ {"version":3,"file":"Telescope-BVfDvVvY.d.mts","names":["_$__types0.TelescopeStats"],"sources":["../src/Telescope.ts"],"mappings":";;;;;;;cA4Ba;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;EAER,YACC,SAAS;IAAqB,UAAU;;;;;EAuBnC,cACL,OAAO,KAAK,oCACV;;;;UA+BW;;;;;;;;;;;EAsBR,IACL,SAAS;IACR;IACA;IACA,UAAU;IACV;OAEC;;;;EAsBG,MACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,MACL,iBACA,UAAU,yBACV,qBACE;UAIW;;;;EA4BR,UAAU,OAAO,OAAO,qBAAqB;;;;EA8B7C,YAAY,UAAU,eAAe,QAAQ;;;;EAO7C,WAAW,aAAa,QAAQ;;;;EAOhC,cAAc,UAAU,eAAe,QAAQ;;;;EAO/C,aAAa,aAAa,QAAQ;;;;EAOlC,QAAQ,UAAU,eAAe,QAAQ;;;;EAOzC,YAAQ,QAPyBA;;;;EAkBvC,WAAW,UAAU,sBAAsB;;;;EAO3C,mBAAmB,UAAU,sBAAsB;;;;EAOnD,mBACC,gBACA,cACA,UAAU,sBACR;;;;EAOH,sBAAsB,UAAU,sBAAsB;;;;EAOtD;;;;EAOA,sBAAsB;;;;;;;EAuBtB,sBAAsB;;;;EAoBtB;;;;EAcA,YAAY,IAAI;;;;EAYhB,eAAe,IAAI;;;;EAOnB,UAAU,OAAO;;;;EAkBX,MAAM,WAAW,OAAO;;;;EAO9B;;;;MAeI;;;;MAOA;;;;MAOA;;;;MAOA;;;;EAOJ,aAAa;UAqBL;UAeA;UA2CM"}
@@ -1,5 +1,5 @@
1
- import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-a9Vistj1.cjs";
2
- import { n as MetricsAggregatorOptions } from "./MetricsAggregator-BxBLQUPj.cjs";
1
+ import { _ as TelescopeEvent, a as LogEntry, c as MetricsSnapshot, f as RequestEntry, g as StatusDistribution, i as ExceptionEntry, n as EndpointDetails, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, u as QueryOptions, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.cjs";
2
+ import { n as MetricsAggregatorOptions } from "./MetricsAggregator-CnC3oT5q.cjs";
3
3
  //#region src/Telescope.d.ts
4
4
  /**
5
5
  * Framework-agnostic Telescope class for debugging and monitoring applications.
@@ -166,4 +166,4 @@ declare class Telescope {
166
166
  }
167
167
  //#endregion
168
168
  export { Telescope as t };
169
- //# sourceMappingURL=Telescope-DnCMZT7V.d.cts.map
169
+ //# sourceMappingURL=Telescope-DeqSHfuB.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Telescope-DnCMZT7V.d.cts","names":["_$__types0.TelescopeStats"],"sources":["../src/Telescope.ts"],"mappings":";;;;;;;cA4Ba;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;EAGP,YAAA,SAAS;IAAqB,UAAU;;;;;EAuBnC,cACL,OAAO,KAAK,oCACV;;;;UA+BW;;;;;;;;;;;EAsBR,IACL,SAAS;IACR;IACA;IACA,UAAU;IACV;OAEC;;;;EAsBG,MACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,MACL,iBACA,UAAU,yBACV,qBACE;UAIW;;;;EA4BR,UAAU,OAAO,OAAO,qBAAqB;;;;EA8B7C,YAAY,UAAU,eAAe,QAAQ;;;;EAO7C,WAAW,aAAa,QAAQ;;;;EAOhC,cAAc,UAAU,eAAe,QAAQ;;;;EAO/C,aAAa,aAAa,QAAQ;;;;EAOlC,QAAQ,UAAU,eAAe,QAAQ;;;;EAOzC,YAAQ,QAPyBA;;;;EAkBvC,WAAW,UAAU,sBAAsB;;;;EAO3C,mBAAmB,UAAU,sBAAsB;;;;EAOnD,mBACC,gBACA,cACA,UAAU,sBACR;;;;EAOH,sBAAsB,UAAU,sBAAsB;;;;EAOtD;;;;EAOA,sBAAsB;;;;;;;EAuBtB,sBAAsB;;;;EAoBtB;;;;EAcA,YAAY,IAAI;;;;EAYhB,eAAe,IAAI;;;;EAOnB,UAAU,OAAO;;;;EAkBX,MAAM,WAAW,OAAO;;;;EAO9B;;;;MAeI;;;;MAOA;;;;MAOA;;;;MAOA;;;;EAOJ,aAAa;UAqBL;UAeA;UA2CM"}
1
+ {"version":3,"file":"Telescope-DeqSHfuB.d.cts","names":["_$__types0.TelescopeStats"],"sources":["../src/Telescope.ts"],"mappings":";;;;;;;cA4Ba;UACJ;UACA;UACA;UACA;UACA;UACA;UACA;EAER,YACC,SAAS;IAAqB,UAAU;;;;;EAuBnC,cACL,OAAO,KAAK,oCACV;;;;UA+BW;;;;;;;;;;;EAsBR,IACL,SAAS;IACR;IACA;IACA,UAAU;IACV;OAEC;;;;EAsBG,MACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,KACL,iBACA,UAAU,yBACV,qBACE;;;;EAOG,MACL,iBACA,UAAU,yBACV,qBACE;UAIW;;;;EA4BR,UAAU,OAAO,OAAO,qBAAqB;;;;EA8B7C,YAAY,UAAU,eAAe,QAAQ;;;;EAO7C,WAAW,aAAa,QAAQ;;;;EAOhC,cAAc,UAAU,eAAe,QAAQ;;;;EAO/C,aAAa,aAAa,QAAQ;;;;EAOlC,QAAQ,UAAU,eAAe,QAAQ;;;;EAOzC,YAAQ,QAPyBA;;;;EAkBvC,WAAW,UAAU,sBAAsB;;;;EAO3C,mBAAmB,UAAU,sBAAsB;;;;EAOnD,mBACC,gBACA,cACA,UAAU,sBACR;;;;EAOH,sBAAsB,UAAU,sBAAsB;;;;EAOtD;;;;EAOA,sBAAsB;;;;;;;EAuBtB,sBAAsB;;;;EAoBtB;;;;EAcA,YAAY,IAAI;;;;EAYhB,eAAe,IAAI;;;;EAOnB,UAAU,OAAO;;;;EAkBX,MAAM,WAAW,OAAO;;;;EAO9B;;;;MAeI;;;;MAOA;;;;MAOA;;;;MAOA;;;;EAOJ,aAAa;UAqBL;UAeA;UA2CM"}
@@ -1,2 +1,2 @@
1
- import { t as Telescope } from "./Telescope-DnCMZT7V.cjs";
1
+ import { t as Telescope } from "./Telescope-DeqSHfuB.cjs";
2
2
  export { Telescope };
@@ -1,2 +1,2 @@
1
- import { t as Telescope } from "./Telescope-BcrWTaar.mjs";
1
+ import { t as Telescope } from "./Telescope-BVfDvVvY.mjs";
2
2
  export { Telescope };
@@ -1,4 +1,4 @@
1
- import { t as Telescope } from "../Telescope-DnCMZT7V.cjs";
1
+ import { t as Telescope } from "../Telescope-DeqSHfuB.cjs";
2
2
  import { AdapterRequestContext, AdapterResponseContext, LambdaAdapterConfig, TelescopeAdapter } from "./types.cjs";
3
3
  import { TelescopeMiddlewareOptions, createTelescopeHandler, telescopeMiddleware } from "./middy.cjs";
4
4
  import { Context } from "aws-lambda";
@@ -1 +1 @@
1
- {"version":3,"file":"lambda.d.cts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;EAEI,YAAA,WAAW,WAAW,SAAQ,QAAQ;EAK5C,WAAW;EAOX,aAAa;;;;EAOnB,sBAAsB,iBAAiB;;;;EAiFvC,uBACC,mBACA,oBACE;;;;EAiCG,SAAS;;;;EAOf,yBAAyB;;;;;;;;;;;;;;;;;wBAoBV,kBAAkB,QAAQ,SACzC,WAAW,WACX,UAAU,OAAO,QAAQ,SAASA,YAAkB,QAAQ,UAC5D,UAAS,QAAQ,wBACd,OAAO,QAAQ,SAASA,YAAkB,QAAQ"}
1
+ {"version":3,"file":"lambda.d.cts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;EAER,YAAY,WAAW,WAAW,SAAQ,QAAQ;EAK5C,WAAW;EAOX,aAAa;;;;EAOnB,sBAAsB,iBAAiB;;;;EAiFvC,uBACC,mBACA,oBACE;;;;EAiCG,SAAS;;;;EAOf,yBAAyB;;;;;;;;;;;;;;;;;wBAoBV,kBAAkB,QAAQ,SACzC,WAAW,WACX,UAAU,OAAO,QAAQ,SAASA,YAAkB,QAAQ,UAC5D,UAAS,QAAQ,wBACd,OAAO,QAAQ,SAASA,YAAkB,QAAQ"}
@@ -1,4 +1,4 @@
1
- import { t as Telescope } from "../Telescope-BcrWTaar.mjs";
1
+ import { t as Telescope } from "../Telescope-BVfDvVvY.mjs";
2
2
  import { AdapterRequestContext, AdapterResponseContext, LambdaAdapterConfig, TelescopeAdapter } from "./types.mjs";
3
3
  import { TelescopeMiddlewareOptions, createTelescopeHandler, telescopeMiddleware } from "./middy.mjs";
4
4
  import { Context } from "aws-lambda";
@@ -1 +1 @@
1
- {"version":3,"file":"lambda.d.mts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;EAEI,YAAA,WAAW,WAAW,SAAQ,QAAQ;EAK5C,WAAW;EAOX,aAAa;;;;EAOnB,sBAAsB,iBAAiB;;;;EAiFvC,uBACC,mBACA,oBACE;;;;EAiCG,SAAS;;;;EAOf,yBAAyB;;;;;;;;;;;;;;;;;wBAoBV,kBAAkB,QAAQ,SACzC,WAAW,WACX,UAAU,OAAO,QAAQ,SAASA,YAAkB,QAAQ,UAC5D,UAAS,QAAQ,wBACd,OAAO,QAAQ,SAASA,YAAkB,QAAQ"}
1
+ {"version":3,"file":"lambda.d.mts","names":["LambdaContext"],"sources":["../../src/adapters/lambda.ts"],"mappings":";;;;;;;;iBAqBiB;EAChB;EACA;EACA;EACA;EACA;EACA;GACC;;;;;wBAMc,yBAAyB;;;;wBAiBzB,+BACf,iBACA,SAASA;EAET;EACA;EACA;EACA;EACA;EACA;;;;;;qBAmCY,yBAAyB,iBAAiB;WAC7C,QAAQ;WACR,WAAW;UACZ;EAER,YAAY,WAAW,WAAW,SAAQ,QAAQ;EAK5C,WAAW;EAOX,aAAa;;;;EAOnB,sBAAsB,iBAAiB;;;;EAiFvC,uBACC,mBACA,oBACE;;;;EAiCG,SAAS;;;;EAOf,yBAAyB;;;;;;;;;;;;;;;;;wBAoBV,kBAAkB,QAAQ,SACzC,WAAW,WACX,UAAU,OAAO,QAAQ,SAASA,YAAkB,QAAQ,UAC5D,UAAS,QAAQ,wBACd,OAAO,QAAQ,SAASA,YAAkB,QAAQ"}
@@ -1,4 +1,4 @@
1
- import { t as Telescope } from "../Telescope-DnCMZT7V.cjs";
1
+ import { t as Telescope } from "../Telescope-DeqSHfuB.cjs";
2
2
  import { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from "aws-lambda";
3
3
  import { MiddlewareObj } from "@middy/core";
4
4
  //#region src/adapters/middy.d.ts
@@ -1,4 +1,4 @@
1
- import { t as Telescope } from "../Telescope-BcrWTaar.mjs";
1
+ import { t as Telescope } from "../Telescope-BVfDvVvY.mjs";
2
2
  import { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from "aws-lambda";
3
3
  import { MiddlewareObj } from "@middy/core";
4
4
  //#region src/adapters/middy.d.ts
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-a9Vistj1.cjs";
2
- import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-BxBLQUPj.cjs";
3
- import { t as Telescope } from "./Telescope-DnCMZT7V.cjs";
1
+ import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.cjs";
2
+ import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-CnC3oT5q.cjs";
3
+ import { t as Telescope } from "./Telescope-DeqSHfuB.cjs";
4
4
  import { InMemoryStorage, InMemoryStorageOptions } from "./storage/memory.cjs";
5
5
  export { type EndpointBucket, type EndpointMetrics, type ExceptionEntry, InMemoryStorage, type InMemoryStorageOptions, type LogEntry, MetricsAggregator, type MetricsAggregatorOptions, type MetricsBucket, type MetricsQueryOptions, type NormalizedTelescopeOptions, type QueryOptions, type RequestContext, type RequestEntry, type RequestMetrics, type SourceContext, type StackFrame, type StatusDistribution, Telescope, type TelescopeEvent, type TelescopeEventType, type TelescopeOptions, type TelescopeStats, type TelescopeStorage, type TimeRange, type TimeSeriesPoint };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-a9Vistj1.mjs";
2
- import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-j9wmZ0K_.mjs";
3
- import { t as Telescope } from "./Telescope-BcrWTaar.mjs";
1
+ import { C as TimeRange, S as TelescopeStorage, _ as TelescopeEvent, a as LogEntry, d as RequestContext, f as RequestEntry, g as StatusDistribution, h as StackFrame, i as ExceptionEntry, l as NormalizedTelescopeOptions, m as SourceContext, o as MetricsBucket, p as RequestMetrics, r as EndpointMetrics, s as MetricsQueryOptions, t as EndpointBucket, u as QueryOptions, v as TelescopeEventType, w as TimeSeriesPoint, x as TelescopeStats, y as TelescopeOptions } from "./types-BVujq4zd.mjs";
2
+ import { n as MetricsAggregatorOptions, t as MetricsAggregator } from "./MetricsAggregator-BJdIvfEv.mjs";
3
+ import { t as Telescope } from "./Telescope-BVfDvVvY.mjs";
4
4
  import { InMemoryStorage, InMemoryStorageOptions } from "./storage/memory.mjs";
5
5
  export { type EndpointBucket, type EndpointMetrics, type ExceptionEntry, InMemoryStorage, type InMemoryStorageOptions, type LogEntry, MetricsAggregator, type MetricsAggregatorOptions, type MetricsBucket, type MetricsQueryOptions, type NormalizedTelescopeOptions, type QueryOptions, type RequestContext, type RequestEntry, type RequestMetrics, type SourceContext, type StackFrame, type StatusDistribution, Telescope, type TelescopeEvent, type TelescopeEventType, type TelescopeOptions, type TelescopeStats, type TelescopeStorage, type TimeRange, type TimeSeriesPoint };
@@ -1,6 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_instrumentation_http = require("./http.cjs");
3
+ const require_instrumentation_trust = require("./trust.cjs");
3
4
  let _opentelemetry_api = require("@opentelemetry/api");
5
+ let hono_route = require("hono/route");
4
6
  //#region src/instrumentation/hono.ts
5
7
  const SPAN_KEY = "telemetry.span";
6
8
  const CONTEXT_KEY = "telemetry.context";
@@ -35,9 +37,9 @@ function honoTelemetryMiddleware(options = {}) {
35
37
  c.req.raw.headers.forEach((value, key) => {
36
38
  headers[key] = value;
37
39
  });
38
- const parentContext = require_instrumentation_http.extractTraceContext(headers);
40
+ const { parent: parentContext, links } = require_instrumentation_http.incomingTraceContext(headers, isTrustedCaller(c, options));
39
41
  const attrs = buildHonoSpanAttributes(c, options);
40
- const span = require_instrumentation_http.createHttpServerSpan(attrs, parentContext);
42
+ const span = require_instrumentation_http.createHttpServerSpan(attrs, parentContext, links);
41
43
  const spanContext = _opentelemetry_api.trace.setSpan(parentContext, span);
42
44
  c.set(SPAN_KEY, span);
43
45
  c.set(CONTEXT_KEY, spanContext);
@@ -49,31 +51,69 @@ function honoTelemetryMiddleware(options = {}) {
49
51
  await _opentelemetry_api.context.with(spanContext, async () => {
50
52
  await next();
51
53
  });
54
+ nameAfterRoute(c, span);
52
55
  const statusCode = c.res.status;
53
56
  if (options.recordResponseBody) try {
54
57
  const body = await c.res.clone().text();
55
58
  if (body) span.setAttribute("http.response.body", body.length > 4096 ? `${body.slice(0, 4096)}...` : body);
56
59
  } catch {}
57
- require_instrumentation_http.endHttpSpan(span, { statusCode });
60
+ require_instrumentation_http.endHttpSpan(span, { statusCode }, c.error);
58
61
  } catch (error) {
62
+ nameAfterRoute(c, span);
59
63
  require_instrumentation_http.endHttpSpan(span, { statusCode: 500 }, error instanceof Error ? error : new Error(String(error)));
60
64
  throw error;
61
65
  }
62
66
  };
63
67
  }
64
68
  /**
69
+ * Whether this request's `traceparent` is continued: from one of the API's
70
+ * own origins, or from an internal caller.
71
+ */
72
+ function isTrustedCaller(c, options) {
73
+ const origin = c.req.header("origin");
74
+ if (origin) {
75
+ const trusted = typeof options.trustedOrigins === "function" ? options.trustedOrigins() : options.trustedOrigins;
76
+ return require_instrumentation_trust.isTrustedOrigin(origin, trusted);
77
+ }
78
+ const internal = options.internalCallers ?? true;
79
+ if (typeof internal === "function") return internal(c);
80
+ if (!internal) return false;
81
+ return require_instrumentation_trust.isInternalCaller({
82
+ headers: c.req.raw.headers,
83
+ remoteAddress: remoteAddressOf(c)
84
+ });
85
+ }
86
+ /** The TCP peer's address under `@hono/node-server`, or undefined. */
87
+ function remoteAddressOf(c) {
88
+ return c.env?.incoming?.socket?.remoteAddress;
89
+ }
90
+ /**
91
+ * The route the request matched, once the handler has run — `/users/:id`,
92
+ * never `/users/42` — or undefined when only middleware ran (a 404).
93
+ *
94
+ * Read after `next()`: before it, the route is this middleware's own `*`.
95
+ */
96
+ function matchedRoute(c) {
97
+ const path = (0, hono_route.routePath)(c);
98
+ return path && !path.includes("*") ? path : void 0;
99
+ }
100
+ /** `GET /users/:id`, or the bare method when no route matched. */
101
+ function nameAfterRoute(c, span) {
102
+ const route = matchedRoute(c);
103
+ if (route) {
104
+ span.setAttribute("http.route", route);
105
+ span.updateName(`${c.req.method} ${route}`);
106
+ } else span.updateName(c.req.method);
107
+ }
108
+ /**
65
109
  * Build span attributes from Hono context
66
110
  */
67
111
  function buildHonoSpanAttributes(c, options) {
68
112
  const req = c.req;
69
113
  const url = new URL(req.url);
70
- const routePath = c.req.routePath;
71
- const route = routePath && routePath !== "*" && !routePath.includes("/*") ? routePath : url.pathname;
72
114
  const attrs = {
73
115
  method: req.method,
74
- url: req.url,
75
116
  path: url.pathname,
76
- route,
77
117
  host: url.host,
78
118
  scheme: url.protocol.replace(":", ""),
79
119
  userAgent: req.header("user-agent"),
@@ -1 +1 @@
1
- {"version":3,"file":"hono.cjs","names":["extractTraceContext","createHttpServerSpan","trace","context"],"sources":["../../src/instrumentation/hono.ts"],"sourcesContent":["import { context, type Span, trace } from '@opentelemetry/api';\n/**\n * OpenTelemetry instrumentation middleware for Hono\n *\n * This middleware automatically creates spans for HTTP requests,\n * extracts trace context from incoming headers, and records\n * request/response metadata as span attributes.\n */\nimport type { Context, MiddlewareHandler } from 'hono';\nimport {\n\tcreateHttpServerSpan,\n\tendHttpSpan,\n\textractTraceContext,\n\ttype HttpSpanAttributes,\n} from './http';\n\n/**\n * Options for the Hono telemetry middleware\n */\nexport interface HonoTelemetryMiddlewareOptions {\n\t/**\n\t * Whether to record request body as span attribute\n\t * @default false\n\t */\n\trecordBody?: boolean;\n\n\t/**\n\t * Whether to record response body as span attribute\n\t * @default false\n\t */\n\trecordResponseBody?: boolean;\n\n\t/**\n\t * Custom function to extract user ID from context\n\t */\n\tgetUserId?: (c: Context) => string | undefined;\n\n\t/**\n\t * Paths to skip tracing (supports wildcards)\n\t */\n\tignorePaths?: string[];\n\n\t/**\n\t * Whether to skip tracing for this request\n\t */\n\tshouldSkip?: (c: Context) => boolean;\n}\n\n// Key for storing span on context\nconst SPAN_KEY = 'telemetry.span';\nconst CONTEXT_KEY = 'telemetry.context';\n\n/**\n * Get the current span from Hono context\n */\nexport function getSpanFromContext(c: Context): Span | undefined {\n\treturn c.get(SPAN_KEY);\n}\n\n/**\n * Get the current trace context from Hono context\n */\nexport function getTraceContextFromHono(c: Context): any {\n\treturn c.get(CONTEXT_KEY);\n}\n\n/**\n * Create a telemetry middleware for Hono applications\n *\n * @example\n * ```typescript\n * import { honoTelemetryMiddleware } from '@geekmidas/telescope/instrumentation';\n *\n * const app = new Hono();\n * app.use('*', honoTelemetryMiddleware());\n * ```\n */\nexport function honoTelemetryMiddleware(\n\toptions: HonoTelemetryMiddlewareOptions = {},\n): MiddlewareHandler {\n\treturn async (c, next) => {\n\t\t// Check if path should be ignored\n\t\tif (\n\t\t\toptions.ignorePaths &&\n\t\t\tshouldIgnorePath(c.req.path, options.ignorePaths)\n\t\t) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Skip if custom skip function returns true\n\t\tif (options.shouldSkip?.(c)) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Extract trace context from headers\n\t\tconst headers: Record<string, string | string[] | undefined> = {};\n\t\tc.req.raw.headers.forEach((value, key) => {\n\t\t\theaders[key] = value;\n\t\t});\n\t\tconst parentContext = extractTraceContext(headers);\n\n\t\t// Build span attributes from request\n\t\tconst attrs = buildHonoSpanAttributes(c, options);\n\n\t\t// Create the span\n\t\tconst span = createHttpServerSpan(attrs, parentContext);\n\t\tconst spanContext = trace.setSpan(parentContext, span);\n\n\t\t// Store span and context on Hono context\n\t\tc.set(SPAN_KEY, span);\n\t\tc.set(CONTEXT_KEY, spanContext);\n\n\t\t// Record body if requested\n\t\tif (options.recordBody) {\n\t\t\ttry {\n\t\t\t\tconst body = await c.req.text();\n\t\t\t\tif (body) {\n\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t'http.request.body',\n\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Body may have already been consumed\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the rest of the middleware chain within span context\n\t\t\tawait context.with(spanContext, async () => {\n\t\t\t\tawait next();\n\t\t\t});\n\n\t\t\t// Record response\n\t\t\tconst statusCode = c.res.status;\n\n\t\t\tif (options.recordResponseBody) {\n\t\t\t\ttry {\n\t\t\t\t\tconst body = await c.res.clone().text();\n\t\t\t\t\tif (body) {\n\t\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t\t'http.response.body',\n\t\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Response body may not be available\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tendHttpSpan(span, { statusCode });\n\t\t} catch (error) {\n\t\t\tendHttpSpan(\n\t\t\t\tspan,\n\t\t\t\t{ statusCode: 500 },\n\t\t\t\terror instanceof Error ? error : new Error(String(error)),\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n\n/**\n * Build span attributes from Hono context\n */\nfunction buildHonoSpanAttributes(\n\tc: Context,\n\toptions: HonoTelemetryMiddlewareOptions,\n): HttpSpanAttributes {\n\tconst req = c.req;\n\tconst url = new URL(req.url);\n\n\t// Use actual path for route unless it's a specific route pattern\n\tconst routePath = c.req.routePath;\n\tconst route =\n\t\troutePath && routePath !== '*' && !routePath.includes('/*')\n\t\t\t? routePath\n\t\t\t: url.pathname;\n\n\tconst attrs: HttpSpanAttributes = {\n\t\tmethod: req.method,\n\t\turl: req.url,\n\t\tpath: url.pathname,\n\t\troute,\n\t\thost: url.host,\n\t\tscheme: url.protocol.replace(':', '') as 'http' | 'https',\n\t\tuserAgent: req.header('user-agent'),\n\t\tclientIp: getClientIp(c),\n\t\trequestId: req.header('x-request-id') || req.header('x-amzn-requestid'),\n\t};\n\n\t// Add user metadata if extractor provided\n\tif (options.getUserId) {\n\t\tconst userId = options.getUserId(c);\n\t\tif (userId) {\n\t\t\tattrs.user = { userId };\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n/**\n * Extract client IP from Hono context\n */\nfunction getClientIp(c: Context): string | undefined {\n\t// Try various headers in order of preference\n\tconst xForwardedFor = c.req.header('x-forwarded-for');\n\tif (xForwardedFor) {\n\t\tconst first = xForwardedFor.split(',')[0];\n\t\treturn first?.trim();\n\t}\n\n\tconst xRealIp = c.req.header('x-real-ip');\n\tif (xRealIp) {\n\t\treturn xRealIp;\n\t}\n\n\t// Try CF-Connecting-IP (Cloudflare)\n\tconst cfConnectingIp = c.req.header('cf-connecting-ip');\n\tif (cfConnectingIp) {\n\t\treturn cfConnectingIp;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Check if path should be ignored\n */\nfunction shouldIgnorePath(path: string, ignorePaths: string[]): boolean {\n\tfor (const pattern of ignorePaths) {\n\t\tif (pattern.endsWith('*')) {\n\t\t\t// Wildcard match\n\t\t\tconst prefix = pattern.slice(0, -1);\n\t\t\tif (path.startsWith(prefix)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (path === pattern) {\n\t\t\t// Exact match\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Run a function within the span context from Hono context\n *\n * @example\n * ```typescript\n * app.get('/api/users', async (c) => {\n * return withHonoSpanContext(c, async () => {\n * // Any spans created here will be children of the request span\n * const users = await fetchUsers();\n * return c.json(users);\n * });\n * });\n * ```\n */\nexport async function withHonoSpanContext<T>(\n\tc: Context,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst ctx = getTraceContextFromHono(c);\n\tif (!ctx) {\n\t\treturn fn();\n\t}\n\treturn context.with(ctx, fn);\n}\n"],"mappings":";;;;AAiDA,MAAM,WAAW;AACjB,MAAM,cAAc;;;;AAKpB,SAAgB,mBAAmB,GAA8B;CAChE,OAAO,EAAE,IAAI,QAAQ;AACtB;;;;AAKA,SAAgB,wBAAwB,GAAiB;CACxD,OAAO,EAAE,IAAI,WAAW;AACzB;;;;;;;;;;;;AAaA,SAAgB,wBACf,UAA0C,CAAC,GACvB;CACpB,OAAO,OAAO,GAAG,SAAS;EAEzB,IACC,QAAQ,eACR,iBAAiB,EAAE,IAAI,MAAM,QAAQ,WAAW,GAEhD,OAAO,KAAK;EAIb,IAAI,QAAQ,aAAa,CAAC,GACzB,OAAO,KAAK;EAIb,MAAM,UAAyD,CAAC;EAChE,EAAE,IAAI,IAAI,QAAQ,SAAS,OAAO,QAAQ;GACzC,QAAQ,OAAO;EAChB,CAAC;EACD,MAAM,gBAAgBA,6BAAAA,oBAAoB,OAAO;EAGjD,MAAM,QAAQ,wBAAwB,GAAG,OAAO;EAGhD,MAAM,OAAOC,6BAAAA,qBAAqB,OAAO,aAAa;EACtD,MAAM,cAAcC,mBAAAA,MAAM,QAAQ,eAAe,IAAI;EAGrD,EAAE,IAAI,UAAU,IAAI;EACpB,EAAE,IAAI,aAAa,WAAW;EAG9B,IAAI,QAAQ,YACX,IAAI;GACH,MAAM,OAAO,MAAM,EAAE,IAAI,KAAK;GAC9B,IAAI,MACH,KAAK,aACJ,qBACA,KAAK,SAAS,OAAO,GAAG,KAAK,MAAM,GAAG,IAAI,EAAE,OAAO,IACpD;EAEF,QAAQ,CAER;EAGD,IAAI;GAEH,MAAMC,mBAAAA,QAAQ,KAAK,aAAa,YAAY;IAC3C,MAAM,KAAK;GACZ,CAAC;GAGD,MAAM,aAAa,EAAE,IAAI;GAEzB,IAAI,QAAQ,oBACX,IAAI;IACH,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,CAAC,KAAK;IACtC,IAAI,MACH,KAAK,aACJ,sBACA,KAAK,SAAS,OAAO,GAAG,KAAK,MAAM,GAAG,IAAI,EAAE,OAAO,IACpD;GAEF,QAAQ,CAER;GAGD,6BAAA,YAAY,MAAM,EAAE,WAAW,CAAC;EACjC,SAAS,OAAO;GACf,6BAAA,YACC,MACA,EAAE,YAAY,IAAI,GAClB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CACzD;GACA,MAAM;EACP;CACD;AACD;;;;AAKA,SAAS,wBACR,GACA,SACqB;CACrB,MAAM,MAAM,EAAE;CACd,MAAM,MAAM,IAAI,IAAI,IAAI,GAAG;CAG3B,MAAM,YAAY,EAAE,IAAI;CACxB,MAAM,QACL,aAAa,cAAc,OAAO,CAAC,UAAU,SAAS,IAAI,IACvD,YACA,IAAI;CAER,MAAM,QAA4B;EACjC,QAAQ,IAAI;EACZ,KAAK,IAAI;EACT,MAAM,IAAI;EACV;EACA,MAAM,IAAI;EACV,QAAQ,IAAI,SAAS,QAAQ,KAAK,EAAE;EACpC,WAAW,IAAI,OAAO,YAAY;EAClC,UAAU,YAAY,CAAC;EACvB,WAAW,IAAI,OAAO,cAAc,KAAK,IAAI,OAAO,kBAAkB;CACvE;CAGA,IAAI,QAAQ,WAAW;EACtB,MAAM,SAAS,QAAQ,UAAU,CAAC;EAClC,IAAI,QACH,MAAM,OAAO,EAAE,OAAO;CAExB;CAEA,OAAO;AACR;;;;AAKA,SAAS,YAAY,GAAgC;CAEpD,MAAM,gBAAgB,EAAE,IAAI,OAAO,iBAAiB;CACpD,IAAI,eAEH,OADc,cAAc,MAAM,GAAG,CAAC,CAAC,EAC3B,EAAE,KAAK;CAGpB,MAAM,UAAU,EAAE,IAAI,OAAO,WAAW;CACxC,IAAI,SACH,OAAO;CAIR,MAAM,iBAAiB,EAAE,IAAI,OAAO,kBAAkB;CACtD,IAAI,gBACH,OAAO;AAIT;;;;AAKA,SAAS,iBAAiB,MAAc,aAAgC;CACvE,KAAK,MAAM,WAAW,aACrB,IAAI,QAAQ,SAAS,GAAG,GAAG;EAE1B,MAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;EAClC,IAAI,KAAK,WAAW,MAAM,GACzB,OAAO;CAET,OAAO,IAAI,SAAS,SAEnB,OAAO;CAGT,OAAO;AACR;;;;;;;;;;;;;;;AAgBA,eAAsB,oBACrB,GACA,IACa;CACb,MAAM,MAAM,wBAAwB,CAAC;CACrC,IAAI,CAAC,KACJ,OAAO,GAAG;CAEX,OAAOA,mBAAAA,QAAQ,KAAK,KAAK,EAAE;AAC5B"}
1
+ {"version":3,"file":"hono.cjs","names":["incomingTraceContext","createHttpServerSpan","trace","context","isTrustedOrigin","isInternalCaller","routePath"],"sources":["../../src/instrumentation/hono.ts"],"sourcesContent":["import { context, type Span, trace } from '@opentelemetry/api';\n/**\n * OpenTelemetry instrumentation middleware for Hono\n *\n * This middleware automatically creates spans for HTTP requests,\n * extracts trace context from incoming headers, and records\n * request/response metadata as span attributes.\n */\nimport type { Context, MiddlewareHandler } from 'hono';\nimport { routePath } from 'hono/route';\nimport {\n\tcreateHttpServerSpan,\n\tendHttpSpan,\n\ttype HttpSpanAttributes,\n\tincomingTraceContext,\n} from './http';\nimport { isInternalCaller, isTrustedOrigin } from './trust';\n\n/**\n * Options for the Hono telemetry middleware\n */\nexport interface HonoTelemetryMiddlewareOptions {\n\t/**\n\t * Whether to record request body as span attribute\n\t * @default false\n\t */\n\trecordBody?: boolean;\n\n\t/**\n\t * Whether to record response body as span attribute\n\t * @default false\n\t */\n\trecordResponseBody?: boolean;\n\n\t/**\n\t * Custom function to extract user ID from context\n\t */\n\tgetUserId?: (c: Context) => string | undefined;\n\n\t/**\n\t * Paths to skip tracing (supports wildcards)\n\t */\n\tignorePaths?: string[];\n\n\t/**\n\t * Whether to skip tracing for this request\n\t */\n\tshouldSkip?: (c: Context) => boolean;\n\n\t/**\n\t * The origins whose `traceparent` is continued: the API's own sites, the\n\t * same list its CORS allows. A request from any other origin starts a new\n\t * trace linked to the one it claimed.\n\t *\n\t * A function is read on each request, for a server that learns its origins\n\t * only once the app has loaded its configuration.\n\t */\n\ttrustedOrigins?: readonly string[] | (() => readonly string[] | undefined);\n\n\t/**\n\t * Whether a request with no `Origin` from an internal caller continues its\n\t * `traceparent` — another service on the private network (see `./trust`):\n\t * no `Origin`, no proxy's forwarding header, and a loopback or private\n\t * peer address, read from `@hono/node-server`'s socket.\n\t *\n\t * `false` trusts no caller without an origin; a function decides itself.\n\t * @default true\n\t */\n\tinternalCallers?: boolean | ((c: Context) => boolean);\n}\n\n// Key for storing span on context\nconst SPAN_KEY = 'telemetry.span';\nconst CONTEXT_KEY = 'telemetry.context';\n\n/**\n * Get the current span from Hono context\n */\nexport function getSpanFromContext(c: Context): Span | undefined {\n\treturn c.get(SPAN_KEY);\n}\n\n/**\n * Get the current trace context from Hono context\n */\nexport function getTraceContextFromHono(c: Context): any {\n\treturn c.get(CONTEXT_KEY);\n}\n\n/**\n * Create a telemetry middleware for Hono applications\n *\n * @example\n * ```typescript\n * import { honoTelemetryMiddleware } from '@geekmidas/telescope/instrumentation';\n *\n * const app = new Hono();\n * app.use('*', honoTelemetryMiddleware());\n * ```\n */\nexport function honoTelemetryMiddleware(\n\toptions: HonoTelemetryMiddlewareOptions = {},\n): MiddlewareHandler {\n\treturn async (c, next) => {\n\t\t// Check if path should be ignored\n\t\tif (\n\t\t\toptions.ignorePaths &&\n\t\t\tshouldIgnorePath(c.req.path, options.ignorePaths)\n\t\t) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Skip if custom skip function returns true\n\t\tif (options.shouldSkip?.(c)) {\n\t\t\treturn next();\n\t\t}\n\n\t\t// Extract trace context from headers\n\t\tconst headers: Record<string, string | string[] | undefined> = {};\n\t\tc.req.raw.headers.forEach((value, key) => {\n\t\t\theaders[key] = value;\n\t\t});\n\t\t// Continued only from a trusted caller; anyone else gets a new trace\n\t\t// that links to the one they claimed.\n\t\tconst { parent: parentContext, links } = incomingTraceContext(\n\t\t\theaders,\n\t\t\tisTrustedCaller(c, options),\n\t\t);\n\n\t\t// Build span attributes from request\n\t\tconst attrs = buildHonoSpanAttributes(c, options);\n\n\t\t// Create the span\n\t\tconst span = createHttpServerSpan(attrs, parentContext, links);\n\t\tconst spanContext = trace.setSpan(parentContext, span);\n\n\t\t// Store span and context on Hono context\n\t\tc.set(SPAN_KEY, span);\n\t\tc.set(CONTEXT_KEY, spanContext);\n\n\t\t// Record body if requested\n\t\tif (options.recordBody) {\n\t\t\ttry {\n\t\t\t\tconst body = await c.req.text();\n\t\t\t\tif (body) {\n\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t'http.request.body',\n\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Body may have already been consumed\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the rest of the middleware chain within span context, so\n\t\t\t// the handler's logs and outbound spans nest under this one.\n\t\t\tawait context.with(spanContext, async () => {\n\t\t\t\tawait next();\n\t\t\t});\n\n\t\t\tnameAfterRoute(c, span);\n\n\t\t\t// Record response\n\t\t\tconst statusCode = c.res.status;\n\n\t\t\tif (options.recordResponseBody) {\n\t\t\t\ttry {\n\t\t\t\t\tconst body = await c.res.clone().text();\n\t\t\t\t\tif (body) {\n\t\t\t\t\t\tspan.setAttribute(\n\t\t\t\t\t\t\t'http.response.body',\n\t\t\t\t\t\t\tbody.length > 4096 ? `${body.slice(0, 4096)}...` : body,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Response body may not be available\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Hono hands a thrown error to `onError` and sets `c.error`\n\t\t\t// rather than rethrowing, so that is where it is found.\n\t\t\tendHttpSpan(span, { statusCode }, c.error);\n\t\t} catch (error) {\n\t\t\tnameAfterRoute(c, span);\n\t\t\tendHttpSpan(\n\t\t\t\tspan,\n\t\t\t\t{ statusCode: 500 },\n\t\t\t\terror instanceof Error ? error : new Error(String(error)),\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n\n/**\n * Whether this request's `traceparent` is continued: from one of the API's\n * own origins, or from an internal caller.\n */\nfunction isTrustedCaller(\n\tc: Context,\n\toptions: HonoTelemetryMiddlewareOptions,\n): boolean {\n\tconst origin = c.req.header('origin');\n\tif (origin) {\n\t\tconst trusted =\n\t\t\ttypeof options.trustedOrigins === 'function'\n\t\t\t\t? options.trustedOrigins()\n\t\t\t\t: options.trustedOrigins;\n\t\treturn isTrustedOrigin(origin, trusted);\n\t}\n\n\tconst internal = options.internalCallers ?? true;\n\tif (typeof internal === 'function') return internal(c);\n\tif (!internal) return false;\n\treturn isInternalCaller({\n\t\theaders: c.req.raw.headers,\n\t\tremoteAddress: remoteAddressOf(c),\n\t});\n}\n\n/** The TCP peer's address under `@hono/node-server`, or undefined. */\nfunction remoteAddressOf(c: Context): string | undefined {\n\tconst env = c.env as\n\t\t| { incoming?: { socket?: { remoteAddress?: string } } }\n\t\t| undefined;\n\treturn env?.incoming?.socket?.remoteAddress;\n}\n\n/**\n * The route the request matched, once the handler has run — `/users/:id`,\n * never `/users/42` — or undefined when only middleware ran (a 404).\n *\n * Read after `next()`: before it, the route is this middleware's own `*`.\n */\nfunction matchedRoute(c: Context): string | undefined {\n\tconst path = routePath(c);\n\treturn path && !path.includes('*') ? path : undefined;\n}\n\n/** `GET /users/:id`, or the bare method when no route matched. */\nfunction nameAfterRoute(c: Context, span: Span): void {\n\tconst route = matchedRoute(c);\n\tif (route) {\n\t\tspan.setAttribute('http.route', route);\n\t\tspan.updateName(`${c.req.method} ${route}`);\n\t} else {\n\t\tspan.updateName(c.req.method);\n\t}\n}\n\n/**\n * Build span attributes from Hono context\n */\nfunction buildHonoSpanAttributes(\n\tc: Context,\n\toptions: HonoTelemetryMiddlewareOptions,\n): HttpSpanAttributes {\n\tconst req = c.req;\n\tconst url = new URL(req.url);\n\n\t// No `url.full`: a query string can carry a token, and the span would\n\t// keep it. The route is named once the handler has run.\n\tconst attrs: HttpSpanAttributes = {\n\t\tmethod: req.method,\n\t\tpath: url.pathname,\n\t\thost: url.host,\n\t\tscheme: url.protocol.replace(':', '') as 'http' | 'https',\n\t\tuserAgent: req.header('user-agent'),\n\t\tclientIp: getClientIp(c),\n\t\trequestId: req.header('x-request-id') || req.header('x-amzn-requestid'),\n\t};\n\n\t// Add user metadata if extractor provided\n\tif (options.getUserId) {\n\t\tconst userId = options.getUserId(c);\n\t\tif (userId) {\n\t\t\tattrs.user = { userId };\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n/**\n * Extract client IP from Hono context\n */\nfunction getClientIp(c: Context): string | undefined {\n\t// Try various headers in order of preference\n\tconst xForwardedFor = c.req.header('x-forwarded-for');\n\tif (xForwardedFor) {\n\t\tconst first = xForwardedFor.split(',')[0];\n\t\treturn first?.trim();\n\t}\n\n\tconst xRealIp = c.req.header('x-real-ip');\n\tif (xRealIp) {\n\t\treturn xRealIp;\n\t}\n\n\t// Try CF-Connecting-IP (Cloudflare)\n\tconst cfConnectingIp = c.req.header('cf-connecting-ip');\n\tif (cfConnectingIp) {\n\t\treturn cfConnectingIp;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Check if path should be ignored\n */\nfunction shouldIgnorePath(path: string, ignorePaths: string[]): boolean {\n\tfor (const pattern of ignorePaths) {\n\t\tif (pattern.endsWith('*')) {\n\t\t\t// Wildcard match\n\t\t\tconst prefix = pattern.slice(0, -1);\n\t\t\tif (path.startsWith(prefix)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (path === pattern) {\n\t\t\t// Exact match\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Run a function within the span context from Hono context\n *\n * @example\n * ```typescript\n * app.get('/api/users', async (c) => {\n * return withHonoSpanContext(c, async () => {\n * // Any spans created here will be children of the request span\n * const users = await fetchUsers();\n * return c.json(users);\n * });\n * });\n * ```\n */\nexport async function withHonoSpanContext<T>(\n\tc: Context,\n\tfn: () => Promise<T>,\n): Promise<T> {\n\tconst ctx = getTraceContextFromHono(c);\n\tif (!ctx) {\n\t\treturn fn();\n\t}\n\treturn context.with(ctx, fn);\n}\n"],"mappings":"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"}
@@ -27,6 +27,25 @@ export interface HonoTelemetryMiddlewareOptions {
27
27
  * Whether to skip tracing for this request
28
28
  */
29
29
  shouldSkip?: (c: Context) => boolean;
30
+ /**
31
+ * The origins whose `traceparent` is continued: the API's own sites, the
32
+ * same list its CORS allows. A request from any other origin starts a new
33
+ * trace linked to the one it claimed.
34
+ *
35
+ * A function is read on each request, for a server that learns its origins
36
+ * only once the app has loaded its configuration.
37
+ */
38
+ trustedOrigins?: readonly string[] | (() => readonly string[] | undefined);
39
+ /**
40
+ * Whether a request with no `Origin` from an internal caller continues its
41
+ * `traceparent` — another service on the private network (see `./trust`):
42
+ * no `Origin`, no proxy's forwarding header, and a loopback or private
43
+ * peer address, read from `@hono/node-server`'s socket.
44
+ *
45
+ * `false` trusts no caller without an origin; a function decides itself.
46
+ * @default true
47
+ */
48
+ internalCallers?: boolean | ((c: Context) => boolean);
30
49
  }
31
50
  /**
32
51
  * Get the current span from Hono context
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.cts","names":[],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;iBAmBiB;;;;;EAKhB;;;;;EAMA;;;;EAKA,aAAa,GAAG;;;;EAKhB;;;;EAKA,cAAc,GAAG;;;;;wBAUF,mBAAmB,GAAG,UAAU;;;;wBAOhC,wBAAwB,GAAG;;;;;;;;;;;;wBAe3B,wBACf,UAAS,iCACP;;;;;;;;;;;;;;;wBAqLmB,oBAAoB,GACzC,GAAG,SACH,UAAU,QAAQ,KAChB,QAAQ"}
1
+ {"version":3,"file":"hono.d.cts","names":[],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;iBAqBiB;;;;;EAKhB;;;;;EAMA;;;;EAKA,aAAa,GAAG;;;;EAKhB;;;;EAKA,cAAc,GAAG;;;;;;;;;EAUjB;;;;;;;;;;EAWA,8BAA8B,GAAG;;;;;wBAUlB,mBAAmB,GAAG,UAAU;;;;wBAOhC,wBAAwB,GAAG;;;;;;;;;;;;wBAe3B,wBACf,UAAS,iCACP;;;;;;;;;;;;;;;wBAiPmB,oBAAoB,GACzC,GAAG,SACH,UAAU,QAAQ,KAChB,QAAQ"}
@@ -27,6 +27,25 @@ export interface HonoTelemetryMiddlewareOptions {
27
27
  * Whether to skip tracing for this request
28
28
  */
29
29
  shouldSkip?: (c: Context$1) => boolean;
30
+ /**
31
+ * The origins whose `traceparent` is continued: the API's own sites, the
32
+ * same list its CORS allows. A request from any other origin starts a new
33
+ * trace linked to the one it claimed.
34
+ *
35
+ * A function is read on each request, for a server that learns its origins
36
+ * only once the app has loaded its configuration.
37
+ */
38
+ trustedOrigins?: readonly string[] | (() => readonly string[] | undefined);
39
+ /**
40
+ * Whether a request with no `Origin` from an internal caller continues its
41
+ * `traceparent` — another service on the private network (see `./trust`):
42
+ * no `Origin`, no proxy's forwarding header, and a loopback or private
43
+ * peer address, read from `@hono/node-server`'s socket.
44
+ *
45
+ * `false` trusts no caller without an origin; a function decides itself.
46
+ * @default true
47
+ */
48
+ internalCallers?: boolean | ((c: Context$1) => boolean);
30
49
  }
31
50
  /**
32
51
  * Get the current span from Hono context
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.mts","names":["Context"],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;iBAmBiB;;;;;EAKhB;;;;;EAMA;;;;EAKA,aAAa,GAAGA;;;;EAKhB;;;;EAKA,cAAc,GAAGA;;;;;wBAUF,mBAAmB,GAAGA,YAAU;;;;wBAOhC,wBAAwB,GAAGA;;;;;;;;;;;;wBAe3B,wBACf,UAAS,iCACP;;;;;;;;;;;;;;;wBAqLmB,oBAAoB,GACzC,GAAGA,WACH,UAAU,QAAQ,KAChB,QAAQ"}
1
+ {"version":3,"file":"hono.d.mts","names":["Context"],"sources":["../../src/instrumentation/hono.ts"],"mappings":";;;;;;iBAqBiB;;;;;EAKhB;;;;;EAMA;;;;EAKA,aAAa,GAAGA;;;;EAKhB;;;;EAKA,cAAc,GAAGA;;;;;;;;;EAUjB;;;;;;;;;;EAWA,8BAA8B,GAAGA;;;;;wBAUlB,mBAAmB,GAAGA,YAAU;;;;wBAOhC,wBAAwB,GAAGA;;;;;;;;;;;;wBAe3B,wBACf,UAAS,iCACP;;;;;;;;;;;;;;;wBAiPmB,oBAAoB,GACzC,GAAGA,WACH,UAAU,QAAQ,KAChB,QAAQ"}
@@ -1,5 +1,7 @@
1
- import { createHttpServerSpan, endHttpSpan, extractTraceContext } from "./http.mjs";
1
+ import { createHttpServerSpan, endHttpSpan, incomingTraceContext } from "./http.mjs";
2
+ import { isInternalCaller, isTrustedOrigin } from "./trust.mjs";
2
3
  import { context, trace } from "@opentelemetry/api";
4
+ import { routePath } from "hono/route";
3
5
  //#region src/instrumentation/hono.ts
4
6
  const SPAN_KEY = "telemetry.span";
5
7
  const CONTEXT_KEY = "telemetry.context";
@@ -34,9 +36,9 @@ function honoTelemetryMiddleware(options = {}) {
34
36
  c.req.raw.headers.forEach((value, key) => {
35
37
  headers[key] = value;
36
38
  });
37
- const parentContext = extractTraceContext(headers);
39
+ const { parent: parentContext, links } = incomingTraceContext(headers, isTrustedCaller(c, options));
38
40
  const attrs = buildHonoSpanAttributes(c, options);
39
- const span = createHttpServerSpan(attrs, parentContext);
41
+ const span = createHttpServerSpan(attrs, parentContext, links);
40
42
  const spanContext = trace.setSpan(parentContext, span);
41
43
  c.set(SPAN_KEY, span);
42
44
  c.set(CONTEXT_KEY, spanContext);
@@ -48,31 +50,69 @@ function honoTelemetryMiddleware(options = {}) {
48
50
  await context.with(spanContext, async () => {
49
51
  await next();
50
52
  });
53
+ nameAfterRoute(c, span);
51
54
  const statusCode = c.res.status;
52
55
  if (options.recordResponseBody) try {
53
56
  const body = await c.res.clone().text();
54
57
  if (body) span.setAttribute("http.response.body", body.length > 4096 ? `${body.slice(0, 4096)}...` : body);
55
58
  } catch {}
56
- endHttpSpan(span, { statusCode });
59
+ endHttpSpan(span, { statusCode }, c.error);
57
60
  } catch (error) {
61
+ nameAfterRoute(c, span);
58
62
  endHttpSpan(span, { statusCode: 500 }, error instanceof Error ? error : new Error(String(error)));
59
63
  throw error;
60
64
  }
61
65
  };
62
66
  }
63
67
  /**
68
+ * Whether this request's `traceparent` is continued: from one of the API's
69
+ * own origins, or from an internal caller.
70
+ */
71
+ function isTrustedCaller(c, options) {
72
+ const origin = c.req.header("origin");
73
+ if (origin) {
74
+ const trusted = typeof options.trustedOrigins === "function" ? options.trustedOrigins() : options.trustedOrigins;
75
+ return isTrustedOrigin(origin, trusted);
76
+ }
77
+ const internal = options.internalCallers ?? true;
78
+ if (typeof internal === "function") return internal(c);
79
+ if (!internal) return false;
80
+ return isInternalCaller({
81
+ headers: c.req.raw.headers,
82
+ remoteAddress: remoteAddressOf(c)
83
+ });
84
+ }
85
+ /** The TCP peer's address under `@hono/node-server`, or undefined. */
86
+ function remoteAddressOf(c) {
87
+ return c.env?.incoming?.socket?.remoteAddress;
88
+ }
89
+ /**
90
+ * The route the request matched, once the handler has run — `/users/:id`,
91
+ * never `/users/42` — or undefined when only middleware ran (a 404).
92
+ *
93
+ * Read after `next()`: before it, the route is this middleware's own `*`.
94
+ */
95
+ function matchedRoute(c) {
96
+ const path = routePath(c);
97
+ return path && !path.includes("*") ? path : void 0;
98
+ }
99
+ /** `GET /users/:id`, or the bare method when no route matched. */
100
+ function nameAfterRoute(c, span) {
101
+ const route = matchedRoute(c);
102
+ if (route) {
103
+ span.setAttribute("http.route", route);
104
+ span.updateName(`${c.req.method} ${route}`);
105
+ } else span.updateName(c.req.method);
106
+ }
107
+ /**
64
108
  * Build span attributes from Hono context
65
109
  */
66
110
  function buildHonoSpanAttributes(c, options) {
67
111
  const req = c.req;
68
112
  const url = new URL(req.url);
69
- const routePath = c.req.routePath;
70
- const route = routePath && routePath !== "*" && !routePath.includes("/*") ? routePath : url.pathname;
71
113
  const attrs = {
72
114
  method: req.method,
73
- url: req.url,
74
115
  path: url.pathname,
75
- route,
76
116
  host: url.host,
77
117
  scheme: url.protocol.replace(":", ""),
78
118
  userAgent: req.header("user-agent"),