@sentry/core 10.39.0 → 10.41.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/build/cjs/client.js +1 -0
  2. package/build/cjs/client.js.map +1 -1
  3. package/build/cjs/exports.js +4 -2
  4. package/build/cjs/exports.js.map +1 -1
  5. package/build/cjs/fetch.js +8 -4
  6. package/build/cjs/fetch.js.map +1 -1
  7. package/build/cjs/index.js +3 -0
  8. package/build/cjs/index.js.map +1 -1
  9. package/build/cjs/integrations/consola.js.map +1 -1
  10. package/build/cjs/tracing/ai/mediaStripping.js +135 -0
  11. package/build/cjs/tracing/ai/mediaStripping.js.map +1 -0
  12. package/build/cjs/tracing/ai/messageTruncation.js +18 -60
  13. package/build/cjs/tracing/ai/messageTruncation.js.map +1 -1
  14. package/build/cjs/tracing/anthropic-ai/index.js +1 -1
  15. package/build/cjs/tracing/anthropic-ai/index.js.map +1 -1
  16. package/build/cjs/tracing/google-genai/index.js +1 -1
  17. package/build/cjs/tracing/google-genai/index.js.map +1 -1
  18. package/build/cjs/tracing/langgraph/index.js +1 -1
  19. package/build/cjs/tracing/langgraph/index.js.map +1 -1
  20. package/build/cjs/tracing/openai/index.js +1 -1
  21. package/build/cjs/tracing/openai/index.js.map +1 -1
  22. package/build/cjs/utils/misc.js +7 -0
  23. package/build/cjs/utils/misc.js.map +1 -1
  24. package/build/cjs/utils/node-stack-trace.js +11 -2
  25. package/build/cjs/utils/node-stack-trace.js.map +1 -1
  26. package/build/cjs/utils/tunnel.js +74 -0
  27. package/build/cjs/utils/tunnel.js.map +1 -0
  28. package/build/cjs/utils/version.js +1 -1
  29. package/build/cjs/utils/version.js.map +1 -1
  30. package/build/cjs/utils/worldwide.js.map +1 -1
  31. package/build/esm/client.js +1 -0
  32. package/build/esm/client.js.map +1 -1
  33. package/build/esm/exports.js +4 -2
  34. package/build/esm/exports.js.map +1 -1
  35. package/build/esm/fetch.js +8 -4
  36. package/build/esm/fetch.js.map +1 -1
  37. package/build/esm/index.js +2 -1
  38. package/build/esm/index.js.map +1 -1
  39. package/build/esm/integrations/consola.js.map +1 -1
  40. package/build/esm/package.json +1 -1
  41. package/build/esm/tracing/ai/mediaStripping.js +132 -0
  42. package/build/esm/tracing/ai/mediaStripping.js.map +1 -0
  43. package/build/esm/tracing/ai/messageTruncation.js +12 -54
  44. package/build/esm/tracing/ai/messageTruncation.js.map +1 -1
  45. package/build/esm/tracing/anthropic-ai/index.js +1 -1
  46. package/build/esm/tracing/anthropic-ai/index.js.map +1 -1
  47. package/build/esm/tracing/google-genai/index.js +1 -1
  48. package/build/esm/tracing/google-genai/index.js.map +1 -1
  49. package/build/esm/tracing/langgraph/index.js +1 -1
  50. package/build/esm/tracing/langgraph/index.js.map +1 -1
  51. package/build/esm/tracing/openai/index.js +1 -1
  52. package/build/esm/tracing/openai/index.js.map +1 -1
  53. package/build/esm/utils/misc.js +7 -1
  54. package/build/esm/utils/misc.js.map +1 -1
  55. package/build/esm/utils/node-stack-trace.js +11 -2
  56. package/build/esm/utils/node-stack-trace.js.map +1 -1
  57. package/build/esm/utils/tunnel.js +72 -0
  58. package/build/esm/utils/tunnel.js.map +1 -0
  59. package/build/esm/utils/version.js +1 -1
  60. package/build/esm/utils/version.js.map +1 -1
  61. package/build/esm/utils/worldwide.js.map +1 -1
  62. package/build/types/client.d.ts.map +1 -1
  63. package/build/types/exports.d.ts.map +1 -1
  64. package/build/types/fetch.d.ts.map +1 -1
  65. package/build/types/index.d.ts +3 -1
  66. package/build/types/index.d.ts.map +1 -1
  67. package/build/types/integrations/consola.d.ts +8 -1
  68. package/build/types/integrations/consola.d.ts.map +1 -1
  69. package/build/types/tracing/ai/mediaStripping.d.ts +40 -0
  70. package/build/types/tracing/ai/mediaStripping.d.ts.map +1 -0
  71. package/build/types/tracing/ai/messageTruncation.d.ts.map +1 -1
  72. package/build/types/types-hoist/replay.d.ts +1 -0
  73. package/build/types/types-hoist/replay.d.ts.map +1 -1
  74. package/build/types/utils/misc.d.ts +7 -0
  75. package/build/types/utils/misc.d.ts.map +1 -1
  76. package/build/types/utils/node-stack-trace.d.ts.map +1 -1
  77. package/build/types/utils/tunnel.d.ts +16 -0
  78. package/build/types/utils/tunnel.d.ts.map +1 -0
  79. package/build/types/utils/worldwide.d.ts +0 -2
  80. package/build/types/utils/worldwide.d.ts.map +1 -1
  81. package/build/types-ts3.8/index.d.ts +3 -1
  82. package/build/types-ts3.8/integrations/consola.d.ts +8 -1
  83. package/build/types-ts3.8/tracing/ai/mediaStripping.d.ts +40 -0
  84. package/build/types-ts3.8/types-hoist/replay.d.ts +4 -0
  85. package/build/types-ts3.8/utils/misc.d.ts +7 -0
  86. package/build/types-ts3.8/utils/tunnel.d.ts +16 -0
  87. package/build/types-ts3.8/utils/worldwide.d.ts +0 -2
  88. package/package.json +2 -3
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.js","sources":["../../src/fetch.ts"],"sourcesContent":["import { getClient } from './currentScopes';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from './semanticAttributes';\nimport { setHttpStatus, SPAN_STATUS_ERROR, startInactiveSpan } from './tracing';\nimport { SentryNonRecordingSpan } from './tracing/sentryNonRecordingSpan';\nimport type { FetchBreadcrumbHint } from './types-hoist/breadcrumb';\nimport type { HandlerDataFetch } from './types-hoist/instrument';\nimport type { ResponseHookInfo } from './types-hoist/request';\nimport type { Span, SpanAttributes, SpanOrigin } from './types-hoist/span';\nimport { SENTRY_BAGGAGE_KEY_PREFIX } from './utils/baggage';\nimport { hasSpansEnabled } from './utils/hasSpansEnabled';\nimport { isInstanceOf, isRequest } from './utils/is';\nimport { getActiveSpan } from './utils/spanUtils';\nimport { getTraceData } from './utils/traceData';\nimport {\n getSanitizedUrlStringFromUrlObject,\n isURLObjectRelative,\n parseStringToURLObject,\n stripDataUrlContent,\n} from './utils/url';\n\ntype PolymorphicRequestHeaders =\n | Record<string, string | undefined>\n | Array<[string, string]>\n // the below is not precisely the Header type used in Request, but it'll pass duck-typing\n | {\n append: (key: string, value: string) => void;\n get: (key: string) => string | null | undefined;\n };\n\ninterface InstrumentFetchRequestOptions {\n spanOrigin?: SpanOrigin;\n propagateTraceparent?: boolean;\n onRequestSpanEnd?: (span: Span, responseInformation: ResponseHookInfo) => void;\n}\n\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @deprecated pass an options object instead of the spanOrigin parameter\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n spanOrigin: SpanOrigin,\n): Span | undefined;\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- needed because the other overload is deprecated\n instrumentFetchRequestOptions: InstrumentFetchRequestOptions,\n): Span | undefined;\n\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n spanOriginOrOptions?: SpanOrigin | InstrumentFetchRequestOptions,\n): Span | undefined {\n if (!handlerData.fetchData) {\n return undefined;\n }\n\n const { method, url } = handlerData.fetchData;\n\n const shouldCreateSpanResult = hasSpansEnabled() && shouldCreateSpan(url);\n\n if (handlerData.endTimestamp && shouldCreateSpanResult) {\n const spanId = handlerData.fetchData.__span;\n if (!spanId) return;\n\n const span = spans[spanId];\n if (span) {\n endSpan(span, handlerData);\n\n _callOnRequestSpanEnd(span, handlerData, spanOriginOrOptions);\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n return undefined;\n }\n\n // Backwards-compatible with the old signature. Needed to introduce the combined optional parameter\n // to avoid API breakage for anyone calling this function with the optional spanOrigin parameter\n // TODO (v11): remove this backwards-compatible code and only accept the options parameter\n const { spanOrigin = 'auto.http.browser', propagateTraceparent = false } =\n typeof spanOriginOrOptions === 'object' ? spanOriginOrOptions : { spanOrigin: spanOriginOrOptions };\n\n const hasParent = !!getActiveSpan();\n\n const span =\n shouldCreateSpanResult && hasParent\n ? startInactiveSpan(getSpanStartOptions(url, method, spanOrigin))\n : new SentryNonRecordingSpan();\n\n handlerData.fetchData.__span = span.spanContext().spanId;\n spans[span.spanContext().spanId] = span;\n\n if (shouldAttachHeaders(handlerData.fetchData.url)) {\n const request: string | Request = handlerData.args[0];\n\n // Shallow clone the options object to avoid mutating the original user-provided object\n // Examples: users re-using same options object for multiple fetch calls, frozen objects\n const options: { [key: string]: unknown } = { ...(handlerData.args[1] || {}) };\n\n const headers = _addTracingHeadersToFetchRequest(\n request,\n options,\n // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction),\n // we do not want to use the span as base for the trace headers,\n // which means that the headers will be generated from the scope and the sampling decision is deferred\n hasSpansEnabled() && hasParent ? span : undefined,\n propagateTraceparent,\n );\n if (headers) {\n // Ensure this is actually set, if no options have been passed previously\n handlerData.args[1] = options;\n options.headers = headers;\n }\n }\n\n const client = getClient();\n\n if (client) {\n const fetchHint = {\n input: handlerData.args,\n response: handlerData.response,\n startTimestamp: handlerData.startTimestamp,\n endTimestamp: handlerData.endTimestamp,\n } satisfies FetchBreadcrumbHint;\n\n client.emit('beforeOutgoingRequestSpan', span, fetchHint);\n }\n\n return span;\n}\n\n/**\n * Calls the onRequestSpanEnd callback if it is defined.\n */\nexport function _callOnRequestSpanEnd(\n span: Span,\n handlerData: HandlerDataFetch,\n spanOriginOrOptions?: SpanOrigin | InstrumentFetchRequestOptions,\n): void {\n const onRequestSpanEnd =\n typeof spanOriginOrOptions === 'object' && spanOriginOrOptions !== null\n ? spanOriginOrOptions.onRequestSpanEnd\n : undefined;\n\n onRequestSpanEnd?.(span, {\n headers: handlerData.response?.headers,\n error: handlerData.error,\n });\n}\n\n/**\n * Adds sentry-trace and baggage headers to the various forms of fetch headers.\n * exported only for testing purposes\n *\n * When we determine if we should add a baggage header, there are 3 cases:\n * 1. No previous baggage header -> add baggage\n * 2. Previous baggage header has no sentry baggage values -> add our baggage\n * 3. Previous baggage header has sentry baggage values -> do nothing (might have been added manually by users)\n */\n// eslint-disable-next-line complexity -- yup it's this complicated :(\nexport function _addTracingHeadersToFetchRequest(\n request: string | Request,\n fetchOptionsObj: {\n headers?:\n | {\n [key: string]: string[] | string | undefined;\n }\n | PolymorphicRequestHeaders;\n },\n span?: Span,\n propagateTraceparent?: boolean,\n): PolymorphicRequestHeaders | undefined {\n const traceHeaders = getTraceData({ span, propagateTraceparent });\n const sentryTrace = traceHeaders['sentry-trace'];\n const baggage = traceHeaders.baggage;\n const traceparent = traceHeaders.traceparent;\n\n // Nothing to do, when we return undefined here, the original headers will be used\n if (!sentryTrace) {\n return undefined;\n }\n\n const originalHeaders = fetchOptionsObj.headers || (isRequest(request) ? request.headers : undefined);\n\n if (!originalHeaders) {\n return { ...traceHeaders };\n } else if (isHeaders(originalHeaders)) {\n const newHeaders = new Headers(originalHeaders);\n\n // We don't want to override manually added sentry headers\n if (!newHeaders.get('sentry-trace')) {\n newHeaders.set('sentry-trace', sentryTrace);\n }\n\n if (propagateTraceparent && traceparent && !newHeaders.get('traceparent')) {\n newHeaders.set('traceparent', traceparent);\n }\n\n if (baggage) {\n const prevBaggageHeader = newHeaders.get('baggage');\n\n if (!prevBaggageHeader) {\n newHeaders.set('baggage', baggage);\n } else if (!baggageHeaderHasSentryBaggageValues(prevBaggageHeader)) {\n newHeaders.set('baggage', `${prevBaggageHeader},${baggage}`);\n }\n }\n\n return newHeaders;\n } else if (Array.isArray(originalHeaders)) {\n const newHeaders = [...originalHeaders];\n\n if (!originalHeaders.find(header => header[0] === 'sentry-trace')) {\n newHeaders.push(['sentry-trace', sentryTrace]);\n }\n\n if (propagateTraceparent && traceparent && !originalHeaders.find(header => header[0] === 'traceparent')) {\n newHeaders.push(['traceparent', traceparent]);\n }\n\n const prevBaggageHeaderWithSentryValues = originalHeaders.find(\n header => header[0] === 'baggage' && baggageHeaderHasSentryBaggageValues(header[1]),\n );\n\n if (baggage && !prevBaggageHeaderWithSentryValues) {\n // If there are multiple entries with the same key, the browser will merge the values into a single request header.\n // Its therefore safe to simply push a \"baggage\" entry, even though there might already be another baggage header.\n newHeaders.push(['baggage', baggage]);\n }\n\n return newHeaders as PolymorphicRequestHeaders;\n } else {\n const existingSentryTraceHeader = 'sentry-trace' in originalHeaders ? originalHeaders['sentry-trace'] : undefined;\n const existingTraceparentHeader = 'traceparent' in originalHeaders ? originalHeaders.traceparent : undefined;\n const existingBaggageHeader = 'baggage' in originalHeaders ? originalHeaders.baggage : undefined;\n\n const newBaggageHeaders: string[] = existingBaggageHeader\n ? Array.isArray(existingBaggageHeader)\n ? [...existingBaggageHeader]\n : [existingBaggageHeader]\n : [];\n\n const prevBaggageHeaderWithSentryValues =\n existingBaggageHeader &&\n (Array.isArray(existingBaggageHeader)\n ? existingBaggageHeader.find(headerItem => baggageHeaderHasSentryBaggageValues(headerItem))\n : baggageHeaderHasSentryBaggageValues(existingBaggageHeader));\n\n if (baggage && !prevBaggageHeaderWithSentryValues) {\n newBaggageHeaders.push(baggage);\n }\n\n const newHeaders: {\n 'sentry-trace': string;\n baggage: string | undefined;\n traceparent?: string;\n } = {\n ...originalHeaders,\n 'sentry-trace': (existingSentryTraceHeader as string | undefined) ?? sentryTrace,\n baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined,\n };\n\n if (propagateTraceparent && traceparent && !existingTraceparentHeader) {\n newHeaders.traceparent = traceparent;\n }\n\n return newHeaders;\n }\n}\n\nfunction endSpan(span: Span, handlerData: HandlerDataFetch): void {\n if (handlerData.response) {\n setHttpStatus(span, handlerData.response.status);\n\n const contentLength = handlerData.response?.headers?.get('content-length');\n\n if (contentLength) {\n const contentLengthNum = parseInt(contentLength);\n if (contentLengthNum > 0) {\n span.setAttribute('http.response_content_length', contentLengthNum);\n }\n }\n } else if (handlerData.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n span.end();\n}\n\nfunction baggageHeaderHasSentryBaggageValues(baggageHeader: string): boolean {\n return baggageHeader.split(',').some(baggageEntry => baggageEntry.trim().startsWith(SENTRY_BAGGAGE_KEY_PREFIX));\n}\n\nfunction isHeaders(headers: unknown): headers is Headers {\n return typeof Headers !== 'undefined' && isInstanceOf(headers, Headers);\n}\n\nfunction getSpanStartOptions(\n url: string,\n method: string,\n spanOrigin: SpanOrigin,\n): Parameters<typeof startInactiveSpan>[0] {\n // Data URLs need special handling because parseStringToURLObject treats them as \"relative\"\n // (no \"://\"), causing getSanitizedUrlStringFromUrlObject to return just the pathname\n // without the \"data:\" prefix, making later stripDataUrlContent calls ineffective.\n // So for data URLs, we strip the content first and use that directly.\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n return {\n name: `${method} ${sanitizedUrl}`,\n attributes: getFetchSpanAttributes(url, undefined, method, spanOrigin),\n };\n }\n\n const parsedUrl = parseStringToURLObject(url);\n const sanitizedUrl = parsedUrl ? getSanitizedUrlStringFromUrlObject(parsedUrl) : url;\n return {\n name: `${method} ${sanitizedUrl}`,\n attributes: getFetchSpanAttributes(url, parsedUrl, method, spanOrigin),\n };\n}\n\nfunction getFetchSpanAttributes(\n url: string,\n parsedUrl: ReturnType<typeof parseStringToURLObject>,\n method: string,\n spanOrigin: SpanOrigin,\n): SpanAttributes {\n const attributes: SpanAttributes = {\n url: stripDataUrlContent(url),\n type: 'fetch',\n 'http.method': method,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',\n };\n if (parsedUrl) {\n if (!isURLObjectRelative(parsedUrl)) {\n attributes['http.url'] = stripDataUrlContent(parsedUrl.href);\n attributes['server.address'] = parsedUrl.host;\n }\n if (parsedUrl.search) {\n attributes['http.query'] = parsedUrl.search;\n }\n if (parsedUrl.hash) {\n attributes['http.fragment'] = parsedUrl.hash;\n }\n }\n return attributes;\n}\n"],"names":["hasSpansEnabled","getActiveSpan","startInactiveSpan","SentryNonRecordingSpan","getClient","getTraceData","isRequest","setHttpStatus","SPAN_STATUS_ERROR","SENTRY_BAGGAGE_KEY_PREFIX","isInstanceOf","url","stripDataUrlContent","parseStringToURLObject","getSanitizedUrlStringFromUrlObject","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","isURLObjectRelative"],"mappings":"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"}
1
+ {"version":3,"file":"fetch.js","sources":["../../src/fetch.ts"],"sourcesContent":["import { getClient } from './currentScopes';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from './semanticAttributes';\nimport { setHttpStatus, SPAN_STATUS_ERROR, startInactiveSpan } from './tracing';\nimport { SentryNonRecordingSpan } from './tracing/sentryNonRecordingSpan';\nimport type { FetchBreadcrumbHint } from './types-hoist/breadcrumb';\nimport type { HandlerDataFetch } from './types-hoist/instrument';\nimport type { ResponseHookInfo } from './types-hoist/request';\nimport type { Span, SpanAttributes, SpanOrigin } from './types-hoist/span';\nimport { SENTRY_BAGGAGE_KEY_PREFIX } from './utils/baggage';\nimport { hasSpansEnabled } from './utils/hasSpansEnabled';\nimport { isInstanceOf, isRequest } from './utils/is';\nimport { getActiveSpan } from './utils/spanUtils';\nimport { getTraceData } from './utils/traceData';\nimport {\n getSanitizedUrlStringFromUrlObject,\n isURLObjectRelative,\n parseStringToURLObject,\n stripDataUrlContent,\n} from './utils/url';\n\ntype PolymorphicRequestHeaders =\n | Record<string, string | undefined>\n | Array<[string, string]>\n // the below is not precisely the Header type used in Request, but it'll pass duck-typing\n | {\n append: (key: string, value: string) => void;\n get: (key: string) => string | null | undefined;\n };\n\ninterface InstrumentFetchRequestOptions {\n spanOrigin?: SpanOrigin;\n propagateTraceparent?: boolean;\n onRequestSpanEnd?: (span: Span, responseInformation: ResponseHookInfo) => void;\n}\n\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @deprecated pass an options object instead of the spanOrigin parameter\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n spanOrigin: SpanOrigin,\n): Span | undefined;\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n // eslint-disable-next-line @typescript-eslint/unified-signatures -- needed because the other overload is deprecated\n instrumentFetchRequestOptions: InstrumentFetchRequestOptions,\n): Span | undefined;\n\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n spanOriginOrOptions?: SpanOrigin | InstrumentFetchRequestOptions,\n): Span | undefined {\n if (!handlerData.fetchData) {\n return undefined;\n }\n\n const { method, url } = handlerData.fetchData;\n\n const shouldCreateSpanResult = hasSpansEnabled() && shouldCreateSpan(url);\n\n if (handlerData.endTimestamp) {\n const spanId = handlerData.fetchData.__span;\n if (!spanId) return;\n\n const span = spans[spanId];\n\n if (span) {\n // Only end the span and call hooks if we're actually recording\n if (shouldCreateSpanResult) {\n endSpan(span, handlerData);\n _callOnRequestSpanEnd(span, handlerData, spanOriginOrOptions);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n\n return undefined;\n }\n\n // Backwards-compatible with the old signature. Needed to introduce the combined optional parameter\n // to avoid API breakage for anyone calling this function with the optional spanOrigin parameter\n // TODO (v11): remove this backwards-compatible code and only accept the options parameter\n const { spanOrigin = 'auto.http.browser', propagateTraceparent = false } =\n typeof spanOriginOrOptions === 'object' ? spanOriginOrOptions : { spanOrigin: spanOriginOrOptions };\n\n const hasParent = !!getActiveSpan();\n\n const span =\n shouldCreateSpanResult && hasParent\n ? startInactiveSpan(getSpanStartOptions(url, method, spanOrigin))\n : new SentryNonRecordingSpan();\n\n handlerData.fetchData.__span = span.spanContext().spanId;\n spans[span.spanContext().spanId] = span;\n\n if (shouldAttachHeaders(handlerData.fetchData.url)) {\n const request: string | Request = handlerData.args[0];\n\n // Shallow clone the options object to avoid mutating the original user-provided object\n // Examples: users re-using same options object for multiple fetch calls, frozen objects\n const options: { [key: string]: unknown } = { ...(handlerData.args[1] || {}) };\n\n const headers = _addTracingHeadersToFetchRequest(\n request,\n options,\n // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction),\n // we do not want to use the span as base for the trace headers,\n // which means that the headers will be generated from the scope and the sampling decision is deferred\n hasSpansEnabled() && hasParent ? span : undefined,\n propagateTraceparent,\n );\n if (headers) {\n // Ensure this is actually set, if no options have been passed previously\n handlerData.args[1] = options;\n options.headers = headers;\n }\n }\n\n const client = getClient();\n\n if (client) {\n const fetchHint = {\n input: handlerData.args,\n response: handlerData.response,\n startTimestamp: handlerData.startTimestamp,\n endTimestamp: handlerData.endTimestamp,\n } satisfies FetchBreadcrumbHint;\n\n client.emit('beforeOutgoingRequestSpan', span, fetchHint);\n }\n\n return span;\n}\n\n/**\n * Calls the onRequestSpanEnd callback if it is defined.\n */\nexport function _callOnRequestSpanEnd(\n span: Span,\n handlerData: HandlerDataFetch,\n spanOriginOrOptions?: SpanOrigin | InstrumentFetchRequestOptions,\n): void {\n const onRequestSpanEnd =\n typeof spanOriginOrOptions === 'object' && spanOriginOrOptions !== null\n ? spanOriginOrOptions.onRequestSpanEnd\n : undefined;\n\n onRequestSpanEnd?.(span, {\n headers: handlerData.response?.headers,\n error: handlerData.error,\n });\n}\n\n/**\n * Adds sentry-trace and baggage headers to the various forms of fetch headers.\n * exported only for testing purposes\n *\n * When we determine if we should add a baggage header, there are 3 cases:\n * 1. No previous baggage header -> add baggage\n * 2. Previous baggage header has no sentry baggage values -> add our baggage\n * 3. Previous baggage header has sentry baggage values -> do nothing (might have been added manually by users)\n */\n// eslint-disable-next-line complexity -- yup it's this complicated :(\nexport function _addTracingHeadersToFetchRequest(\n request: string | Request,\n fetchOptionsObj: {\n headers?:\n | {\n [key: string]: string[] | string | undefined;\n }\n | PolymorphicRequestHeaders;\n },\n span?: Span,\n propagateTraceparent?: boolean,\n): PolymorphicRequestHeaders | undefined {\n const traceHeaders = getTraceData({ span, propagateTraceparent });\n const sentryTrace = traceHeaders['sentry-trace'];\n const baggage = traceHeaders.baggage;\n const traceparent = traceHeaders.traceparent;\n\n // Nothing to do, when we return undefined here, the original headers will be used\n if (!sentryTrace) {\n return undefined;\n }\n\n const originalHeaders = fetchOptionsObj.headers || (isRequest(request) ? request.headers : undefined);\n\n if (!originalHeaders) {\n return { ...traceHeaders };\n } else if (isHeaders(originalHeaders)) {\n const newHeaders = new Headers(originalHeaders);\n\n // We don't want to override manually added sentry headers\n if (!newHeaders.get('sentry-trace')) {\n newHeaders.set('sentry-trace', sentryTrace);\n }\n\n if (propagateTraceparent && traceparent && !newHeaders.get('traceparent')) {\n newHeaders.set('traceparent', traceparent);\n }\n\n if (baggage) {\n const prevBaggageHeader = newHeaders.get('baggage');\n\n if (!prevBaggageHeader) {\n newHeaders.set('baggage', baggage);\n } else if (!baggageHeaderHasSentryBaggageValues(prevBaggageHeader)) {\n newHeaders.set('baggage', `${prevBaggageHeader},${baggage}`);\n }\n }\n\n return newHeaders;\n } else if (Array.isArray(originalHeaders)) {\n const newHeaders = [...originalHeaders];\n\n if (!originalHeaders.find(header => header[0] === 'sentry-trace')) {\n newHeaders.push(['sentry-trace', sentryTrace]);\n }\n\n if (propagateTraceparent && traceparent && !originalHeaders.find(header => header[0] === 'traceparent')) {\n newHeaders.push(['traceparent', traceparent]);\n }\n\n const prevBaggageHeaderWithSentryValues = originalHeaders.find(\n header => header[0] === 'baggage' && baggageHeaderHasSentryBaggageValues(header[1]),\n );\n\n if (baggage && !prevBaggageHeaderWithSentryValues) {\n // If there are multiple entries with the same key, the browser will merge the values into a single request header.\n // Its therefore safe to simply push a \"baggage\" entry, even though there might already be another baggage header.\n newHeaders.push(['baggage', baggage]);\n }\n\n return newHeaders as PolymorphicRequestHeaders;\n } else {\n const existingSentryTraceHeader = 'sentry-trace' in originalHeaders ? originalHeaders['sentry-trace'] : undefined;\n const existingTraceparentHeader = 'traceparent' in originalHeaders ? originalHeaders.traceparent : undefined;\n const existingBaggageHeader = 'baggage' in originalHeaders ? originalHeaders.baggage : undefined;\n\n const newBaggageHeaders: string[] = existingBaggageHeader\n ? Array.isArray(existingBaggageHeader)\n ? [...existingBaggageHeader]\n : [existingBaggageHeader]\n : [];\n\n const prevBaggageHeaderWithSentryValues =\n existingBaggageHeader &&\n (Array.isArray(existingBaggageHeader)\n ? existingBaggageHeader.find(headerItem => baggageHeaderHasSentryBaggageValues(headerItem))\n : baggageHeaderHasSentryBaggageValues(existingBaggageHeader));\n\n if (baggage && !prevBaggageHeaderWithSentryValues) {\n newBaggageHeaders.push(baggage);\n }\n\n const newHeaders: {\n 'sentry-trace': string;\n baggage: string | undefined;\n traceparent?: string;\n } = {\n ...originalHeaders,\n 'sentry-trace': (existingSentryTraceHeader as string | undefined) ?? sentryTrace,\n baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined,\n };\n\n if (propagateTraceparent && traceparent && !existingTraceparentHeader) {\n newHeaders.traceparent = traceparent;\n }\n\n return newHeaders;\n }\n}\n\nfunction endSpan(span: Span, handlerData: HandlerDataFetch): void {\n if (handlerData.response) {\n setHttpStatus(span, handlerData.response.status);\n\n const contentLength = handlerData.response?.headers?.get('content-length');\n\n if (contentLength) {\n const contentLengthNum = parseInt(contentLength);\n if (contentLengthNum > 0) {\n span.setAttribute('http.response_content_length', contentLengthNum);\n }\n }\n } else if (handlerData.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n span.end();\n}\n\nfunction baggageHeaderHasSentryBaggageValues(baggageHeader: string): boolean {\n return baggageHeader.split(',').some(baggageEntry => baggageEntry.trim().startsWith(SENTRY_BAGGAGE_KEY_PREFIX));\n}\n\nfunction isHeaders(headers: unknown): headers is Headers {\n return typeof Headers !== 'undefined' && isInstanceOf(headers, Headers);\n}\n\nfunction getSpanStartOptions(\n url: string,\n method: string,\n spanOrigin: SpanOrigin,\n): Parameters<typeof startInactiveSpan>[0] {\n // Data URLs need special handling because parseStringToURLObject treats them as \"relative\"\n // (no \"://\"), causing getSanitizedUrlStringFromUrlObject to return just the pathname\n // without the \"data:\" prefix, making later stripDataUrlContent calls ineffective.\n // So for data URLs, we strip the content first and use that directly.\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n return {\n name: `${method} ${sanitizedUrl}`,\n attributes: getFetchSpanAttributes(url, undefined, method, spanOrigin),\n };\n }\n\n const parsedUrl = parseStringToURLObject(url);\n const sanitizedUrl = parsedUrl ? getSanitizedUrlStringFromUrlObject(parsedUrl) : url;\n return {\n name: `${method} ${sanitizedUrl}`,\n attributes: getFetchSpanAttributes(url, parsedUrl, method, spanOrigin),\n };\n}\n\nfunction getFetchSpanAttributes(\n url: string,\n parsedUrl: ReturnType<typeof parseStringToURLObject>,\n method: string,\n spanOrigin: SpanOrigin,\n): SpanAttributes {\n const attributes: SpanAttributes = {\n url: stripDataUrlContent(url),\n type: 'fetch',\n 'http.method': method,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',\n };\n if (parsedUrl) {\n if (!isURLObjectRelative(parsedUrl)) {\n attributes['http.url'] = stripDataUrlContent(parsedUrl.href);\n attributes['server.address'] = parsedUrl.host;\n }\n if (parsedUrl.search) {\n attributes['http.query'] = parsedUrl.search;\n }\n if (parsedUrl.hash) {\n attributes['http.fragment'] = parsedUrl.hash;\n }\n }\n return attributes;\n}\n"],"names":["hasSpansEnabled","getActiveSpan","startInactiveSpan","SentryNonRecordingSpan","getClient","getTraceData","isRequest","setHttpStatus","SPAN_STATUS_ERROR","SENTRY_BAGGAGE_KEY_PREFIX","isInstanceOf","url","stripDataUrlContent","parseStringToURLObject","getSanitizedUrlStringFromUrlObject","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","isURLObjectRelative"],"mappings":"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"}
@@ -38,6 +38,7 @@ const hasSpansEnabled = require('./utils/hasSpansEnabled.js');
38
38
  const isSentryRequestUrl = require('./utils/isSentryRequestUrl.js');
39
39
  const handleCallbackErrors = require('./utils/handleCallbackErrors.js');
40
40
  const parameterize = require('./utils/parameterize.js');
41
+ const tunnel = require('./utils/tunnel.js');
41
42
  const ipAddress = require('./utils/ipAddress.js');
42
43
  const spanUtils = require('./utils/spanUtils.js');
43
44
  const spanOnScope = require('./utils/spanOnScope.js');
@@ -254,6 +255,7 @@ exports.isSentryRequestUrl = isSentryRequestUrl.isSentryRequestUrl;
254
255
  exports.handleCallbackErrors = handleCallbackErrors.handleCallbackErrors;
255
256
  exports.fmt = parameterize.fmt;
256
257
  exports.parameterize = parameterize.parameterize;
258
+ exports.handleTunnelRequest = tunnel.handleTunnelRequest;
257
259
  exports.addAutoIpAddressToSession = ipAddress.addAutoIpAddressToSession;
258
260
  exports.addAutoIpAddressToUser = ipAddress.addAutoIpAddressToUser;
259
261
  exports.addChildSpanToSpan = spanUtils.addChildSpanToSpan;
@@ -380,6 +382,7 @@ exports.addExceptionMechanism = misc.addExceptionMechanism;
380
382
  exports.addExceptionTypeValue = misc.addExceptionTypeValue;
381
383
  exports.checkOrSetAlreadyCaught = misc.checkOrSetAlreadyCaught;
382
384
  exports.getEventDescription = misc.getEventDescription;
385
+ exports.isAlreadyCaptured = misc.isAlreadyCaptured;
383
386
  exports.parseSemver = misc.parseSemver;
384
387
  exports.uuid4 = misc.uuid4;
385
388
  exports.isNodeEnv = node.isNodeEnv;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"consola.js","sources":["../../../src/integrations/consola.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { getClient } from '../currentScopes';\nimport { _INTERNAL_captureLog } from '../logs/internal';\nimport { formatConsoleArgs } from '../logs/utils';\nimport type { LogSeverityLevel } from '../types-hoist/log';\n\n/**\n * Options for the Sentry Consola reporter.\n */\ninterface ConsolaReporterOptions {\n /**\n * Use this option to filter which levels should be captured. By default, all levels are captured.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Only capture error and warn logs\n * levels: ['error', 'warn'],\n * });\n * consola.addReporter(sentryReporter);\n * ```\n */\n levels?: Array<LogSeverityLevel>;\n\n /**\n * Optionally provide a specific Sentry client instance to use for capturing logs.\n * If not provided, the current client will be retrieved using `getClient()`.\n *\n * This is useful when you want to use specific client options for log normalization\n * or when working with multiple client instances.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * client: myCustomClient,\n * });\n * ```\n */\n client?: Client;\n}\n\nexport interface ConsolaReporter {\n log: (logObj: ConsolaLogObject) => void;\n}\n\n/**\n * Represents a log object that Consola reporters receive.\n *\n * This interface matches the structure of log objects passed to Consola reporters.\n * See: https://github.com/unjs/consola#custom-reporters\n *\n * @example\n * ```ts\n * const reporter = {\n * log(logObj: ConsolaLogObject) {\n * console.log(`[${logObj.type}] ${logObj.message || logObj.args?.join(' ')}`);\n * }\n * };\n * consola.addReporter(reporter);\n * ```\n */\nexport interface ConsolaLogObject {\n /**\n * Allows additional custom properties to be set on the log object.\n * These properties will be captured as log attributes with a 'consola.' prefix.\n *\n * @example\n * ```ts\n * const reporter = Sentry.createConsolaReporter();\n * reporter.log({\n * type: 'info',\n * message: 'User action',\n * userId: 123,\n * sessionId: 'abc-123'\n * });\n * // Will create attributes: consola.userId and consola.sessionId\n * ```\n */\n [key: string]: unknown;\n\n /**\n * The numeric log level (0-5) or null.\n *\n * Consola log levels:\n * - 0: Fatal and Error\n * - 1: Warnings\n * - 2: Normal logs\n * - 3: Informational logs, success, fail, ready, start, box, ...\n * - 4: Debug logs\n * - 5: Trace logs\n * - null: Some special types like 'verbose'\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-level\n */\n level?: number | null;\n\n /**\n * The log type/method name (e.g., 'error', 'warn', 'info', 'debug', 'trace', 'success', 'fail', etc.).\n *\n * Consola built-in types include:\n * - Standard: silent, fatal, error, warn, log, info, success, fail, ready, start, box, debug, trace, verbose\n * - Custom types can also be defined\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-types\n */\n type?: string;\n\n /**\n * An optional tag/scope for the log entry.\n *\n * Tags are created using `consola.withTag('scope')` and help categorize logs.\n *\n * @example\n * ```ts\n * const scopedLogger = consola.withTag('auth');\n * scopedLogger.info('User logged in'); // tag will be 'auth'\n * ```\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#withtagtag\n */\n tag?: string;\n\n /**\n * The raw arguments passed to the log method.\n *\n * When `message` is not provided, these args are typically formatted into the final message.\n *\n * @example\n * ```ts\n * consola.info('Hello', 'world', { user: 'john' });\n * // args = ['Hello', 'world', { user: 'john' }]\n * ```\n */\n args?: unknown[];\n\n /**\n * The timestamp when the log was created.\n *\n * This is automatically set by Consola when the log is created.\n */\n date?: Date;\n\n /**\n * The formatted log message.\n *\n * When provided, this is the final formatted message. When not provided,\n * the message should be constructed from the `args` array.\n */\n message?: string;\n}\n\nconst DEFAULT_CAPTURED_LEVELS: Array<LogSeverityLevel> = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n\n/**\n * Creates a new Sentry reporter for Consola that forwards logs to Sentry. Requires the `enableLogs` option to be enabled.\n *\n * **Note: This integration supports Consola v3.x only.** The reporter interface and log object structure\n * may differ in other versions of Consola.\n *\n * @param options - Configuration options for the reporter.\n * @returns A Consola reporter that can be added to consola instances.\n *\n * @example\n * ```ts\n * import * as Sentry from '@sentry/node';\n * import { consola } from 'consola';\n *\n * Sentry.init({\n * enableLogs: true,\n * });\n *\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Optional: filter levels to capture\n * levels: ['error', 'warn', 'info'],\n * });\n *\n * consola.addReporter(sentryReporter);\n *\n * // Now consola logs will be captured by Sentry\n * consola.info('This will be sent to Sentry');\n * consola.error('This error will also be sent to Sentry');\n * ```\n */\nexport function createConsolaReporter(options: ConsolaReporterOptions = {}): ConsolaReporter {\n const levels = new Set(options.levels ?? DEFAULT_CAPTURED_LEVELS);\n const providedClient = options.client;\n\n return {\n log(logObj: ConsolaLogObject) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type, level, message: consolaMessage, args, tag, date: _date, ...attributes } = logObj;\n\n // Get client - use provided client or current client\n const client = providedClient || getClient();\n if (!client) {\n return;\n }\n\n // Determine the log severity level\n const logSeverityLevel = getLogSeverityLevel(type, level);\n\n // Early exit if this level should not be captured\n if (!levels.has(logSeverityLevel)) {\n return;\n }\n\n const { normalizeDepth = 3, normalizeMaxBreadth = 1_000 } = client.getOptions();\n\n // Format the log message using the same approach as consola's basic reporter\n const messageParts = [];\n if (consolaMessage) {\n messageParts.push(consolaMessage);\n }\n if (args && args.length > 0) {\n messageParts.push(formatConsoleArgs(args, normalizeDepth, normalizeMaxBreadth));\n }\n const message = messageParts.join(' ');\n\n // Build attributes\n attributes['sentry.origin'] = 'auto.log.consola';\n\n if (tag) {\n attributes['consola.tag'] = tag;\n }\n\n if (type) {\n attributes['consola.type'] = type;\n }\n\n // Only add level if it's a valid number (not null/undefined)\n if (level != null && typeof level === 'number') {\n attributes['consola.level'] = level;\n }\n\n _INTERNAL_captureLog({\n level: logSeverityLevel,\n message,\n attributes,\n });\n },\n };\n}\n\n// Mapping from consola log types to Sentry log severity levels\nconst CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP: Record<string, LogSeverityLevel> = {\n // Consola built-in types\n silent: 'trace',\n fatal: 'fatal',\n error: 'error',\n warn: 'warn',\n log: 'info',\n info: 'info',\n success: 'info',\n fail: 'error',\n ready: 'info',\n start: 'info',\n box: 'info',\n debug: 'debug',\n trace: 'trace',\n verbose: 'debug',\n // Custom types that might exist\n critical: 'fatal',\n notice: 'info',\n};\n\n// Mapping from consola log levels (numbers) to Sentry log severity levels\nconst CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP: Record<number, LogSeverityLevel> = {\n 0: 'fatal', // Fatal and Error\n 1: 'warn', // Warnings\n 2: 'info', // Normal logs\n 3: 'info', // Informational logs, success, fail, ready, start, ...\n 4: 'debug', // Debug logs\n 5: 'trace', // Trace logs\n};\n\n/**\n * Determines the log severity level from Consola type and level.\n *\n * @param type - The Consola log type (e.g., 'error', 'warn', 'info')\n * @param level - The Consola numeric log level (0-5) or null for some types like 'verbose'\n * @returns The corresponding Sentry log severity level\n */\nfunction getLogSeverityLevel(type?: string, level?: number | null): LogSeverityLevel {\n // Handle special case for verbose logs (level can be null with infinite level in Consola)\n if (type === 'verbose') {\n return 'debug';\n }\n\n // Handle silent logs - these should be at trace level\n if (type === 'silent') {\n return 'trace';\n }\n\n // First try to map by type (more specific)\n if (type) {\n const mappedLevel = CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP[type];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Fallback to level mapping (handle null level)\n if (typeof level === 'number') {\n const mappedLevel = CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP[level];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Default fallback\n return 'info';\n}\n"],"names":["getClient","formatConsoleArgs","_INTERNAL_captureLog"],"mappings":"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"}
1
+ {"version":3,"file":"consola.js","sources":["../../../src/integrations/consola.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { getClient } from '../currentScopes';\nimport { _INTERNAL_captureLog } from '../logs/internal';\nimport { formatConsoleArgs } from '../logs/utils';\nimport type { LogSeverityLevel } from '../types-hoist/log';\n\n/**\n * Options for the Sentry Consola reporter.\n */\ninterface ConsolaReporterOptions {\n /**\n * Use this option to filter which levels should be captured. By default, all levels are captured.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Only capture error and warn logs\n * levels: ['error', 'warn'],\n * });\n * consola.addReporter(sentryReporter);\n * ```\n */\n levels?: Array<LogSeverityLevel>;\n\n /**\n * Optionally provide a specific Sentry client instance to use for capturing logs.\n * If not provided, the current client will be retrieved using `getClient()`.\n *\n * This is useful when you want to use specific client options for log normalization\n * or when working with multiple client instances.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * client: myCustomClient,\n * });\n * ```\n */\n client?: Client;\n}\n\nexport interface ConsolaReporter {\n log: (logObj: ConsolaLogObject) => void;\n}\n\n/**\n * Represents a log object that Consola reporters receive.\n *\n * This interface matches the structure of log objects passed to Consola reporters.\n * See: https://github.com/unjs/consola#custom-reporters\n *\n * @example\n * ```ts\n * const reporter = {\n * log(logObj: ConsolaLogObject) {\n * console.log(`[${logObj.type}] ${logObj.message || logObj.args?.join(' ')}`);\n * }\n * };\n * consola.addReporter(reporter);\n * ```\n */\nexport interface ConsolaLogObject {\n /**\n * Allows additional custom properties to be set on the log object.\n * These properties will be captured as log attributes with a 'consola.' prefix.\n *\n * @example\n * ```ts\n * const reporter = Sentry.createConsolaReporter();\n * reporter.log({\n * type: 'info',\n * message: 'User action',\n * userId: 123,\n * sessionId: 'abc-123'\n * });\n * // Will create attributes: consola.userId and consola.sessionId\n * ```\n */\n [key: string]: unknown;\n\n /**\n * The numeric log level (0-5) or null.\n *\n * Consola log levels:\n * - 0: Fatal and Error\n * - 1: Warnings\n * - 2: Normal logs\n * - 3: Informational logs, success, fail, ready, start, box, ...\n * - 4: Debug logs\n * - 5: Trace logs\n * - null: Some special types like 'verbose'\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-level\n */\n level?: number | null;\n\n /**\n * The log type/method name (e.g., 'error', 'warn', 'info', 'debug', 'trace', 'success', 'fail', etc.).\n *\n * Consola built-in types include:\n * - Standard: silent, fatal, error, warn, log, info, success, fail, ready, start, box, debug, trace, verbose\n * - Custom types can also be defined\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-types\n */\n type?: string;\n\n /**\n * An optional tag/scope for the log entry.\n *\n * Tags are created using `consola.withTag('scope')` and help categorize logs.\n *\n * @example\n * ```ts\n * const scopedLogger = consola.withTag('auth');\n * scopedLogger.info('User logged in'); // tag will be 'auth'\n * ```\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#withtagtag\n */\n tag?: string;\n\n /**\n * The raw arguments passed to the log method.\n *\n * These args are typically formatted into the final `message`. In Consola reporters, `message` is not provided.\n *\n * @example\n * ```ts\n * consola.info('Hello', 'world', { user: 'john' });\n * // args = ['Hello', 'world', { user: 'john' }]\n * ```\n *\n * @example\n * ```ts\n * // `message` is a reserved property in Consola\n * consola.log({ message: 'Hello' });\n * // args = ['Hello']\n * ```\n */\n args?: unknown[];\n\n /**\n * The timestamp when the log was created.\n *\n * This is automatically set by Consola when the log is created.\n */\n date?: Date;\n\n /**\n * The formatted log message.\n *\n * When provided, this is the final formatted message. When not provided,\n * the message should be constructed from the `args` array.\n */\n message?: string;\n}\n\nconst DEFAULT_CAPTURED_LEVELS: Array<LogSeverityLevel> = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n\n/**\n * Creates a new Sentry reporter for Consola that forwards logs to Sentry. Requires the `enableLogs` option to be enabled.\n *\n * **Note: This integration supports Consola v3.x only.** The reporter interface and log object structure\n * may differ in other versions of Consola.\n *\n * @param options - Configuration options for the reporter.\n * @returns A Consola reporter that can be added to consola instances.\n *\n * @example\n * ```ts\n * import * as Sentry from '@sentry/node';\n * import { consola } from 'consola';\n *\n * Sentry.init({\n * enableLogs: true,\n * });\n *\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Optional: filter levels to capture\n * levels: ['error', 'warn', 'info'],\n * });\n *\n * consola.addReporter(sentryReporter);\n *\n * // Now consola logs will be captured by Sentry\n * consola.info('This will be sent to Sentry');\n * consola.error('This error will also be sent to Sentry');\n * ```\n */\nexport function createConsolaReporter(options: ConsolaReporterOptions = {}): ConsolaReporter {\n const levels = new Set(options.levels ?? DEFAULT_CAPTURED_LEVELS);\n const providedClient = options.client;\n\n return {\n log(logObj: ConsolaLogObject) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type, level, message: consolaMessage, args, tag, date: _date, ...attributes } = logObj;\n\n // Get client - use provided client or current client\n const client = providedClient || getClient();\n if (!client) {\n return;\n }\n\n // Determine the log severity level\n const logSeverityLevel = getLogSeverityLevel(type, level);\n\n // Early exit if this level should not be captured\n if (!levels.has(logSeverityLevel)) {\n return;\n }\n\n const { normalizeDepth = 3, normalizeMaxBreadth = 1_000 } = client.getOptions();\n\n // Format the log message using the same approach as consola's basic reporter\n const messageParts = [];\n if (consolaMessage) {\n messageParts.push(consolaMessage);\n }\n if (args && args.length > 0) {\n messageParts.push(formatConsoleArgs(args, normalizeDepth, normalizeMaxBreadth));\n }\n const message = messageParts.join(' ');\n\n // Build attributes\n attributes['sentry.origin'] = 'auto.log.consola';\n\n if (tag) {\n attributes['consola.tag'] = tag;\n }\n\n if (type) {\n attributes['consola.type'] = type;\n }\n\n // Only add level if it's a valid number (not null/undefined)\n if (level != null && typeof level === 'number') {\n attributes['consola.level'] = level;\n }\n\n _INTERNAL_captureLog({\n level: logSeverityLevel,\n message,\n attributes,\n });\n },\n };\n}\n\n// Mapping from consola log types to Sentry log severity levels\nconst CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP: Record<string, LogSeverityLevel> = {\n // Consola built-in types\n silent: 'trace',\n fatal: 'fatal',\n error: 'error',\n warn: 'warn',\n log: 'info',\n info: 'info',\n success: 'info',\n fail: 'error',\n ready: 'info',\n start: 'info',\n box: 'info',\n debug: 'debug',\n trace: 'trace',\n verbose: 'debug',\n // Custom types that might exist\n critical: 'fatal',\n notice: 'info',\n};\n\n// Mapping from consola log levels (numbers) to Sentry log severity levels\nconst CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP: Record<number, LogSeverityLevel> = {\n 0: 'fatal', // Fatal and Error\n 1: 'warn', // Warnings\n 2: 'info', // Normal logs\n 3: 'info', // Informational logs, success, fail, ready, start, ...\n 4: 'debug', // Debug logs\n 5: 'trace', // Trace logs\n};\n\n/**\n * Determines the log severity level from Consola type and level.\n *\n * @param type - The Consola log type (e.g., 'error', 'warn', 'info')\n * @param level - The Consola numeric log level (0-5) or null for some types like 'verbose'\n * @returns The corresponding Sentry log severity level\n */\nfunction getLogSeverityLevel(type?: string, level?: number | null): LogSeverityLevel {\n // Handle special case for verbose logs (level can be null with infinite level in Consola)\n if (type === 'verbose') {\n return 'debug';\n }\n\n // Handle silent logs - these should be at trace level\n if (type === 'silent') {\n return 'trace';\n }\n\n // First try to map by type (more specific)\n if (type) {\n const mappedLevel = CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP[type];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Fallback to level mapping (handle null level)\n if (typeof level === 'number') {\n const mappedLevel = CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP[level];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Default fallback\n return 'info';\n}\n"],"names":["getClient","formatConsoleArgs","_INTERNAL_captureLog"],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ /**
4
+ * Inline media content source, with a potentially very large base64
5
+ * blob or data: uri.
6
+ */
7
+
8
+ /**
9
+ * Check if a content part is an OpenAI/Anthropic media source
10
+ */
11
+ function isContentMedia(part) {
12
+ if (!part || typeof part !== 'object') return false;
13
+
14
+ return (
15
+ isContentMediaSource(part) ||
16
+ hasInlineData(part) ||
17
+ hasImageUrl(part) ||
18
+ hasInputAudio(part) ||
19
+ hasFileData(part) ||
20
+ hasMediaTypeData(part) ||
21
+ hasBlobOrBase64Type(part) ||
22
+ hasB64Json(part) ||
23
+ hasImageGenerationResult(part) ||
24
+ hasDataUri(part)
25
+ );
26
+ }
27
+
28
+ function hasImageUrl(part) {
29
+ if (!('image_url' in part)) return false;
30
+ if (typeof part.image_url === 'string') return part.image_url.startsWith('data:');
31
+ return hasNestedImageUrl(part);
32
+ }
33
+
34
+ function hasNestedImageUrl(part) {
35
+ return (
36
+ 'image_url' in part &&
37
+ !!part.image_url &&
38
+ typeof part.image_url === 'object' &&
39
+ 'url' in part.image_url &&
40
+ typeof part.image_url.url === 'string' &&
41
+ part.image_url.url.startsWith('data:')
42
+ );
43
+ }
44
+
45
+ function isContentMediaSource(part) {
46
+ return 'type' in part && typeof part.type === 'string' && 'source' in part && isContentMedia(part.source);
47
+ }
48
+
49
+ function hasInlineData(part) {
50
+ return (
51
+ 'inlineData' in part &&
52
+ !!part.inlineData &&
53
+ typeof part.inlineData === 'object' &&
54
+ 'data' in part.inlineData &&
55
+ typeof part.inlineData.data === 'string'
56
+ );
57
+ }
58
+
59
+ function hasInputAudio(part) {
60
+ return (
61
+ 'type' in part &&
62
+ part.type === 'input_audio' &&
63
+ 'input_audio' in part &&
64
+ !!part.input_audio &&
65
+ typeof part.input_audio === 'object' &&
66
+ 'data' in part.input_audio &&
67
+ typeof part.input_audio.data === 'string'
68
+ );
69
+ }
70
+
71
+ function hasFileData(part) {
72
+ return (
73
+ 'type' in part &&
74
+ part.type === 'file' &&
75
+ 'file' in part &&
76
+ !!part.file &&
77
+ typeof part.file === 'object' &&
78
+ 'file_data' in part.file &&
79
+ typeof part.file.file_data === 'string'
80
+ );
81
+ }
82
+
83
+ function hasMediaTypeData(part) {
84
+ return 'media_type' in part && typeof part.media_type === 'string' && 'data' in part;
85
+ }
86
+
87
+ function hasBlobOrBase64Type(part) {
88
+ return 'type' in part && (part.type === 'blob' || part.type === 'base64');
89
+ }
90
+
91
+ function hasB64Json(part) {
92
+ return 'b64_json' in part;
93
+ }
94
+
95
+ function hasImageGenerationResult(part) {
96
+ return 'type' in part && 'result' in part && part.type === 'image_generation';
97
+ }
98
+
99
+ function hasDataUri(part) {
100
+ return 'uri' in part && typeof part.uri === 'string' && part.uri.startsWith('data:');
101
+ }
102
+
103
+ const REMOVED_STRING = '[Blob substitute]';
104
+
105
+ const MEDIA_FIELDS = ['image_url', 'data', 'content', 'b64_json', 'result', 'uri'] ;
106
+
107
+ /**
108
+ * Replace inline binary data in a single media content part with a placeholder.
109
+ */
110
+ function stripInlineMediaFromSingleMessage(part) {
111
+ const strip = { ...part };
112
+ if (isContentMedia(strip.source)) {
113
+ strip.source = stripInlineMediaFromSingleMessage(strip.source);
114
+ }
115
+ if (hasInlineData(part)) {
116
+ strip.inlineData = { ...part.inlineData, data: REMOVED_STRING };
117
+ }
118
+ if (hasNestedImageUrl(part)) {
119
+ strip.image_url = { ...part.image_url, url: REMOVED_STRING };
120
+ }
121
+ if (hasInputAudio(part)) {
122
+ strip.input_audio = { ...part.input_audio, data: REMOVED_STRING };
123
+ }
124
+ if (hasFileData(part)) {
125
+ strip.file = { ...part.file, file_data: REMOVED_STRING };
126
+ }
127
+ for (const field of MEDIA_FIELDS) {
128
+ if (typeof strip[field] === 'string') strip[field] = REMOVED_STRING;
129
+ }
130
+ return strip;
131
+ }
132
+
133
+ exports.isContentMedia = isContentMedia;
134
+ exports.stripInlineMediaFromSingleMessage = stripInlineMediaFromSingleMessage;
135
+ //# sourceMappingURL=mediaStripping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaStripping.js","sources":["../../../../src/tracing/ai/mediaStripping.ts"],"sourcesContent":["/**\n * Inline media content source, with a potentially very large base64\n * blob or data: uri.\n */\nexport type ContentMedia = Record<string, unknown> &\n (\n | {\n media_type: string;\n data: string;\n }\n | {\n image_url: `data:${string}`;\n }\n | {\n image_url: { url: `data:${string}` };\n }\n | {\n type: 'blob' | 'base64';\n content: string;\n }\n | {\n b64_json: string;\n }\n | {\n uri: `data:${string}`;\n }\n | {\n type: 'input_audio';\n input_audio: { data: string };\n }\n | {\n type: 'file';\n file: { file_data?: string };\n }\n );\n\n/**\n * Check if a content part is an OpenAI/Anthropic media source\n */\nexport function isContentMedia(part: unknown): part is ContentMedia {\n if (!part || typeof part !== 'object') return false;\n\n return (\n isContentMediaSource(part) ||\n hasInlineData(part) ||\n hasImageUrl(part) ||\n hasInputAudio(part) ||\n hasFileData(part) ||\n hasMediaTypeData(part) ||\n hasBlobOrBase64Type(part) ||\n hasB64Json(part) ||\n hasImageGenerationResult(part) ||\n hasDataUri(part)\n );\n}\n\nfunction hasImageUrl(part: NonNullable<unknown>): boolean {\n if (!('image_url' in part)) return false;\n if (typeof part.image_url === 'string') return part.image_url.startsWith('data:');\n return hasNestedImageUrl(part);\n}\n\nfunction hasNestedImageUrl(part: NonNullable<unknown>): part is { image_url: { url: string } } {\n return (\n 'image_url' in part &&\n !!part.image_url &&\n typeof part.image_url === 'object' &&\n 'url' in part.image_url &&\n typeof part.image_url.url === 'string' &&\n part.image_url.url.startsWith('data:')\n );\n}\n\nfunction isContentMediaSource(part: NonNullable<unknown>): boolean {\n return 'type' in part && typeof part.type === 'string' && 'source' in part && isContentMedia(part.source);\n}\n\nfunction hasInlineData(part: NonNullable<unknown>): part is { inlineData: { data?: string } } {\n return (\n 'inlineData' in part &&\n !!part.inlineData &&\n typeof part.inlineData === 'object' &&\n 'data' in part.inlineData &&\n typeof part.inlineData.data === 'string'\n );\n}\n\nfunction hasInputAudio(part: NonNullable<unknown>): part is { type: 'input_audio'; input_audio: { data: string } } {\n return (\n 'type' in part &&\n part.type === 'input_audio' &&\n 'input_audio' in part &&\n !!part.input_audio &&\n typeof part.input_audio === 'object' &&\n 'data' in part.input_audio &&\n typeof part.input_audio.data === 'string'\n );\n}\n\nfunction hasFileData(part: NonNullable<unknown>): part is { type: 'file'; file: { file_data: string } } {\n return (\n 'type' in part &&\n part.type === 'file' &&\n 'file' in part &&\n !!part.file &&\n typeof part.file === 'object' &&\n 'file_data' in part.file &&\n typeof part.file.file_data === 'string'\n );\n}\n\nfunction hasMediaTypeData(part: NonNullable<unknown>): part is { media_type: string; data: string } {\n return 'media_type' in part && typeof part.media_type === 'string' && 'data' in part;\n}\n\nfunction hasBlobOrBase64Type(part: NonNullable<unknown>): part is { type: 'blob' | 'base64'; content: string } {\n return 'type' in part && (part.type === 'blob' || part.type === 'base64');\n}\n\nfunction hasB64Json(part: NonNullable<unknown>): part is { b64_json: string } {\n return 'b64_json' in part;\n}\n\nfunction hasImageGenerationResult(part: NonNullable<unknown>): part is { type: 'image_generation'; result: string } {\n return 'type' in part && 'result' in part && part.type === 'image_generation';\n}\n\nfunction hasDataUri(part: NonNullable<unknown>): part is { uri: string } {\n return 'uri' in part && typeof part.uri === 'string' && part.uri.startsWith('data:');\n}\n\nconst REMOVED_STRING = '[Blob substitute]';\n\nconst MEDIA_FIELDS = ['image_url', 'data', 'content', 'b64_json', 'result', 'uri'] as const;\n\n/**\n * Replace inline binary data in a single media content part with a placeholder.\n */\nexport function stripInlineMediaFromSingleMessage(part: ContentMedia): ContentMedia {\n const strip = { ...part };\n if (isContentMedia(strip.source)) {\n strip.source = stripInlineMediaFromSingleMessage(strip.source);\n }\n if (hasInlineData(part)) {\n strip.inlineData = { ...part.inlineData, data: REMOVED_STRING };\n }\n if (hasNestedImageUrl(part)) {\n strip.image_url = { ...part.image_url, url: REMOVED_STRING };\n }\n if (hasInputAudio(part)) {\n strip.input_audio = { ...part.input_audio, data: REMOVED_STRING };\n }\n if (hasFileData(part)) {\n strip.file = { ...part.file, file_data: REMOVED_STRING };\n }\n for (const field of MEDIA_FIELDS) {\n if (typeof strip[field] === 'string') strip[field] = REMOVED_STRING;\n }\n return strip;\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
+ const mediaStripping = require('./mediaStripping.js');
4
+
3
5
  /**
4
6
  * Default maximum size in bytes for GenAI messages.
5
7
  * Messages exceeding this limit will be truncated.
@@ -25,12 +27,12 @@ const jsonBytes = (value) => {
25
27
  };
26
28
 
27
29
  /**
28
- * Truncate a string to fit within maxBytes when encoded as UTF-8.
30
+ * Truncate a string to fit within maxBytes (inclusive) when encoded as UTF-8.
29
31
  * Uses binary search for efficiency with multi-byte characters.
30
32
  *
31
33
  * @param text - The string to truncate
32
- * @param maxBytes - Maximum byte length (UTF-8 encoded)
33
- * @returns Truncated string that fits within maxBytes
34
+ * @param maxBytes - Maximum byte length (inclusive, UTF-8 encoded)
35
+ * @returns Truncated string whose UTF-8 byte length is at most maxBytes
34
36
  */
35
37
  function truncateTextByBytes(text, maxBytes) {
36
38
  if (utf8Bytes(text) <= maxBytes) {
@@ -104,36 +106,6 @@ function isContentArrayMessage(message) {
104
106
  return message !== null && typeof message === 'object' && 'content' in message && Array.isArray(message.content);
105
107
  }
106
108
 
107
- /**
108
- * Check if a content part is an OpenAI/Anthropic media source
109
- */
110
- function isContentMedia(part) {
111
- if (!part || typeof part !== 'object') return false;
112
-
113
- return (
114
- isContentMediaSource(part) ||
115
- hasInlineData(part) ||
116
- ('media_type' in part && typeof part.media_type === 'string' && 'data' in part) ||
117
- ('image_url' in part && typeof part.image_url === 'string' && part.image_url.startsWith('data:')) ||
118
- ('type' in part && (part.type === 'blob' || part.type === 'base64')) ||
119
- 'b64_json' in part ||
120
- ('type' in part && 'result' in part && part.type === 'image_generation') ||
121
- ('uri' in part && typeof part.uri === 'string' && part.uri.startsWith('data:'))
122
- );
123
- }
124
- function isContentMediaSource(part) {
125
- return 'type' in part && typeof part.type === 'string' && 'source' in part && isContentMedia(part.source);
126
- }
127
- function hasInlineData(part) {
128
- return (
129
- 'inlineData' in part &&
130
- !!part.inlineData &&
131
- typeof part.inlineData === 'object' &&
132
- 'data' in part.inlineData &&
133
- typeof part.inlineData.data === 'string'
134
- );
135
- }
136
-
137
109
  /**
138
110
  * Check if a message has the Google GenAI parts format.
139
111
  */
@@ -258,25 +230,6 @@ function truncateSingleMessage(message, maxBytes) {
258
230
  return [];
259
231
  }
260
232
 
261
- const REMOVED_STRING = '[Filtered]';
262
-
263
- const MEDIA_FIELDS = ['image_url', 'data', 'content', 'b64_json', 'result', 'uri'] ;
264
-
265
- function stripInlineMediaFromSingleMessage(part) {
266
- const strip = { ...part };
267
- if (isContentMedia(strip.source)) {
268
- strip.source = stripInlineMediaFromSingleMessage(strip.source);
269
- }
270
- // google genai inline data blob objects
271
- if (hasInlineData(part)) {
272
- strip.inlineData = { ...part.inlineData, data: REMOVED_STRING };
273
- }
274
- for (const field of MEDIA_FIELDS) {
275
- if (typeof strip[field] === 'string') strip[field] = REMOVED_STRING;
276
- }
277
- return strip;
278
- }
279
-
280
233
  /**
281
234
  * Strip the inline media from message arrays.
282
235
  *
@@ -292,10 +245,10 @@ function stripInlineMediaFromMessages(messages) {
292
245
  ...message,
293
246
  content: stripInlineMediaFromMessages(message.content),
294
247
  };
295
- } else if ('content' in message && isContentMedia(message.content)) {
248
+ } else if ('content' in message && mediaStripping.isContentMedia(message.content)) {
296
249
  newMessage = {
297
250
  ...message,
298
- content: stripInlineMediaFromSingleMessage(message.content),
251
+ content: mediaStripping.stripInlineMediaFromSingleMessage(message.content),
299
252
  };
300
253
  }
301
254
  if (isPartsMessage(message)) {
@@ -305,10 +258,10 @@ function stripInlineMediaFromMessages(messages) {
305
258
  parts: stripInlineMediaFromMessages(message.parts),
306
259
  };
307
260
  }
308
- if (isContentMedia(newMessage)) {
309
- newMessage = stripInlineMediaFromSingleMessage(newMessage);
310
- } else if (isContentMedia(message)) {
311
- newMessage = stripInlineMediaFromSingleMessage(message);
261
+ if (mediaStripping.isContentMedia(newMessage)) {
262
+ newMessage = mediaStripping.stripInlineMediaFromSingleMessage(newMessage);
263
+ } else if (mediaStripping.isContentMedia(message)) {
264
+ newMessage = mediaStripping.stripInlineMediaFromSingleMessage(message);
312
265
  }
313
266
  }
314
267
  return newMessage ?? message;
@@ -341,6 +294,11 @@ function truncateMessagesByBytes(messages, maxBytes) {
341
294
  return messages;
342
295
  }
343
296
 
297
+ // The result is always a single-element array that callers wrap with
298
+ // JSON.stringify([message]), so subtract the 2-byte array wrapper ("[" and "]")
299
+ // to ensure the final serialized value stays under the limit.
300
+ const effectiveMaxBytes = maxBytes - 2;
301
+
344
302
  // Always keep only the last message
345
303
  const lastMessage = messages[messages.length - 1];
346
304
 
@@ -350,12 +308,12 @@ function truncateMessagesByBytes(messages, maxBytes) {
350
308
 
351
309
  // Check if it fits
352
310
  const messageBytes = jsonBytes(strippedMessage);
353
- if (messageBytes <= maxBytes) {
311
+ if (messageBytes <= effectiveMaxBytes) {
354
312
  return stripped;
355
313
  }
356
314
 
357
315
  // Truncate the single message if needed
358
- return truncateSingleMessage(strippedMessage, maxBytes);
316
+ return truncateSingleMessage(strippedMessage, effectiveMaxBytes);
359
317
  }
360
318
 
361
319
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"messageTruncation.js","sources":["../../../../src/tracing/ai/messageTruncation.ts"],"sourcesContent":["/**\n * Default maximum size in bytes for GenAI messages.\n * Messages exceeding this limit will be truncated.\n */\nexport const DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT = 20000;\n\n/**\n * Message format used by OpenAI and Anthropic APIs.\n */\ntype ContentMessage = {\n [key: string]: unknown;\n content: string;\n};\n\n/**\n * Message format used by OpenAI and Anthropic APIs for media.\n */\ntype ContentArrayMessage = {\n [key: string]: unknown;\n content: {\n [key: string]: unknown;\n type: string;\n }[];\n};\n\n/**\n * Inline media content source, with a potentially very large base64\n * blob or data: uri.\n */\ntype ContentMedia = Record<string, unknown> &\n (\n | {\n media_type: string;\n data: string;\n }\n | {\n image_url: `data:${string}`;\n }\n | {\n type: 'blob' | 'base64';\n content: string;\n }\n | {\n b64_json: string;\n }\n | {\n uri: `data:${string}`;\n }\n );\n\n/**\n * Message format used by Google GenAI API.\n * Parts can be strings or objects with a text property.\n */\ntype PartsMessage = {\n [key: string]: unknown;\n parts: Array<TextPart | MediaPart>;\n};\n\n/**\n * A part in a Google GenAI message that contains text.\n */\ntype TextPart = string | { text: string };\n\n/**\n * A part in a Google GenAI that contains media.\n */\ntype MediaPart = {\n type: string;\n content: string;\n};\n\n/**\n * Calculate the UTF-8 byte length of a string.\n */\nconst utf8Bytes = (text: string): number => {\n return new TextEncoder().encode(text).length;\n};\n\n/**\n * Calculate the UTF-8 byte length of a value's JSON representation.\n */\nconst jsonBytes = (value: unknown): number => {\n return utf8Bytes(JSON.stringify(value));\n};\n\n/**\n * Truncate a string to fit within maxBytes when encoded as UTF-8.\n * Uses binary search for efficiency with multi-byte characters.\n *\n * @param text - The string to truncate\n * @param maxBytes - Maximum byte length (UTF-8 encoded)\n * @returns Truncated string that fits within maxBytes\n */\nfunction truncateTextByBytes(text: string, maxBytes: number): string {\n if (utf8Bytes(text) <= maxBytes) {\n return text;\n }\n\n let low = 0;\n let high = text.length;\n let bestFit = '';\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n const candidate = text.slice(0, mid);\n const byteSize = utf8Bytes(candidate);\n\n if (byteSize <= maxBytes) {\n bestFit = candidate;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return bestFit;\n}\n\n/**\n * Extract text content from a Google GenAI message part.\n * Parts are either plain strings or objects with a text property.\n *\n * @returns The text content\n */\nfunction getPartText(part: TextPart | MediaPart): string {\n if (typeof part === 'string') {\n return part;\n }\n if ('text' in part) return part.text;\n return '';\n}\n\n/**\n * Create a new part with updated text content while preserving the original structure.\n *\n * @param part - Original part (string or object)\n * @param text - New text content\n * @returns New part with updated text\n */\nfunction withPartText(part: TextPart | MediaPart, text: string): TextPart {\n if (typeof part === 'string') {\n return text;\n }\n return { ...part, text };\n}\n\n/**\n * Check if a message has the OpenAI/Anthropic content format.\n */\nfunction isContentMessage(message: unknown): message is ContentMessage {\n return (\n message !== null &&\n typeof message === 'object' &&\n 'content' in message &&\n typeof (message as ContentMessage).content === 'string'\n );\n}\n\n/**\n * Check if a message has the OpenAI/Anthropic content array format.\n */\nfunction isContentArrayMessage(message: unknown): message is ContentArrayMessage {\n return message !== null && typeof message === 'object' && 'content' in message && Array.isArray(message.content);\n}\n\n/**\n * Check if a content part is an OpenAI/Anthropic media source\n */\nfunction isContentMedia(part: unknown): part is ContentMedia {\n if (!part || typeof part !== 'object') return false;\n\n return (\n isContentMediaSource(part) ||\n hasInlineData(part) ||\n ('media_type' in part && typeof part.media_type === 'string' && 'data' in part) ||\n ('image_url' in part && typeof part.image_url === 'string' && part.image_url.startsWith('data:')) ||\n ('type' in part && (part.type === 'blob' || part.type === 'base64')) ||\n 'b64_json' in part ||\n ('type' in part && 'result' in part && part.type === 'image_generation') ||\n ('uri' in part && typeof part.uri === 'string' && part.uri.startsWith('data:'))\n );\n}\nfunction isContentMediaSource(part: NonNullable<unknown>): boolean {\n return 'type' in part && typeof part.type === 'string' && 'source' in part && isContentMedia(part.source);\n}\nfunction hasInlineData(part: NonNullable<unknown>): part is { inlineData: { data?: string } } {\n return (\n 'inlineData' in part &&\n !!part.inlineData &&\n typeof part.inlineData === 'object' &&\n 'data' in part.inlineData &&\n typeof part.inlineData.data === 'string'\n );\n}\n\n/**\n * Check if a message has the Google GenAI parts format.\n */\nfunction isPartsMessage(message: unknown): message is PartsMessage {\n return (\n message !== null &&\n typeof message === 'object' &&\n 'parts' in message &&\n Array.isArray((message as PartsMessage).parts) &&\n (message as PartsMessage).parts.length > 0\n );\n}\n\n/**\n * Truncate a message with `content: string` format (OpenAI/Anthropic).\n *\n * @param message - Message with content property\n * @param maxBytes - Maximum byte limit\n * @returns Array with truncated message, or empty array if it doesn't fit\n */\nfunction truncateContentMessage(message: ContentMessage, maxBytes: number): unknown[] {\n // Calculate overhead (message structure without content)\n const emptyMessage = { ...message, content: '' };\n const overhead = jsonBytes(emptyMessage);\n const availableForContent = maxBytes - overhead;\n\n if (availableForContent <= 0) {\n return [];\n }\n\n const truncatedContent = truncateTextByBytes(message.content, availableForContent);\n return [{ ...message, content: truncatedContent }];\n}\n\n/**\n * Truncate a message with `parts: [...]` format (Google GenAI).\n * Keeps as many complete parts as possible, only truncating the first part if needed.\n *\n * @param message - Message with parts array\n * @param maxBytes - Maximum byte limit\n * @returns Array with truncated message, or empty array if it doesn't fit\n */\nfunction truncatePartsMessage(message: PartsMessage, maxBytes: number): unknown[] {\n const { parts } = message;\n\n // Calculate overhead by creating empty text parts\n const emptyParts = parts.map(part => withPartText(part, ''));\n const overhead = jsonBytes({ ...message, parts: emptyParts });\n let remainingBytes = maxBytes - overhead;\n\n if (remainingBytes <= 0) {\n return [];\n }\n\n // Include parts until we run out of space\n const includedParts: (TextPart | MediaPart)[] = [];\n\n for (const part of parts) {\n const text = getPartText(part);\n const textSize = utf8Bytes(text);\n\n if (textSize <= remainingBytes) {\n // Part fits: include it as-is\n includedParts.push(part);\n remainingBytes -= textSize;\n } else if (includedParts.length === 0) {\n // First part doesn't fit: truncate it\n const truncated = truncateTextByBytes(text, remainingBytes);\n if (truncated) {\n includedParts.push(withPartText(part, truncated));\n }\n break;\n } else {\n // Subsequent part doesn't fit: stop here\n break;\n }\n }\n\n /* c8 ignore start\n * for type safety only, algorithm guarantees SOME text included */\n if (includedParts.length <= 0) {\n return [];\n } else {\n /* c8 ignore stop */\n return [{ ...message, parts: includedParts }];\n }\n}\n\n/**\n * Truncate a single message to fit within maxBytes.\n *\n * Supports two message formats:\n * - OpenAI/Anthropic: `{ ..., content: string }`\n * - Google GenAI: `{ ..., parts: Array<string | {text: string} | non-text> }`\n *\n * @param message - The message to truncate\n * @param maxBytes - Maximum byte limit for the message\n * @returns Array containing the truncated message, or empty array if truncation fails\n */\nfunction truncateSingleMessage(message: unknown, maxBytes: number): unknown[] {\n if (!message) return [];\n\n // Handle plain strings (e.g., embeddings input)\n if (typeof message === 'string') {\n const truncated = truncateTextByBytes(message, maxBytes);\n return truncated ? [truncated] : [];\n }\n\n if (typeof message !== 'object') {\n return [];\n }\n\n if (isContentMessage(message)) {\n return truncateContentMessage(message, maxBytes);\n }\n\n if (isPartsMessage(message)) {\n return truncatePartsMessage(message, maxBytes);\n }\n\n // Unknown message format: cannot truncate safely\n return [];\n}\n\nconst REMOVED_STRING = '[Filtered]';\n\nconst MEDIA_FIELDS = ['image_url', 'data', 'content', 'b64_json', 'result', 'uri'] as const;\n\nfunction stripInlineMediaFromSingleMessage(part: ContentMedia): ContentMedia {\n const strip = { ...part };\n if (isContentMedia(strip.source)) {\n strip.source = stripInlineMediaFromSingleMessage(strip.source);\n }\n // google genai inline data blob objects\n if (hasInlineData(part)) {\n strip.inlineData = { ...part.inlineData, data: REMOVED_STRING };\n }\n for (const field of MEDIA_FIELDS) {\n if (typeof strip[field] === 'string') strip[field] = REMOVED_STRING;\n }\n return strip;\n}\n\n/**\n * Strip the inline media from message arrays.\n *\n * This returns a stripped message. We do NOT want to mutate the data in place,\n * because of course we still want the actual API/client to handle the media.\n */\nfunction stripInlineMediaFromMessages(messages: unknown[]): unknown[] {\n const stripped = messages.map(message => {\n let newMessage: Record<string, unknown> | undefined = undefined;\n if (!!message && typeof message === 'object') {\n if (isContentArrayMessage(message)) {\n newMessage = {\n ...message,\n content: stripInlineMediaFromMessages(message.content),\n };\n } else if ('content' in message && isContentMedia(message.content)) {\n newMessage = {\n ...message,\n content: stripInlineMediaFromSingleMessage(message.content),\n };\n }\n if (isPartsMessage(message)) {\n newMessage = {\n // might have to strip content AND parts\n ...(newMessage ?? message),\n parts: stripInlineMediaFromMessages(message.parts),\n };\n }\n if (isContentMedia(newMessage)) {\n newMessage = stripInlineMediaFromSingleMessage(newMessage);\n } else if (isContentMedia(message)) {\n newMessage = stripInlineMediaFromSingleMessage(message);\n }\n }\n return newMessage ?? message;\n });\n return stripped;\n}\n\n/**\n * Truncate an array of messages to fit within a byte limit.\n *\n * Strategy:\n * - Always keeps only the last (newest) message\n * - Strips inline media from the message\n * - Truncates the message content if it exceeds the byte limit\n *\n * @param messages - Array of messages to truncate\n * @param maxBytes - Maximum total byte limit for the message\n * @returns Array containing only the last message (possibly truncated)\n *\n * @example\n * ```ts\n * const messages = [msg1, msg2, msg3, msg4]; // newest is msg4\n * const truncated = truncateMessagesByBytes(messages, 10000);\n * // Returns [msg4] (truncated if needed)\n * ```\n */\nfunction truncateMessagesByBytes(messages: unknown[], maxBytes: number): unknown[] {\n // Early return for empty or invalid input\n if (!Array.isArray(messages) || messages.length === 0) {\n return messages;\n }\n\n // Always keep only the last message\n const lastMessage = messages[messages.length - 1];\n\n // Strip inline media from the single message\n const stripped = stripInlineMediaFromMessages([lastMessage]);\n const strippedMessage = stripped[0];\n\n // Check if it fits\n const messageBytes = jsonBytes(strippedMessage);\n if (messageBytes <= maxBytes) {\n return stripped;\n }\n\n // Truncate the single message if needed\n return truncateSingleMessage(strippedMessage, maxBytes);\n}\n\n/**\n * Truncate GenAI messages using the default byte limit.\n *\n * Convenience wrapper around `truncateMessagesByBytes` with the default limit.\n *\n * @param messages - Array of messages to truncate\n * @returns Truncated array of messages\n */\nexport function truncateGenAiMessages(messages: unknown[]): unknown[] {\n return truncateMessagesByBytes(messages, DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT);\n}\n\n/**\n * Truncate GenAI string input using the default byte limit.\n *\n * @param input - The string to truncate\n * @returns Truncated string\n */\nexport function truncateGenAiStringInput(input: string): string {\n return truncateTextByBytes(input, DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messageTruncation.js","sources":["../../../../src/tracing/ai/messageTruncation.ts"],"sourcesContent":["import { isContentMedia, stripInlineMediaFromSingleMessage } from './mediaStripping';\n\n/**\n * Default maximum size in bytes for GenAI messages.\n * Messages exceeding this limit will be truncated.\n */\nexport const DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT = 20000;\n\n/**\n * Message format used by OpenAI and Anthropic APIs.\n */\ntype ContentMessage = {\n [key: string]: unknown;\n content: string;\n};\n\n/**\n * Message format used by OpenAI and Anthropic APIs for media.\n */\ntype ContentArrayMessage = {\n [key: string]: unknown;\n content: {\n [key: string]: unknown;\n type: string;\n }[];\n};\n\n/**\n * Message format used by Google GenAI API.\n * Parts can be strings or objects with a text property.\n */\ntype PartsMessage = {\n [key: string]: unknown;\n parts: Array<TextPart | MediaPart>;\n};\n\n/**\n * A part in a Google GenAI message that contains text.\n */\ntype TextPart = string | { text: string };\n\n/**\n * A part in a Google GenAI that contains media.\n */\ntype MediaPart = {\n type: string;\n content: string;\n};\n\n/**\n * Calculate the UTF-8 byte length of a string.\n */\nconst utf8Bytes = (text: string): number => {\n return new TextEncoder().encode(text).length;\n};\n\n/**\n * Calculate the UTF-8 byte length of a value's JSON representation.\n */\nconst jsonBytes = (value: unknown): number => {\n return utf8Bytes(JSON.stringify(value));\n};\n\n/**\n * Truncate a string to fit within maxBytes (inclusive) when encoded as UTF-8.\n * Uses binary search for efficiency with multi-byte characters.\n *\n * @param text - The string to truncate\n * @param maxBytes - Maximum byte length (inclusive, UTF-8 encoded)\n * @returns Truncated string whose UTF-8 byte length is at most maxBytes\n */\nfunction truncateTextByBytes(text: string, maxBytes: number): string {\n if (utf8Bytes(text) <= maxBytes) {\n return text;\n }\n\n let low = 0;\n let high = text.length;\n let bestFit = '';\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n const candidate = text.slice(0, mid);\n const byteSize = utf8Bytes(candidate);\n\n if (byteSize <= maxBytes) {\n bestFit = candidate;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return bestFit;\n}\n\n/**\n * Extract text content from a Google GenAI message part.\n * Parts are either plain strings or objects with a text property.\n *\n * @returns The text content\n */\nfunction getPartText(part: TextPart | MediaPart): string {\n if (typeof part === 'string') {\n return part;\n }\n if ('text' in part) return part.text;\n return '';\n}\n\n/**\n * Create a new part with updated text content while preserving the original structure.\n *\n * @param part - Original part (string or object)\n * @param text - New text content\n * @returns New part with updated text\n */\nfunction withPartText(part: TextPart | MediaPart, text: string): TextPart {\n if (typeof part === 'string') {\n return text;\n }\n return { ...part, text };\n}\n\n/**\n * Check if a message has the OpenAI/Anthropic content format.\n */\nfunction isContentMessage(message: unknown): message is ContentMessage {\n return (\n message !== null &&\n typeof message === 'object' &&\n 'content' in message &&\n typeof (message as ContentMessage).content === 'string'\n );\n}\n\n/**\n * Check if a message has the OpenAI/Anthropic content array format.\n */\nfunction isContentArrayMessage(message: unknown): message is ContentArrayMessage {\n return message !== null && typeof message === 'object' && 'content' in message && Array.isArray(message.content);\n}\n\n/**\n * Check if a message has the Google GenAI parts format.\n */\nfunction isPartsMessage(message: unknown): message is PartsMessage {\n return (\n message !== null &&\n typeof message === 'object' &&\n 'parts' in message &&\n Array.isArray((message as PartsMessage).parts) &&\n (message as PartsMessage).parts.length > 0\n );\n}\n\n/**\n * Truncate a message with `content: string` format (OpenAI/Anthropic).\n *\n * @param message - Message with content property\n * @param maxBytes - Maximum byte limit\n * @returns Array with truncated message, or empty array if it doesn't fit\n */\nfunction truncateContentMessage(message: ContentMessage, maxBytes: number): unknown[] {\n // Calculate overhead (message structure without content)\n const emptyMessage = { ...message, content: '' };\n const overhead = jsonBytes(emptyMessage);\n const availableForContent = maxBytes - overhead;\n\n if (availableForContent <= 0) {\n return [];\n }\n\n const truncatedContent = truncateTextByBytes(message.content, availableForContent);\n return [{ ...message, content: truncatedContent }];\n}\n\n/**\n * Truncate a message with `parts: [...]` format (Google GenAI).\n * Keeps as many complete parts as possible, only truncating the first part if needed.\n *\n * @param message - Message with parts array\n * @param maxBytes - Maximum byte limit\n * @returns Array with truncated message, or empty array if it doesn't fit\n */\nfunction truncatePartsMessage(message: PartsMessage, maxBytes: number): unknown[] {\n const { parts } = message;\n\n // Calculate overhead by creating empty text parts\n const emptyParts = parts.map(part => withPartText(part, ''));\n const overhead = jsonBytes({ ...message, parts: emptyParts });\n let remainingBytes = maxBytes - overhead;\n\n if (remainingBytes <= 0) {\n return [];\n }\n\n // Include parts until we run out of space\n const includedParts: (TextPart | MediaPart)[] = [];\n\n for (const part of parts) {\n const text = getPartText(part);\n const textSize = utf8Bytes(text);\n\n if (textSize <= remainingBytes) {\n // Part fits: include it as-is\n includedParts.push(part);\n remainingBytes -= textSize;\n } else if (includedParts.length === 0) {\n // First part doesn't fit: truncate it\n const truncated = truncateTextByBytes(text, remainingBytes);\n if (truncated) {\n includedParts.push(withPartText(part, truncated));\n }\n break;\n } else {\n // Subsequent part doesn't fit: stop here\n break;\n }\n }\n\n /* c8 ignore start\n * for type safety only, algorithm guarantees SOME text included */\n if (includedParts.length <= 0) {\n return [];\n } else {\n /* c8 ignore stop */\n return [{ ...message, parts: includedParts }];\n }\n}\n\n/**\n * Truncate a single message to fit within maxBytes.\n *\n * Supports two message formats:\n * - OpenAI/Anthropic: `{ ..., content: string }`\n * - Google GenAI: `{ ..., parts: Array<string | {text: string} | non-text> }`\n *\n * @param message - The message to truncate\n * @param maxBytes - Maximum byte limit for the message\n * @returns Array containing the truncated message, or empty array if truncation fails\n */\nfunction truncateSingleMessage(message: unknown, maxBytes: number): unknown[] {\n if (!message) return [];\n\n // Handle plain strings (e.g., embeddings input)\n if (typeof message === 'string') {\n const truncated = truncateTextByBytes(message, maxBytes);\n return truncated ? [truncated] : [];\n }\n\n if (typeof message !== 'object') {\n return [];\n }\n\n if (isContentMessage(message)) {\n return truncateContentMessage(message, maxBytes);\n }\n\n if (isPartsMessage(message)) {\n return truncatePartsMessage(message, maxBytes);\n }\n\n // Unknown message format: cannot truncate safely\n return [];\n}\n\n/**\n * Strip the inline media from message arrays.\n *\n * This returns a stripped message. We do NOT want to mutate the data in place,\n * because of course we still want the actual API/client to handle the media.\n */\nfunction stripInlineMediaFromMessages(messages: unknown[]): unknown[] {\n const stripped = messages.map(message => {\n let newMessage: Record<string, unknown> | undefined = undefined;\n if (!!message && typeof message === 'object') {\n if (isContentArrayMessage(message)) {\n newMessage = {\n ...message,\n content: stripInlineMediaFromMessages(message.content),\n };\n } else if ('content' in message && isContentMedia(message.content)) {\n newMessage = {\n ...message,\n content: stripInlineMediaFromSingleMessage(message.content),\n };\n }\n if (isPartsMessage(message)) {\n newMessage = {\n // might have to strip content AND parts\n ...(newMessage ?? message),\n parts: stripInlineMediaFromMessages(message.parts),\n };\n }\n if (isContentMedia(newMessage)) {\n newMessage = stripInlineMediaFromSingleMessage(newMessage);\n } else if (isContentMedia(message)) {\n newMessage = stripInlineMediaFromSingleMessage(message);\n }\n }\n return newMessage ?? message;\n });\n return stripped;\n}\n\n/**\n * Truncate an array of messages to fit within a byte limit.\n *\n * Strategy:\n * - Always keeps only the last (newest) message\n * - Strips inline media from the message\n * - Truncates the message content if it exceeds the byte limit\n *\n * @param messages - Array of messages to truncate\n * @param maxBytes - Maximum total byte limit for the message\n * @returns Array containing only the last message (possibly truncated)\n *\n * @example\n * ```ts\n * const messages = [msg1, msg2, msg3, msg4]; // newest is msg4\n * const truncated = truncateMessagesByBytes(messages, 10000);\n * // Returns [msg4] (truncated if needed)\n * ```\n */\nfunction truncateMessagesByBytes(messages: unknown[], maxBytes: number): unknown[] {\n // Early return for empty or invalid input\n if (!Array.isArray(messages) || messages.length === 0) {\n return messages;\n }\n\n // The result is always a single-element array that callers wrap with\n // JSON.stringify([message]), so subtract the 2-byte array wrapper (\"[\" and \"]\")\n // to ensure the final serialized value stays under the limit.\n const effectiveMaxBytes = maxBytes - 2;\n\n // Always keep only the last message\n const lastMessage = messages[messages.length - 1];\n\n // Strip inline media from the single message\n const stripped = stripInlineMediaFromMessages([lastMessage]);\n const strippedMessage = stripped[0];\n\n // Check if it fits\n const messageBytes = jsonBytes(strippedMessage);\n if (messageBytes <= effectiveMaxBytes) {\n return stripped;\n }\n\n // Truncate the single message if needed\n return truncateSingleMessage(strippedMessage, effectiveMaxBytes);\n}\n\n/**\n * Truncate GenAI messages using the default byte limit.\n *\n * Convenience wrapper around `truncateMessagesByBytes` with the default limit.\n *\n * @param messages - Array of messages to truncate\n * @returns Truncated array of messages\n */\nexport function truncateGenAiMessages(messages: unknown[]): unknown[] {\n return truncateMessagesByBytes(messages, DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT);\n}\n\n/**\n * Truncate GenAI string input using the default byte limit.\n *\n * @param input - The string to truncate\n * @returns Truncated string\n */\nexport function truncateGenAiStringInput(input: string): string {\n return truncateTextByBytes(input, DEFAULT_GEN_AI_MESSAGES_BYTE_LIMIT);\n}\n"],"names":["isContentMedia","stripInlineMediaFromSingleMessage"],"mappings":"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"}
@@ -183,7 +183,7 @@ function handleStreamingRequest(
183
183
  ) {
184
184
  const model = requestAttributes[genAiAttributes.GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';
185
185
  const spanConfig = {
186
- name: `${operationName} ${model} stream-response`,
186
+ name: `${operationName} ${model}`,
187
187
  op: utils$1.getSpanOperation(methodPath),
188
188
  attributes: requestAttributes ,
189
189
  };