@sentry/nitro 10.60.0 → 10.62.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.
@@ -1 +1 @@
1
- {"type":"module","version":"10.60.0","sideEffects":false}
1
+ {"type":"module","version":"10.62.0","sideEffects":false}
@@ -1,5 +1,6 @@
1
- import { GLOBAL_OBJ, startSpanManual, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP, captureException, SPAN_STATUS_ERROR, flushIfServerless, SEMANTIC_ATTRIBUTE_CACHE_HIT, SPAN_STATUS_OK } from '@sentry/core';
2
- import { tracingChannel } from '@sentry/opentelemetry/tracing-channel';
1
+ import * as dc from 'node:diagnostics_channel';
2
+ import { GLOBAL_OBJ, startInactiveSpan, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_CACHE_HIT, flushIfServerless } from '@sentry/core';
3
+ import { bindTracingChannelToSpan } from '@sentry/server-utils';
3
4
 
4
5
  const ORIGIN = "auto.cache.nitro";
5
6
  const globalWithStorageChannels = GLOBAL_OBJ;
@@ -29,10 +30,14 @@ function captureStorageEvents() {
29
30
  function setupStorageTracingChannel(operation) {
30
31
  const keys = (data) => data.keys ?? [];
31
32
  const mountBase = (data) => (data.base ?? "").replace(/:$/, "");
32
- const channel = tracingChannel(`unstorage.${operation}`, (data) => {
33
- const cacheKeys = keys(data);
34
- return startSpanManual(
35
- {
33
+ if (!dc.tracingChannel) {
34
+ return;
35
+ }
36
+ bindTracingChannelToSpan(
37
+ dc.tracingChannel(`unstorage.${operation}`),
38
+ (data) => {
39
+ const cacheKeys = keys(data);
40
+ return startInactiveSpan({
36
41
  name: cacheKeys.join(", ") || operation,
37
42
  attributes: {
38
43
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `cache.${normalizeMethodName(operation)}`,
@@ -42,29 +47,21 @@ function setupStorageTracingChannel(operation) {
42
47
  "db.collection.name": mountBase(data),
43
48
  "db.system.name": data.driver?.name ?? "unknown"
44
49
  }
45
- },
46
- (span) => span
47
- );
48
- });
49
- channel.subscribe({
50
- asyncEnd(data) {
51
- if (data._sentrySpan && CACHE_HIT_OPERATIONS.has(operation)) {
52
- const hit = operation === "hasItem" ? Boolean(data.result) : isCacheHit(data.keys?.[0], data.result);
53
- data._sentrySpan.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);
54
- }
55
- data._sentrySpan?.setStatus({ code: SPAN_STATUS_OK });
56
- data._sentrySpan?.end();
57
- void flushIfServerless();
58
- },
59
- error(data) {
60
- captureException(data.error, {
61
- mechanism: { handled: false, type: ORIGIN }
62
50
  });
63
- data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: "internal_error" });
64
- data._sentrySpan?.end();
65
- void flushIfServerless();
51
+ },
52
+ {
53
+ beforeSpanEnd(span, data) {
54
+ if (!("error" in data)) {
55
+ const result = data.result;
56
+ if (CACHE_HIT_OPERATIONS.has(operation)) {
57
+ const hit = operation === "hasItem" ? Boolean(result) : isCacheHit(data.keys?.[0], result);
58
+ span.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);
59
+ }
60
+ }
61
+ void flushIfServerless();
62
+ }
66
63
  }
67
- });
64
+ );
68
65
  }
69
66
  function normalizeMethodName(methodName) {
70
67
  return methodName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
@@ -1 +1 @@
1
- {"version":3,"file":"captureStorageEvents.js","sources":["../../../../src/runtime/hooks/captureStorageEvents.ts"],"sourcesContent":["import {\n captureException,\n flushIfServerless,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_CACHE_HIT,\n SEMANTIC_ATTRIBUTE_CACHE_KEY,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n SPAN_STATUS_OK,\n startSpanManual,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport type { TraceContext } from 'unstorage/tracing';\n\nconst ORIGIN = 'auto.cache.nitro';\n\nconst globalWithStorageChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__: boolean;\n};\n\nconst TRACED_OPERATIONS = [\n 'hasItem',\n 'getItem',\n 'getItemRaw',\n 'getItems',\n 'setItem',\n 'setItemRaw',\n 'setItems',\n 'removeItem',\n 'getKeys',\n 'clear',\n] as const;\n\ntype TracedOperation = (typeof TRACED_OPERATIONS)[number];\n\nconst CACHE_HIT_OPERATIONS = new Set<TracedOperation>(['hasItem', 'getItem', 'getItemRaw']);\n\nconst CACHED_FN_HANDLERS_RE = /^nitro:(functions|handlers):/i;\n\n/**\n * Subscribes to unstorage tracing channels and creates Sentry spans for storage operations.\n */\nexport function captureStorageEvents(): void {\n if (globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n for (const operation of TRACED_OPERATIONS) {\n setupStorageTracingChannel(operation);\n }\n\n globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__ = true;\n}\n\nfunction setupStorageTracingChannel(operation: TracedOperation): void {\n const keys = (data: TraceContext): string[] => data.keys ?? [];\n const mountBase = (data: TraceContext): string => (data.base ?? '').replace(/:$/, '');\n\n const channel = tracingChannel<TraceContext>(`unstorage.${operation}`, data => {\n const cacheKeys = keys(data);\n\n return startSpanManual(\n {\n name: cacheKeys.join(', ') || operation,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `cache.${normalizeMethodName(operation)}`,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_CACHE_KEY]: cacheKeys.length > 1 ? cacheKeys : cacheKeys[0],\n 'db.operation.name': operation,\n 'db.collection.name': mountBase(data),\n 'db.system.name': data.driver?.name ?? 'unknown',\n },\n },\n span => span,\n );\n });\n\n channel.subscribe({\n asyncEnd(data: TracingChannelContextWithSpan<TraceContext & { result?: unknown }>) {\n if (data._sentrySpan && CACHE_HIT_OPERATIONS.has(operation)) {\n const hit = operation === 'hasItem' ? Boolean(data.result) : isCacheHit(data.keys?.[0], data.result);\n data._sentrySpan.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);\n }\n\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_OK });\n data._sentrySpan?.end();\n\n void flushIfServerless();\n },\n error(data: TracingChannelContextWithSpan<TraceContext & { error?: unknown }>) {\n captureException(data.error, {\n mechanism: { handled: false, type: ORIGIN },\n });\n\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n data._sentrySpan?.end();\n\n void flushIfServerless();\n },\n });\n}\n\nfunction normalizeMethodName(methodName: string): string {\n return methodName.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction isEmptyValue(value: unknown): value is null | undefined {\n return value === null || value === undefined;\n}\n\ninterface CacheEntry<T = unknown> {\n value?: T;\n expires?: number;\n}\n\ninterface ResponseCacheEntry {\n status?: number;\n body?: unknown;\n headers?: Record<string, string | undefined>;\n}\n\nfunction isCacheHit(key: unknown, value: unknown): boolean {\n try {\n const isEmpty = isEmptyValue(value);\n if (isEmpty || typeof key !== 'string' || !CACHED_FN_HANDLERS_RE.test(key)) {\n return !isEmpty;\n }\n\n const entry = typeof value === 'string' ? (JSON.parse(value) as CacheEntry) : (value as CacheEntry);\n\n return validateCacheEntry(key, entry);\n } catch {\n return false;\n }\n}\n\nfunction validateCacheEntry(\n key: string,\n entry: CacheEntry | CacheEntry<ResponseCacheEntry & { status: number }>,\n): boolean {\n if (isEmptyValue(entry.value)) {\n return false;\n }\n\n if (Date.now() > (entry.expires || 0)) {\n return false;\n }\n\n if (isResponseCacheEntry(key, entry)) {\n if ((entry.value.status ?? 0) >= 400) {\n return false;\n }\n\n if (entry.value.body === undefined) {\n return false;\n }\n\n if (entry.value.headers?.etag === 'undefined' || entry.value.headers?.['last-modified'] === 'undefined') {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isResponseCacheEntry(key: string, _: CacheEntry): _ is CacheEntry<ResponseCacheEntry & { status: number }> {\n return key.startsWith('nitro:handlers:');\n}\n"],"names":[],"mappings":";;;AAeA,MAAM,MAAA,GAAS,kBAAA;AAEf,MAAM,yBAAA,GAA4B,UAAA;AAIlC,MAAM,iBAAA,GAAoB;AAAA,EACxB,SAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAIA,MAAM,uCAAuB,IAAI,GAAA,CAAqB,CAAC,SAAA,EAAW,SAAA,EAAW,YAAY,CAAC,CAAA;AAE1F,MAAM,qBAAA,GAAwB,+BAAA;AAKvB,SAAS,oBAAA,GAA6B;AAC3C,EAAA,IAAI,0BAA0B,8CAAA,EAAgD;AAC5E,IAAA;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,aAAa,iBAAA,EAAmB;AACzC,IAAA,0BAAA,CAA2B,SAAS,CAAA;AAAA,EACtC;AAEA,EAAA,yBAAA,CAA0B,8CAAA,GAAiD,IAAA;AAC7E;AAEA,SAAS,2BAA2B,SAAA,EAAkC;AACpE,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAiC,IAAA,CAAK,QAAQ,EAAC;AAC7D,EAAA,MAAM,SAAA,GAAY,CAAC,IAAA,KAAA,CAAgC,IAAA,CAAK,QAAQ,EAAA,EAAI,OAAA,CAAQ,MAAM,EAAE,CAAA;AAEpF,EAAA,MAAM,OAAA,GAAU,cAAA,CAA6B,CAAA,UAAA,EAAa,SAAS,IAAI,CAAA,IAAA,KAAQ;AAC7E,IAAA,MAAM,SAAA,GAAY,KAAK,IAAI,CAAA;AAE3B,IAAA,OAAO,eAAA;AAAA,MACL;AAAA,QACE,IAAA,EAAM,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,IAAK,SAAA;AAAA,QAC9B,UAAA,EAAY;AAAA,UACV,CAAC,4BAA4B,GAAG,CAAA,MAAA,EAAS,mBAAA,CAAoB,SAAS,CAAC,CAAA,CAAA;AAAA,UACvE,CAAC,gCAAgC,GAAG,MAAA;AAAA,UACpC,CAAC,4BAA4B,GAAG,SAAA,CAAU,SAAS,CAAA,GAAI,SAAA,GAAY,UAAU,CAAC,CAAA;AAAA,UAC9E,mBAAA,EAAqB,SAAA;AAAA,UACrB,oBAAA,EAAsB,UAAU,IAAI,CAAA;AAAA,UACpC,gBAAA,EAAkB,IAAA,CAAK,MAAA,EAAQ,IAAA,IAAQ;AAAA;AACzC,OACF;AAAA,MACA,CAAA,IAAA,KAAQ;AAAA,KACV;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,SAAA,CAAU;AAAA,IAChB,SAAS,IAAA,EAA0E;AACjF,MAAA,IAAI,IAAA,CAAK,WAAA,IAAe,oBAAA,CAAqB,GAAA,CAAI,SAAS,CAAA,EAAG;AAC3D,QAAA,MAAM,GAAA,GAAM,SAAA,KAAc,SAAA,GAAY,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,GAAI,UAAA,CAAW,IAAA,CAAK,IAAA,GAAO,CAAC,CAAA,EAAG,KAAK,MAAM,CAAA;AACnG,QAAA,IAAA,CAAK,WAAA,CAAY,YAAA,CAAa,4BAAA,EAA8B,GAAG,CAAA;AAAA,MACjE;AAEA,MAAA,IAAA,CAAK,WAAA,EAAa,SAAA,CAAU,EAAE,IAAA,EAAM,gBAAgB,CAAA;AACpD,MAAA,IAAA,CAAK,aAAa,GAAA,EAAI;AAEtB,MAAA,KAAK,iBAAA,EAAkB;AAAA,IACzB,CAAA;AAAA,IACA,MAAM,IAAA,EAAyE;AAC7E,MAAA,gBAAA,CAAiB,KAAK,KAAA,EAAO;AAAA,QAC3B,SAAA,EAAW,EAAE,OAAA,EAAS,KAAA,EAAO,MAAM,MAAA;AAAO,OAC3C,CAAA;AAED,MAAA,IAAA,CAAK,aAAa,SAAA,CAAU,EAAE,MAAM,iBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AAClF,MAAA,IAAA,CAAK,aAAa,GAAA,EAAI;AAEtB,MAAA,KAAK,iBAAA,EAAkB;AAAA,IACzB;AAAA,GACD,CAAA;AACH;AAEA,SAAS,oBAAoB,UAAA,EAA4B;AACvD,EAAA,OAAO,UAAA,CAAW,QAAQ,QAAA,EAAU,CAAA,MAAA,KAAU,IAAI,MAAA,CAAO,WAAA,EAAa,CAAA,CAAE,CAAA;AAC1E;AAEA,SAAS,aAAa,KAAA,EAA2C;AAC/D,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAaA,SAAS,UAAA,CAAW,KAAc,KAAA,EAAyB;AACzD,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,aAAa,KAAK,CAAA;AAClC,IAAA,IAAI,OAAA,IAAW,OAAO,GAAA,KAAQ,QAAA,IAAY,CAAC,qBAAA,CAAsB,IAAA,CAAK,GAAG,CAAA,EAAG;AAC1E,MAAA,OAAO,CAAC,OAAA;AAAA,IACV;AAEA,IAAA,MAAM,QAAQ,OAAO,KAAA,KAAU,WAAY,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,GAAoB,KAAA;AAE/E,IAAA,OAAO,kBAAA,CAAmB,KAAK,KAAK,CAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAA,CACP,KACA,KAAA,EACS;AACT,EAAA,IAAI,YAAA,CAAa,KAAA,CAAM,KAAK,CAAA,EAAG;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,WAAW,CAAA,CAAA,EAAI;AACrC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,oBAAA,CAAqB,GAAU,CAAA,EAAG;AACpC,IAAA,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,MAAA,IAAU,CAAA,KAAM,GAAA,EAAK;AACpC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,CAAM,IAAA,KAAS,MAAA,EAAW;AAClC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,CAAM,OAAA,EAAS,IAAA,KAAS,WAAA,IAAe,MAAM,KAAA,CAAM,OAAA,GAAU,eAAe,CAAA,KAAM,WAAA,EAAa;AACvG,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,oBAAA,CAAqB,KAAa,CAAA,EAAyE;AAClH,EAAA,OAAO,GAAA,CAAI,WAAW,iBAAiB,CAAA;AACzC;;;;"}
1
+ {"version":3,"file":"captureStorageEvents.js","sources":["../../../../src/runtime/hooks/captureStorageEvents.ts"],"sourcesContent":["import * as dc from 'node:diagnostics_channel';\nimport {\n flushIfServerless,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_CACHE_HIT,\n SEMANTIC_ATTRIBUTE_CACHE_KEY,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startInactiveSpan,\n} from '@sentry/core';\nimport { bindTracingChannelToSpan } from '@sentry/server-utils';\nimport type { TraceContext } from 'unstorage/tracing';\n\nconst ORIGIN = 'auto.cache.nitro';\n\nconst globalWithStorageChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__: boolean;\n};\n\nconst TRACED_OPERATIONS = [\n 'hasItem',\n 'getItem',\n 'getItemRaw',\n 'getItems',\n 'setItem',\n 'setItemRaw',\n 'setItems',\n 'removeItem',\n 'getKeys',\n 'clear',\n] as const;\n\ntype TracedOperation = (typeof TRACED_OPERATIONS)[number];\n\nconst CACHE_HIT_OPERATIONS = new Set<TracedOperation>(['hasItem', 'getItem', 'getItemRaw']);\n\nconst CACHED_FN_HANDLERS_RE = /^nitro:(functions|handlers):/i;\n\n/**\n * Subscribes to unstorage tracing channels and creates Sentry spans for storage operations.\n */\nexport function captureStorageEvents(): void {\n if (globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n for (const operation of TRACED_OPERATIONS) {\n setupStorageTracingChannel(operation);\n }\n\n globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__ = true;\n}\n\nfunction setupStorageTracingChannel(operation: TracedOperation): void {\n const keys = (data: TraceContext): string[] => data.keys ?? [];\n const mountBase = (data: TraceContext): string => (data.base ?? '').replace(/:$/, '');\n\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n bindTracingChannelToSpan(\n dc.tracingChannel<TraceContext>(`unstorage.${operation}`),\n data => {\n const cacheKeys = keys(data);\n\n return startInactiveSpan({\n name: cacheKeys.join(', ') || operation,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `cache.${normalizeMethodName(operation)}`,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_CACHE_KEY]: cacheKeys.length > 1 ? cacheKeys : cacheKeys[0],\n 'db.operation.name': operation,\n 'db.collection.name': mountBase(data),\n 'db.system.name': data.driver?.name ?? 'unknown',\n },\n });\n },\n {\n beforeSpanEnd(span, data) {\n // Error status is set by the binding; the error itself is captured at the request boundary,\n // not here (cache ops aren't an error boundary). Only enrich the success path.\n if (!('error' in data)) {\n const result = (data as { result?: unknown }).result;\n if (CACHE_HIT_OPERATIONS.has(operation)) {\n const hit = operation === 'hasItem' ? Boolean(result) : isCacheHit(data.keys?.[0], result);\n span.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);\n }\n }\n\n void flushIfServerless();\n },\n },\n );\n}\n\nfunction normalizeMethodName(methodName: string): string {\n return methodName.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction isEmptyValue(value: unknown): value is null | undefined {\n return value === null || value === undefined;\n}\n\ninterface CacheEntry<T = unknown> {\n value?: T;\n expires?: number;\n}\n\ninterface ResponseCacheEntry {\n status?: number;\n body?: unknown;\n headers?: Record<string, string | undefined>;\n}\n\nfunction isCacheHit(key: unknown, value: unknown): boolean {\n try {\n const isEmpty = isEmptyValue(value);\n if (isEmpty || typeof key !== 'string' || !CACHED_FN_HANDLERS_RE.test(key)) {\n return !isEmpty;\n }\n\n const entry = typeof value === 'string' ? (JSON.parse(value) as CacheEntry) : (value as CacheEntry);\n\n return validateCacheEntry(key, entry);\n } catch {\n return false;\n }\n}\n\nfunction validateCacheEntry(\n key: string,\n entry: CacheEntry | CacheEntry<ResponseCacheEntry & { status: number }>,\n): boolean {\n if (isEmptyValue(entry.value)) {\n return false;\n }\n\n if (Date.now() > (entry.expires || 0)) {\n return false;\n }\n\n if (isResponseCacheEntry(key, entry)) {\n if ((entry.value.status ?? 0) >= 400) {\n return false;\n }\n\n if (entry.value.body === undefined) {\n return false;\n }\n\n if (entry.value.headers?.etag === 'undefined' || entry.value.headers?.['last-modified'] === 'undefined') {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isResponseCacheEntry(key: string, _: CacheEntry): _ is CacheEntry<ResponseCacheEntry & { status: number }> {\n return key.startsWith('nitro:handlers:');\n}\n"],"names":[],"mappings":";;;;AAaA,MAAM,MAAA,GAAS,kBAAA;AAEf,MAAM,yBAAA,GAA4B,UAAA;AAIlC,MAAM,iBAAA,GAAoB;AAAA,EACxB,SAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAIA,MAAM,uCAAuB,IAAI,GAAA,CAAqB,CAAC,SAAA,EAAW,SAAA,EAAW,YAAY,CAAC,CAAA;AAE1F,MAAM,qBAAA,GAAwB,+BAAA;AAKvB,SAAS,oBAAA,GAA6B;AAC3C,EAAA,IAAI,0BAA0B,8CAAA,EAAgD;AAC5E,IAAA;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,aAAa,iBAAA,EAAmB;AACzC,IAAA,0BAAA,CAA2B,SAAS,CAAA;AAAA,EACtC;AAEA,EAAA,yBAAA,CAA0B,8CAAA,GAAiD,IAAA;AAC7E;AAEA,SAAS,2BAA2B,SAAA,EAAkC;AACpE,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAiC,IAAA,CAAK,QAAQ,EAAC;AAC7D,EAAA,MAAM,SAAA,GAAY,CAAC,IAAA,KAAA,CAAgC,IAAA,CAAK,QAAQ,EAAA,EAAI,OAAA,CAAQ,MAAM,EAAE,CAAA;AAGpF,EAAA,IAAI,CAAC,GAAG,cAAA,EAAgB;AACtB,IAAA;AAAA,EACF;AAEA,EAAA,wBAAA;AAAA,IACE,EAAA,CAAG,cAAA,CAA6B,CAAA,UAAA,EAAa,SAAS,CAAA,CAAE,CAAA;AAAA,IACxD,CAAA,IAAA,KAAQ;AACN,MAAA,MAAM,SAAA,GAAY,KAAK,IAAI,CAAA;AAE3B,MAAA,OAAO,iBAAA,CAAkB;AAAA,QACvB,IAAA,EAAM,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,IAAK,SAAA;AAAA,QAC9B,UAAA,EAAY;AAAA,UACV,CAAC,4BAA4B,GAAG,CAAA,MAAA,EAAS,mBAAA,CAAoB,SAAS,CAAC,CAAA,CAAA;AAAA,UACvE,CAAC,gCAAgC,GAAG,MAAA;AAAA,UACpC,CAAC,4BAA4B,GAAG,SAAA,CAAU,SAAS,CAAA,GAAI,SAAA,GAAY,UAAU,CAAC,CAAA;AAAA,UAC9E,mBAAA,EAAqB,SAAA;AAAA,UACrB,oBAAA,EAAsB,UAAU,IAAI,CAAA;AAAA,UACpC,gBAAA,EAAkB,IAAA,CAAK,MAAA,EAAQ,IAAA,IAAQ;AAAA;AACzC,OACD,CAAA;AAAA,IACH,CAAA;AAAA,IACA;AAAA,MACE,aAAA,CAAc,MAAM,IAAA,EAAM;AAGxB,QAAA,IAAI,EAAE,WAAW,IAAA,CAAA,EAAO;AACtB,UAAA,MAAM,SAAU,IAAA,CAA8B,MAAA;AAC9C,UAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,SAAS,CAAA,EAAG;AACvC,YAAA,MAAM,GAAA,GAAM,SAAA,KAAc,SAAA,GAAY,OAAA,CAAQ,MAAM,CAAA,GAAI,UAAA,CAAW,IAAA,CAAK,IAAA,GAAO,CAAC,CAAA,EAAG,MAAM,CAAA;AACzF,YAAA,IAAA,CAAK,YAAA,CAAa,8BAA8B,GAAG,CAAA;AAAA,UACrD;AAAA,QACF;AAEA,QAAA,KAAK,iBAAA,EAAkB;AAAA,MACzB;AAAA;AACF,GACF;AACF;AAEA,SAAS,oBAAoB,UAAA,EAA4B;AACvD,EAAA,OAAO,UAAA,CAAW,QAAQ,QAAA,EAAU,CAAA,MAAA,KAAU,IAAI,MAAA,CAAO,WAAA,EAAa,CAAA,CAAE,CAAA;AAC1E;AAEA,SAAS,aAAa,KAAA,EAA2C;AAC/D,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAaA,SAAS,UAAA,CAAW,KAAc,KAAA,EAAyB;AACzD,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,aAAa,KAAK,CAAA;AAClC,IAAA,IAAI,OAAA,IAAW,OAAO,GAAA,KAAQ,QAAA,IAAY,CAAC,qBAAA,CAAsB,IAAA,CAAK,GAAG,CAAA,EAAG;AAC1E,MAAA,OAAO,CAAC,OAAA;AAAA,IACV;AAEA,IAAA,MAAM,QAAQ,OAAO,KAAA,KAAU,WAAY,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,GAAoB,KAAA;AAE/E,IAAA,OAAO,kBAAA,CAAmB,KAAK,KAAK,CAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAA,CACP,KACA,KAAA,EACS;AACT,EAAA,IAAI,YAAA,CAAa,KAAA,CAAM,KAAK,CAAA,EAAG;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,WAAW,CAAA,CAAA,EAAI;AACrC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,oBAAA,CAAqB,GAAU,CAAA,EAAG;AACpC,IAAA,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,MAAA,IAAU,CAAA,KAAM,GAAA,EAAK;AACpC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,CAAM,IAAA,KAAS,MAAA,EAAW;AAClC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,CAAM,OAAA,EAAS,IAAA,KAAS,WAAA,IAAe,MAAM,KAAA,CAAM,OAAA,GAAU,eAAe,CAAA,KAAM,WAAA,EAAa;AACvG,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,oBAAA,CAAqB,KAAa,CAAA,EAAyE;AAClH,EAAA,OAAO,GAAA,CAAI,WAAW,iBAAiB,CAAA;AACzC;;;;"}
@@ -1,5 +1,6 @@
1
- import { GLOBAL_OBJ, parseStringToURLObject, getHttpSpanDetailsFromUrlObject, startSpanManual, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getRootSpan, updateSpanName, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, httpHeadersToSpanAttributes, getClient, getActiveSpan, captureException, SPAN_STATUS_ERROR, setHttpStatus } from '@sentry/core';
2
- import { tracingChannel } from '@sentry/opentelemetry/tracing-channel';
1
+ import * as dc from 'node:diagnostics_channel';
2
+ import { GLOBAL_OBJ, parseStringToURLObject, getHttpSpanDetailsFromUrlObject, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getRootSpan, updateSpanName, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, httpHeadersToSpanAttributes, getClient, getActiveSpan, setHttpStatus } from '@sentry/core';
3
+ import { bindTracingChannelToSpan } from '@sentry/server-utils';
3
4
  import { setServerTimingHeaders } from './setServerTimingHeaders.js';
4
5
 
5
6
  const globalWithTraceChannels = GLOBAL_OBJ;
@@ -17,17 +18,11 @@ function getResponseStatusCode(result) {
17
18
  }
18
19
  return void 0;
19
20
  }
20
- function onTraceEnd(data) {
21
+ function applyResponseStatus(span, data) {
21
22
  const statusCode = getResponseStatusCode(data.result);
22
- if (data._sentrySpan && statusCode !== void 0) {
23
- setHttpStatus(data._sentrySpan, statusCode);
23
+ if (statusCode !== void 0) {
24
+ setHttpStatus(span, statusCode);
24
25
  }
25
- data._sentrySpan?.end();
26
- }
27
- function onTraceError(data) {
28
- captureException(data.error, { mechanism: { type: "auto.http.nitro.onTraceError", handled: false } });
29
- data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: "internal_error" });
30
- data._sentrySpan?.end();
31
26
  }
32
27
  function getParameterizedRoute(event) {
33
28
  const matchedRoute = event.context?.matchedRoute;
@@ -41,69 +36,79 @@ function getParameterizedRoute(event) {
41
36
  return routePath;
42
37
  }
43
38
  function setupH3TracingChannels() {
44
- const h3Channel = tracingChannel("h3.request", (data) => {
45
- const parsedUrl = parseStringToURLObject(data.event.url.href);
46
- const routePattern = getParameterizedRoute(data.event);
47
- const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(
48
- parsedUrl,
49
- "server",
50
- "auto.http.nitro.h3",
51
- { method: data.event.req.method },
52
- routePattern
53
- );
54
- return startSpanManual(
55
- {
39
+ if (!dc.tracingChannel) {
40
+ return;
41
+ }
42
+ const { channel: h3Channel } = bindTracingChannelToSpan(
43
+ dc.tracingChannel("h3.request"),
44
+ (data) => {
45
+ const parsedUrl = parseStringToURLObject(data.event.url.href);
46
+ const routePattern = getParameterizedRoute(data.event);
47
+ const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(
48
+ parsedUrl,
49
+ "server",
50
+ "auto.http.nitro.h3",
51
+ { method: data.event.req.method },
52
+ routePattern
53
+ );
54
+ const span = startInactiveSpan({
56
55
  name: spanName,
57
56
  attributes: {
58
57
  ...urlAttributes,
59
58
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.nitro.h3",
60
59
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data?.type === "middleware" ? "middleware.nitro" : "http.server"
61
60
  }
62
- },
63
- (span) => {
64
- setParameterizedRouteAttributes(span, data.event);
65
- return span;
61
+ });
62
+ setParameterizedRouteAttributes(span, data.event);
63
+ return span;
64
+ },
65
+ {
66
+ captureError: () => ({
67
+ mechanism: {
68
+ handled: false,
69
+ type: "auto.http.nitro.onTraceError"
70
+ }
71
+ }),
72
+ beforeSpanEnd(span, data) {
73
+ applyResponseStatus(span, data);
74
+ const rootSpan = getRootSpan(span);
75
+ if (rootSpan && rootSpan !== span) {
76
+ const routePattern = getParameterizedRoute(data.event);
77
+ if (routePattern) {
78
+ const method = data.event.req.method || "GET";
79
+ updateSpanName(rootSpan, `${method} ${routePattern}`);
80
+ rootSpan.setAttributes({
81
+ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
82
+ "http.route": routePattern
83
+ });
84
+ }
85
+ }
66
86
  }
67
- );
68
- });
87
+ }
88
+ );
69
89
  h3Channel.subscribe({
70
90
  start: (data) => {
71
91
  setServerTimingHeaders(data.event);
72
- },
73
- asyncEnd: (data) => {
74
- onTraceEnd(data);
75
- if (!data._sentrySpan) {
76
- return;
77
- }
78
- const rootSpan = getRootSpan(data._sentrySpan);
79
- if (rootSpan && rootSpan !== data._sentrySpan) {
80
- const routePattern = getParameterizedRoute(data.event);
81
- if (routePattern) {
82
- const method = data.event.req.method || "GET";
83
- updateSpanName(rootSpan, `${method} ${routePattern}`);
84
- rootSpan.setAttributes({
85
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
86
- "http.route": routePattern
87
- });
88
- }
89
- }
90
- },
91
- error: onTraceError
92
+ }
92
93
  });
93
94
  }
94
95
  function setupSrvxTracingChannels() {
96
+ if (!dc.tracingChannel) {
97
+ return;
98
+ }
95
99
  const requestParentSpans = /* @__PURE__ */ new WeakMap();
96
- const fetchChannel = tracingChannel("srvx.request", (data) => {
97
- const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : void 0;
98
- const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, "server", "auto.http.nitro.srvx", {
99
- method: data.request.method
100
- });
101
- const headerAttributes = httpHeadersToSpanAttributes(
102
- Object.fromEntries(data.request.headers.entries()),
103
- getClient()?.getDataCollectionOptions() ?? false
104
- );
105
- return startSpanManual(
106
- {
100
+ bindTracingChannelToSpan(
101
+ dc.tracingChannel("srvx.request"),
102
+ (data) => {
103
+ const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : void 0;
104
+ const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, "server", "auto.http.nitro.srvx", {
105
+ method: data.request.method
106
+ });
107
+ const headerAttributes = httpHeadersToSpanAttributes(
108
+ Object.fromEntries(data.request.headers.entries()),
109
+ getClient()?.getDataCollectionOptions() ?? false
110
+ );
111
+ return startInactiveSpan({
107
112
  name: spanName,
108
113
  attributes: {
109
114
  ...urlAttributes,
@@ -114,33 +119,29 @@ function setupSrvxTracingChannels() {
114
119
  },
115
120
  // Use the same parent span as middleware to make them siblings
116
121
  parentSpan: requestParentSpans.get(data.request) || void 0
117
- },
118
- (span) => span
119
- );
120
- });
121
- fetchChannel.subscribe({
122
- asyncEnd: (data) => {
123
- onTraceEnd(data);
124
- requestParentSpans.delete(data.request);
122
+ });
125
123
  },
126
- error: (data) => {
127
- onTraceError(data);
128
- requestParentSpans.delete(data.request);
129
- }
130
- });
131
- const middlewareChannel = tracingChannel("srvx.middleware", (data) => {
132
- if (data.middleware?.index === 0) {
133
- const activeSpan = getActiveSpan();
134
- if (activeSpan) {
135
- requestParentSpans.set(data.request, activeSpan);
124
+ {
125
+ beforeSpanEnd(span, data) {
126
+ applyResponseStatus(span, data);
127
+ requestParentSpans.delete(data.request);
136
128
  }
137
129
  }
138
- const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : void 0;
139
- const [, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, "server", "auto.http.nitro.srvx", {
140
- method: data.request.method
141
- });
142
- return startSpanManual(
143
- {
130
+ );
131
+ bindTracingChannelToSpan(
132
+ dc.tracingChannel("srvx.middleware"),
133
+ (data) => {
134
+ if (data.middleware?.index === 0) {
135
+ const activeSpan = getActiveSpan();
136
+ if (activeSpan) {
137
+ requestParentSpans.set(data.request, activeSpan);
138
+ }
139
+ }
140
+ const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : void 0;
141
+ const [, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, "server", "auto.http.nitro.srvx", {
142
+ method: data.request.method
143
+ });
144
+ return startInactiveSpan({
144
145
  name: `${data.middleware?.handler.name ?? "unknown"} - ${data.request.method} ${data.request._url?.pathname}`,
145
146
  attributes: {
146
147
  ...urlAttributes,
@@ -148,14 +149,14 @@ function setupSrvxTracingChannels() {
148
149
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "middleware.nitro"
149
150
  },
150
151
  parentSpan: requestParentSpans.get(data.request) || void 0
151
- },
152
- (span) => span
153
- );
154
- });
155
- middlewareChannel.subscribe({
156
- asyncEnd: onTraceEnd,
157
- error: onTraceError
158
- });
152
+ });
153
+ },
154
+ {
155
+ beforeSpanEnd(span, data) {
156
+ applyResponseStatus(span, data);
157
+ }
158
+ }
159
+ );
159
160
  }
160
161
  function setParameterizedRouteAttributes(span, event) {
161
162
  const rootSpan = getRootSpan(span);
@@ -1 +1 @@
1
- {"version":3,"file":"captureTracingEvents.js","sources":["../../../../src/runtime/hooks/captureTracingEvents.ts"],"sourcesContent":["import {\n captureException,\n getActiveSpan,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n getRootSpan,\n GLOBAL_OBJ,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n type Span,\n SPAN_STATUS_ERROR,\n startSpanManual,\n updateSpanName,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport type { TracingRequestEvent as H3TracingRequestEvent } from 'h3/tracing';\nimport type { RequestEvent as SrvxRequestEvent } from 'srvx/tracing';\nimport { setServerTimingHeaders } from './setServerTimingHeaders';\n\n/**\n * Global object with the trace channels\n */\nconst globalWithTraceChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__: boolean;\n};\n\n/**\n * Captures tracing events emitted by Nitro tracing channels.\n */\nexport function captureTracingEvents(): void {\n if (globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n setupH3TracingChannels();\n setupSrvxTracingChannels();\n globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__ = true;\n}\n\n/**\n * Extracts the HTTP status code from a tracing channel result.\n * The result is the return value of the traced handler, which is a Response for srvx\n * and may or may not be a Response for h3.\n */\nfunction getResponseStatusCode(result: unknown): number | undefined {\n if (result && typeof result === 'object' && 'status' in result && typeof result.status === 'number') {\n return result.status;\n }\n return undefined;\n}\n\nfunction onTraceEnd(data: TracingChannelContextWithSpan<{ result?: unknown }>): void {\n const statusCode = getResponseStatusCode(data.result);\n if (data._sentrySpan && statusCode !== undefined) {\n setHttpStatus(data._sentrySpan, statusCode);\n }\n\n data._sentrySpan?.end();\n}\n\nfunction onTraceError(data: TracingChannelContextWithSpan<{ error: unknown }>): void {\n captureException(data.error, { mechanism: { type: 'auto.http.nitro.onTraceError', handled: false } });\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n data._sentrySpan?.end();\n}\n\n/**\n * Extracts the parameterized route pattern from the h3 event context.\n */\nfunction getParameterizedRoute(event: H3TracingRequestEvent['event']): string | undefined {\n const matchedRoute = event.context?.matchedRoute;\n if (!matchedRoute) {\n return undefined;\n }\n\n const routePath = matchedRoute.route;\n\n // Skip catch-all routes as they're not useful for transaction grouping\n if (!routePath || routePath === '/**') {\n return undefined;\n }\n\n return routePath;\n}\n\nfunction setupH3TracingChannels(): void {\n const h3Channel = tracingChannel<H3TracingRequestEvent>('h3.request', data => {\n const parsedUrl = parseStringToURLObject(data.event.url.href);\n const routePattern = getParameterizedRoute(data.event);\n\n const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(\n parsedUrl,\n 'server',\n 'auto.http.nitro.h3',\n { method: data.event.req.method },\n routePattern,\n );\n\n return startSpanManual(\n {\n name: spanName,\n attributes: {\n ...urlAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.h3',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data?.type === 'middleware' ? 'middleware.nitro' : 'http.server',\n },\n },\n span => {\n setParameterizedRouteAttributes(span, data.event);\n\n return span;\n },\n );\n });\n\n h3Channel.subscribe({\n start: (data: H3TracingRequestEvent) => {\n setServerTimingHeaders(data.event);\n },\n asyncEnd: (data: TracingChannelContextWithSpan<H3TracingRequestEvent>) => {\n onTraceEnd(data);\n\n if (!data._sentrySpan) {\n return;\n }\n\n // Update the root span (srvx transaction) with the parameterized route name.\n // The srvx span is created before h3 resolves the route, so it initially has the raw URL.\n // Note: data.type is always 'middleware' in asyncEnd regardless of handler type,\n // so we rely on getParameterizedRoute() to filter out catch-all routes instead.\n const rootSpan = getRootSpan(data._sentrySpan);\n if (rootSpan && rootSpan !== data._sentrySpan) {\n const routePattern = getParameterizedRoute(data.event);\n if (routePattern) {\n const method = data.event.req.method || 'GET';\n updateSpanName(rootSpan, `${method} ${routePattern}`);\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n 'http.route': routePattern,\n });\n }\n }\n },\n error: onTraceError,\n });\n}\n\nfunction setupSrvxTracingChannels(): void {\n // Store the parent span per-request so middleware and fetch share the same parent.\n // WeakMap ensures per-request isolation in concurrent environments and automatic cleanup.\n const requestParentSpans = new WeakMap<Request, Span>();\n\n const fetchChannel = tracingChannel<SrvxRequestEvent>('srvx.request', data => {\n const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;\n const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {\n method: data.request.method,\n });\n\n const headerAttributes = httpHeadersToSpanAttributes(\n Object.fromEntries(data.request.headers.entries()),\n getClient()?.getDataCollectionOptions() ?? false,\n );\n\n return startSpanManual(\n {\n name: spanName,\n attributes: {\n ...urlAttributes,\n ...headerAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data.middleware ? 'middleware.nitro' : 'http.server',\n 'server.port': data.server.options.port,\n },\n // Use the same parent span as middleware to make them siblings\n parentSpan: requestParentSpans.get(data.request) || undefined,\n },\n span => span,\n );\n });\n\n // Subscribe to events (span already created in bindStore)\n fetchChannel.subscribe({\n asyncEnd: data => {\n onTraceEnd(data);\n\n // Clean up parent span reference after the fetch handler completes.\n requestParentSpans.delete(data.request);\n },\n error: data => {\n onTraceError(data);\n // Clean up parent span reference on error too\n requestParentSpans.delete(data.request);\n },\n });\n\n const middlewareChannel = tracingChannel<SrvxRequestEvent>('srvx.middleware', data => {\n // For the first middleware, capture the current parent span per-request\n if (data.middleware?.index === 0) {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n requestParentSpans.set(data.request, activeSpan);\n }\n }\n\n const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;\n const [, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {\n method: data.request.method,\n });\n\n // Create span as a child of the original parent, not the previous middleware\n return startSpanManual(\n {\n name: `${data.middleware?.handler.name ?? 'unknown'} - ${data.request.method} ${data.request._url?.pathname}`,\n attributes: {\n ...urlAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.nitro',\n },\n parentSpan: requestParentSpans.get(data.request) || undefined,\n },\n span => span,\n );\n });\n\n // Subscribe to events (span already created in bindStore)\n middlewareChannel.subscribe({\n asyncEnd: onTraceEnd,\n error: onTraceError,\n });\n}\n\n/**\n * Sets the parameterized route attributes on the span.\n */\nfunction setParameterizedRouteAttributes(span: Span, event: H3TracingRequestEvent['event']): void {\n const rootSpan = getRootSpan(span);\n if (!rootSpan) {\n return;\n }\n\n const matchedRoutePath = getParameterizedRoute(event);\n if (!matchedRoutePath) {\n return;\n }\n\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n 'http.route': matchedRoutePath,\n });\n\n const params = event.context?.params;\n\n if (params && typeof params === 'object') {\n Object.entries(params).forEach(([key, value]) => {\n // Based on this convention: https://getsentry.github.io/sentry-conventions/generated/attributes/url.html#urlpathparameterkey\n rootSpan.setAttributes({\n [`url.path.parameter.${key}`]: String(value),\n [`params.${key}`]: String(value),\n });\n });\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captureTracingEvents.js","sources":["../../../../src/runtime/hooks/captureTracingEvents.ts"],"sourcesContent":["import * as dc from 'node:diagnostics_channel';\nimport {\n getActiveSpan,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n getRootSpan,\n GLOBAL_OBJ,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n type Span,\n startInactiveSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { bindTracingChannelToSpan, type TracingChannelPayloadWithSpan } from '@sentry/server-utils';\nimport type { TracingRequestEvent as H3TracingRequestEvent } from 'h3/tracing';\nimport type { RequestEvent as SrvxRequestEvent } from 'srvx/tracing';\nimport { setServerTimingHeaders } from './setServerTimingHeaders';\n\n/**\n * Global object with the trace channels\n */\nconst globalWithTraceChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__: boolean;\n};\n\n/**\n * Captures tracing events emitted by Nitro tracing channels.\n */\nexport function captureTracingEvents(): void {\n if (globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n setupH3TracingChannels();\n setupSrvxTracingChannels();\n globalWithTraceChannels.__SENTRY_NITRO_HTTP_CHANNELS_INSTRUMENTED__ = true;\n}\n\n/**\n * Extracts the HTTP status code from a tracing channel result.\n * The result is the return value of the traced handler, which is a Response for srvx\n * and may or may not be a Response for h3.\n */\nfunction getResponseStatusCode(result: unknown): number | undefined {\n if (result && typeof result === 'object' && 'status' in result && typeof result.status === 'number') {\n return result.status;\n }\n return undefined;\n}\n\n/** Applies the HTTP status from the traced handler's result to the span, when present. */\nfunction applyResponseStatus(span: Span, data: TracingChannelPayloadWithSpan<{ result?: unknown }>): void {\n const statusCode = getResponseStatusCode(data.result);\n if (statusCode !== undefined) {\n setHttpStatus(span, statusCode);\n }\n}\n\n/**\n * Extracts the parameterized route pattern from the h3 event context.\n */\nfunction getParameterizedRoute(event: H3TracingRequestEvent['event']): string | undefined {\n const matchedRoute = event.context?.matchedRoute;\n if (!matchedRoute) {\n return undefined;\n }\n\n const routePath = matchedRoute.route;\n\n // Skip catch-all routes as they're not useful for transaction grouping\n if (!routePath || routePath === '/**') {\n return undefined;\n }\n\n return routePath;\n}\n\nfunction setupH3TracingChannels(): void {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n const { channel: h3Channel } = bindTracingChannelToSpan(\n dc.tracingChannel<H3TracingRequestEvent>('h3.request'),\n data => {\n const parsedUrl = parseStringToURLObject(data.event.url.href);\n const routePattern = getParameterizedRoute(data.event);\n\n const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(\n parsedUrl,\n 'server',\n 'auto.http.nitro.h3',\n { method: data.event.req.method },\n routePattern,\n );\n\n const span = startInactiveSpan({\n name: spanName,\n attributes: {\n ...urlAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.h3',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data?.type === 'middleware' ? 'middleware.nitro' : 'http.server',\n },\n });\n\n setParameterizedRouteAttributes(span, data.event);\n\n return span;\n },\n {\n captureError: () => ({\n mechanism: {\n handled: false,\n type: 'auto.http.nitro.onTraceError',\n },\n }),\n beforeSpanEnd(span, data) {\n applyResponseStatus(span, data);\n\n // Update the root span (srvx transaction) with the parameterized route name.\n // The srvx span is created before h3 resolves the route, so it initially has the raw URL.\n // Note: data.type is always 'middleware' here regardless of handler type, so we rely on\n // getParameterizedRoute() to filter out catch-all routes instead.\n const rootSpan = getRootSpan(span);\n if (rootSpan && rootSpan !== span) {\n const routePattern = getParameterizedRoute(data.event);\n if (routePattern) {\n const method = data.event.req.method || 'GET';\n updateSpanName(rootSpan, `${method} ${routePattern}`);\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n 'http.route': routePattern,\n });\n }\n }\n },\n },\n );\n\n h3Channel.subscribe({\n start: (data: H3TracingRequestEvent) => {\n setServerTimingHeaders(data.event);\n },\n });\n}\n\nfunction setupSrvxTracingChannels(): void {\n if (!dc.tracingChannel) {\n return;\n }\n\n // Store the parent span per-request so middleware and fetch share the same parent.\n // WeakMap ensures per-request isolation in concurrent environments and automatic cleanup.\n const requestParentSpans = new WeakMap<Request, Span>();\n\n bindTracingChannelToSpan(\n dc.tracingChannel<SrvxRequestEvent>('srvx.request'),\n data => {\n const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;\n const [spanName, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {\n method: data.request.method,\n });\n\n const headerAttributes = httpHeadersToSpanAttributes(\n Object.fromEntries(data.request.headers.entries()),\n getClient()?.getDataCollectionOptions() ?? false,\n );\n\n return startInactiveSpan({\n name: spanName,\n attributes: {\n ...urlAttributes,\n ...headerAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: data.middleware ? 'middleware.nitro' : 'http.server',\n 'server.port': data.server.options.port,\n },\n // Use the same parent span as middleware to make them siblings\n parentSpan: requestParentSpans.get(data.request) || undefined,\n });\n },\n {\n beforeSpanEnd(span, data) {\n applyResponseStatus(span, data);\n\n // Clean up parent span reference after the fetch handler completes (success or error).\n requestParentSpans.delete(data.request);\n },\n },\n );\n\n bindTracingChannelToSpan(\n dc.tracingChannel<SrvxRequestEvent>('srvx.middleware'),\n data => {\n // For the first middleware, capture the current parent span per-request\n if (data.middleware?.index === 0) {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n requestParentSpans.set(data.request, activeSpan);\n }\n }\n\n const parsedUrl = data.request._url ? parseStringToURLObject(data.request._url.href) : undefined;\n const [, urlAttributes] = getHttpSpanDetailsFromUrlObject(parsedUrl, 'server', 'auto.http.nitro.srvx', {\n method: data.request.method,\n });\n\n // Create span as a child of the original parent, not the previous middleware\n return startInactiveSpan({\n name: `${data.middleware?.handler.name ?? 'unknown'} - ${data.request.method} ${data.request._url?.pathname}`,\n attributes: {\n ...urlAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.nitro.srvx',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.nitro',\n },\n parentSpan: requestParentSpans.get(data.request) || undefined,\n });\n },\n {\n beforeSpanEnd(span, data) {\n applyResponseStatus(span, data);\n },\n },\n );\n}\n\n/**\n * Sets the parameterized route attributes on the span.\n */\nfunction setParameterizedRouteAttributes(span: Span, event: H3TracingRequestEvent['event']): void {\n const rootSpan = getRootSpan(span);\n if (!rootSpan) {\n return;\n }\n\n const matchedRoutePath = getParameterizedRoute(event);\n if (!matchedRoutePath) {\n return;\n }\n\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n 'http.route': matchedRoutePath,\n });\n\n const params = event.context?.params;\n\n if (params && typeof params === 'object') {\n Object.entries(params).forEach(([key, value]) => {\n // Based on this convention: https://getsentry.github.io/sentry-conventions/generated/attributes/url.html#urlpathparameterkey\n rootSpan.setAttributes({\n [`url.path.parameter.${key}`]: String(value),\n [`params.${key}`]: String(value),\n });\n });\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"captureStorageEvents.d.ts","sourceRoot":"","sources":["../../../../src/runtime/hooks/captureStorageEvents.ts"],"names":[],"mappings":"AAwCA;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAU3C"}
1
+ {"version":3,"file":"captureStorageEvents.d.ts","sourceRoot":"","sources":["../../../../src/runtime/hooks/captureStorageEvents.ts"],"names":[],"mappings":"AAsCA;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAU3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"captureTracingEvents.d.ts","sourceRoot":"","sources":["../../../../src/runtime/hooks/captureTracingEvents.ts"],"names":[],"mappings":"AA8BA;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAQ3C"}
1
+ {"version":3,"file":"captureTracingEvents.d.ts","sourceRoot":"","sources":["../../../../src/runtime/hooks/captureTracingEvents.ts"],"names":[],"mappings":"AA6BA;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAQ3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/nitro",
3
- "version": "10.60.0",
3
+ "version": "10.62.0",
4
4
  "description": "Official Sentry SDK for Nitro",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/nitro",
@@ -36,9 +36,9 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@sentry/bundler-plugin-core": "^5.3.0",
39
- "@sentry/core": "10.60.0",
40
- "@sentry/node": "10.60.0",
41
- "@sentry/opentelemetry": "10.60.0"
39
+ "@sentry/core": "10.62.0",
40
+ "@sentry/node": "10.62.0",
41
+ "@sentry/server-utils": "10.62.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "nitro": "^3.0.260415-beta",