@sentry/core 10.50.0 → 10.51.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 (188) hide show
  1. package/build/cjs/client.js +27 -3
  2. package/build/cjs/client.js.map +1 -1
  3. package/build/cjs/envelope.js +4 -1
  4. package/build/cjs/envelope.js.map +1 -1
  5. package/build/cjs/index.js +10 -5
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/instrument/console.js +3 -1
  8. package/build/cjs/instrument/console.js.map +1 -1
  9. package/build/cjs/instrument/fetch.js +6 -2
  10. package/build/cjs/instrument/fetch.js.map +1 -1
  11. package/build/cjs/instrument/handlers.js +11 -1
  12. package/build/cjs/instrument/handlers.js.map +1 -1
  13. package/build/cjs/integrations/console.js +3 -1
  14. package/build/cjs/integrations/console.js.map +1 -1
  15. package/build/cjs/integrations/extraerrordata.js +2 -2
  16. package/build/cjs/integrations/extraerrordata.js.map +1 -1
  17. package/build/cjs/integrations/postgresjs.js +10 -1
  18. package/build/cjs/integrations/postgresjs.js.map +1 -1
  19. package/build/cjs/integrations/requestdata.js +9 -5
  20. package/build/cjs/integrations/requestdata.js.map +1 -1
  21. package/build/cjs/integrations/supabase.js +39 -12
  22. package/build/cjs/integrations/supabase.js.map +1 -1
  23. package/build/cjs/logs/console-integration.js +3 -1
  24. package/build/cjs/logs/console-integration.js.map +1 -1
  25. package/build/cjs/server-runtime-client.js +20 -2
  26. package/build/cjs/server-runtime-client.js.map +1 -1
  27. package/build/cjs/tracing/ai/gen-ai-attributes.js +6 -0
  28. package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
  29. package/build/cjs/tracing/idleSpan.js +7 -1
  30. package/build/cjs/tracing/idleSpan.js.map +1 -1
  31. package/build/cjs/tracing/langchain/index.js +43 -8
  32. package/build/cjs/tracing/langchain/index.js.map +1 -1
  33. package/build/cjs/tracing/langchain/utils.js +44 -10
  34. package/build/cjs/tracing/langchain/utils.js.map +1 -1
  35. package/build/cjs/tracing/langgraph/index.js +105 -2
  36. package/build/cjs/tracing/langgraph/index.js.map +1 -1
  37. package/build/cjs/tracing/langgraph/utils.js +168 -0
  38. package/build/cjs/tracing/langgraph/utils.js.map +1 -1
  39. package/build/cjs/tracing/spans/captureSpan.js +125 -0
  40. package/build/cjs/tracing/spans/captureSpan.js.map +1 -1
  41. package/build/cjs/tracing/spans/envelope.js +13 -3
  42. package/build/cjs/tracing/spans/envelope.js.map +1 -1
  43. package/build/cjs/tracing/trace.js +1 -0
  44. package/build/cjs/tracing/trace.js.map +1 -1
  45. package/build/cjs/trpc.js +2 -3
  46. package/build/cjs/trpc.js.map +1 -1
  47. package/build/cjs/utils/isSentryRequestUrl.js +9 -1
  48. package/build/cjs/utils/isSentryRequestUrl.js.map +1 -1
  49. package/build/cjs/utils/normalizationHints.js +38 -0
  50. package/build/cjs/utils/normalizationHints.js.map +1 -0
  51. package/build/cjs/utils/normalize.js +7 -11
  52. package/build/cjs/utils/normalize.js.map +1 -1
  53. package/build/cjs/utils/object.js +1 -1
  54. package/build/cjs/utils/object.js.map +1 -1
  55. package/build/cjs/utils/request.js +63 -12
  56. package/build/cjs/utils/request.js.map +1 -1
  57. package/build/cjs/utils/should-ignore-span.js +27 -8
  58. package/build/cjs/utils/should-ignore-span.js.map +1 -1
  59. package/build/cjs/utils/version.js +1 -1
  60. package/build/esm/client.js +27 -3
  61. package/build/esm/client.js.map +1 -1
  62. package/build/esm/envelope.js +4 -1
  63. package/build/esm/envelope.js.map +1 -1
  64. package/build/esm/index.js +3 -2
  65. package/build/esm/index.js.map +1 -1
  66. package/build/esm/instrument/console.js +3 -1
  67. package/build/esm/instrument/console.js.map +1 -1
  68. package/build/esm/instrument/fetch.js +6 -2
  69. package/build/esm/instrument/fetch.js.map +1 -1
  70. package/build/esm/instrument/handlers.js +11 -1
  71. package/build/esm/instrument/handlers.js.map +1 -1
  72. package/build/esm/integrations/console.js +3 -1
  73. package/build/esm/integrations/console.js.map +1 -1
  74. package/build/esm/integrations/extraerrordata.js +2 -2
  75. package/build/esm/integrations/extraerrordata.js.map +1 -1
  76. package/build/esm/integrations/postgresjs.js +10 -1
  77. package/build/esm/integrations/postgresjs.js.map +1 -1
  78. package/build/esm/integrations/requestdata.js +9 -5
  79. package/build/esm/integrations/requestdata.js.map +1 -1
  80. package/build/esm/integrations/supabase.js +39 -12
  81. package/build/esm/integrations/supabase.js.map +1 -1
  82. package/build/esm/logs/console-integration.js +3 -1
  83. package/build/esm/logs/console-integration.js.map +1 -1
  84. package/build/esm/package.json +1 -1
  85. package/build/esm/server-runtime-client.js +20 -2
  86. package/build/esm/server-runtime-client.js.map +1 -1
  87. package/build/esm/tracing/ai/gen-ai-attributes.js +6 -1
  88. package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
  89. package/build/esm/tracing/idleSpan.js +7 -1
  90. package/build/esm/tracing/idleSpan.js.map +1 -1
  91. package/build/esm/tracing/langchain/index.js +45 -10
  92. package/build/esm/tracing/langchain/index.js.map +1 -1
  93. package/build/esm/tracing/langchain/utils.js +44 -12
  94. package/build/esm/tracing/langchain/utils.js.map +1 -1
  95. package/build/esm/tracing/langgraph/index.js +107 -5
  96. package/build/esm/tracing/langgraph/index.js.map +1 -1
  97. package/build/esm/tracing/langgraph/utils.js +166 -2
  98. package/build/esm/tracing/langgraph/utils.js.map +1 -1
  99. package/build/esm/tracing/spans/captureSpan.js +126 -2
  100. package/build/esm/tracing/spans/captureSpan.js.map +1 -1
  101. package/build/esm/tracing/spans/envelope.js +13 -3
  102. package/build/esm/tracing/spans/envelope.js.map +1 -1
  103. package/build/esm/tracing/trace.js +1 -0
  104. package/build/esm/tracing/trace.js.map +1 -1
  105. package/build/esm/trpc.js +2 -3
  106. package/build/esm/trpc.js.map +1 -1
  107. package/build/esm/utils/isSentryRequestUrl.js +9 -1
  108. package/build/esm/utils/isSentryRequestUrl.js.map +1 -1
  109. package/build/esm/utils/normalizationHints.js +33 -0
  110. package/build/esm/utils/normalizationHints.js.map +1 -0
  111. package/build/esm/utils/normalize.js +7 -11
  112. package/build/esm/utils/normalize.js.map +1 -1
  113. package/build/esm/utils/object.js +1 -1
  114. package/build/esm/utils/object.js.map +1 -1
  115. package/build/esm/utils/request.js +63 -12
  116. package/build/esm/utils/request.js.map +1 -1
  117. package/build/esm/utils/should-ignore-span.js +27 -8
  118. package/build/esm/utils/should-ignore-span.js.map +1 -1
  119. package/build/esm/utils/version.js +1 -1
  120. package/build/types/client.d.ts +12 -1
  121. package/build/types/client.d.ts.map +1 -1
  122. package/build/types/envelope.d.ts.map +1 -1
  123. package/build/types/index.d.ts +4 -2
  124. package/build/types/index.d.ts.map +1 -1
  125. package/build/types/instrument/console.d.ts +2 -1
  126. package/build/types/instrument/console.d.ts.map +1 -1
  127. package/build/types/instrument/fetch.d.ts +4 -2
  128. package/build/types/instrument/fetch.d.ts.map +1 -1
  129. package/build/types/instrument/handlers.d.ts +2 -2
  130. package/build/types/instrument/handlers.d.ts.map +1 -1
  131. package/build/types/integrations/console.d.ts.map +1 -1
  132. package/build/types/integrations/postgresjs.d.ts.map +1 -1
  133. package/build/types/integrations/supabase.d.ts.map +1 -1
  134. package/build/types/logs/console-integration.d.ts.map +1 -1
  135. package/build/types/server-runtime-client.d.ts +5 -0
  136. package/build/types/server-runtime-client.d.ts.map +1 -1
  137. package/build/types/tracing/idleSpan.d.ts.map +1 -1
  138. package/build/types/tracing/langchain/index.d.ts.map +1 -1
  139. package/build/types/tracing/langchain/types.d.ts +8 -0
  140. package/build/types/tracing/langchain/types.d.ts.map +1 -1
  141. package/build/types/tracing/langchain/utils.d.ts +2 -0
  142. package/build/types/tracing/langchain/utils.d.ts.map +1 -1
  143. package/build/types/tracing/langgraph/index.d.ts +4 -0
  144. package/build/types/tracing/langgraph/index.d.ts.map +1 -1
  145. package/build/types/tracing/langgraph/utils.d.ts +18 -2
  146. package/build/types/tracing/langgraph/utils.d.ts.map +1 -1
  147. package/build/types/tracing/spans/captureSpan.d.ts +10 -0
  148. package/build/types/tracing/spans/captureSpan.d.ts.map +1 -1
  149. package/build/types/tracing/spans/envelope.d.ts.map +1 -1
  150. package/build/types/trpc.d.ts.map +1 -1
  151. package/build/types/types-hoist/feedback/config.d.ts +20 -0
  152. package/build/types/types-hoist/feedback/config.d.ts.map +1 -1
  153. package/build/types/types-hoist/feedback/index.d.ts +2 -2
  154. package/build/types/types-hoist/feedback/index.d.ts.map +1 -1
  155. package/build/types/types-hoist/feedback/sendFeedback.d.ts +3 -0
  156. package/build/types/types-hoist/feedback/sendFeedback.d.ts.map +1 -1
  157. package/build/types/types-hoist/options.d.ts +37 -2
  158. package/build/types/types-hoist/options.d.ts.map +1 -1
  159. package/build/types/types-hoist/span.d.ts +5 -0
  160. package/build/types/types-hoist/span.d.ts.map +1 -1
  161. package/build/types/utils/normalizationHints.d.ts +9 -0
  162. package/build/types/utils/normalizationHints.d.ts.map +1 -0
  163. package/build/types/utils/normalize.d.ts.map +1 -1
  164. package/build/types/utils/object.d.ts +1 -1
  165. package/build/types/utils/object.d.ts.map +1 -1
  166. package/build/types/utils/request.d.ts.map +1 -1
  167. package/build/types/utils/should-ignore-span.d.ts +3 -1
  168. package/build/types/utils/should-ignore-span.d.ts.map +1 -1
  169. package/build/types-ts3.8/client.d.ts +12 -1
  170. package/build/types-ts3.8/index.d.ts +4 -2
  171. package/build/types-ts3.8/instrument/console.d.ts +2 -1
  172. package/build/types-ts3.8/instrument/fetch.d.ts +4 -2
  173. package/build/types-ts3.8/instrument/handlers.d.ts +2 -2
  174. package/build/types-ts3.8/server-runtime-client.d.ts +5 -0
  175. package/build/types-ts3.8/tracing/langchain/types.d.ts +8 -0
  176. package/build/types-ts3.8/tracing/langchain/utils.d.ts +2 -0
  177. package/build/types-ts3.8/tracing/langgraph/index.d.ts +4 -0
  178. package/build/types-ts3.8/tracing/langgraph/utils.d.ts +18 -2
  179. package/build/types-ts3.8/tracing/spans/captureSpan.d.ts +10 -0
  180. package/build/types-ts3.8/types-hoist/feedback/config.d.ts +20 -0
  181. package/build/types-ts3.8/types-hoist/feedback/index.d.ts +2 -2
  182. package/build/types-ts3.8/types-hoist/feedback/sendFeedback.d.ts +3 -0
  183. package/build/types-ts3.8/types-hoist/options.d.ts +37 -2
  184. package/build/types-ts3.8/types-hoist/span.d.ts +5 -0
  185. package/build/types-ts3.8/utils/normalizationHints.d.ts +9 -0
  186. package/build/types-ts3.8/utils/object.d.ts +1 -1
  187. package/build/types-ts3.8/utils/should-ignore-span.d.ts +3 -1
  188. package/package.json +1 -1
@@ -12,6 +12,7 @@ import { addHandler, maybeInstrument, triggerHandlers } from './handlers.js';
12
12
  * Add an instrumentation handler for when a fetch request happens.
13
13
  * The handler function is called once when the request starts and once when it ends,
14
14
  * which can be identified by checking if it has an `endTimestamp`.
15
+ * Returns a function to remove the handler.
15
16
  *
16
17
  * Use at your own risk, this might break without changelog notice, only used internally.
17
18
  * @hidden
@@ -21,22 +22,25 @@ function addFetchInstrumentationHandler(
21
22
  skipNativeFetchCheck,
22
23
  ) {
23
24
  const type = 'fetch';
24
- addHandler(type, handler);
25
+ const removeHandler = addHandler(type, handler);
25
26
  maybeInstrument(type, () => instrumentFetch(undefined, skipNativeFetchCheck));
27
+ return removeHandler;
26
28
  }
27
29
 
28
30
  /**
29
31
  * Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch.
30
32
  * The handler will resolve the request body and emit the actual `endTimestamp`, so that the
31
33
  * span can be updated accordingly.
34
+ * Returns a function to remove the handler.
32
35
  *
33
36
  * Only used internally
34
37
  * @hidden
35
38
  */
36
39
  function addFetchEndInstrumentationHandler(handler) {
37
40
  const type = 'fetch-body-resolved';
38
- addHandler(type, handler);
41
+ const removeHandler = addHandler(type, handler);
39
42
  maybeInstrument(type, () => instrumentFetch(streamHandler));
43
+ return removeHandler;
40
44
  }
41
45
 
42
46
  function instrumentFetch(onFetchResolved, skipNativeFetchCheck = false) {
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.js","sources":["../../../src/instrument/fetch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { getClient } from '../currentScopes';\nimport type { HandlerDataFetch } from '../types-hoist/instrument';\nimport type { WebFetchHeaders } from '../types-hoist/webfetchapi';\nimport { isError, isRequest } from '../utils/is';\nimport { addNonEnumerableProperty, fill } from '../utils/object';\nimport { supportsNativeFetch } from '../utils/supports';\nimport { timestampInSeconds } from '../utils/time';\nimport { GLOBAL_OBJ } from '../utils/worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './handlers';\n\ntype FetchResource = string | { toString(): string } | { url: string };\n\n/**\n * Add an instrumentation handler for when a fetch request happens.\n * The handler function is called once when the request starts and once when it ends,\n * which can be identified by checking if it has an `endTimestamp`.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addFetchInstrumentationHandler(\n handler: (data: HandlerDataFetch) => void,\n skipNativeFetchCheck?: boolean,\n): void {\n const type = 'fetch';\n addHandler(type, handler);\n maybeInstrument(type, () => instrumentFetch(undefined, skipNativeFetchCheck));\n}\n\n/**\n * Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch.\n * The handler will resolve the request body and emit the actual `endTimestamp`, so that the\n * span can be updated accordingly.\n *\n * Only used internally\n * @hidden\n */\nexport function addFetchEndInstrumentationHandler(handler: (data: HandlerDataFetch) => void): void {\n const type = 'fetch-body-resolved';\n addHandler(type, handler);\n maybeInstrument(type, () => instrumentFetch(streamHandler));\n}\n\nfunction instrumentFetch(onFetchResolved?: (response: Response) => void, skipNativeFetchCheck: boolean = false): void {\n if (skipNativeFetchCheck && !supportsNativeFetch()) {\n return;\n }\n\n fill(GLOBAL_OBJ, 'fetch', function (originalFetch: () => void): () => void {\n return function (...args: any[]): void {\n // We capture the error right here and not in the Promise error callback because Safari (and probably other\n // browsers too) will wipe the stack trace up to this point, only leaving us with this file which is useless.\n\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the error, that was caused by your fetch call did not\n // have a stack trace, so the SDK backfilled the stack trace so\n // you can see which fetch call failed.\n const virtualError = new Error();\n\n const { method, url } = parseFetchArgs(args);\n const handlerData: HandlerDataFetch = {\n args,\n fetchData: {\n method,\n url,\n },\n startTimestamp: timestampInSeconds() * 1000,\n // // Adding the error to be able to fingerprint the failed fetch event in HttpClient instrumentation\n virtualError,\n headers: getHeadersFromFetchArgs(args),\n };\n\n // if there is no callback, fetch is instrumented directly\n if (!onFetchResolved) {\n triggerHandlers('fetch', {\n ...handlerData,\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return originalFetch.apply(GLOBAL_OBJ, args).then(\n async (response: Response) => {\n if (onFetchResolved) {\n onFetchResolved(response);\n } else {\n triggerHandlers('fetch', {\n ...handlerData,\n endTimestamp: timestampInSeconds() * 1000,\n response,\n });\n }\n\n return response;\n },\n (error: Error) => {\n triggerHandlers('fetch', {\n ...handlerData,\n endTimestamp: timestampInSeconds() * 1000,\n error,\n });\n\n if (isError(error) && error.stack === undefined) {\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the error, that was caused by your fetch call did not\n // have a stack trace, so the SDK backfilled the stack trace so\n // you can see which fetch call failed.\n error.stack = virtualError.stack;\n addNonEnumerableProperty(error, 'framesToPop', 1);\n }\n\n // We enhance fetch error messages with hostname information based on the configuration.\n // Possible messages we handle here:\n // * \"Failed to fetch\" (chromium)\n // * \"Load failed\" (webkit)\n // * \"NetworkError when attempting to fetch resource.\" (firefox)\n const client = getClient();\n const enhanceOption = client?.getOptions().enhanceFetchErrorMessages ?? 'always';\n const shouldEnhance = enhanceOption !== false;\n\n if (\n shouldEnhance &&\n error instanceof TypeError &&\n (error.message === 'Failed to fetch' ||\n error.message === 'Load failed' ||\n error.message === 'NetworkError when attempting to fetch resource.')\n ) {\n try {\n const url = new URL(handlerData.fetchData.url);\n const hostname = url.host;\n\n if (enhanceOption === 'always') {\n // Modify the error message directly\n error.message = `${error.message} (${hostname})`;\n } else {\n // Store hostname as non-enumerable property for Sentry-only enhancement\n // This preserves the original error message for third-party packages\n addNonEnumerableProperty(error, '__sentry_fetch_url_host__', hostname);\n }\n } catch {\n // ignore it if errors happen here\n }\n }\n\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the sentry.javascript SDK caught an error invoking your application code.\n // This is expected behavior and NOT indicative of a bug with sentry.javascript.\n throw error;\n },\n );\n };\n });\n}\n\nasync function resolveResponse(res: Response | undefined, onFinishedResolving: () => void): Promise<void> {\n if (res?.body) {\n const body = res.body;\n const responseReader = body.getReader();\n\n // Define a maximum duration after which we just cancel\n const maxFetchDurationTimeout = setTimeout(\n () => {\n body.cancel().then(null, () => {\n // noop\n });\n },\n 90 * 1000, // 90s\n );\n\n let readingActive = true;\n while (readingActive) {\n let chunkTimeout;\n try {\n // abort reading if read op takes more than 5s\n chunkTimeout = setTimeout(() => {\n body.cancel().then(null, () => {\n // noop on error\n });\n }, 5000);\n\n // This .read() call will reject/throw when we abort due to timeouts through `body.cancel()`\n const { done } = await responseReader.read();\n\n clearTimeout(chunkTimeout);\n\n if (done) {\n onFinishedResolving();\n readingActive = false;\n }\n } catch {\n readingActive = false;\n } finally {\n clearTimeout(chunkTimeout);\n }\n }\n\n clearTimeout(maxFetchDurationTimeout);\n\n responseReader.releaseLock();\n body.cancel().then(null, () => {\n // noop on error\n });\n }\n}\n\nfunction streamHandler(response: Response): void {\n // clone response for awaiting stream\n let clonedResponseForResolving: Response;\n try {\n clonedResponseForResolving = response.clone();\n } catch {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n resolveResponse(clonedResponseForResolving, () => {\n triggerHandlers('fetch-body-resolved', {\n endTimestamp: timestampInSeconds() * 1000,\n response,\n });\n });\n}\n\nfunction hasProp<T extends string>(obj: unknown, prop: T): obj is Record<string, string> {\n return !!obj && typeof obj === 'object' && !!(obj as Record<string, string>)[prop];\n}\n\nfunction getUrlFromResource(resource: FetchResource): string {\n if (typeof resource === 'string') {\n return resource;\n }\n\n if (!resource) {\n return '';\n }\n\n if (hasProp(resource, 'url')) {\n return resource.url;\n }\n\n if (resource.toString) {\n return resource.toString();\n }\n\n return '';\n}\n\n/**\n * Parses the fetch arguments to find the used Http method and the url of the request.\n * Exported for tests only.\n */\nexport function parseFetchArgs(fetchArgs: unknown[]): { method: string; url: string } {\n if (fetchArgs.length === 0) {\n return { method: 'GET', url: '' };\n }\n\n if (fetchArgs.length === 2) {\n const [resource, options] = fetchArgs as [FetchResource, object];\n\n return {\n url: getUrlFromResource(resource),\n method: hasProp(options, 'method')\n ? String(options.method).toUpperCase()\n : // Request object as first argument\n isRequest(resource) && hasProp(resource, 'method')\n ? String(resource.method).toUpperCase()\n : 'GET',\n };\n }\n\n const arg = fetchArgs[0];\n return {\n url: getUrlFromResource(arg as FetchResource),\n method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',\n };\n}\n\nfunction getHeadersFromFetchArgs(fetchArgs: unknown[]): WebFetchHeaders | undefined {\n const [requestArgument, optionsArgument] = fetchArgs;\n\n try {\n if (\n typeof optionsArgument === 'object' &&\n optionsArgument !== null &&\n 'headers' in optionsArgument &&\n optionsArgument.headers\n ) {\n return new Headers(optionsArgument.headers as any);\n }\n\n if (isRequest(requestArgument)) {\n return new Headers(requestArgument.headers);\n }\n } catch {\n // noop\n }\n\n return;\n}\n"],"names":[],"mappings":";;;;;;;;AAAA;;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,8BAA8B;AAC9C,EAAE,OAAO;AACT,EAAE,oBAAoB;AACtB,EAAQ;AACR,EAAE,MAAM,IAAA,GAAO,OAAO;AACtB,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;AAC3B,EAAE,eAAe,CAAC,IAAI,EAAE,MAAM,eAAe,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AAC/E;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iCAAiC,CAAC,OAAO,EAA0C;AACnG,EAAE,MAAM,IAAA,GAAO,qBAAqB;AACpC,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;AAC3B,EAAE,eAAe,CAAC,IAAI,EAAE,MAAM,eAAe,CAAC,aAAa,CAAC,CAAC;AAC7D;;AAEA,SAAS,eAAe,CAAC,eAAe,EAAiC,oBAAoB,GAAY,KAAK,EAAQ;AACtH,EAAE,IAAI,oBAAA,IAAwB,CAAC,mBAAmB,EAAE,EAAE;AACtD,IAAI;AACJ,EAAE;;AAEF,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,aAAa,EAA0B;AAC7E,IAAI,OAAO,UAAU,GAAG,IAAI,EAAe;AAC3C;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM,MAAM,YAAA,GAAe,IAAI,KAAK,EAAE;;AAEtC,MAAM,MAAM,EAAE,MAAM,EAAE,GAAA,KAAQ,cAAc,CAAC,IAAI,CAAC;AAClD,MAAM,MAAM,WAAW,GAAqB;AAC5C,QAAQ,IAAI;AACZ,QAAQ,SAAS,EAAE;AACnB,UAAU,MAAM;AAChB,UAAU,GAAG;AACb,SAAS;AACT,QAAQ,cAAc,EAAE,kBAAkB,EAAC,GAAI,IAAI;AACnD;AACA,QAAQ,YAAY;AACpB,QAAQ,OAAO,EAAE,uBAAuB,CAAC,IAAI,CAAC;AAC9C,OAAO;;AAEP;AACA,MAAM,IAAI,CAAC,eAAe,EAAE;AAC5B,QAAQ,eAAe,CAAC,OAAO,EAAE;AACjC,UAAU,GAAG,WAAW;AACxB,SAAS,CAAC;AACV,MAAM;;AAEN;AACA,MAAM,OAAO,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,IAAI;AACvD,QAAQ,OAAO,QAAQ,KAAe;AACtC,UAAU,IAAI,eAAe,EAAE;AAC/B,YAAY,eAAe,CAAC,QAAQ,CAAC;AACrC,UAAU,OAAO;AACjB,YAAY,eAAe,CAAC,OAAO,EAAE;AACrC,cAAc,GAAG,WAAW;AAC5B,cAAc,YAAY,EAAE,kBAAkB,EAAC,GAAI,IAAI;AACvD,cAAc,QAAQ;AACtB,aAAa,CAAC;AACd,UAAU;;AAEV,UAAU,OAAO,QAAQ;AACzB,QAAQ,CAAC;AACT,QAAQ,CAAC,KAAK,KAAY;AAC1B,UAAU,eAAe,CAAC,OAAO,EAAE;AACnC,YAAY,GAAG,WAAW;AAC1B,YAAY,YAAY,EAAE,kBAAkB,EAAC,GAAI,IAAI;AACrD,YAAY,KAAK;AACjB,WAAW,CAAC;;AAEZ,UAAU,IAAI,OAAO,CAAC,KAAK,CAAA,IAAK,KAAK,CAAC,KAAA,KAAU,SAAS,EAAE;AAC3D;AACA;AACA;AACA;AACA,YAAY,KAAK,CAAC,KAAA,GAAQ,YAAY,CAAC,KAAK;AAC5C,YAAY,wBAAwB,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;AAC7D,UAAU;;AAEV;AACA;AACA;AACA;AACA;AACA,UAAU,MAAM,MAAA,GAAS,SAAS,EAAE;AACpC,UAAU,MAAM,aAAA,GAAgB,MAAM,EAAE,UAAU,EAAE,CAAC,yBAAA,IAA6B,QAAQ;AAC1F,UAAU,MAAM,aAAA,GAAgB,aAAA,KAAkB,KAAK;;AAEvD,UAAU;AACV,YAAY,aAAA;AACZ,YAAY,KAAA,YAAiB,SAAA;AAC7B,aAAa,KAAK,CAAC,OAAA,KAAY,iBAAA;AAC/B,cAAc,KAAK,CAAC,OAAA,KAAY,aAAA;AAChC,cAAc,KAAK,CAAC,OAAA,KAAY,iDAAiD;AACjF,YAAY;AACZ,YAAY,IAAI;AAChB,cAAc,MAAM,GAAA,GAAM,IAAI,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC;AAC5D,cAAc,MAAM,QAAA,GAAW,GAAG,CAAC,IAAI;;AAEvC,cAAc,IAAI,aAAA,KAAkB,QAAQ,EAAE;AAC9C;AACA,gBAAgB,KAAK,CAAC,OAAA,GAAU,CAAC,EAAA,KAAA,CAAA,OAAA,CAAA,EAAA,EAAA,QAAA,CAAA,CAAA,CAAA;AACA,cAAA,CAAA,MAAA;AACA;AACA;AACA,gBAAA,wBAAA,CAAA,KAAA,EAAA,2BAAA,EAAA,QAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA,CAAA,MAAA;AACA;AACA,YAAA;AACA,UAAA;;AAEA;AACA;AACA;AACA,UAAA,MAAA,KAAA;AACA,QAAA,CAAA;AACA,OAAA;AACA,IAAA,CAAA;AACA,EAAA,CAAA,CAAA;AACA;;AAEA,eAAA,eAAA,CAAA,GAAA,EAAA,mBAAA,EAAA;AACA,EAAA,IAAA,GAAA,EAAA,IAAA,EAAA;AACA,IAAA,MAAA,IAAA,GAAA,GAAA,CAAA,IAAA;AACA,IAAA,MAAA,cAAA,GAAA,IAAA,CAAA,SAAA,EAAA;;AAEA;AACA,IAAA,MAAA,uBAAA,GAAA,UAAA;AACA,MAAA,MAAA;AACA,QAAA,IAAA,CAAA,MAAA,EAAA,CAAA,IAAA,CAAA,IAAA,EAAA,MAAA;AACA;AACA,QAAA,CAAA,CAAA;AACA,MAAA,CAAA;AACA,MAAA,EAAA,GAAA,IAAA;AACA,KAAA;;AAEA,IAAA,IAAA,aAAA,GAAA,IAAA;AACA,IAAA,OAAA,aAAA,EAAA;AACA,MAAA,IAAA,YAAA;AACA,MAAA,IAAA;AACA;AACA,QAAA,YAAA,GAAA,UAAA,CAAA,MAAA;AACA,UAAA,IAAA,CAAA,MAAA,EAAA,CAAA,IAAA,CAAA,IAAA,EAAA,MAAA;AACA;AACA,UAAA,CAAA,CAAA;AACA,QAAA,CAAA,EAAA,IAAA,CAAA;;AAEA;AACA,QAAA,MAAA,EAAA,IAAA,EAAA,GAAA,MAAA,cAAA,CAAA,IAAA,EAAA;;AAEA,QAAA,YAAA,CAAA,YAAA,CAAA;;AAEA,QAAA,IAAA,IAAA,EAAA;AACA,UAAA,mBAAA,EAAA;AACA,UAAA,aAAA,GAAA,KAAA;AACA,QAAA;AACA,MAAA,CAAA,CAAA,MAAA;AACA,QAAA,aAAA,GAAA,KAAA;AACA,MAAA,CAAA,SAAA;AACA,QAAA,YAAA,CAAA,YAAA,CAAA;AACA,MAAA;AACA,IAAA;;AAEA,IAAA,YAAA,CAAA,uBAAA,CAAA;;AAEA,IAAA,cAAA,CAAA,WAAA,EAAA;AACA,IAAA,IAAA,CAAA,MAAA,EAAA,CAAA,IAAA,CAAA,IAAA,EAAA,MAAA;AACA;AACA,IAAA,CAAA,CAAA;AACA,EAAA;AACA;;AAEA,SAAA,aAAA,CAAA,QAAA,EAAA;AACA;AACA,EAAA,IAAA,0BAAA;AACA,EAAA,IAAA;AACA,IAAA,0BAAA,GAAA,QAAA,CAAA,KAAA,EAAA;AACA,EAAA,CAAA,CAAA,MAAA;AACA,IAAA;AACA,EAAA;;AAEA;AACA,EAAA,eAAA,CAAA,0BAAA,EAAA,MAAA;AACA,IAAA,eAAA,CAAA,qBAAA,EAAA;AACA,MAAA,YAAA,EAAA,kBAAA,EAAA,GAAA,IAAA;AACA,MAAA,QAAA;AACA,KAAA,CAAA;AACA,EAAA,CAAA,CAAA;AACA;;AAEA,SAAA,OAAA,CAAA,GAAA,EAAA,IAAA,EAAA;AACA,EAAA,OAAA,CAAA,CAAA,GAAA,IAAA,OAAA,GAAA,KAAA,QAAA,IAAA,CAAA,CAAA,CAAA,GAAA,GAAA,IAAA,CAAA;AACA;;AAEA,SAAA,kBAAA,CAAA,QAAA,EAAA;AACA,EAAA,IAAA,OAAA,QAAA,KAAA,QAAA,EAAA;AACA,IAAA,OAAA,QAAA;AACA,EAAA;;AAEA,EAAA,IAAA,CAAA,QAAA,EAAA;AACA,IAAA,OAAA,EAAA;AACA,EAAA;;AAEA,EAAA,IAAA,OAAA,CAAA,QAAA,EAAA,KAAA,CAAA,EAAA;AACA,IAAA,OAAA,QAAA,CAAA,GAAA;AACA,EAAA;;AAEA,EAAA,IAAA,QAAA,CAAA,QAAA,EAAA;AACA,IAAA,OAAA,QAAA,CAAA,QAAA,EAAA;AACA,EAAA;;AAEA,EAAA,OAAA,EAAA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAA,cAAA,CAAA,SAAA,EAAA;AACA,EAAA,IAAA,SAAA,CAAA,MAAA,KAAA,CAAA,EAAA;AACA,IAAA,OAAA,EAAA,MAAA,EAAA,KAAA,EAAA,GAAA,EAAA,EAAA,EAAA;AACA,EAAA;;AAEA,EAAA,IAAA,SAAA,CAAA,MAAA,KAAA,CAAA,EAAA;AACA,IAAA,MAAA,CAAA,QAAA,EAAA,OAAA,CAAA,GAAA,SAAA;;AAEA,IAAA,OAAA;AACA,MAAA,GAAA,EAAA,kBAAA,CAAA,QAAA,CAAA;AACA,MAAA,MAAA,EAAA,OAAA,CAAA,OAAA,EAAA,QAAA;AACA,UAAA,MAAA,CAAA,OAAA,CAAA,MAAA,CAAA,CAAA,WAAA;AACA;AACA,UAAA,SAAA,CAAA,QAAA,CAAA,IAAA,OAAA,CAAA,QAAA,EAAA,QAAA;AACA,YAAA,MAAA,CAAA,QAAA,CAAA,MAAA,CAAA,CAAA,WAAA;AACA,YAAA,KAAA;AACA,KAAA;AACA,EAAA;;AAEA,EAAA,MAAA,GAAA,GAAA,SAAA,CAAA,CAAA,CAAA;AACA,EAAA,OAAA;AACA,IAAA,GAAA,EAAA,kBAAA,CAAA,GAAA,EAAA;AACA,IAAA,MAAA,EAAA,OAAA,CAAA,GAAA,EAAA,QAAA,CAAA,GAAA,MAAA,CAAA,GAAA,CAAA,MAAA,CAAA,CAAA,WAAA,EAAA,GAAA,KAAA;AACA,GAAA;AACA;;AAEA,SAAA,uBAAA,CAAA,SAAA,EAAA;AACA,EAAA,MAAA,CAAA,eAAA,EAAA,eAAA,CAAA,GAAA,SAAA;;AAEA,EAAA,IAAA;AACA,IAAA;AACA,MAAA,OAAA,eAAA,KAAA,QAAA;AACA,MAAA,eAAA,KAAA,IAAA;AACA,MAAA,SAAA,IAAA,eAAA;AACA,MAAA,eAAA,CAAA;AACA,MAAA;AACA,MAAA,OAAA,IAAA,OAAA,CAAA,eAAA,CAAA,OAAA,EAAA;AACA,IAAA;;AAEA,IAAA,IAAA,SAAA,CAAA,eAAA,CAAA,EAAA;AACA,MAAA,OAAA,IAAA,OAAA,CAAA,eAAA,CAAA,OAAA,CAAA;AACA,IAAA;AACA,EAAA,CAAA,CAAA,MAAA;AACA;AACA,EAAA;;AAEA,EAAA;AACA;;;;"}
1
+ {"version":3,"file":"fetch.js","sources":["../../../src/instrument/fetch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { getClient } from '../currentScopes';\nimport type { HandlerDataFetch } from '../types-hoist/instrument';\nimport type { WebFetchHeaders } from '../types-hoist/webfetchapi';\nimport { isError, isRequest } from '../utils/is';\nimport { addNonEnumerableProperty, fill } from '../utils/object';\nimport { supportsNativeFetch } from '../utils/supports';\nimport { timestampInSeconds } from '../utils/time';\nimport { GLOBAL_OBJ } from '../utils/worldwide';\nimport { addHandler, maybeInstrument, triggerHandlers } from './handlers';\n\ntype FetchResource = string | { toString(): string } | { url: string };\n\n/**\n * Add an instrumentation handler for when a fetch request happens.\n * The handler function is called once when the request starts and once when it ends,\n * which can be identified by checking if it has an `endTimestamp`.\n * Returns a function to remove the handler.\n *\n * Use at your own risk, this might break without changelog notice, only used internally.\n * @hidden\n */\nexport function addFetchInstrumentationHandler(\n handler: (data: HandlerDataFetch) => void,\n skipNativeFetchCheck?: boolean,\n): () => void {\n const type = 'fetch';\n const removeHandler = addHandler(type, handler);\n maybeInstrument(type, () => instrumentFetch(undefined, skipNativeFetchCheck));\n return removeHandler;\n}\n\n/**\n * Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch.\n * The handler will resolve the request body and emit the actual `endTimestamp`, so that the\n * span can be updated accordingly.\n * Returns a function to remove the handler.\n *\n * Only used internally\n * @hidden\n */\nexport function addFetchEndInstrumentationHandler(handler: (data: HandlerDataFetch) => void): () => void {\n const type = 'fetch-body-resolved';\n const removeHandler = addHandler(type, handler);\n maybeInstrument(type, () => instrumentFetch(streamHandler));\n return removeHandler;\n}\n\nfunction instrumentFetch(onFetchResolved?: (response: Response) => void, skipNativeFetchCheck: boolean = false): void {\n if (skipNativeFetchCheck && !supportsNativeFetch()) {\n return;\n }\n\n fill(GLOBAL_OBJ, 'fetch', function (originalFetch: () => void): () => void {\n return function (...args: any[]): void {\n // We capture the error right here and not in the Promise error callback because Safari (and probably other\n // browsers too) will wipe the stack trace up to this point, only leaving us with this file which is useless.\n\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the error, that was caused by your fetch call did not\n // have a stack trace, so the SDK backfilled the stack trace so\n // you can see which fetch call failed.\n const virtualError = new Error();\n\n const { method, url } = parseFetchArgs(args);\n const handlerData: HandlerDataFetch = {\n args,\n fetchData: {\n method,\n url,\n },\n startTimestamp: timestampInSeconds() * 1000,\n // // Adding the error to be able to fingerprint the failed fetch event in HttpClient instrumentation\n virtualError,\n headers: getHeadersFromFetchArgs(args),\n };\n\n // if there is no callback, fetch is instrumented directly\n if (!onFetchResolved) {\n triggerHandlers('fetch', {\n ...handlerData,\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return originalFetch.apply(GLOBAL_OBJ, args).then(\n async (response: Response) => {\n if (onFetchResolved) {\n onFetchResolved(response);\n } else {\n triggerHandlers('fetch', {\n ...handlerData,\n endTimestamp: timestampInSeconds() * 1000,\n response,\n });\n }\n\n return response;\n },\n (error: Error) => {\n triggerHandlers('fetch', {\n ...handlerData,\n endTimestamp: timestampInSeconds() * 1000,\n error,\n });\n\n if (isError(error) && error.stack === undefined) {\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the error, that was caused by your fetch call did not\n // have a stack trace, so the SDK backfilled the stack trace so\n // you can see which fetch call failed.\n error.stack = virtualError.stack;\n addNonEnumerableProperty(error, 'framesToPop', 1);\n }\n\n // We enhance fetch error messages with hostname information based on the configuration.\n // Possible messages we handle here:\n // * \"Failed to fetch\" (chromium)\n // * \"Load failed\" (webkit)\n // * \"NetworkError when attempting to fetch resource.\" (firefox)\n const client = getClient();\n const enhanceOption = client?.getOptions().enhanceFetchErrorMessages ?? 'always';\n const shouldEnhance = enhanceOption !== false;\n\n if (\n shouldEnhance &&\n error instanceof TypeError &&\n (error.message === 'Failed to fetch' ||\n error.message === 'Load failed' ||\n error.message === 'NetworkError when attempting to fetch resource.')\n ) {\n try {\n const url = new URL(handlerData.fetchData.url);\n const hostname = url.host;\n\n if (enhanceOption === 'always') {\n // Modify the error message directly\n error.message = `${error.message} (${hostname})`;\n } else {\n // Store hostname as non-enumerable property for Sentry-only enhancement\n // This preserves the original error message for third-party packages\n addNonEnumerableProperty(error, '__sentry_fetch_url_host__', hostname);\n }\n } catch {\n // ignore it if errors happen here\n }\n }\n\n // NOTE: If you are a Sentry user, and you are seeing this stack frame,\n // it means the sentry.javascript SDK caught an error invoking your application code.\n // This is expected behavior and NOT indicative of a bug with sentry.javascript.\n throw error;\n },\n );\n };\n });\n}\n\nasync function resolveResponse(res: Response | undefined, onFinishedResolving: () => void): Promise<void> {\n if (res?.body) {\n const body = res.body;\n const responseReader = body.getReader();\n\n // Define a maximum duration after which we just cancel\n const maxFetchDurationTimeout = setTimeout(\n () => {\n body.cancel().then(null, () => {\n // noop\n });\n },\n 90 * 1000, // 90s\n );\n\n let readingActive = true;\n while (readingActive) {\n let chunkTimeout;\n try {\n // abort reading if read op takes more than 5s\n chunkTimeout = setTimeout(() => {\n body.cancel().then(null, () => {\n // noop on error\n });\n }, 5000);\n\n // This .read() call will reject/throw when we abort due to timeouts through `body.cancel()`\n const { done } = await responseReader.read();\n\n clearTimeout(chunkTimeout);\n\n if (done) {\n onFinishedResolving();\n readingActive = false;\n }\n } catch {\n readingActive = false;\n } finally {\n clearTimeout(chunkTimeout);\n }\n }\n\n clearTimeout(maxFetchDurationTimeout);\n\n responseReader.releaseLock();\n body.cancel().then(null, () => {\n // noop on error\n });\n }\n}\n\nfunction streamHandler(response: Response): void {\n // clone response for awaiting stream\n let clonedResponseForResolving: Response;\n try {\n clonedResponseForResolving = response.clone();\n } catch {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n resolveResponse(clonedResponseForResolving, () => {\n triggerHandlers('fetch-body-resolved', {\n endTimestamp: timestampInSeconds() * 1000,\n response,\n });\n });\n}\n\nfunction hasProp<T extends string>(obj: unknown, prop: T): obj is Record<string, string> {\n return !!obj && typeof obj === 'object' && !!(obj as Record<string, string>)[prop];\n}\n\nfunction getUrlFromResource(resource: FetchResource): string {\n if (typeof resource === 'string') {\n return resource;\n }\n\n if (!resource) {\n return '';\n }\n\n if (hasProp(resource, 'url')) {\n return resource.url;\n }\n\n if (resource.toString) {\n return resource.toString();\n }\n\n return '';\n}\n\n/**\n * Parses the fetch arguments to find the used Http method and the url of the request.\n * Exported for tests only.\n */\nexport function parseFetchArgs(fetchArgs: unknown[]): { method: string; url: string } {\n if (fetchArgs.length === 0) {\n return { method: 'GET', url: '' };\n }\n\n if (fetchArgs.length === 2) {\n const [resource, options] = fetchArgs as [FetchResource, object];\n\n return {\n url: getUrlFromResource(resource),\n method: hasProp(options, 'method')\n ? String(options.method).toUpperCase()\n : // Request object as first argument\n isRequest(resource) && hasProp(resource, 'method')\n ? String(resource.method).toUpperCase()\n : 'GET',\n };\n }\n\n const arg = fetchArgs[0];\n return {\n url: getUrlFromResource(arg as FetchResource),\n method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',\n };\n}\n\nfunction getHeadersFromFetchArgs(fetchArgs: unknown[]): WebFetchHeaders | undefined {\n const [requestArgument, optionsArgument] = fetchArgs;\n\n try {\n if (\n typeof optionsArgument === 'object' &&\n optionsArgument !== null &&\n 'headers' in optionsArgument &&\n optionsArgument.headers\n ) {\n return new Headers(optionsArgument.headers as any);\n }\n\n if (isRequest(requestArgument)) {\n return new Headers(requestArgument.headers);\n }\n } catch {\n // noop\n }\n\n return;\n}\n"],"names":[],"mappings":"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"}
@@ -6,10 +6,20 @@ import { getFunctionName } from '../utils/stacktrace.js';
6
6
  const handlers = {};
7
7
  const instrumented = {};
8
8
 
9
- /** Add a handler function. */
9
+ /** Add a handler function. Returns a function to remove the handler. */
10
10
  function addHandler(type, handler) {
11
11
  handlers[type] = handlers[type] || [];
12
12
  handlers[type].push(handler);
13
+
14
+ return () => {
15
+ const typeHandlers = handlers[type];
16
+ if (typeHandlers) {
17
+ const index = typeHandlers.indexOf(handler);
18
+ if (index !== -1) {
19
+ typeHandlers.splice(index, 1);
20
+ }
21
+ }
22
+ };
13
23
  }
14
24
 
15
25
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.js","sources":["../../../src/instrument/handlers.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport { debug } from '../utils/debug-logger';\nimport { getFunctionName } from '../utils/stacktrace';\n\nexport type InstrumentHandlerType =\n | 'console'\n | 'dom'\n | 'fetch'\n | 'fetch-body-resolved'\n | 'history'\n | 'xhr'\n | 'error'\n | 'unhandledrejection';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type InstrumentHandlerCallback = (data: any) => void;\n\n// We keep the handlers globally\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\n/** Add a handler function. */\nexport function addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n}\n\n/**\n * Reset all instrumentation handlers.\n * This can be used by tests to ensure we have a clean slate of instrumentation handlers.\n */\nexport function resetInstrumentationHandlers(): void {\n Object.keys(handlers).forEach(key => {\n handlers[key as InstrumentHandlerType] = undefined;\n });\n}\n\n/** Maybe run an instrumentation function, unless it was already called. */\nexport function maybeInstrument(type: InstrumentHandlerType, instrumentFn: () => void): void {\n if (!instrumented[type]) {\n instrumented[type] = true;\n try {\n instrumentFn();\n } catch (e) {\n DEBUG_BUILD && debug.error(`Error while instrumenting ${type}`, e);\n }\n }\n}\n\n/** Trigger handlers for a given instrumentation type. */\nexport function triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = type && handlers[type];\n if (!typeHandlers) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n"],"names":[],"mappings":";;;;AAgBA;AACA,MAAM,QAAQ,GAAqE,EAAE;AACrF,MAAM,YAAY,GAAiD,EAAE;;AAErE;AACO,SAAS,UAAU,CAAC,IAAI,EAAyB,OAAO,EAAmC;AAClG,EAAE,QAAQ,CAAC,IAAI,CAAA,GAAI,QAAQ,CAAC,IAAI,CAAA,IAAK,EAAE;AACvC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC9B;;AAEA;AACA;AACA;AACA;AACO,SAAS,4BAA4B,GAAS;AACrD,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAA,IAAO;AACvC,IAAI,QAAQ,CAAC,GAAA,EAAI,GAA4B,SAAS;AACtD,EAAE,CAAC,CAAC;AACJ;;AAEA;AACO,SAAS,eAAe,CAAC,IAAI,EAAyB,YAAY,EAAoB;AAC7F,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;AAC3B,IAAI,YAAY,CAAC,IAAI,CAAA,GAAI,IAAI;AAC7B,IAAI,IAAI;AACR,MAAM,YAAY,EAAE;AACpB,IAAI,CAAA,CAAE,OAAO,CAAC,EAAE;AAChB,MAAM,WAAA,IAAe,KAAK,CAAC,KAAK,CAAC,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAA,EAAA,CAAA,CAAA;AACA,IAAA;AACA,EAAA;AACA;;AAEA;AACA,SAAA,eAAA,CAAA,IAAA,EAAA,IAAA,EAAA;AACA,EAAA,MAAA,YAAA,GAAA,IAAA,IAAA,QAAA,CAAA,IAAA,CAAA;AACA,EAAA,IAAA,CAAA,YAAA,EAAA;AACA,IAAA;AACA,EAAA;;AAEA,EAAA,KAAA,MAAA,OAAA,IAAA,YAAA,EAAA;AACA,IAAA,IAAA;AACA,MAAA,OAAA,CAAA,IAAA,CAAA;AACA,IAAA,CAAA,CAAA,OAAA,CAAA,EAAA;AACA,MAAA,WAAA;AACA,QAAA,KAAA,CAAA,KAAA;AACA,UAAA,CAAA,uDAAA,EAAA,IAAA,CAAA,QAAA,EAAA,eAAA,CAAA,OAAA,CAAA,CAAA,QAAA,CAAA;AACA,UAAA,CAAA;AACA,SAAA;AACA,IAAA;AACA,EAAA;AACA;;;;"}
1
+ {"version":3,"file":"handlers.js","sources":["../../../src/instrument/handlers.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport { debug } from '../utils/debug-logger';\nimport { getFunctionName } from '../utils/stacktrace';\n\nexport type InstrumentHandlerType =\n | 'console'\n | 'dom'\n | 'fetch'\n | 'fetch-body-resolved'\n | 'history'\n | 'xhr'\n | 'error'\n | 'unhandledrejection';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type InstrumentHandlerCallback = (data: any) => void;\n\n// We keep the handlers globally\nconst handlers: { [key in InstrumentHandlerType]?: InstrumentHandlerCallback[] } = {};\nconst instrumented: { [key in InstrumentHandlerType]?: boolean } = {};\n\n/** Add a handler function. Returns a function to remove the handler. */\nexport function addHandler(type: InstrumentHandlerType, handler: InstrumentHandlerCallback): () => void {\n handlers[type] = handlers[type] || [];\n handlers[type].push(handler);\n\n return () => {\n const typeHandlers = handlers[type];\n if (typeHandlers) {\n const index = typeHandlers.indexOf(handler);\n if (index !== -1) {\n typeHandlers.splice(index, 1);\n }\n }\n };\n}\n\n/**\n * Reset all instrumentation handlers.\n * This can be used by tests to ensure we have a clean slate of instrumentation handlers.\n */\nexport function resetInstrumentationHandlers(): void {\n Object.keys(handlers).forEach(key => {\n handlers[key as InstrumentHandlerType] = undefined;\n });\n}\n\n/** Maybe run an instrumentation function, unless it was already called. */\nexport function maybeInstrument(type: InstrumentHandlerType, instrumentFn: () => void): void {\n if (!instrumented[type]) {\n instrumented[type] = true;\n try {\n instrumentFn();\n } catch (e) {\n DEBUG_BUILD && debug.error(`Error while instrumenting ${type}`, e);\n }\n }\n}\n\n/** Trigger handlers for a given instrumentation type. */\nexport function triggerHandlers(type: InstrumentHandlerType, data: unknown): void {\n const typeHandlers = type && handlers[type];\n if (!typeHandlers) {\n return;\n }\n\n for (const handler of typeHandlers) {\n try {\n handler(data);\n } catch (e) {\n DEBUG_BUILD &&\n debug.error(\n `Error while triggering instrumentation handler.\\nType: ${type}\\nName: ${getFunctionName(handler)}\\nError:`,\n e,\n );\n }\n }\n}\n"],"names":[],"mappings":";;;;AAgBA;AACA,MAAM,QAAQ,GAAqE,EAAE;AACrF,MAAM,YAAY,GAAiD,EAAE;;AAErE;AACO,SAAS,UAAU,CAAC,IAAI,EAAyB,OAAO,EAAyC;AACxG,EAAE,QAAQ,CAAC,IAAI,CAAA,GAAI,QAAQ,CAAC,IAAI,CAAA,IAAK,EAAE;AACvC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;;AAE9B,EAAE,OAAO,MAAM;AACf,IAAI,MAAM,YAAA,GAAe,QAAQ,CAAC,IAAI,CAAC;AACvC,IAAI,IAAI,YAAY,EAAE;AACtB,MAAM,MAAM,QAAQ,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC;AACjD,MAAM,IAAI,KAAA,KAAU,EAAE,EAAE;AACxB,QAAQ,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AACrC,MAAM;AACN,IAAI;AACJ,EAAE,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACO,SAAS,4BAA4B,GAAS;AACrD,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAA,IAAO;AACvC,IAAI,QAAQ,CAAC,GAAA,EAAI,GAA4B,SAAS;AACtD,EAAE,CAAC,CAAC;AACJ;;AAEA;AACO,SAAS,eAAe,CAAC,IAAI,EAAyB,YAAY,EAAoB;AAC7F,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;AAC3B,IAAI,YAAY,CAAC,IAAI,CAAA,GAAI,IAAI;AAC7B,IAAI,IAAI;AACR,MAAM,YAAY,EAAE;AACpB,IAAI,CAAA,CAAE,OAAO,CAAC,EAAE;AAChB,MAAM,WAAA,IAAe,KAAK,CAAC,KAAK,CAAC,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAA,EAAA,CAAA,CAAA;AACA,IAAA;AACA,EAAA;AACA;;AAEA;AACA,SAAA,eAAA,CAAA,IAAA,EAAA,IAAA,EAAA;AACA,EAAA,MAAA,YAAA,GAAA,IAAA,IAAA,QAAA,CAAA,IAAA,CAAA;AACA,EAAA,IAAA,CAAA,YAAA,EAAA;AACA,IAAA;AACA,EAAA;;AAEA,EAAA,KAAA,MAAA,OAAA,IAAA,YAAA,EAAA;AACA,IAAA,IAAA;AACA,MAAA,OAAA,CAAA,IAAA,CAAA;AACA,IAAA,CAAA,CAAA,OAAA,CAAA,EAAA;AACA,MAAA,WAAA;AACA,QAAA,KAAA,CAAA,KAAA;AACA,UAAA,CAAA,uDAAA,EAAA,IAAA,CAAA,QAAA,EAAA,eAAA,CAAA,OAAA,CAAA,CAAA,QAAA,CAAA;AACA,UAAA,CAAA;AACA,SAAA;AACA,IAAA;AACA,EAAA;AACA;;;;"}
@@ -30,13 +30,15 @@ const consoleIntegration = defineIntegration((options = {}) => {
30
30
  return {
31
31
  name: INTEGRATION_NAME,
32
32
  setup(client) {
33
- addConsoleInstrumentationHandler(({ args, level }) => {
33
+ const unsubscribe = addConsoleInstrumentationHandler(({ args, level }) => {
34
34
  if (getClient() !== client || !levels.has(level)) {
35
35
  return;
36
36
  }
37
37
 
38
38
  addConsoleBreadcrumb(level, args);
39
39
  });
40
+
41
+ client.registerCleanup(unsubscribe);
40
42
  },
41
43
  };
42
44
  });
@@ -1 +1 @@
1
- {"version":3,"file":"console.js","sources":["../../../src/integrations/console.ts"],"sourcesContent":["import { addBreadcrumb } from '../breadcrumbs';\nimport { getClient } from '../currentScopes';\nimport { addConsoleInstrumentationHandler } from '../instrument/console';\nimport { defineIntegration } from '../integration';\nimport type { ConsoleLevel } from '../types-hoist/instrument';\nimport { CONSOLE_LEVELS } from '../utils/debug-logger';\nimport { severityLevelFromString } from '../utils/severity';\nimport { safeJoin } from '../utils/string';\nimport { GLOBAL_OBJ } from '../utils/worldwide';\n\ninterface ConsoleIntegrationOptions {\n levels: ConsoleLevel[];\n}\n\ntype GlobalObjectWithUtil = typeof GLOBAL_OBJ & {\n util: {\n format: (...args: unknown[]) => string;\n };\n};\n\nconst INTEGRATION_NAME = 'Console';\n\n/**\n * Captures calls to the `console` API as breadcrumbs in Sentry.\n *\n * By default the integration instruments `console.debug`, `console.info`, `console.warn`, `console.error`,\n * `console.log`, `console.trace`, and `console.assert`. You can use the `levels` option to customize which\n * levels are captured.\n *\n * @example\n *\n * ```js\n * Sentry.init({\n * integrations: [Sentry.consoleIntegration({ levels: ['error', 'warn'] })],\n * });\n * ```\n */\nexport const consoleIntegration = defineIntegration((options: Partial<ConsoleIntegrationOptions> = {}) => {\n const levels = new Set(options.levels || CONSOLE_LEVELS);\n\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n addConsoleInstrumentationHandler(({ args, level }) => {\n if (getClient() !== client || !levels.has(level)) {\n return;\n }\n\n addConsoleBreadcrumb(level, args);\n });\n },\n };\n});\n\n/**\n * Capture a console breadcrumb.\n *\n * Exported just for tests.\n */\nexport function addConsoleBreadcrumb(level: ConsoleLevel, args: unknown[]): void {\n const breadcrumb = {\n category: 'console',\n data: {\n arguments: args,\n logger: 'console',\n },\n level: severityLevelFromString(level),\n message: formatConsoleArgs(args),\n };\n\n if (level === 'assert') {\n if (args[0] === false) {\n const assertionArgs = args.slice(1);\n breadcrumb.message =\n assertionArgs.length > 0 ? `Assertion failed: ${formatConsoleArgs(assertionArgs)}` : 'Assertion failed';\n breadcrumb.data.arguments = assertionArgs;\n } else {\n // Don't capture a breadcrumb for passed assertions\n return;\n }\n }\n\n addBreadcrumb(breadcrumb, {\n input: args,\n level,\n });\n}\n\nfunction formatConsoleArgs(values: unknown[]): string {\n return 'util' in GLOBAL_OBJ && typeof (GLOBAL_OBJ as GlobalObjectWithUtil).util.format === 'function'\n ? (GLOBAL_OBJ as GlobalObjectWithUtil).util.format(...values)\n : safeJoin(values, ' ');\n}\n"],"names":[],"mappings":";;;;;;;;;AAoBA,MAAM,gBAAA,GAAmB,SAAS;;AAElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,kBAAA,GAAqB,iBAAiB,CAAC,CAAC,OAAO,GAAuC,EAAE,KAAK;AAC1G,EAAE,MAAM,MAAA,GAAS,IAAI,GAAG,CAAC,OAAO,CAAC,MAAA,IAAU,cAAc,CAAC;;AAE1D,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,gCAAgC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAA,EAAO,KAAK;AAC5D,QAAQ,IAAI,SAAS,OAAO,MAAA,IAAU,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC1D,UAAU;AACV,QAAQ;;AAER,QAAQ,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC;AACzC,MAAM,CAAC,CAAC;AACR,IAAI,CAAC;AACL,GAAG;AACH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,KAAK,EAAgB,IAAI,EAAmB;AACjF,EAAE,MAAM,aAAa;AACrB,IAAI,QAAQ,EAAE,SAAS;AACvB,IAAI,IAAI,EAAE;AACV,MAAM,SAAS,EAAE,IAAI;AACrB,MAAM,MAAM,EAAE,SAAS;AACvB,KAAK;AACL,IAAI,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC;AACzC,IAAI,OAAO,EAAE,iBAAiB,CAAC,IAAI,CAAC;AACpC,GAAG;;AAEH,EAAE,IAAI,KAAA,KAAU,QAAQ,EAAE;AAC1B,IAAI,IAAI,IAAI,CAAC,CAAC,CAAA,KAAM,KAAK,EAAE;AAC3B,MAAM,MAAM,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,MAAM,UAAU,CAAC,OAAA;AACjB,QAAQ,aAAa,CAAC,MAAA,GAAS,IAAI,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAA,GAAA,kBAAA;AACA,MAAA,UAAA,CAAA,IAAA,CAAA,SAAA,GAAA,aAAA;AACA,IAAA,CAAA,MAAA;AACA;AACA,MAAA;AACA,IAAA;AACA,EAAA;;AAEA,EAAA,aAAA,CAAA,UAAA,EAAA;AACA,IAAA,KAAA,EAAA,IAAA;AACA,IAAA,KAAA;AACA,GAAA,CAAA;AACA;;AAEA,SAAA,iBAAA,CAAA,MAAA,EAAA;AACA,EAAA,OAAA,MAAA,IAAA,UAAA,IAAA,OAAA,CAAA,UAAA,GAAA,IAAA,CAAA,MAAA,KAAA;AACA,MAAA,CAAA,UAAA,GAAA,IAAA,CAAA,MAAA,CAAA,GAAA,MAAA;AACA,MAAA,QAAA,CAAA,MAAA,EAAA,GAAA,CAAA;AACA;;;;"}
1
+ {"version":3,"file":"console.js","sources":["../../../src/integrations/console.ts"],"sourcesContent":["import { addBreadcrumb } from '../breadcrumbs';\nimport { getClient } from '../currentScopes';\nimport { addConsoleInstrumentationHandler } from '../instrument/console';\nimport { defineIntegration } from '../integration';\nimport type { ConsoleLevel } from '../types-hoist/instrument';\nimport { CONSOLE_LEVELS } from '../utils/debug-logger';\nimport { severityLevelFromString } from '../utils/severity';\nimport { safeJoin } from '../utils/string';\nimport { GLOBAL_OBJ } from '../utils/worldwide';\n\ninterface ConsoleIntegrationOptions {\n levels: ConsoleLevel[];\n}\n\ntype GlobalObjectWithUtil = typeof GLOBAL_OBJ & {\n util: {\n format: (...args: unknown[]) => string;\n };\n};\n\nconst INTEGRATION_NAME = 'Console';\n\n/**\n * Captures calls to the `console` API as breadcrumbs in Sentry.\n *\n * By default the integration instruments `console.debug`, `console.info`, `console.warn`, `console.error`,\n * `console.log`, `console.trace`, and `console.assert`. You can use the `levels` option to customize which\n * levels are captured.\n *\n * @example\n *\n * ```js\n * Sentry.init({\n * integrations: [Sentry.consoleIntegration({ levels: ['error', 'warn'] })],\n * });\n * ```\n */\nexport const consoleIntegration = defineIntegration((options: Partial<ConsoleIntegrationOptions> = {}) => {\n const levels = new Set(options.levels || CONSOLE_LEVELS);\n\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const unsubscribe = addConsoleInstrumentationHandler(({ args, level }) => {\n if (getClient() !== client || !levels.has(level)) {\n return;\n }\n\n addConsoleBreadcrumb(level, args);\n });\n\n client.registerCleanup(unsubscribe);\n },\n };\n});\n\n/**\n * Capture a console breadcrumb.\n *\n * Exported just for tests.\n */\nexport function addConsoleBreadcrumb(level: ConsoleLevel, args: unknown[]): void {\n const breadcrumb = {\n category: 'console',\n data: {\n arguments: args,\n logger: 'console',\n },\n level: severityLevelFromString(level),\n message: formatConsoleArgs(args),\n };\n\n if (level === 'assert') {\n if (args[0] === false) {\n const assertionArgs = args.slice(1);\n breadcrumb.message =\n assertionArgs.length > 0 ? `Assertion failed: ${formatConsoleArgs(assertionArgs)}` : 'Assertion failed';\n breadcrumb.data.arguments = assertionArgs;\n } else {\n // Don't capture a breadcrumb for passed assertions\n return;\n }\n }\n\n addBreadcrumb(breadcrumb, {\n input: args,\n level,\n });\n}\n\nfunction formatConsoleArgs(values: unknown[]): string {\n return 'util' in GLOBAL_OBJ && typeof (GLOBAL_OBJ as GlobalObjectWithUtil).util.format === 'function'\n ? (GLOBAL_OBJ as GlobalObjectWithUtil).util.format(...values)\n : safeJoin(values, ' ');\n}\n"],"names":[],"mappings":";;;;;;;;;AAoBA,MAAM,gBAAA,GAAmB,SAAS;;AAElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,kBAAA,GAAqB,iBAAiB,CAAC,CAAC,OAAO,GAAuC,EAAE,KAAK;AAC1G,EAAE,MAAM,MAAA,GAAS,IAAI,GAAG,CAAC,OAAO,CAAC,MAAA,IAAU,cAAc,CAAC;;AAE1D,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,MAAM,WAAA,GAAc,gCAAgC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAA,EAAO,KAAK;AAChF,QAAQ,IAAI,SAAS,OAAO,MAAA,IAAU,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC1D,UAAU;AACV,QAAQ;;AAER,QAAQ,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC;AACzC,MAAM,CAAC,CAAC;;AAER,MAAM,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC;AACzC,IAAI,CAAC;AACL,GAAG;AACH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,KAAK,EAAgB,IAAI,EAAmB;AACjF,EAAE,MAAM,aAAa;AACrB,IAAI,QAAQ,EAAE,SAAS;AACvB,IAAI,IAAI,EAAE;AACV,MAAM,SAAS,EAAE,IAAI;AACrB,MAAM,MAAM,EAAE,SAAS;AACvB,KAAK;AACL,IAAI,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC;AACzC,IAAI,OAAO,EAAE,iBAAiB,CAAC,IAAI,CAAC;AACpC,GAAG;;AAEH,EAAE,IAAI,KAAA,KAAU,QAAQ,EAAE;AAC1B,IAAI,IAAI,IAAI,CAAC,CAAC,CAAA,KAAM,KAAK,EAAE;AAC3B,MAAM,MAAM,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,MAAM,UAAU,CAAC,OAAA;AACjB,QAAQ,aAAa,CAAC,MAAA,GAAS,IAAI,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAA,GAAA,kBAAA;AACA,MAAA,UAAA,CAAA,IAAA,CAAA,SAAA,GAAA,aAAA;AACA,IAAA,CAAA,MAAA;AACA;AACA,MAAA;AACA,IAAA;AACA,EAAA;;AAEA,EAAA,aAAA,CAAA,UAAA,EAAA;AACA,IAAA,KAAA,EAAA,IAAA;AACA,IAAA,KAAA;AACA,GAAA,CAAA;AACA;;AAEA,SAAA,iBAAA,CAAA,MAAA,EAAA;AACA,EAAA,OAAA,MAAA,IAAA,UAAA,IAAA,OAAA,CAAA,UAAA,GAAA,IAAA,CAAA,MAAA,KAAA;AACA,MAAA,CAAA,UAAA,GAAA,IAAA,CAAA,MAAA,CAAA,GAAA,MAAA;AACA,MAAA,QAAA,CAAA,MAAA,EAAA,GAAA,CAAA;AACA;;;;"}
@@ -3,7 +3,7 @@ import { defineIntegration } from '../integration.js';
3
3
  import { debug } from '../utils/debug-logger.js';
4
4
  import { isError, isPlainObject } from '../utils/is.js';
5
5
  import { normalize } from '../utils/normalize.js';
6
- import { addNonEnumerableProperty } from '../utils/object.js';
6
+ import { setSkipNormalizationHint } from '../utils/normalizationHints.js';
7
7
  import { truncate } from '../utils/string.js';
8
8
 
9
9
  const INTEGRATION_NAME = 'ExtraErrorData';
@@ -48,7 +48,7 @@ function _enhanceEventWithErrorData(
48
48
  if (isPlainObject(normalizedErrorData)) {
49
49
  // We mark the error data as "already normalized" here, because we don't want other normalization procedures to
50
50
  // potentially truncate the data we just already normalized, with a certain depth setting.
51
- addNonEnumerableProperty(normalizedErrorData, '__sentry_skip_normalization__', true);
51
+ setSkipNormalizationHint(normalizedErrorData);
52
52
  contexts[exceptionName] = normalizedErrorData;
53
53
  }
54
54
 
@@ -1 +1 @@
1
- {"version":3,"file":"extraerrordata.js","sources":["../../../src/integrations/extraerrordata.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport { defineIntegration } from '../integration';\nimport type { Contexts } from '../types-hoist/context';\nimport type { ExtendedError } from '../types-hoist/error';\nimport type { Event, EventHint } from '../types-hoist/event';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport { debug } from '../utils/debug-logger';\nimport { isError, isPlainObject } from '../utils/is';\nimport { normalize } from '../utils/normalize';\nimport { addNonEnumerableProperty } from '../utils/object';\nimport { truncate } from '../utils/string';\n\nconst INTEGRATION_NAME = 'ExtraErrorData';\n\ninterface ExtraErrorDataOptions {\n /**\n * The object depth up to which to capture data on error objects.\n */\n depth: number;\n\n /**\n * Whether to capture error causes. Defaults to true.\n *\n * More information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause\n */\n captureErrorCause: boolean;\n}\n\n/**\n * Extract additional data for from original exceptions.\n */\nconst _extraErrorDataIntegration = ((options: Partial<ExtraErrorDataOptions> = {}) => {\n const { depth = 3, captureErrorCause = true } = options;\n return {\n name: INTEGRATION_NAME,\n processEvent(event, hint, client) {\n const { maxValueLength } = client.getOptions();\n return _enhanceEventWithErrorData(event, hint, depth, captureErrorCause, maxValueLength);\n },\n };\n}) satisfies IntegrationFn;\n\nexport const extraErrorDataIntegration = defineIntegration(_extraErrorDataIntegration);\n\nfunction _enhanceEventWithErrorData(\n event: Event,\n hint: EventHint = {},\n depth: number,\n captureErrorCause: boolean,\n maxValueLength: number | undefined,\n): Event {\n if (!hint.originalException || !isError(hint.originalException)) {\n return event;\n }\n const exceptionName = (hint.originalException as ExtendedError).name || hint.originalException.constructor.name;\n\n const errorData = _extractErrorData(hint.originalException as ExtendedError, captureErrorCause, maxValueLength);\n\n if (errorData) {\n const contexts: Contexts = {\n ...event.contexts,\n };\n\n const normalizedErrorData = normalize(errorData, depth);\n\n if (isPlainObject(normalizedErrorData)) {\n // We mark the error data as \"already normalized\" here, because we don't want other normalization procedures to\n // potentially truncate the data we just already normalized, with a certain depth setting.\n addNonEnumerableProperty(normalizedErrorData, '__sentry_skip_normalization__', true);\n contexts[exceptionName] = normalizedErrorData;\n }\n\n return {\n ...event,\n contexts,\n };\n }\n\n return event;\n}\n\n/**\n * Extract extra information from the Error object\n */\nfunction _extractErrorData(\n error: ExtendedError,\n captureErrorCause: boolean,\n maxValueLength: number | undefined,\n): Record<string, unknown> | null {\n // We are trying to enhance already existing event, so no harm done if it won't succeed\n try {\n const nativeKeys = [\n 'name',\n 'message',\n 'stack',\n 'line',\n 'column',\n 'fileName',\n 'lineNumber',\n 'columnNumber',\n 'toJSON',\n ];\n\n const extraErrorInfo: Record<string, unknown> = {};\n\n // We want only enumerable properties, thus `getOwnPropertyNames` is redundant here, as we filter keys anyway.\n for (const key of Object.keys(error)) {\n if (nativeKeys.indexOf(key) !== -1) {\n continue;\n }\n const value = error[key];\n extraErrorInfo[key] =\n isError(value) || typeof value === 'string'\n ? maxValueLength\n ? truncate(`${value}`, maxValueLength)\n : `${value}`\n : value;\n }\n\n // Error.cause is a standard property that is non enumerable, we therefore need to access it separately.\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause\n if (captureErrorCause && error.cause !== undefined) {\n if (isError(error.cause)) {\n const errorName = error.cause.name || error.cause.constructor.name;\n extraErrorInfo.cause = { [errorName]: _extractErrorData(error.cause as ExtendedError, false, maxValueLength) };\n } else {\n extraErrorInfo.cause = error.cause;\n }\n }\n\n // Check if someone attached `toJSON` method to grab even more properties (eg. axios is doing that)\n if (typeof error.toJSON === 'function') {\n const serializedError = error.toJSON() as Record<string, unknown>;\n\n for (const key of Object.keys(serializedError)) {\n const value = serializedError[key];\n extraErrorInfo[key] = isError(value) ? value.toString() : value;\n }\n }\n\n return extraErrorInfo;\n } catch (oO) {\n DEBUG_BUILD && debug.error('Unable to extract extra data from the Error object:', oO);\n }\n\n return null;\n}\n"],"names":[],"mappings":";;;;;;;;AAYA,MAAM,gBAAA,GAAmB,gBAAgB;;AAgBzC;AACA;AACA;AACA,MAAM,0BAAA,IAA8B,CAAC,OAAO,GAAmC,EAAE,KAAK;AACtF,EAAE,MAAM,EAAE,KAAA,GAAQ,CAAC,EAAE,iBAAA,GAAoB,IAAA,EAAK,GAAI,OAAO;AACzD,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AACtC,MAAM,MAAM,EAAE,cAAA,EAAe,GAAI,MAAM,CAAC,UAAU,EAAE;AACpD,MAAM,OAAO,0BAA0B,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,iBAAiB,EAAE,cAAc,CAAC;AAC9F,IAAI,CAAC;AACL,GAAG;AACH,CAAC,CAAA;;MAEY,yBAAA,GAA4B,iBAAiB,CAAC,0BAA0B;;AAErF,SAAS,0BAA0B;AACnC,EAAE,KAAK;AACP,EAAE,IAAI,GAAc,EAAE;AACtB,EAAE,KAAK;AACP,EAAE,iBAAiB;AACnB,EAAE,cAAc;AAChB,EAAS;AACT,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAA,IAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE;AACnE,IAAI,OAAO,KAAK;AAChB,EAAE;AACF,EAAE,MAAM,aAAA,GAAgB,CAAC,IAAI,CAAC,iBAAA,GAAoC,IAAA,IAAQ,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,IAAI;;AAEjH,EAAE,MAAM,SAAA,GAAY,iBAAiB,CAAC,IAAI,CAAC,iBAAA,GAAoC,iBAAiB,EAAE,cAAc,CAAC;;AAEjH,EAAE,IAAI,SAAS,EAAE;AACjB,IAAI,MAAM,QAAQ,GAAa;AAC/B,MAAM,GAAG,KAAK,CAAC,QAAQ;AACvB,KAAK;;AAEL,IAAI,MAAM,sBAAsB,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC;;AAE3D,IAAI,IAAI,aAAa,CAAC,mBAAmB,CAAC,EAAE;AAC5C;AACA;AACA,MAAM,wBAAwB,CAAC,mBAAmB,EAAE,+BAA+B,EAAE,IAAI,CAAC;AAC1F,MAAM,QAAQ,CAAC,aAAa,CAAA,GAAI,mBAAmB;AACnD,IAAI;;AAEJ,IAAI,OAAO;AACX,MAAM,GAAG,KAAK;AACd,MAAM,QAAQ;AACd,KAAK;AACL,EAAE;;AAEF,EAAE,OAAO,KAAK;AACd;;AAEA;AACA;AACA;AACA,SAAS,iBAAiB;AAC1B,EAAE,KAAK;AACP,EAAE,iBAAiB;AACnB,EAAE,cAAc;AAChB,EAAkC;AAClC;AACA,EAAE,IAAI;AACN,IAAI,MAAM,aAAa;AACvB,MAAM,MAAM;AACZ,MAAM,SAAS;AACf,MAAM,OAAO;AACb,MAAM,MAAM;AACZ,MAAM,QAAQ;AACd,MAAM,UAAU;AAChB,MAAM,YAAY;AAClB,MAAM,cAAc;AACpB,MAAM,QAAQ;AACd,KAAK;;AAEL,IAAI,MAAM,cAAc,GAA4B,EAAE;;AAEtD;AACA,IAAI,KAAK,MAAM,GAAA,IAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AAC1C,MAAM,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAA,KAAM,CAAC,CAAC,EAAE;AAC1C,QAAQ;AACR,MAAM;AACN,MAAM,MAAM,KAAA,GAAQ,KAAK,CAAC,GAAG,CAAC;AAC9B,MAAM,cAAc,CAAC,GAAG,CAAA;AACxB,QAAQ,OAAO,CAAC,KAAK,KAAK,OAAO,UAAU;AAC3C,YAAY;AACZ,cAAc,QAAQ,CAAC,CAAC,EAAA,KAAA,CAAA,CAAA,EAAA,cAAA;AACA,cAAA,CAAA,EAAA,KAAA,CAAA;AACA,YAAA,KAAA;AACA,IAAA;;AAEA;AACA;AACA,IAAA,IAAA,iBAAA,IAAA,KAAA,CAAA,KAAA,KAAA,SAAA,EAAA;AACA,MAAA,IAAA,OAAA,CAAA,KAAA,CAAA,KAAA,CAAA,EAAA;AACA,QAAA,MAAA,SAAA,GAAA,KAAA,CAAA,KAAA,CAAA,IAAA,IAAA,KAAA,CAAA,KAAA,CAAA,WAAA,CAAA,IAAA;AACA,QAAA,cAAA,CAAA,KAAA,GAAA,EAAA,CAAA,SAAA,GAAA,iBAAA,CAAA,KAAA,CAAA,KAAA,GAAA,KAAA,EAAA,cAAA,CAAA,EAAA;AACA,MAAA,CAAA,MAAA;AACA,QAAA,cAAA,CAAA,KAAA,GAAA,KAAA,CAAA,KAAA;AACA,MAAA;AACA,IAAA;;AAEA;AACA,IAAA,IAAA,OAAA,KAAA,CAAA,MAAA,KAAA,UAAA,EAAA;AACA,MAAA,MAAA,eAAA,GAAA,KAAA,CAAA,MAAA,EAAA;;AAEA,MAAA,KAAA,MAAA,GAAA,IAAA,MAAA,CAAA,IAAA,CAAA,eAAA,CAAA,EAAA;AACA,QAAA,MAAA,KAAA,GAAA,eAAA,CAAA,GAAA,CAAA;AACA,QAAA,cAAA,CAAA,GAAA,CAAA,GAAA,OAAA,CAAA,KAAA,CAAA,GAAA,KAAA,CAAA,QAAA,EAAA,GAAA,KAAA;AACA,MAAA;AACA,IAAA;;AAEA,IAAA,OAAA,cAAA;AACA,EAAA,CAAA,CAAA,OAAA,EAAA,EAAA;AACA,IAAA,WAAA,IAAA,KAAA,CAAA,KAAA,CAAA,qDAAA,EAAA,EAAA,CAAA;AACA,EAAA;;AAEA,EAAA,OAAA,IAAA;AACA;;;;"}
1
+ {"version":3,"file":"extraerrordata.js","sources":["../../../src/integrations/extraerrordata.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport { defineIntegration } from '../integration';\nimport type { Contexts } from '../types-hoist/context';\nimport type { ExtendedError } from '../types-hoist/error';\nimport type { Event, EventHint } from '../types-hoist/event';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport { debug } from '../utils/debug-logger';\nimport { isError, isPlainObject } from '../utils/is';\nimport { normalize } from '../utils/normalize';\nimport { setSkipNormalizationHint } from '../utils/normalizationHints';\nimport { truncate } from '../utils/string';\n\nconst INTEGRATION_NAME = 'ExtraErrorData';\n\ninterface ExtraErrorDataOptions {\n /**\n * The object depth up to which to capture data on error objects.\n */\n depth: number;\n\n /**\n * Whether to capture error causes. Defaults to true.\n *\n * More information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause\n */\n captureErrorCause: boolean;\n}\n\n/**\n * Extract additional data for from original exceptions.\n */\nconst _extraErrorDataIntegration = ((options: Partial<ExtraErrorDataOptions> = {}) => {\n const { depth = 3, captureErrorCause = true } = options;\n return {\n name: INTEGRATION_NAME,\n processEvent(event, hint, client) {\n const { maxValueLength } = client.getOptions();\n return _enhanceEventWithErrorData(event, hint, depth, captureErrorCause, maxValueLength);\n },\n };\n}) satisfies IntegrationFn;\n\nexport const extraErrorDataIntegration = defineIntegration(_extraErrorDataIntegration);\n\nfunction _enhanceEventWithErrorData(\n event: Event,\n hint: EventHint = {},\n depth: number,\n captureErrorCause: boolean,\n maxValueLength: number | undefined,\n): Event {\n if (!hint.originalException || !isError(hint.originalException)) {\n return event;\n }\n const exceptionName = (hint.originalException as ExtendedError).name || hint.originalException.constructor.name;\n\n const errorData = _extractErrorData(hint.originalException as ExtendedError, captureErrorCause, maxValueLength);\n\n if (errorData) {\n const contexts: Contexts = {\n ...event.contexts,\n };\n\n const normalizedErrorData = normalize(errorData, depth);\n\n if (isPlainObject(normalizedErrorData)) {\n // We mark the error data as \"already normalized\" here, because we don't want other normalization procedures to\n // potentially truncate the data we just already normalized, with a certain depth setting.\n setSkipNormalizationHint(normalizedErrorData);\n contexts[exceptionName] = normalizedErrorData;\n }\n\n return {\n ...event,\n contexts,\n };\n }\n\n return event;\n}\n\n/**\n * Extract extra information from the Error object\n */\nfunction _extractErrorData(\n error: ExtendedError,\n captureErrorCause: boolean,\n maxValueLength: number | undefined,\n): Record<string, unknown> | null {\n // We are trying to enhance already existing event, so no harm done if it won't succeed\n try {\n const nativeKeys = [\n 'name',\n 'message',\n 'stack',\n 'line',\n 'column',\n 'fileName',\n 'lineNumber',\n 'columnNumber',\n 'toJSON',\n ];\n\n const extraErrorInfo: Record<string, unknown> = {};\n\n // We want only enumerable properties, thus `getOwnPropertyNames` is redundant here, as we filter keys anyway.\n for (const key of Object.keys(error)) {\n if (nativeKeys.indexOf(key) !== -1) {\n continue;\n }\n const value = error[key];\n extraErrorInfo[key] =\n isError(value) || typeof value === 'string'\n ? maxValueLength\n ? truncate(`${value}`, maxValueLength)\n : `${value}`\n : value;\n }\n\n // Error.cause is a standard property that is non enumerable, we therefore need to access it separately.\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause\n if (captureErrorCause && error.cause !== undefined) {\n if (isError(error.cause)) {\n const errorName = error.cause.name || error.cause.constructor.name;\n extraErrorInfo.cause = { [errorName]: _extractErrorData(error.cause as ExtendedError, false, maxValueLength) };\n } else {\n extraErrorInfo.cause = error.cause;\n }\n }\n\n // Check if someone attached `toJSON` method to grab even more properties (eg. axios is doing that)\n if (typeof error.toJSON === 'function') {\n const serializedError = error.toJSON() as Record<string, unknown>;\n\n for (const key of Object.keys(serializedError)) {\n const value = serializedError[key];\n extraErrorInfo[key] = isError(value) ? value.toString() : value;\n }\n }\n\n return extraErrorInfo;\n } catch (oO) {\n DEBUG_BUILD && debug.error('Unable to extract extra data from the Error object:', oO);\n }\n\n return null;\n}\n"],"names":[],"mappings":"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"}
@@ -321,6 +321,8 @@ function _reconstructQuery(strings) {
321
321
  return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');
322
322
  }
323
323
 
324
+ let integerLiteralRE;
325
+
324
326
  /**
325
327
  * Sanitize SQL query as per the OTEL semantic conventions
326
328
  * https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext
@@ -335,6 +337,13 @@ function _sanitizeSqlQuery(sqlQuery) {
335
337
  return 'Unknown SQL Query';
336
338
  }
337
339
 
340
+ // Lazy init: constructing this at module scope would evaluate the lookbehind
341
+ // on import and crash Safari <16.4 browser bundles that reach this file via
342
+ // the core barrel. Building it on first call keeps the cost off the import path.
343
+ if (!integerLiteralRE) {
344
+ integerLiteralRE = new RegExp('(?<!\\$)-?\\b\\d+\\b', 'g');
345
+ }
346
+
338
347
  return (
339
348
  sqlQuery
340
349
  // Remove comments first (they may contain newlines and extra spaces)
@@ -357,7 +366,7 @@ function _sanitizeSqlQuery(sqlQuery) {
357
366
  .replace(/-?\b\d+\.?\d*[eE][+-]?\d+\b/g, '?') // Scientific notation
358
367
  .replace(/-?\b\d+\.\d+\b/g, '?') // Decimals
359
368
  .replace(/-?\.\d+\b/g, '?') // Decimals starting with dot
360
- .replace(/(?<!\$)-?\b\d+\b/g, '?') // Integers (NOT $n placeholders)
369
+ .replace(integerLiteralRE, '?') // Integers (NOT $n placeholders)
361
370
  // Collapse IN clauses for cardinality (both ? and $n variants)
362
371
  .replace(/\bIN\b\s*\(\s*\?(?:\s*,\s*\?)*\s*\)/gi, 'IN (?)')
363
372
  .replace(/\bIN\b\s*\(\s*\$\d+(?:\s*,\s*\$\d+)*\s*\)/gi, 'IN ($?)')
@@ -1 +1 @@
1
- {"version":3,"file":"postgresjs.js","sources":["../../../src/integrations/postgresjs.ts"],"sourcesContent":["// Portable instrumentation for https://github.com/porsager/postgres\n// This can be used in any environment (Node.js, Cloudflare Workers, etc.)\n// without depending on OpenTelemetry module hooking.\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes';\nimport { SPAN_STATUS_ERROR, startSpanManual } from '../tracing';\nimport type { Span } from '../types-hoist/span';\nimport { debug } from '../utils/debug-logger';\nimport { getActiveSpan } from '../utils/spanUtils';\n\nconst SQL_OPERATION_REGEX = /^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)/i;\n\ntype PostgresConnectionContext = {\n ATTR_DB_NAMESPACE?: string;\n ATTR_SERVER_ADDRESS?: string;\n ATTR_SERVER_PORT?: string;\n};\n\ninterface PostgresJsSqlInstrumentationOptions {\n /**\n * Whether to require a parent span for the instrumentation.\n * If set to true, the instrumentation will only create spans if there is a parent span\n * available in the current scope.\n * @default true\n */\n requireParentSpan?: boolean;\n /**\n * Hook to modify the span before it is started.\n * This can be used to set additional attributes or modify the span in any way.\n */\n requestHook?: (span: Span, sanitizedSqlQuery: string, postgresConnectionContext?: PostgresConnectionContext) => void;\n}\n\nconst CONNECTION_CONTEXT_SYMBOL = Symbol('sentryPostgresConnectionContext');\n\n// Use the same Symbol.for() markers as the Node.js OTel instrumentation\n// so that both approaches recognize each other and prevent double-wrapping.\nconst INSTRUMENTED_MARKER = Symbol.for('sentry.instrumented.postgresjs');\n// Marker to track if a query was created from an instrumented sql instance.\n// This prevents double-spanning when both the wrapper and the Node.js Query.prototype\n// fallback patch are active simultaneously.\nconst QUERY_FROM_INSTRUMENTED_SQL = Symbol.for('sentry.query.from.instrumented.sql');\n\n/**\n * Instruments a postgres.js `sql` instance with Sentry tracing.\n *\n * This is a portable instrumentation function that works in any environment\n * (Node.js, Cloudflare Workers, etc.) without depending on OpenTelemetry.\n *\n * @example\n * ```javascript\n * import postgres from 'postgres';\n * import * as Sentry from '@sentry/cloudflare'; // or '@sentry/deno'\n *\n * const sql = Sentry.instrumentPostgresJsSql(\n * postgres({ host: 'localhost', database: 'mydb' })\n * );\n *\n * // All queries now create Sentry spans\n * await sql`SELECT * FROM users WHERE id = ${userId}`;\n * ```\n */\nexport function instrumentPostgresJsSql<T>(sql: T, options?: PostgresJsSqlInstrumentationOptions): T {\n if (!sql || typeof sql !== 'function') {\n DEBUG_BUILD && debug.warn('instrumentPostgresJsSql: provided value is not a valid postgres.js sql instance');\n return sql;\n }\n\n return _instrumentSqlInstance(sql, { requireParentSpan: true, ...options }) as T;\n}\n\n/**\n * Instruments a sql instance by wrapping its query execution methods.\n */\nfunction _instrumentSqlInstance(\n sql: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n parentConnectionContext?: PostgresConnectionContext,\n): unknown {\n // Check if already instrumented to prevent double-wrapping\n // Using Symbol.for() ensures the marker survives proxying\n if ((sql as Record<symbol, unknown>)[INSTRUMENTED_MARKER]) {\n return sql;\n }\n\n // Wrap the sql function to intercept query creation\n const proxiedSql: unknown = new Proxy(sql as (...args: unknown[]) => unknown, {\n apply(target, thisArg, argumentsList: unknown[]) {\n const query = Reflect.apply(target, thisArg, argumentsList);\n\n if (query && typeof query === 'object' && 'handle' in query) {\n _wrapSingleQueryHandle(query as { handle: unknown; strings?: string[] }, proxiedSql, options);\n }\n\n return query;\n },\n get(target, prop) {\n const original = (target as unknown as Record<string | symbol, unknown>)[prop];\n\n if (typeof prop !== 'string' || typeof original !== 'function') {\n return original;\n }\n\n // Wrap methods that return PendingQuery objects (unsafe, file)\n if (prop === 'unsafe' || prop === 'file') {\n return _wrapQueryMethod(original as (...args: unknown[]) => unknown, target, proxiedSql, options);\n }\n\n // Wrap begin and reserve (not savepoint to avoid duplicate spans)\n if (prop === 'begin' || prop === 'reserve') {\n return _wrapCallbackMethod(original as (...args: unknown[]) => unknown, target, proxiedSql, options);\n }\n\n return original;\n },\n });\n\n // Use provided parent context if available, otherwise extract from sql.options\n if (parentConnectionContext) {\n (proxiedSql as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] = parentConnectionContext;\n } else {\n _attachConnectionContext(sql, proxiedSql as Record<symbol, unknown>);\n }\n\n // Mark both the original and proxy as instrumented to prevent double-wrapping\n (sql as Record<symbol, unknown>)[INSTRUMENTED_MARKER] = true;\n (proxiedSql as Record<symbol, unknown>)[INSTRUMENTED_MARKER] = true;\n\n return proxiedSql;\n}\n\n/**\n * Wraps query-returning methods (unsafe, file) to ensure their queries are instrumented.\n */\nfunction _wrapQueryMethod(\n original: (...args: unknown[]) => unknown,\n target: unknown,\n proxiedSql: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): (...args: unknown[]) => unknown {\n return function (this: unknown, ...args: unknown[]): unknown {\n const query = Reflect.apply(original, target, args);\n\n if (query && typeof query === 'object' && 'handle' in query) {\n _wrapSingleQueryHandle(query as { handle: unknown; strings?: string[] }, proxiedSql, options);\n }\n\n return query;\n };\n}\n\n/**\n * Wraps callback-based methods (begin, reserve) to recursively instrument Sql instances.\n * Note: These methods can also be used as tagged templates, which we pass through unchanged.\n *\n * Savepoint is not wrapped to avoid complex nested transaction instrumentation issues.\n * Queries within savepoint callbacks are still instrumented through the parent transaction's Sql instance.\n */\nfunction _wrapCallbackMethod(\n original: (...args: unknown[]) => unknown,\n target: unknown,\n parentSqlInstance: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): (...args: unknown[]) => unknown {\n return function (this: unknown, ...args: unknown[]): unknown {\n // Extract parent context to propagate to child instances\n const parentContext = (parentSqlInstance as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] as\n | PostgresConnectionContext\n | undefined;\n\n // Check if this is a callback-based call by verifying the last argument is a function\n const isCallbackBased = typeof args[args.length - 1] === 'function';\n\n if (!isCallbackBased) {\n // Not a callback-based call - could be tagged template or promise-based\n const result = Reflect.apply(original, target, args);\n // If result is a Promise (e.g., reserve() without callback), instrument the resolved Sql instance\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).then((sqlInstance: unknown) => {\n return _instrumentSqlInstance(sqlInstance, options, parentContext);\n });\n }\n return result;\n }\n\n // Callback-based call: wrap the callback to instrument the Sql instance\n const callback = (args.length === 1 ? args[0] : args[1]) as (sql: unknown) => unknown;\n const wrappedCallback = function (sqlInstance: unknown): unknown {\n const instrumentedSql = _instrumentSqlInstance(sqlInstance, options, parentContext);\n return callback(instrumentedSql);\n };\n\n const newArgs = args.length === 1 ? [wrappedCallback] : [args[0], wrappedCallback];\n return Reflect.apply(original, target, newArgs);\n };\n}\n\n/**\n * Wraps a single query's handle method to create spans.\n */\nfunction _wrapSingleQueryHandle(\n query: { handle: unknown; strings?: string[]; __sentryWrapped?: boolean },\n sqlInstance: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): void {\n // Prevent double wrapping - check if the handle itself is already wrapped\n if ((query.handle as { __sentryWrapped?: boolean })?.__sentryWrapped) {\n return;\n }\n\n // Mark this query as coming from an instrumented sql instance.\n // This prevents the Node.js Query.prototype fallback patch from double-spanning.\n (query as Record<symbol, unknown>)[QUERY_FROM_INSTRUMENTED_SQL] = true;\n\n const originalHandle = query.handle as (...args: unknown[]) => Promise<unknown>;\n\n // IMPORTANT: We must replace the handle function directly, not use a Proxy,\n // because Query.then() internally calls this.handle(), which would bypass a Proxy wrapper.\n const wrappedHandle = async function (this: unknown, ...args: unknown[]): Promise<unknown> {\n if (!_shouldCreateSpans(options)) {\n return originalHandle.apply(this, args);\n }\n\n const fullQuery = _reconstructQuery(query.strings);\n const sanitizedSqlQuery = _sanitizeSqlQuery(fullQuery);\n\n return startSpanManual(\n {\n name: sanitizedSqlQuery || 'postgresjs.query',\n op: 'db',\n },\n (span: Span) => {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.postgresjs');\n\n span.setAttributes({\n 'db.system.name': 'postgres',\n 'db.query.text': sanitizedSqlQuery,\n });\n\n const connectionContext = sqlInstance\n ? ((sqlInstance as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] as\n | PostgresConnectionContext\n | undefined)\n : undefined;\n\n _setConnectionAttributes(span, connectionContext);\n\n if (options.requestHook) {\n try {\n options.requestHook(span, sanitizedSqlQuery, connectionContext);\n } catch (e) {\n span.setAttribute('sentry.hook.error', 'requestHook failed');\n DEBUG_BUILD && debug.error('Error in requestHook for PostgresJs instrumentation:', e);\n }\n }\n\n const queryWithCallbacks = this as {\n resolve: unknown;\n reject: unknown;\n };\n\n queryWithCallbacks.resolve = new Proxy(queryWithCallbacks.resolve as (...args: unknown[]) => unknown, {\n apply: (resolveTarget, resolveThisArg, resolveArgs: [{ command?: string }]) => {\n try {\n _setOperationName(span, sanitizedSqlQuery, resolveArgs?.[0]?.command);\n span.end();\n } catch (e) {\n DEBUG_BUILD && debug.error('Error ending span in resolve callback:', e);\n }\n\n return Reflect.apply(resolveTarget, resolveThisArg, resolveArgs);\n },\n });\n\n queryWithCallbacks.reject = new Proxy(queryWithCallbacks.reject as (...args: unknown[]) => unknown, {\n apply: (rejectTarget, rejectThisArg, rejectArgs: { message?: string; code?: string; name?: string }[]) => {\n try {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: rejectArgs?.[0]?.message || 'unknown_error',\n });\n\n span.setAttribute('db.response.status_code', rejectArgs?.[0]?.code || 'unknown');\n span.setAttribute('error.type', rejectArgs?.[0]?.name || 'unknown');\n\n _setOperationName(span, sanitizedSqlQuery);\n span.end();\n } catch (e) {\n DEBUG_BUILD && debug.error('Error ending span in reject callback:', e);\n }\n return Reflect.apply(rejectTarget, rejectThisArg, rejectArgs);\n },\n });\n\n // Handle synchronous errors that might occur before promise is created\n try {\n return originalHandle.apply(this, args);\n } catch (e) {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: e instanceof Error ? e.message : 'unknown_error',\n });\n span.end();\n throw e;\n }\n },\n );\n };\n\n (wrappedHandle as { __sentryWrapped?: boolean }).__sentryWrapped = true;\n query.handle = wrappedHandle;\n}\n\n/**\n * Determines whether a span should be created based on the current context.\n * If `requireParentSpan` is set to true in the options, a span will\n * only be created if there is a parent span available.\n */\nfunction _shouldCreateSpans(options: PostgresJsSqlInstrumentationOptions): boolean {\n const hasParentSpan = getActiveSpan() !== undefined;\n return hasParentSpan || !options.requireParentSpan;\n}\n\n/**\n * Reconstructs the full SQL query from template strings with PostgreSQL placeholders.\n *\n * For sql`SELECT * FROM users WHERE id = ${123} AND name = ${'foo'}`:\n * strings = [\"SELECT * FROM users WHERE id = \", \" AND name = \", \"\"]\n * returns: \"SELECT * FROM users WHERE id = $1 AND name = $2\"\n *\n * @internal Exported for testing only\n */\nexport function _reconstructQuery(strings: string[] | undefined): string | undefined {\n if (!strings?.length) {\n return undefined;\n }\n if (strings.length === 1) {\n return strings[0] || undefined;\n }\n // Join template parts with PostgreSQL placeholders ($1, $2, etc.)\n return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');\n}\n\n/**\n * Sanitize SQL query as per the OTEL semantic conventions\n * https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext\n *\n * PostgreSQL $n placeholders are preserved per OTEL spec - they're parameterized queries,\n * not sensitive literals. Only actual values (strings, numbers, booleans) are sanitized.\n *\n * @internal Exported for testing only\n */\nexport function _sanitizeSqlQuery(sqlQuery: string | undefined): string {\n if (!sqlQuery) {\n return 'Unknown SQL Query';\n }\n\n return (\n sqlQuery\n // Remove comments first (they may contain newlines and extra spaces)\n .replace(/--.*$/gm, '') // Single line comments (multiline mode)\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Multi-line comments\n .replace(/;\\s*$/, '') // Remove trailing semicolons\n // Collapse whitespace to a single space (after removing comments)\n .replace(/\\s+/g, ' ')\n .trim() // Remove extra spaces and trim\n // Sanitize hex/binary literals before string literals\n .replace(/\\bX'[0-9A-Fa-f]*'/gi, '?') // Hex string literals\n .replace(/\\bB'[01]*'/gi, '?') // Binary string literals\n // Sanitize string literals (handles escaped quotes)\n .replace(/'(?:[^']|'')*'/g, '?')\n // Sanitize hex numbers\n .replace(/\\b0x[0-9A-Fa-f]+/gi, '?')\n // Sanitize boolean literals\n .replace(/\\b(?:TRUE|FALSE)\\b/gi, '?')\n // Sanitize numeric literals (preserve $n placeholders via negative lookbehind)\n .replace(/-?\\b\\d+\\.?\\d*[eE][+-]?\\d+\\b/g, '?') // Scientific notation\n .replace(/-?\\b\\d+\\.\\d+\\b/g, '?') // Decimals\n .replace(/-?\\.\\d+\\b/g, '?') // Decimals starting with dot\n .replace(/(?<!\\$)-?\\b\\d+\\b/g, '?') // Integers (NOT $n placeholders)\n // Collapse IN clauses for cardinality (both ? and $n variants)\n .replace(/\\bIN\\b\\s*\\(\\s*\\?(?:\\s*,\\s*\\?)*\\s*\\)/gi, 'IN (?)')\n .replace(/\\bIN\\b\\s*\\(\\s*\\$\\d+(?:\\s*,\\s*\\$\\d+)*\\s*\\)/gi, 'IN ($?)')\n );\n}\n\n/**\n * Sets connection context attributes on a span.\n */\nfunction _setConnectionAttributes(span: Span, connectionContext: PostgresConnectionContext | undefined): void {\n if (!connectionContext) {\n return;\n }\n if (connectionContext.ATTR_DB_NAMESPACE) {\n span.setAttribute('db.namespace', connectionContext.ATTR_DB_NAMESPACE);\n }\n if (connectionContext.ATTR_SERVER_ADDRESS) {\n span.setAttribute('server.address', connectionContext.ATTR_SERVER_ADDRESS);\n }\n if (connectionContext.ATTR_SERVER_PORT !== undefined) {\n // Port is stored as string in PostgresConnectionContext for requestHook backwards compatibility,\n // but semantic conventions expect port as a number for span attributes\n const portNumber = parseInt(connectionContext.ATTR_SERVER_PORT, 10);\n if (!isNaN(portNumber)) {\n span.setAttribute('server.port', portNumber);\n }\n }\n}\n\n/**\n * Extracts DB operation name from SQL query and sets it on the span.\n */\nfunction _setOperationName(span: Span, sanitizedQuery: string | undefined, command?: string): void {\n if (command) {\n span.setAttribute('db.operation.name', command);\n return;\n }\n // Fallback: extract operation from the SQL query\n const operationMatch = sanitizedQuery?.match(SQL_OPERATION_REGEX);\n if (operationMatch?.[1]) {\n span.setAttribute('db.operation.name', operationMatch[1].toUpperCase());\n }\n}\n\n/**\n * Extracts and stores connection context from sql.options.\n */\nfunction _attachConnectionContext(sql: unknown, proxiedSql: Record<symbol, unknown>): void {\n const sqlInstance = sql as { options?: { host?: string[]; port?: number[]; database?: string } };\n if (!sqlInstance.options || typeof sqlInstance.options !== 'object') {\n return;\n }\n\n const opts = sqlInstance.options;\n // postgres.js stores parsed options with host and port as arrays\n // The library defaults to 'localhost' and 5432 if not specified, but we're defensive here\n const host = opts.host?.[0] || 'localhost';\n const port = opts.port?.[0] || 5432;\n\n const connectionContext: PostgresConnectionContext = {\n ATTR_DB_NAMESPACE: typeof opts.database === 'string' && opts.database !== '' ? opts.database : undefined,\n ATTR_SERVER_ADDRESS: host,\n ATTR_SERVER_PORT: String(port),\n };\n\n proxiedSql[CONNECTION_CONTEXT_SYMBOL] = connectionContext;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"postgresjs.js","sources":["../../../src/integrations/postgresjs.ts"],"sourcesContent":["// Portable instrumentation for https://github.com/porsager/postgres\n// This can be used in any environment (Node.js, Cloudflare Workers, etc.)\n// without depending on OpenTelemetry module hooking.\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes';\nimport { SPAN_STATUS_ERROR, startSpanManual } from '../tracing';\nimport type { Span } from '../types-hoist/span';\nimport { debug } from '../utils/debug-logger';\nimport { getActiveSpan } from '../utils/spanUtils';\n\nconst SQL_OPERATION_REGEX = /^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)/i;\n\ntype PostgresConnectionContext = {\n ATTR_DB_NAMESPACE?: string;\n ATTR_SERVER_ADDRESS?: string;\n ATTR_SERVER_PORT?: string;\n};\n\ninterface PostgresJsSqlInstrumentationOptions {\n /**\n * Whether to require a parent span for the instrumentation.\n * If set to true, the instrumentation will only create spans if there is a parent span\n * available in the current scope.\n * @default true\n */\n requireParentSpan?: boolean;\n /**\n * Hook to modify the span before it is started.\n * This can be used to set additional attributes or modify the span in any way.\n */\n requestHook?: (span: Span, sanitizedSqlQuery: string, postgresConnectionContext?: PostgresConnectionContext) => void;\n}\n\nconst CONNECTION_CONTEXT_SYMBOL = Symbol('sentryPostgresConnectionContext');\n\n// Use the same Symbol.for() markers as the Node.js OTel instrumentation\n// so that both approaches recognize each other and prevent double-wrapping.\nconst INSTRUMENTED_MARKER = Symbol.for('sentry.instrumented.postgresjs');\n// Marker to track if a query was created from an instrumented sql instance.\n// This prevents double-spanning when both the wrapper and the Node.js Query.prototype\n// fallback patch are active simultaneously.\nconst QUERY_FROM_INSTRUMENTED_SQL = Symbol.for('sentry.query.from.instrumented.sql');\n\n/**\n * Instruments a postgres.js `sql` instance with Sentry tracing.\n *\n * This is a portable instrumentation function that works in any environment\n * (Node.js, Cloudflare Workers, etc.) without depending on OpenTelemetry.\n *\n * @example\n * ```javascript\n * import postgres from 'postgres';\n * import * as Sentry from '@sentry/cloudflare'; // or '@sentry/deno'\n *\n * const sql = Sentry.instrumentPostgresJsSql(\n * postgres({ host: 'localhost', database: 'mydb' })\n * );\n *\n * // All queries now create Sentry spans\n * await sql`SELECT * FROM users WHERE id = ${userId}`;\n * ```\n */\nexport function instrumentPostgresJsSql<T>(sql: T, options?: PostgresJsSqlInstrumentationOptions): T {\n if (!sql || typeof sql !== 'function') {\n DEBUG_BUILD && debug.warn('instrumentPostgresJsSql: provided value is not a valid postgres.js sql instance');\n return sql;\n }\n\n return _instrumentSqlInstance(sql, { requireParentSpan: true, ...options }) as T;\n}\n\n/**\n * Instruments a sql instance by wrapping its query execution methods.\n */\nfunction _instrumentSqlInstance(\n sql: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n parentConnectionContext?: PostgresConnectionContext,\n): unknown {\n // Check if already instrumented to prevent double-wrapping\n // Using Symbol.for() ensures the marker survives proxying\n if ((sql as Record<symbol, unknown>)[INSTRUMENTED_MARKER]) {\n return sql;\n }\n\n // Wrap the sql function to intercept query creation\n const proxiedSql: unknown = new Proxy(sql as (...args: unknown[]) => unknown, {\n apply(target, thisArg, argumentsList: unknown[]) {\n const query = Reflect.apply(target, thisArg, argumentsList);\n\n if (query && typeof query === 'object' && 'handle' in query) {\n _wrapSingleQueryHandle(query as { handle: unknown; strings?: string[] }, proxiedSql, options);\n }\n\n return query;\n },\n get(target, prop) {\n const original = (target as unknown as Record<string | symbol, unknown>)[prop];\n\n if (typeof prop !== 'string' || typeof original !== 'function') {\n return original;\n }\n\n // Wrap methods that return PendingQuery objects (unsafe, file)\n if (prop === 'unsafe' || prop === 'file') {\n return _wrapQueryMethod(original as (...args: unknown[]) => unknown, target, proxiedSql, options);\n }\n\n // Wrap begin and reserve (not savepoint to avoid duplicate spans)\n if (prop === 'begin' || prop === 'reserve') {\n return _wrapCallbackMethod(original as (...args: unknown[]) => unknown, target, proxiedSql, options);\n }\n\n return original;\n },\n });\n\n // Use provided parent context if available, otherwise extract from sql.options\n if (parentConnectionContext) {\n (proxiedSql as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] = parentConnectionContext;\n } else {\n _attachConnectionContext(sql, proxiedSql as Record<symbol, unknown>);\n }\n\n // Mark both the original and proxy as instrumented to prevent double-wrapping\n (sql as Record<symbol, unknown>)[INSTRUMENTED_MARKER] = true;\n (proxiedSql as Record<symbol, unknown>)[INSTRUMENTED_MARKER] = true;\n\n return proxiedSql;\n}\n\n/**\n * Wraps query-returning methods (unsafe, file) to ensure their queries are instrumented.\n */\nfunction _wrapQueryMethod(\n original: (...args: unknown[]) => unknown,\n target: unknown,\n proxiedSql: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): (...args: unknown[]) => unknown {\n return function (this: unknown, ...args: unknown[]): unknown {\n const query = Reflect.apply(original, target, args);\n\n if (query && typeof query === 'object' && 'handle' in query) {\n _wrapSingleQueryHandle(query as { handle: unknown; strings?: string[] }, proxiedSql, options);\n }\n\n return query;\n };\n}\n\n/**\n * Wraps callback-based methods (begin, reserve) to recursively instrument Sql instances.\n * Note: These methods can also be used as tagged templates, which we pass through unchanged.\n *\n * Savepoint is not wrapped to avoid complex nested transaction instrumentation issues.\n * Queries within savepoint callbacks are still instrumented through the parent transaction's Sql instance.\n */\nfunction _wrapCallbackMethod(\n original: (...args: unknown[]) => unknown,\n target: unknown,\n parentSqlInstance: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): (...args: unknown[]) => unknown {\n return function (this: unknown, ...args: unknown[]): unknown {\n // Extract parent context to propagate to child instances\n const parentContext = (parentSqlInstance as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] as\n | PostgresConnectionContext\n | undefined;\n\n // Check if this is a callback-based call by verifying the last argument is a function\n const isCallbackBased = typeof args[args.length - 1] === 'function';\n\n if (!isCallbackBased) {\n // Not a callback-based call - could be tagged template or promise-based\n const result = Reflect.apply(original, target, args);\n // If result is a Promise (e.g., reserve() without callback), instrument the resolved Sql instance\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).then((sqlInstance: unknown) => {\n return _instrumentSqlInstance(sqlInstance, options, parentContext);\n });\n }\n return result;\n }\n\n // Callback-based call: wrap the callback to instrument the Sql instance\n const callback = (args.length === 1 ? args[0] : args[1]) as (sql: unknown) => unknown;\n const wrappedCallback = function (sqlInstance: unknown): unknown {\n const instrumentedSql = _instrumentSqlInstance(sqlInstance, options, parentContext);\n return callback(instrumentedSql);\n };\n\n const newArgs = args.length === 1 ? [wrappedCallback] : [args[0], wrappedCallback];\n return Reflect.apply(original, target, newArgs);\n };\n}\n\n/**\n * Wraps a single query's handle method to create spans.\n */\nfunction _wrapSingleQueryHandle(\n query: { handle: unknown; strings?: string[]; __sentryWrapped?: boolean },\n sqlInstance: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): void {\n // Prevent double wrapping - check if the handle itself is already wrapped\n if ((query.handle as { __sentryWrapped?: boolean })?.__sentryWrapped) {\n return;\n }\n\n // Mark this query as coming from an instrumented sql instance.\n // This prevents the Node.js Query.prototype fallback patch from double-spanning.\n (query as Record<symbol, unknown>)[QUERY_FROM_INSTRUMENTED_SQL] = true;\n\n const originalHandle = query.handle as (...args: unknown[]) => Promise<unknown>;\n\n // IMPORTANT: We must replace the handle function directly, not use a Proxy,\n // because Query.then() internally calls this.handle(), which would bypass a Proxy wrapper.\n const wrappedHandle = async function (this: unknown, ...args: unknown[]): Promise<unknown> {\n if (!_shouldCreateSpans(options)) {\n return originalHandle.apply(this, args);\n }\n\n const fullQuery = _reconstructQuery(query.strings);\n const sanitizedSqlQuery = _sanitizeSqlQuery(fullQuery);\n\n return startSpanManual(\n {\n name: sanitizedSqlQuery || 'postgresjs.query',\n op: 'db',\n },\n (span: Span) => {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.postgresjs');\n\n span.setAttributes({\n 'db.system.name': 'postgres',\n 'db.query.text': sanitizedSqlQuery,\n });\n\n const connectionContext = sqlInstance\n ? ((sqlInstance as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] as\n | PostgresConnectionContext\n | undefined)\n : undefined;\n\n _setConnectionAttributes(span, connectionContext);\n\n if (options.requestHook) {\n try {\n options.requestHook(span, sanitizedSqlQuery, connectionContext);\n } catch (e) {\n span.setAttribute('sentry.hook.error', 'requestHook failed');\n DEBUG_BUILD && debug.error('Error in requestHook for PostgresJs instrumentation:', e);\n }\n }\n\n const queryWithCallbacks = this as {\n resolve: unknown;\n reject: unknown;\n };\n\n queryWithCallbacks.resolve = new Proxy(queryWithCallbacks.resolve as (...args: unknown[]) => unknown, {\n apply: (resolveTarget, resolveThisArg, resolveArgs: [{ command?: string }]) => {\n try {\n _setOperationName(span, sanitizedSqlQuery, resolveArgs?.[0]?.command);\n span.end();\n } catch (e) {\n DEBUG_BUILD && debug.error('Error ending span in resolve callback:', e);\n }\n\n return Reflect.apply(resolveTarget, resolveThisArg, resolveArgs);\n },\n });\n\n queryWithCallbacks.reject = new Proxy(queryWithCallbacks.reject as (...args: unknown[]) => unknown, {\n apply: (rejectTarget, rejectThisArg, rejectArgs: { message?: string; code?: string; name?: string }[]) => {\n try {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: rejectArgs?.[0]?.message || 'unknown_error',\n });\n\n span.setAttribute('db.response.status_code', rejectArgs?.[0]?.code || 'unknown');\n span.setAttribute('error.type', rejectArgs?.[0]?.name || 'unknown');\n\n _setOperationName(span, sanitizedSqlQuery);\n span.end();\n } catch (e) {\n DEBUG_BUILD && debug.error('Error ending span in reject callback:', e);\n }\n return Reflect.apply(rejectTarget, rejectThisArg, rejectArgs);\n },\n });\n\n // Handle synchronous errors that might occur before promise is created\n try {\n return originalHandle.apply(this, args);\n } catch (e) {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: e instanceof Error ? e.message : 'unknown_error',\n });\n span.end();\n throw e;\n }\n },\n );\n };\n\n (wrappedHandle as { __sentryWrapped?: boolean }).__sentryWrapped = true;\n query.handle = wrappedHandle;\n}\n\n/**\n * Determines whether a span should be created based on the current context.\n * If `requireParentSpan` is set to true in the options, a span will\n * only be created if there is a parent span available.\n */\nfunction _shouldCreateSpans(options: PostgresJsSqlInstrumentationOptions): boolean {\n const hasParentSpan = getActiveSpan() !== undefined;\n return hasParentSpan || !options.requireParentSpan;\n}\n\n/**\n * Reconstructs the full SQL query from template strings with PostgreSQL placeholders.\n *\n * For sql`SELECT * FROM users WHERE id = ${123} AND name = ${'foo'}`:\n * strings = [\"SELECT * FROM users WHERE id = \", \" AND name = \", \"\"]\n * returns: \"SELECT * FROM users WHERE id = $1 AND name = $2\"\n *\n * @internal Exported for testing only\n */\nexport function _reconstructQuery(strings: string[] | undefined): string | undefined {\n if (!strings?.length) {\n return undefined;\n }\n if (strings.length === 1) {\n return strings[0] || undefined;\n }\n // Join template parts with PostgreSQL placeholders ($1, $2, etc.)\n return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');\n}\n\nlet integerLiteralRE: RegExp | undefined;\n\n/**\n * Sanitize SQL query as per the OTEL semantic conventions\n * https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext\n *\n * PostgreSQL $n placeholders are preserved per OTEL spec - they're parameterized queries,\n * not sensitive literals. Only actual values (strings, numbers, booleans) are sanitized.\n *\n * @internal Exported for testing only\n */\nexport function _sanitizeSqlQuery(sqlQuery: string | undefined): string {\n if (!sqlQuery) {\n return 'Unknown SQL Query';\n }\n\n // Lazy init: constructing this at module scope would evaluate the lookbehind\n // on import and crash Safari <16.4 browser bundles that reach this file via\n // the core barrel. Building it on first call keeps the cost off the import path.\n if (!integerLiteralRE) {\n integerLiteralRE = new RegExp('(?<!\\\\$)-?\\\\b\\\\d+\\\\b', 'g');\n }\n\n return (\n sqlQuery\n // Remove comments first (they may contain newlines and extra spaces)\n .replace(/--.*$/gm, '') // Single line comments (multiline mode)\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Multi-line comments\n .replace(/;\\s*$/, '') // Remove trailing semicolons\n // Collapse whitespace to a single space (after removing comments)\n .replace(/\\s+/g, ' ')\n .trim() // Remove extra spaces and trim\n // Sanitize hex/binary literals before string literals\n .replace(/\\bX'[0-9A-Fa-f]*'/gi, '?') // Hex string literals\n .replace(/\\bB'[01]*'/gi, '?') // Binary string literals\n // Sanitize string literals (handles escaped quotes)\n .replace(/'(?:[^']|'')*'/g, '?')\n // Sanitize hex numbers\n .replace(/\\b0x[0-9A-Fa-f]+/gi, '?')\n // Sanitize boolean literals\n .replace(/\\b(?:TRUE|FALSE)\\b/gi, '?')\n // Sanitize numeric literals (preserve $n placeholders via negative lookbehind)\n .replace(/-?\\b\\d+\\.?\\d*[eE][+-]?\\d+\\b/g, '?') // Scientific notation\n .replace(/-?\\b\\d+\\.\\d+\\b/g, '?') // Decimals\n .replace(/-?\\.\\d+\\b/g, '?') // Decimals starting with dot\n .replace(integerLiteralRE, '?') // Integers (NOT $n placeholders)\n // Collapse IN clauses for cardinality (both ? and $n variants)\n .replace(/\\bIN\\b\\s*\\(\\s*\\?(?:\\s*,\\s*\\?)*\\s*\\)/gi, 'IN (?)')\n .replace(/\\bIN\\b\\s*\\(\\s*\\$\\d+(?:\\s*,\\s*\\$\\d+)*\\s*\\)/gi, 'IN ($?)')\n );\n}\n\n/**\n * Sets connection context attributes on a span.\n */\nfunction _setConnectionAttributes(span: Span, connectionContext: PostgresConnectionContext | undefined): void {\n if (!connectionContext) {\n return;\n }\n if (connectionContext.ATTR_DB_NAMESPACE) {\n span.setAttribute('db.namespace', connectionContext.ATTR_DB_NAMESPACE);\n }\n if (connectionContext.ATTR_SERVER_ADDRESS) {\n span.setAttribute('server.address', connectionContext.ATTR_SERVER_ADDRESS);\n }\n if (connectionContext.ATTR_SERVER_PORT !== undefined) {\n // Port is stored as string in PostgresConnectionContext for requestHook backwards compatibility,\n // but semantic conventions expect port as a number for span attributes\n const portNumber = parseInt(connectionContext.ATTR_SERVER_PORT, 10);\n if (!isNaN(portNumber)) {\n span.setAttribute('server.port', portNumber);\n }\n }\n}\n\n/**\n * Extracts DB operation name from SQL query and sets it on the span.\n */\nfunction _setOperationName(span: Span, sanitizedQuery: string | undefined, command?: string): void {\n if (command) {\n span.setAttribute('db.operation.name', command);\n return;\n }\n // Fallback: extract operation from the SQL query\n const operationMatch = sanitizedQuery?.match(SQL_OPERATION_REGEX);\n if (operationMatch?.[1]) {\n span.setAttribute('db.operation.name', operationMatch[1].toUpperCase());\n }\n}\n\n/**\n * Extracts and stores connection context from sql.options.\n */\nfunction _attachConnectionContext(sql: unknown, proxiedSql: Record<symbol, unknown>): void {\n const sqlInstance = sql as { options?: { host?: string[]; port?: number[]; database?: string } };\n if (!sqlInstance.options || typeof sqlInstance.options !== 'object') {\n return;\n }\n\n const opts = sqlInstance.options;\n // postgres.js stores parsed options with host and port as arrays\n // The library defaults to 'localhost' and 5432 if not specified, but we're defensive here\n const host = opts.host?.[0] || 'localhost';\n const port = opts.port?.[0] || 5432;\n\n const connectionContext: PostgresConnectionContext = {\n ATTR_DB_NAMESPACE: typeof opts.database === 'string' && opts.database !== '' ? opts.database : undefined,\n ATTR_SERVER_ADDRESS: host,\n ATTR_SERVER_PORT: String(port),\n };\n\n proxiedSql[CONNECTION_CONTEXT_SYMBOL] = connectionContext;\n}\n"],"names":[],"mappings":"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"}
@@ -87,12 +87,16 @@ function extractNormalizedRequestData(
87
87
  delete (headers ).cookie;
88
88
  }
89
89
 
90
- // Remove IP headers in case IP data should not be included in the event
90
+ // Remove IP headers in case IP data should not be included in the event.
91
+ // Match case-insensitively — same as getClientIPAddress — so lowercase keys are stripped too.
91
92
  if (!include.ip) {
92
- ipHeaderNames.forEach(ipHeaderName => {
93
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
94
- delete (headers )[ipHeaderName];
95
- });
93
+ const ipHeaderNamesLower = new Set(ipHeaderNames.map(name => name.toLowerCase()));
94
+ for (const key of Object.keys(headers)) {
95
+ if (ipHeaderNamesLower.has(key.toLowerCase())) {
96
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
97
+ delete (headers )[key];
98
+ }
99
+ }
96
100
  }
97
101
  }
98
102
 
@@ -1 +1 @@
1
- {"version":3,"file":"requestdata.js","sources":["../../../src/integrations/requestdata.ts"],"sourcesContent":["import { defineIntegration } from '../integration';\nimport type { Event } from '../types-hoist/event';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport type { RequestEventData } from '../types-hoist/request';\nimport { parseCookie } from '../utils/cookie';\nimport { getClientIPAddress, ipHeaderNames } from '../vendor/getIpAddress';\n\ninterface RequestDataIncludeOptions {\n cookies?: boolean;\n data?: boolean;\n headers?: boolean;\n ip?: boolean;\n query_string?: boolean;\n url?: boolean;\n}\n\ntype RequestDataIntegrationOptions = {\n /**\n * Controls what data is pulled from the request and added to the event.\n */\n include?: RequestDataIncludeOptions;\n};\n\n// TODO(v11): Change defaults based on `sendDefaultPii`\nconst DEFAULT_INCLUDE: RequestDataIncludeOptions = {\n cookies: true,\n data: true,\n headers: true,\n query_string: true,\n url: true,\n};\n\nconst INTEGRATION_NAME = 'RequestData';\n\nconst _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) => {\n const include = {\n ...DEFAULT_INCLUDE,\n ...options.include,\n };\n\n return {\n name: INTEGRATION_NAME,\n processEvent(event, _hint, client) {\n const { sdkProcessingMetadata = {} } = event;\n const { normalizedRequest, ipAddress } = sdkProcessingMetadata;\n\n const includeWithDefaultPiiApplied: RequestDataIncludeOptions = {\n ...include,\n ip: include.ip ?? client.getOptions().sendDefaultPii,\n };\n\n if (normalizedRequest) {\n addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, includeWithDefaultPiiApplied);\n }\n\n return event;\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/core`\n * so it can be used in cross-platform SDKs like `@sentry/nextjs`.\n */\nexport const requestDataIntegration = defineIntegration(_requestDataIntegration);\n\n/**\n * Add already normalized request data to an event.\n * This mutates the passed in event.\n */\nfunction addNormalizedRequestDataToEvent(\n event: Event,\n req: RequestEventData,\n // Data that should not go into `event.request` but is somehow related to requests\n additionalData: { ipAddress?: string },\n include: RequestDataIncludeOptions,\n): void {\n event.request = {\n ...event.request,\n ...extractNormalizedRequestData(req, include),\n };\n\n if (include.ip) {\n const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress;\n if (ip) {\n event.user = {\n ...event.user,\n ip_address: ip,\n };\n }\n }\n}\n\nfunction extractNormalizedRequestData(\n normalizedRequest: RequestEventData,\n include: RequestDataIncludeOptions,\n): RequestEventData {\n const requestData: RequestEventData = {};\n const headers = { ...normalizedRequest.headers };\n\n if (include.headers) {\n requestData.headers = headers;\n\n // Remove the Cookie header in case cookie data should not be included in the event\n if (!include.cookies) {\n delete (headers as { cookie?: string }).cookie;\n }\n\n // Remove IP headers in case IP data should not be included in the event\n if (!include.ip) {\n ipHeaderNames.forEach(ipHeaderName => {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (headers as Record<string, unknown>)[ipHeaderName];\n });\n }\n }\n\n requestData.method = normalizedRequest.method;\n\n if (include.url) {\n requestData.url = normalizedRequest.url;\n }\n\n if (include.cookies) {\n const cookies = normalizedRequest.cookies || (headers?.cookie ? parseCookie(headers.cookie) : undefined);\n requestData.cookies = cookies || {};\n }\n\n if (include.query_string) {\n requestData.query_string = normalizedRequest.query_string;\n }\n\n if (include.data) {\n requestData.data = normalizedRequest.data;\n }\n\n return requestData;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"requestdata.js","sources":["../../../src/integrations/requestdata.ts"],"sourcesContent":["import { defineIntegration } from '../integration';\nimport type { Event } from '../types-hoist/event';\nimport type { IntegrationFn } from '../types-hoist/integration';\nimport type { RequestEventData } from '../types-hoist/request';\nimport { parseCookie } from '../utils/cookie';\nimport { getClientIPAddress, ipHeaderNames } from '../vendor/getIpAddress';\n\ninterface RequestDataIncludeOptions {\n cookies?: boolean;\n data?: boolean;\n headers?: boolean;\n ip?: boolean;\n query_string?: boolean;\n url?: boolean;\n}\n\ntype RequestDataIntegrationOptions = {\n /**\n * Controls what data is pulled from the request and added to the event.\n */\n include?: RequestDataIncludeOptions;\n};\n\n// TODO(v11): Change defaults based on `sendDefaultPii`\nconst DEFAULT_INCLUDE: RequestDataIncludeOptions = {\n cookies: true,\n data: true,\n headers: true,\n query_string: true,\n url: true,\n};\n\nconst INTEGRATION_NAME = 'RequestData';\n\nconst _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) => {\n const include = {\n ...DEFAULT_INCLUDE,\n ...options.include,\n };\n\n return {\n name: INTEGRATION_NAME,\n processEvent(event, _hint, client) {\n const { sdkProcessingMetadata = {} } = event;\n const { normalizedRequest, ipAddress } = sdkProcessingMetadata;\n\n const includeWithDefaultPiiApplied: RequestDataIncludeOptions = {\n ...include,\n ip: include.ip ?? client.getOptions().sendDefaultPii,\n };\n\n if (normalizedRequest) {\n addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, includeWithDefaultPiiApplied);\n }\n\n return event;\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/core`\n * so it can be used in cross-platform SDKs like `@sentry/nextjs`.\n */\nexport const requestDataIntegration = defineIntegration(_requestDataIntegration);\n\n/**\n * Add already normalized request data to an event.\n * This mutates the passed in event.\n */\nfunction addNormalizedRequestDataToEvent(\n event: Event,\n req: RequestEventData,\n // Data that should not go into `event.request` but is somehow related to requests\n additionalData: { ipAddress?: string },\n include: RequestDataIncludeOptions,\n): void {\n event.request = {\n ...event.request,\n ...extractNormalizedRequestData(req, include),\n };\n\n if (include.ip) {\n const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress;\n if (ip) {\n event.user = {\n ...event.user,\n ip_address: ip,\n };\n }\n }\n}\n\nfunction extractNormalizedRequestData(\n normalizedRequest: RequestEventData,\n include: RequestDataIncludeOptions,\n): RequestEventData {\n const requestData: RequestEventData = {};\n const headers = { ...normalizedRequest.headers };\n\n if (include.headers) {\n requestData.headers = headers;\n\n // Remove the Cookie header in case cookie data should not be included in the event\n if (!include.cookies) {\n delete (headers as { cookie?: string }).cookie;\n }\n\n // Remove IP headers in case IP data should not be included in the event.\n // Match case-insensitively — same as getClientIPAddress — so lowercase keys are stripped too.\n if (!include.ip) {\n const ipHeaderNamesLower = new Set(ipHeaderNames.map(name => name.toLowerCase()));\n for (const key of Object.keys(headers)) {\n if (ipHeaderNamesLower.has(key.toLowerCase())) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (headers as Record<string, unknown>)[key];\n }\n }\n }\n }\n\n requestData.method = normalizedRequest.method;\n\n if (include.url) {\n requestData.url = normalizedRequest.url;\n }\n\n if (include.cookies) {\n const cookies = normalizedRequest.cookies || (headers?.cookie ? parseCookie(headers.cookie) : undefined);\n requestData.cookies = cookies || {};\n }\n\n if (include.query_string) {\n requestData.query_string = normalizedRequest.query_string;\n }\n\n if (include.data) {\n requestData.data = normalizedRequest.data;\n }\n\n return requestData;\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { addBreadcrumb } from '../breadcrumbs.js';
2
+ import { getClient } from '../currentScopes.js';
2
3
  import { DEBUG_BUILD } from '../debug-build.js';
3
4
  import { captureException } from '../exports.js';
4
5
  import { defineIntegration } from '../integration.js';
@@ -83,6 +84,25 @@ function isInstrumented(fn) {
83
84
  }
84
85
  }
85
86
 
87
+ /**
88
+ * Plain-object bodies are copied into `plainBody`; array inserts (and other non-plain shapes) stay only on `rawBody`.
89
+ * Returns a payload suitable for span attributes / breadcrumbs when the client has `sendDefaultPii` enabled.
90
+ */
91
+ function getMutationBodyPayloadForTelemetry(rawBody, plainBody) {
92
+ if (Object.keys(plainBody).length > 0) {
93
+ return plainBody;
94
+ }
95
+ if (Array.isArray(rawBody) && rawBody.length > 0) {
96
+ return rawBody;
97
+ }
98
+ return undefined;
99
+ }
100
+
101
+ /** True when the PostgREST builder carries a mutation body (for `insert(...)`, etc. in span descriptions). */
102
+ function hasMutationBodyForDescription(rawBody, plainBody) {
103
+ return getMutationBodyPayloadForTelemetry(rawBody, plainBody) !== undefined;
104
+ }
105
+
86
106
  /**
87
107
  * Extracts the database operation type from the HTTP method and headers
88
108
  * @param method - The HTTP method of the request
@@ -296,12 +316,19 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder) {
296
316
  }
297
317
  }
298
318
 
319
+ const sendDefaultPii = Boolean(getClient()?.getOptions().sendDefaultPii);
320
+ const bodyPayload = getMutationBodyPayloadForTelemetry(typedThis.body, body);
321
+
299
322
  // Adding operation to the beginning of the description if it's not a `select` operation
300
323
  // For example, it can be an `insert` or `update` operation but the query can be `select(...)`
301
324
  // For `select` operations, we don't need repeat it in the description
302
- const description = `${operation === 'select' ? '' : `${operation}${body ? '(...) ' : ''}`}${queryItems.join(
303
- ' ',
304
- )} from(${table})`;
325
+ const mutationPart =
326
+ operation === 'select'
327
+ ? ''
328
+ : `${operation}${hasMutationBodyForDescription(typedThis.body, body) ? '(...) ' : ''}`;
329
+ const queryPart = sendDefaultPii ? queryItems.join(' ') : queryItems.length > 0 ? '[redacted]' : '';
330
+ const descriptionMiddle = [mutationPart.trimEnd(), queryPart].filter(Boolean).join(' ');
331
+ const description = descriptionMiddle ? `${descriptionMiddle} from(${table})` : `from(${table})`;
305
332
 
306
333
  const attributes = {
307
334
  'db.table': table,
@@ -314,12 +341,12 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder) {
314
341
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db',
315
342
  };
316
343
 
317
- if (queryItems.length) {
344
+ if (queryItems.length && sendDefaultPii) {
318
345
  attributes['db.query'] = queryItems;
319
346
  }
320
347
 
321
- if (Object.keys(body).length) {
322
- attributes['db.body'] = body;
348
+ if (bodyPayload !== undefined && sendDefaultPii) {
349
+ attributes['db.body'] = bodyPayload;
323
350
  }
324
351
 
325
352
  return startSpan(
@@ -348,11 +375,11 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder) {
348
375
  }
349
376
 
350
377
  const supabaseContext = {};
351
- if (queryItems.length) {
378
+ if (queryItems.length && sendDefaultPii) {
352
379
  supabaseContext.query = queryItems;
353
380
  }
354
- if (Object.keys(body).length) {
355
- supabaseContext.body = body;
381
+ if (bodyPayload !== undefined && sendDefaultPii) {
382
+ supabaseContext.body = bodyPayload;
356
383
  }
357
384
 
358
385
  captureException(err, scope => {
@@ -379,12 +406,12 @@ function instrumentPostgRESTFilterBuilder(PostgRESTFilterBuilder) {
379
406
 
380
407
  const data = {};
381
408
 
382
- if (queryItems.length) {
409
+ if (queryItems.length && sendDefaultPii) {
383
410
  data.query = queryItems;
384
411
  }
385
412
 
386
- if (Object.keys(body).length) {
387
- data.body = body;
413
+ if (bodyPayload !== undefined && sendDefaultPii) {
414
+ data.body = bodyPayload;
388
415
  }
389
416
 
390
417
  if (Object.keys(data).length) {