@sentry/profiling-node 8.9.2 → 8.10.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 (153) hide show
  1. package/bindings/cpu_profiler.cc +2 -2
  2. package/lib/cjs/index.js +743 -33
  3. package/lib/cjs/index.js.map +1 -1
  4. package/lib/esm/index.js +744 -34
  5. package/lib/esm/index.js.map +1 -1
  6. package/lib/sentry_cpu_profiler-darwin-arm64-108.node +0 -0
  7. package/lib/sentry_cpu_profiler-darwin-arm64-115.node +0 -0
  8. package/lib/sentry_cpu_profiler-darwin-arm64-127.node +0 -0
  9. package/lib/sentry_cpu_profiler-darwin-arm64-93.node +0 -0
  10. package/lib/sentry_cpu_profiler-darwin-x64-108.node +0 -0
  11. package/lib/sentry_cpu_profiler-darwin-x64-115.node +0 -0
  12. package/lib/sentry_cpu_profiler-darwin-x64-127.node +0 -0
  13. package/lib/sentry_cpu_profiler-darwin-x64-93.node +0 -0
  14. package/lib/sentry_cpu_profiler-linux-arm64-glibc-108.node +0 -0
  15. package/lib/sentry_cpu_profiler-linux-arm64-glibc-115.node +0 -0
  16. package/lib/sentry_cpu_profiler-linux-arm64-glibc-127.node +0 -0
  17. package/lib/sentry_cpu_profiler-linux-arm64-glibc-93.node +0 -0
  18. package/lib/sentry_cpu_profiler-linux-arm64-musl-108.node +0 -0
  19. package/lib/sentry_cpu_profiler-linux-arm64-musl-115.node +0 -0
  20. package/lib/sentry_cpu_profiler-linux-arm64-musl-127.node +0 -0
  21. package/lib/sentry_cpu_profiler-linux-arm64-musl-93.node +0 -0
  22. package/lib/sentry_cpu_profiler-linux-x64-glibc-108.node +0 -0
  23. package/lib/sentry_cpu_profiler-linux-x64-glibc-115.node +0 -0
  24. package/lib/sentry_cpu_profiler-linux-x64-glibc-127.node +0 -0
  25. package/lib/sentry_cpu_profiler-linux-x64-glibc-93.node +0 -0
  26. package/lib/sentry_cpu_profiler-linux-x64-musl-108.node +0 -0
  27. package/lib/sentry_cpu_profiler-linux-x64-musl-115.node +0 -0
  28. package/lib/sentry_cpu_profiler-linux-x64-musl-127.node +0 -0
  29. package/lib/sentry_cpu_profiler-linux-x64-musl-93.node +0 -0
  30. package/lib/sentry_cpu_profiler-win32-x64-108.node +0 -0
  31. package/lib/sentry_cpu_profiler-win32-x64-115.node +0 -0
  32. package/lib/sentry_cpu_profiler-win32-x64-127.node +0 -0
  33. package/lib/sentry_cpu_profiler-win32-x64-93.node +0 -0
  34. package/lib/types/core/src/asyncContext/index.d.ts +14 -0
  35. package/lib/types/core/src/asyncContext/index.d.ts.map +1 -0
  36. package/lib/types/core/src/asyncContext/stackStrategy.d.ts +52 -0
  37. package/lib/types/core/src/asyncContext/stackStrategy.d.ts.map +1 -0
  38. package/lib/types/core/src/asyncContext/types.d.ts +47 -0
  39. package/lib/types/core/src/asyncContext/types.d.ts.map +1 -0
  40. package/lib/types/core/src/carrier.d.ts +37 -0
  41. package/lib/types/core/src/carrier.d.ts.map +1 -0
  42. package/lib/types/core/src/constants.d.ts +2 -0
  43. package/lib/types/core/src/constants.d.ts.map +1 -0
  44. package/lib/types/core/src/currentScopes.d.ts +55 -0
  45. package/lib/types/core/src/currentScopes.d.ts.map +1 -0
  46. package/lib/types/core/src/debug-build.d.ts.map +1 -0
  47. package/lib/types/core/src/defaultScopes.d.ts +6 -0
  48. package/lib/types/core/src/defaultScopes.d.ts.map +1 -0
  49. package/lib/types/core/src/envelope.d.ts +15 -0
  50. package/lib/types/core/src/envelope.d.ts.map +1 -0
  51. package/lib/types/core/src/metrics/constants.d.ts +19 -0
  52. package/lib/types/core/src/metrics/constants.d.ts.map +1 -0
  53. package/lib/types/core/src/metrics/metric-summary.d.ts +13 -0
  54. package/lib/types/core/src/metrics/metric-summary.d.ts.map +1 -0
  55. package/lib/types/core/src/metrics/types.d.ts +5 -0
  56. package/lib/types/core/src/metrics/types.d.ts.map +1 -0
  57. package/lib/types/core/src/scope.d.ts +211 -0
  58. package/lib/types/core/src/scope.d.ts.map +1 -0
  59. package/lib/types/core/src/semanticAttributes.d.ts +33 -0
  60. package/lib/types/core/src/semanticAttributes.d.ts.map +1 -0
  61. package/lib/types/core/src/session.d.ts +35 -0
  62. package/lib/types/core/src/session.d.ts.map +1 -0
  63. package/lib/types/core/src/tracing/dynamicSamplingContext.d.ts +24 -0
  64. package/lib/types/core/src/tracing/dynamicSamplingContext.d.ts.map +1 -0
  65. package/lib/types/core/src/tracing/logSpans.d.ts +10 -0
  66. package/lib/types/core/src/tracing/logSpans.d.ts.map +1 -0
  67. package/lib/types/core/src/tracing/measurement.d.ts +10 -0
  68. package/lib/types/core/src/tracing/measurement.d.ts.map +1 -0
  69. package/lib/types/core/src/tracing/sampling.d.ts +9 -0
  70. package/lib/types/core/src/tracing/sampling.d.ts.map +1 -0
  71. package/lib/types/core/src/tracing/sentryNonRecordingSpan.d.ts +26 -0
  72. package/lib/types/core/src/tracing/sentryNonRecordingSpan.d.ts.map +1 -0
  73. package/lib/types/core/src/tracing/sentrySpan.d.ts +86 -0
  74. package/lib/types/core/src/tracing/sentrySpan.d.ts.map +1 -0
  75. package/lib/types/core/src/tracing/spanstatus.d.ts +17 -0
  76. package/lib/types/core/src/tracing/spanstatus.d.ts.map +1 -0
  77. package/lib/types/core/src/tracing/trace.d.ts +76 -0
  78. package/lib/types/core/src/tracing/trace.d.ts.map +1 -0
  79. package/lib/types/core/src/tracing/utils.d.ts +13 -0
  80. package/lib/types/core/src/tracing/utils.d.ts.map +1 -0
  81. package/lib/types/core/src/utils/handleCallbackErrors.d.ts +13 -0
  82. package/lib/types/core/src/utils/handleCallbackErrors.d.ts.map +1 -0
  83. package/lib/types/core/src/utils/hasTracingEnabled.d.ts +8 -0
  84. package/lib/types/core/src/utils/hasTracingEnabled.d.ts.map +1 -0
  85. package/lib/types/core/src/utils/parseSampleRate.d.ts +9 -0
  86. package/lib/types/core/src/utils/parseSampleRate.d.ts.map +1 -0
  87. package/lib/types/core/src/utils/spanOnScope.d.ts +17 -0
  88. package/lib/types/core/src/utils/spanOnScope.d.ts.map +1 -0
  89. package/lib/types/core/src/utils/spanUtils.d.ts +74 -0
  90. package/lib/types/core/src/utils/spanUtils.d.ts.map +1 -0
  91. package/lib/types/profiling-node/src/cpu_profiler.d.ts.map +1 -0
  92. package/lib/types/profiling-node/src/debug-build.d.ts +7 -0
  93. package/lib/types/profiling-node/src/debug-build.d.ts.map +1 -0
  94. package/lib/types/profiling-node/src/index.d.ts.map +1 -0
  95. package/lib/types/{integration.d.ts → profiling-node/src/integration.d.ts} +18 -0
  96. package/lib/types/profiling-node/src/integration.d.ts.map +1 -0
  97. package/lib/types/profiling-node/src/nodeVersion.d.ts.map +1 -0
  98. package/lib/types/profiling-node/src/spanProfileUtils.d.ts.map +1 -0
  99. package/lib/types/profiling-node/src/types.d.ts.map +1 -0
  100. package/lib/types/{utils.d.ts → profiling-node/src/utils.d.ts} +3 -1
  101. package/lib/types/profiling-node/src/utils.d.ts.map +1 -0
  102. package/lib/types-ts3.8/core/src/asyncContext/index.d.ts +14 -0
  103. package/lib/types-ts3.8/core/src/asyncContext/stackStrategy.d.ts +52 -0
  104. package/lib/types-ts3.8/core/src/asyncContext/types.d.ts +47 -0
  105. package/lib/types-ts3.8/core/src/carrier.d.ts +37 -0
  106. package/lib/types-ts3.8/core/src/constants.d.ts +2 -0
  107. package/lib/types-ts3.8/core/src/currentScopes.d.ts +55 -0
  108. package/lib/types-ts3.8/core/src/defaultScopes.d.ts +6 -0
  109. package/lib/types-ts3.8/core/src/envelope.d.ts +18 -0
  110. package/lib/types-ts3.8/core/src/metrics/constants.d.ts +19 -0
  111. package/lib/types-ts3.8/core/src/metrics/metric-summary.d.ts +13 -0
  112. package/lib/types-ts3.8/core/src/metrics/types.d.ts +5 -0
  113. package/lib/types-ts3.8/core/src/scope.d.ts +211 -0
  114. package/lib/types-ts3.8/core/src/semanticAttributes.d.ts +33 -0
  115. package/lib/types-ts3.8/core/src/session.d.ts +35 -0
  116. package/lib/types-ts3.8/core/src/tracing/dynamicSamplingContext.d.ts +24 -0
  117. package/lib/types-ts3.8/core/src/tracing/logSpans.d.ts +10 -0
  118. package/lib/types-ts3.8/core/src/tracing/measurement.d.ts +10 -0
  119. package/lib/types-ts3.8/core/src/tracing/sampling.d.ts +12 -0
  120. package/lib/types-ts3.8/core/src/tracing/sentryNonRecordingSpan.d.ts +26 -0
  121. package/lib/types-ts3.8/core/src/tracing/sentrySpan.d.ts +86 -0
  122. package/lib/types-ts3.8/core/src/tracing/spanstatus.d.ts +17 -0
  123. package/lib/types-ts3.8/core/src/tracing/trace.d.ts +76 -0
  124. package/lib/types-ts3.8/core/src/tracing/utils.d.ts +13 -0
  125. package/lib/types-ts3.8/core/src/utils/handleCallbackErrors.d.ts +13 -0
  126. package/lib/types-ts3.8/core/src/utils/hasTracingEnabled.d.ts +8 -0
  127. package/lib/types-ts3.8/core/src/utils/parseSampleRate.d.ts +9 -0
  128. package/lib/types-ts3.8/core/src/utils/spanOnScope.d.ts +17 -0
  129. package/lib/types-ts3.8/core/src/utils/spanUtils.d.ts +74 -0
  130. package/lib/types-ts3.8/profiling-node/src/debug-build.d.ts +7 -0
  131. package/lib/types-ts3.8/{integration.d.ts → profiling-node/src/integration.d.ts} +18 -0
  132. package/lib/types-ts3.8/{utils.d.ts → profiling-node/src/utils.d.ts} +3 -1
  133. package/package.json +5 -5
  134. package/lib/types/cpu_profiler.d.ts.map +0 -1
  135. package/lib/types/debug-build.d.ts.map +0 -1
  136. package/lib/types/index.d.ts.map +0 -1
  137. package/lib/types/integration.d.ts.map +0 -1
  138. package/lib/types/nodeVersion.d.ts.map +0 -1
  139. package/lib/types/spanProfileUtils.d.ts.map +0 -1
  140. package/lib/types/types.d.ts.map +0 -1
  141. package/lib/types/utils.d.ts.map +0 -1
  142. /package/lib/types/{debug-build.d.ts → core/src/debug-build.d.ts} +0 -0
  143. /package/lib/types/{cpu_profiler.d.ts → profiling-node/src/cpu_profiler.d.ts} +0 -0
  144. /package/lib/types/{index.d.ts → profiling-node/src/index.d.ts} +0 -0
  145. /package/lib/types/{nodeVersion.d.ts → profiling-node/src/nodeVersion.d.ts} +0 -0
  146. /package/lib/types/{spanProfileUtils.d.ts → profiling-node/src/spanProfileUtils.d.ts} +0 -0
  147. /package/lib/types/{types.d.ts → profiling-node/src/types.d.ts} +0 -0
  148. /package/lib/types-ts3.8/{debug-build.d.ts → core/src/debug-build.d.ts} +0 -0
  149. /package/lib/types-ts3.8/{cpu_profiler.d.ts → profiling-node/src/cpu_profiler.d.ts} +0 -0
  150. /package/lib/types-ts3.8/{index.d.ts → profiling-node/src/index.d.ts} +0 -0
  151. /package/lib/types-ts3.8/{nodeVersion.d.ts → profiling-node/src/nodeVersion.d.ts} +0 -0
  152. /package/lib/types-ts3.8/{spanProfileUtils.d.ts → profiling-node/src/spanProfileUtils.d.ts} +0 -0
  153. /package/lib/types-ts3.8/{types.d.ts → profiling-node/src/types.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/debug-build.ts","../../src/cpu_profiler.ts","../../src/nodeVersion.ts","../../src/utils.ts","../../src/spanProfileUtils.ts","../../src/types.ts","../../src/integration.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n","import { arch as _arch, platform as _platform } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { env, versions } from 'node:process';\nimport { threadId } from 'node:worker_threads';\nimport { familySync } from 'detect-libc';\nimport { getAbi } from 'node-abi';\n\nimport { GLOBAL_OBJ, logger } from '@sentry/utils';\nimport { DEBUG_BUILD } from './debug-build';\nimport type {\n PrivateV8CpuProfilerBindings,\n RawChunkCpuProfile,\n RawThreadCpuProfile,\n V8CpuProfilerBindings,\n} from './types';\nimport type { ProfileFormat } from './types';\n\nconst stdlib = familySync();\nconst platform = process.env['BUILD_PLATFORM'] || _platform();\nconst arch = process.env['BUILD_ARCH'] || _arch();\nconst abi = getAbi(versions.node, 'node');\nconst identifier = [platform, arch, stdlib, abi].filter(c => c !== undefined && c !== null).join('-');\n\nconst built_from_source_path = resolve(__dirname, '..', `./sentry_cpu_profiler-${identifier}`);\n\n/**\n * Imports cpp bindings based on the current platform and architecture.\n */\n// eslint-disable-next-line complexity\nexport function importCppBindingsModule(): PrivateV8CpuProfilerBindings {\n // If a binary path is specified, use that.\n if (env['SENTRY_PROFILER_BINARY_PATH']) {\n const envPath = env['SENTRY_PROFILER_BINARY_PATH'];\n return require(envPath);\n }\n\n // If a user specifies a different binary dir, they are in control of the binaries being moved there\n if (env['SENTRY_PROFILER_BINARY_DIR']) {\n const binaryPath = join(resolve(env['SENTRY_PROFILER_BINARY_DIR']), `sentry_cpu_profiler-${identifier}`);\n return require(`${binaryPath}.node`);\n }\n\n // We need the fallthrough so that in the end, we can fallback to the require dynamice require.\n // This is for cases where precompiled binaries were not provided, but may have been compiled from source.\n if (platform === 'darwin') {\n if (arch === 'x64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-darwin-x64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-darwin-x64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-darwin-x64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-darwin-x64-127.node');\n }\n }\n\n if (arch === 'arm64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-darwin-arm64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-darwin-arm64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-darwin-arm64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-darwin-arm64-127.node');\n }\n }\n }\n\n if (platform === 'win32') {\n if (arch === 'x64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-win32-x64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-win32-x64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-win32-x64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-win32-x64-127.node');\n }\n }\n }\n\n if (platform === 'linux') {\n if (arch === 'x64') {\n if (stdlib === 'musl') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-x64-musl-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-x64-musl-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-x64-musl-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-x64-musl-127.node');\n }\n }\n if (stdlib === 'glibc') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-127.node');\n }\n }\n }\n if (arch === 'arm64') {\n if (stdlib === 'musl') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-127.node');\n }\n }\n if (stdlib === 'glibc') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-127.node');\n }\n }\n }\n }\n return require(`${built_from_source_path}.node`);\n}\n\nconst PrivateCpuProfilerBindings: PrivateV8CpuProfilerBindings = importCppBindingsModule();\n\nclass Bindings implements V8CpuProfilerBindings {\n public startProfiling(name: string): void {\n if (!PrivateCpuProfilerBindings) {\n DEBUG_BUILD && logger.log('[Profiling] Bindings not loaded, ignoring call to startProfiling.');\n return;\n }\n\n return PrivateCpuProfilerBindings.startProfiling(name);\n }\n\n public stopProfiling(name: string, format: ProfileFormat.THREAD): RawThreadCpuProfile | null;\n public stopProfiling(name: string, format: ProfileFormat.CHUNK): RawChunkCpuProfile | null;\n public stopProfiling(\n name: string,\n format: ProfileFormat.CHUNK | ProfileFormat.THREAD,\n ): RawThreadCpuProfile | RawChunkCpuProfile | null {\n if (!PrivateCpuProfilerBindings) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Bindings not loaded or profile was never started, ignoring call to stopProfiling.');\n return null;\n }\n\n return PrivateCpuProfilerBindings.stopProfiling(\n name,\n format as unknown as any,\n threadId,\n !!GLOBAL_OBJ._sentryDebugIds,\n );\n }\n}\n\nconst CpuProfilerBindings = new Bindings();\n\nexport { PrivateCpuProfilerBindings };\nexport { CpuProfilerBindings };\n","import { parseSemver } from '@sentry/utils';\n\nexport const NODE_VERSION = parseSemver(process.versions.node) as { major: number; minor: number; patch: number };\nexport const NODE_MAJOR = NODE_VERSION.major;\n","/* eslint-disable max-lines */\nimport * as os from 'os';\nimport type {\n Client,\n Context,\n ContinuousThreadCpuProfile,\n DebugImage,\n DsnComponents,\n Envelope,\n Event,\n EventEnvelopeHeaders,\n Profile,\n ProfileChunk,\n ProfileChunkEnvelope,\n ProfileChunkItem,\n SdkInfo,\n StackFrame,\n StackParser,\n ThreadCpuProfile,\n} from '@sentry/types';\nimport { GLOBAL_OBJ, createEnvelope, dsnToString, forEachEnvelopeItem, logger, uuid4 } from '@sentry/utils';\n\nimport { env, versions } from 'process';\nimport { isMainThread, threadId } from 'worker_threads';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport type { RawChunkCpuProfile, RawThreadCpuProfile } from './types';\n\n// We require the file because if we import it, it will be included in the bundle.\n// I guess tsc does not check file contents when it's imported.\nconst THREAD_ID_STRING = String(threadId);\nconst THREAD_NAME = isMainThread ? 'main' : 'worker';\nconst FORMAT_VERSION = '1';\nconst CONTINUOUS_FORMAT_VERSION = '2';\n\n// Os machine was backported to 16.18, but this was not reflected in the types\n// @ts-expect-error ignore missing\nconst machine = typeof os.machine === 'function' ? os.machine() : os.arch();\n\n// Machine properties (eval only once)\nconst PLATFORM = os.platform();\nconst RELEASE = os.release();\nconst VERSION = os.version();\nconst TYPE = os.type();\nconst MODEL = machine;\nconst ARCH = os.arch();\n\n/**\n * Checks if the profile is a raw profile or a profile enriched with thread information.\n * @param {ThreadCpuProfile | RawThreadCpuProfile} profile\n * @returns {boolean}\n */\nfunction isRawThreadCpuProfile(\n profile: ThreadCpuProfile | RawThreadCpuProfile | ContinuousThreadCpuProfile | RawChunkCpuProfile,\n): profile is RawThreadCpuProfile | RawChunkCpuProfile {\n return !('thread_metadata' in profile);\n}\n\n/**\n * Enriches the profile with threadId of the current thread.\n * This is done in node as we seem to not be able to get the info from C native code.\n *\n * @param {ThreadCpuProfile | RawThreadCpuProfile} profile\n * @returns {ThreadCpuProfile}\n */\nexport function enrichWithThreadInformation(\n profile: ThreadCpuProfile | RawThreadCpuProfile | ContinuousThreadCpuProfile | RawChunkCpuProfile,\n): ThreadCpuProfile | ContinuousThreadCpuProfile {\n if (!isRawThreadCpuProfile(profile)) {\n return profile;\n }\n\n return {\n samples: profile.samples,\n frames: profile.frames,\n stacks: profile.stacks,\n thread_metadata: {\n [THREAD_ID_STRING]: {\n name: THREAD_NAME,\n },\n },\n } as ThreadCpuProfile | ContinuousThreadCpuProfile;\n}\n\n/**\n * Creates a profiling envelope item, if the profile does not pass validation, returns null.\n * @param {RawThreadCpuProfile}\n * @param {Event}\n * @returns {Profile | null}\n */\nexport function createProfilingEvent(client: Client, profile: RawThreadCpuProfile, event: Event): Profile | null {\n if (!isValidProfile(profile)) {\n return null;\n }\n\n return createProfilePayload(client, profile, {\n release: event.release ?? '',\n environment: event.environment ?? '',\n event_id: event.event_id ?? '',\n transaction: event.transaction ?? '',\n start_timestamp: event.start_timestamp ? event.start_timestamp * 1000 : Date.now(),\n trace_id: event.contexts?.['trace']?.['trace_id'] ?? '',\n profile_id: profile.profile_id,\n });\n}\n\n/**\n * Create a profile\n * @param {RawThreadCpuProfile} cpuProfile\n * @param {options}\n * @returns {Profile}\n */\nfunction createProfilePayload(\n client: Client,\n cpuProfile: RawThreadCpuProfile,\n {\n release,\n environment,\n event_id,\n transaction,\n start_timestamp,\n trace_id,\n profile_id,\n }: {\n release: string;\n environment: string;\n event_id: string;\n transaction: string;\n start_timestamp: number;\n trace_id: string | undefined;\n profile_id: string;\n },\n): Profile {\n // Log a warning if the profile has an invalid traceId (should be uuidv4).\n // All profiles and transactions are rejected if this is the case and we want to\n // warn users that this is happening if they enable debug flag\n if (trace_id && trace_id.length !== 32) {\n DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);\n }\n\n const enrichedThreadProfile = enrichWithThreadInformation(cpuProfile);\n\n const profile: Profile = {\n event_id: profile_id,\n timestamp: new Date(start_timestamp).toISOString(),\n platform: 'node',\n version: FORMAT_VERSION,\n release: release,\n environment: environment,\n measurements: cpuProfile.measurements,\n runtime: {\n name: 'node',\n version: versions.node || '',\n },\n os: {\n name: PLATFORM,\n version: RELEASE,\n build_number: VERSION,\n },\n device: {\n locale: env['LC_ALL'] || env['LC_MESSAGES'] || env['LANG'] || env['LANGUAGE'] || '',\n model: MODEL,\n manufacturer: TYPE,\n architecture: ARCH,\n is_emulator: false,\n },\n debug_meta: {\n images: applyDebugMetadata(client, cpuProfile.resources),\n },\n profile: enrichedThreadProfile as ThreadCpuProfile,\n transaction: {\n name: transaction,\n id: event_id,\n trace_id: trace_id || '',\n active_thread_id: THREAD_ID_STRING,\n },\n };\n\n return profile;\n}\n\n/**\n * Create a profile chunk from raw thread profile\n * @param {RawThreadCpuProfile} cpuProfile\n * @param {options}\n * @returns {Profile}\n */\nfunction createProfileChunkPayload(\n client: Client,\n cpuProfile: RawChunkCpuProfile,\n {\n release,\n environment,\n start_timestamp,\n trace_id,\n profiler_id,\n chunk_id,\n }: {\n release: string;\n environment: string;\n start_timestamp: number;\n trace_id: string | undefined;\n chunk_id: string;\n profiler_id: string;\n },\n): ProfileChunk {\n // Log a warning if the profile has an invalid traceId (should be uuidv4).\n // All profiles and transactions are rejected if this is the case and we want to\n // warn users that this is happening if they enable debug flag\n if (trace_id && trace_id.length !== 32) {\n DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);\n }\n\n const enrichedThreadProfile = enrichWithThreadInformation(cpuProfile);\n\n const profile: ProfileChunk = {\n chunk_id: chunk_id,\n profiler_id: profiler_id,\n timestamp: new Date(start_timestamp).toISOString(),\n platform: 'node',\n version: CONTINUOUS_FORMAT_VERSION,\n release: release,\n environment: environment,\n measurements: cpuProfile.measurements,\n debug_meta: {\n images: applyDebugMetadata(client, cpuProfile.resources),\n },\n profile: enrichedThreadProfile as ContinuousThreadCpuProfile,\n };\n\n return profile;\n}\n\n/**\n * Creates a profiling chunk envelope item, if the profile does not pass validation, returns null.\n */\nexport function createProfilingChunkEvent(\n start_timestamp: number,\n client: Client,\n options: { release?: string; environment?: string },\n profile: RawChunkCpuProfile,\n identifiers: { trace_id: string | undefined; chunk_id: string; profiler_id: string },\n): ProfileChunk | null {\n if (!isValidProfileChunk(profile)) {\n return null;\n }\n\n return createProfileChunkPayload(client, profile, {\n release: options.release ?? '',\n environment: options.environment ?? '',\n start_timestamp: start_timestamp,\n trace_id: identifiers.trace_id ?? '',\n chunk_id: identifiers.chunk_id,\n profiler_id: identifiers.profiler_id,\n });\n}\n\n/**\n * Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1).\n * @param {unknown} rate\n * @returns {boolean}\n */\nexport function isValidSampleRate(rate: unknown): boolean {\n // we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck\n if ((typeof rate !== 'number' && typeof rate !== 'boolean') || (typeof rate === 'number' && isNaN(rate))) {\n DEBUG_BUILD &&\n logger.warn(\n `[Profiling] Invalid sample rate. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify(\n rate,\n )} of type ${JSON.stringify(typeof rate)}.`,\n );\n return false;\n }\n\n // Boolean sample rates are always valid\n if (rate === true || rate === false) {\n return true;\n }\n\n // in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false\n if (rate < 0 || rate > 1) {\n DEBUG_BUILD && logger.warn(`[Profiling] Invalid sample rate. Sample rate must be between 0 and 1. Got ${rate}.`);\n return false;\n }\n return true;\n}\n\n/**\n * Checks if the profile is valid and can be sent to Sentry.\n * @param {RawThreadCpuProfile} profile\n * @returns {boolean}\n */\nexport function isValidProfile(profile: RawThreadCpuProfile): profile is RawThreadCpuProfile & { profile_id: string } {\n if (profile.samples.length <= 1) {\n DEBUG_BUILD &&\n // Log a warning if the profile has less than 2 samples so users can know why\n // they are not seeing any profiling data and we cant avoid the back and forth\n // of asking them to provide us with a dump of the profile data.\n logger.log('[Profiling] Discarding profile because it contains less than 2 samples');\n return false;\n }\n\n if (!profile.profile_id) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Checks if the profile chunk is valid and can be sent to Sentry.\n * @param profile\n * @returns\n */\nexport function isValidProfileChunk(profile: RawChunkCpuProfile): profile is RawChunkCpuProfile {\n if (profile.samples.length <= 1) {\n DEBUG_BUILD &&\n // Log a warning if the profile has less than 2 samples so users can know why\n // they are not seeing any profiling data and we cant avoid the back and forth\n // of asking them to provide us with a dump of the profile data.\n logger.log('[Profiling] Discarding profile chunk because it contains less than 2 samples');\n return false;\n }\n\n return true;\n}\n\n/**\n * Adds items to envelope if they are not already present - mutates the envelope.\n * @param {Envelope} envelope\n * @param {Profile[]} profiles\n * @returns {Envelope}\n */\nexport function addProfilesToEnvelope(envelope: Envelope, profiles: Profile[]): Envelope {\n if (!profiles.length) {\n return envelope;\n }\n\n for (const profile of profiles) {\n // @ts-expect-error untyped envelope\n envelope[1].push([{ type: 'profile' }, profile]);\n }\n return envelope;\n}\n\n/**\n * Finds transactions with profile_id context in the envelope\n * @param {Envelope} envelope\n * @returns {Event[]}\n */\nexport function findProfiledTransactionsFromEnvelope(envelope: Envelope): Event[] {\n const events: Event[] = [];\n\n forEachEnvelopeItem(envelope, (item, type) => {\n if (type !== 'transaction') {\n return;\n }\n\n // First item is the type, so we can skip it, everything else is an event\n for (let j = 1; j < item.length; j++) {\n const event = item[j];\n\n if (!event) {\n // Shouldnt happen, but lets be safe\n continue;\n }\n\n // @ts-expect-error profile_id is not part of the metadata type\n const profile_id = (event.contexts as Context)?.['profile']?.['profile_id'];\n\n if (event && profile_id) {\n events.push(item[j] as Event);\n }\n }\n });\n\n return events;\n}\n\n/**\n * Creates event envelope headers for a profile chunk. This is separate from createEventEnvelopeHeaders util\n * as the profile chunk does not conform to the sentry event type\n */\nexport function createEventEnvelopeHeaders(\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): EventEnvelopeHeaders {\n return {\n event_id: uuid4(),\n sent_at: new Date().toISOString(),\n ...(sdkInfo && { sdk: sdkInfo }),\n ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),\n };\n}\n\n/**\n * Creates a standalone profile_chunk envelope.\n */\nexport function makeProfileChunkEnvelope(\n chunk: ProfileChunk,\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): ProfileChunkEnvelope {\n const profileChunkHeader: ProfileChunkItem[0] = {\n type: 'profile_chunk',\n };\n\n return createEnvelope<ProfileChunkEnvelope>(createEventEnvelopeHeaders(sdkInfo, tunnel, dsn), [\n [profileChunkHeader, chunk],\n ]);\n}\n\nconst debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();\n\n/**\n * Cross reference profile collected resources with debug_ids and return a list of debug images.\n * @param {string[]} resource_paths\n * @returns {DebugImage[]}\n */\nexport function applyDebugMetadata(client: Client, resource_paths: ReadonlyArray<string>): DebugImage[] {\n const debugIdMap = GLOBAL_OBJ._sentryDebugIds;\n if (!debugIdMap) {\n return [];\n }\n\n const options = client.getOptions();\n\n if (!options || !options.stackParser) {\n return [];\n }\n\n let debugIdStackFramesCache: Map<string, StackFrame[]>;\n const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(options.stackParser);\n if (cachedDebugIdStackFrameCache) {\n debugIdStackFramesCache = cachedDebugIdStackFrameCache;\n } else {\n debugIdStackFramesCache = new Map<string, StackFrame[]>();\n debugIdStackParserCache.set(options.stackParser, debugIdStackFramesCache);\n }\n\n // Build a map of filename -> debug_id.\n const filenameDebugIdMap = Object.keys(debugIdMap).reduce<Record<string, string>>((acc, debugIdStackTrace) => {\n let parsedStack: StackFrame[];\n\n const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);\n if (cachedParsedStack) {\n parsedStack = cachedParsedStack;\n } else {\n parsedStack = options.stackParser(debugIdStackTrace);\n debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);\n }\n\n for (let i = parsedStack.length - 1; i >= 0; i--) {\n const stackFrame = parsedStack[i];\n const file = stackFrame && stackFrame.filename;\n\n if (stackFrame && file) {\n acc[file] = debugIdMap[debugIdStackTrace] as string;\n break;\n }\n }\n return acc;\n }, {});\n\n const images: DebugImage[] = [];\n\n for (const resource of resource_paths) {\n if (resource && filenameDebugIdMap[resource]) {\n images.push({\n type: 'sourcemap',\n code_file: resource,\n debug_id: filenameDebugIdMap[resource] as string,\n });\n }\n }\n\n return images;\n}\n","import { spanIsSampled, spanToJSON } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport type { CustomSamplingContext, Span } from '@sentry/types';\nimport { logger, uuid4 } from '@sentry/utils';\n\nimport { CpuProfilerBindings } from './cpu_profiler';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { RawThreadCpuProfile } from './types';\nimport { isValidSampleRate } from './utils';\n\nexport const MAX_PROFILE_DURATION_MS = 30 * 1000;\n\n/**\n * Takes a transaction and determines if it should be profiled or not. If it should be profiled, it returns the\n * profile_id, otherwise returns undefined. Takes care of setting profile context on transaction as well\n */\nexport function maybeProfileSpan(\n client: NodeClient | undefined,\n span: Span,\n customSamplingContext?: CustomSamplingContext,\n): string | undefined {\n // profilesSampleRate is multiplied with tracesSampleRate to get the final sampling rate. We dont perform\n // the actual multiplication to get the final rate, but we discard the profile if the span was sampled,\n // so anything after this block from here is based on the span sampling.\n if (!spanIsSampled(span)) {\n return;\n }\n\n // Client and options are required for profiling\n if (!client) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling disabled, no client found.');\n return;\n }\n\n const options = client.getOptions();\n if (!options) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling disabled, no options found.');\n return;\n }\n\n const profilesSampler = options.profilesSampler;\n let profilesSampleRate: number | boolean | undefined = options.profilesSampleRate;\n\n // Prefer sampler to sample rate if both are provided.\n if (typeof profilesSampler === 'function') {\n const { description: spanName = '<unknown>', data } = spanToJSON(span);\n // We bail out early if that is not the case\n const parentSampled = true;\n\n profilesSampleRate = profilesSampler({\n name: spanName,\n attributes: data,\n transactionContext: {\n name: spanName,\n parentSampled,\n },\n parentSampled,\n ...customSamplingContext,\n });\n }\n\n // Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The\n // only valid values are booleans or numbers between 0 and 1.)\n if (!isValidSampleRate(profilesSampleRate)) {\n DEBUG_BUILD && logger.warn('[Profiling] Discarding profile because of invalid sample rate.');\n return;\n }\n\n // if the function returned 0 (or false), or if `profileSampleRate` is 0, it's a sign the profile should be dropped\n if (!profilesSampleRate) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Discarding profile because ${\n typeof profilesSampler === 'function'\n ? 'profileSampler returned 0 or false'\n : 'a negative sampling decision was inherited or profileSampleRate is set to 0'\n }`,\n );\n return;\n }\n\n // Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is\n // a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false.\n const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate;\n // Check if we should sample this profile\n if (!sampled) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(\n profilesSampleRate,\n )})`,\n );\n return;\n }\n\n const profile_id = uuid4();\n CpuProfilerBindings.startProfiling(profile_id);\n DEBUG_BUILD && logger.log(`[Profiling] started profiling transaction: ${spanToJSON(span).description}`);\n\n // set transaction context - do this regardless if profiling fails down the line\n // so that we can still see the profile_id in the transaction context\n return profile_id;\n}\n\n/**\n * Stops the profiler for profile_id and returns the profile\n * @param transaction\n * @param profile_id\n * @returns\n */\nexport function stopSpanProfile(span: Span, profile_id: string | undefined): RawThreadCpuProfile | null {\n // Should not happen, but satisfy the type checker and be safe regardless.\n if (!profile_id) {\n return null;\n }\n\n const profile = CpuProfilerBindings.stopProfiling(profile_id, 0);\n\n DEBUG_BUILD && logger.log(`[Profiling] stopped profiling of transaction: ${spanToJSON(span).description}`);\n\n // In case of an overlapping span, stopProfiling may return null and silently ignore the overlapping profile.\n if (!profile) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] profiler returned null profile for: ${spanToJSON(span).description}`,\n 'this may indicate an overlapping span or a call to stopProfiling with a profile title that was never started',\n );\n return null;\n }\n\n // Assign profile_id to the profile\n profile.profile_id = profile_id;\n return profile;\n}\n","import type { Event } from '@sentry/types';\n\ninterface Sample {\n stack_id: number;\n thread_id: string;\n elapsed_since_start_ns: string;\n}\n\ninterface ChunkSample {\n stack_id: number;\n thread_id: string;\n timestamp: number;\n}\n\ntype Frame = {\n function: string;\n file: string;\n lineno: number;\n colno: number;\n};\n\ninterface Measurement {\n unit: string;\n values: {\n elapsed_since_start_ns: number;\n value: number;\n }[];\n}\n\n// Profile is marked as optional because it is deleted from the metadata\n// by the integration before the event is processed by other integrations.\nexport interface ProfiledEvent extends Event {\n sdkProcessingMetadata: {\n profile?: RawThreadCpuProfile;\n };\n}\n\ninterface BaseProfile {\n profile_id?: string;\n stacks: number[][];\n frames: Frame[];\n resources: string[];\n profiler_logging_mode: 'eager' | 'lazy';\n measurements: Record<string, Measurement>;\n}\nexport interface RawThreadCpuProfile extends BaseProfile {\n samples: Sample[];\n}\n\nexport interface RawChunkCpuProfile extends BaseProfile {\n samples: ChunkSample[];\n}\n\nexport interface PrivateV8CpuProfilerBindings {\n startProfiling(name: string): void;\n\n stopProfiling(\n name: string,\n format: ProfileFormat.THREAD,\n threadId: number,\n collectResources: boolean,\n ): RawThreadCpuProfile | null;\n stopProfiling(\n name: string,\n format: ProfileFormat.CHUNK,\n threadId: number,\n collectResources: boolean,\n ): RawChunkCpuProfile | null;\n\n // Helper methods exposed for testing\n getFrameModule(abs_path: string): string;\n}\n\nexport enum ProfileFormat {\n THREAD = 0,\n CHUNK = 1,\n}\n\nexport interface V8CpuProfilerBindings {\n startProfiling(name: string): void;\n\n stopProfiling(name: string, format: ProfileFormat.THREAD): RawThreadCpuProfile | null;\n stopProfiling(name: string, format: ProfileFormat.CHUNK): RawChunkCpuProfile | null;\n}\n","import { defineIntegration, getCurrentScope, getIsolationScope, getRootSpan, spanToJSON } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport type { Integration, IntegrationFn, Profile, ProfileChunk, Span } from '@sentry/types';\n\nimport { LRUMap, logger, timestampInSeconds, uuid4 } from '@sentry/utils';\n\nimport { CpuProfilerBindings } from './cpu_profiler';\nimport { DEBUG_BUILD } from './debug-build';\nimport { NODE_MAJOR, NODE_VERSION } from './nodeVersion';\nimport { MAX_PROFILE_DURATION_MS, maybeProfileSpan, stopSpanProfile } from './spanProfileUtils';\nimport type { RawThreadCpuProfile } from './types';\nimport { ProfileFormat } from './types';\n\nimport {\n addProfilesToEnvelope,\n createProfilingChunkEvent,\n createProfilingEvent,\n findProfiledTransactionsFromEnvelope,\n makeProfileChunkEnvelope,\n} from './utils';\n\nconst CHUNK_INTERVAL_MS = 5000;\nconst PROFILE_MAP = new LRUMap<string, RawThreadCpuProfile>(50);\nconst PROFILE_TIMEOUTS: Record<string, NodeJS.Timeout> = {};\n\nfunction addToProfileQueue(profile_id: string, profile: RawThreadCpuProfile): void {\n PROFILE_MAP.set(profile_id, profile);\n}\n\nfunction takeFromProfileQueue(profile_id: string): RawThreadCpuProfile | undefined {\n const profile = PROFILE_MAP.get(profile_id);\n PROFILE_MAP.remove(profile_id);\n return profile;\n}\n\n/**\n * Instruments the client to automatically invoke the profiler on span start and stop events.\n * @param client\n */\nfunction setupAutomatedSpanProfiling(client: NodeClient): void {\n const spanToProfileIdMap = new WeakMap<Span, string>();\n\n client.on('spanStart', span => {\n if (span !== getRootSpan(span)) {\n return;\n }\n\n const profile_id = maybeProfileSpan(client, span);\n\n if (profile_id) {\n const options = client.getOptions();\n // Not intended for external use, hence missing types, but we want to profile a couple of things at Sentry that\n // currently exceed the default timeout set by the SDKs.\n const maxProfileDurationMs =\n (options._experiments && options._experiments['maxProfileDurationMs']) || MAX_PROFILE_DURATION_MS;\n\n if (PROFILE_TIMEOUTS[profile_id]) {\n global.clearTimeout(PROFILE_TIMEOUTS[profile_id]);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete PROFILE_TIMEOUTS[profile_id];\n }\n\n // Enqueue a timeout to prevent profiles from running over max duration.\n const timeout = global.setTimeout(() => {\n DEBUG_BUILD &&\n logger.log('[Profiling] max profile duration elapsed, stopping profiling for:', spanToJSON(span).description);\n\n const profile = stopSpanProfile(span, profile_id);\n if (profile) {\n addToProfileQueue(profile_id, profile);\n }\n }, maxProfileDurationMs);\n\n // Unref timeout so it doesn't keep the process alive.\n timeout.unref();\n\n getCurrentScope().setContext('profile', { profile_id });\n spanToProfileIdMap.set(span, profile_id);\n }\n });\n\n client.on('spanEnd', span => {\n const profile_id = spanToProfileIdMap.get(span);\n\n if (profile_id) {\n if (PROFILE_TIMEOUTS[profile_id]) {\n global.clearTimeout(PROFILE_TIMEOUTS[profile_id]);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete PROFILE_TIMEOUTS[profile_id];\n }\n const profile = stopSpanProfile(span, profile_id);\n\n if (profile) {\n addToProfileQueue(profile_id, profile);\n }\n }\n });\n\n client.on('beforeEnvelope', (envelope): void => {\n // if not profiles are in queue, there is nothing to add to the envelope.\n if (!PROFILE_MAP.size) {\n return;\n }\n\n const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);\n if (!profiledTransactionEvents.length) {\n return;\n }\n\n const profilesToAddToEnvelope: Profile[] = [];\n\n for (const profiledTransaction of profiledTransactionEvents) {\n const profileContext = profiledTransaction.contexts?.['profile'];\n const profile_id = profileContext?.['profile_id'];\n\n if (!profile_id) {\n throw new TypeError('[Profiling] cannot find profile for a transaction without a profile context');\n }\n\n // Remove the profile from the transaction context before sending, relay will take care of the rest.\n if (profileContext) {\n delete profiledTransaction.contexts?.['profile'];\n }\n\n const cpuProfile = takeFromProfileQueue(profile_id);\n if (!cpuProfile) {\n DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);\n continue;\n }\n\n const profile = createProfilingEvent(client, cpuProfile, profiledTransaction);\n if (!profile) return;\n\n profilesToAddToEnvelope.push(profile);\n\n // @ts-expect-error profile does not inherit from Event\n client.emit('preprocessEvent', profile, {\n event_id: profiledTransaction.event_id,\n });\n }\n\n addProfilesToEnvelope(envelope, profilesToAddToEnvelope);\n });\n}\n\ninterface ChunkData {\n id: string;\n timer: NodeJS.Timeout | undefined;\n startTimestampMS: number;\n startTraceID: string;\n}\nclass ContinuousProfiler {\n private _profilerId = uuid4();\n private _client: NodeClient | undefined = undefined;\n private _chunkData: ChunkData | undefined = undefined;\n\n /**\n * Called when the profiler is attached to the client (continuous mode is enabled). If of the profiler\n * methods called before the profiler is initialized will result in a noop action with debug logs.\n * @param client\n */\n public initialize(client: NodeClient): void {\n this._client = client;\n }\n\n /**\n * Recursively schedules chunk profiling to start and stop at a set interval.\n * Once the user calls stop(), the current chunk will be stopped and flushed to Sentry and no new chunks will\n * will be started. To restart continuous mode after calling stop(), the user must call start() again.\n * @returns void\n */\n public start(): void {\n if (!this._client) {\n // The client is not attached to the profiler if the user has not enabled continuous profiling.\n // In this case, calling start() and stop() is a noop action.The reason this exists is because\n // it makes the types easier to work with and avoids users having to do null checks.\n DEBUG_BUILD && logger.log('[Profiling] Profiler was never attached to the client.');\n return;\n }\n if (this._chunkData) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Chunk with chunk_id ${this._chunkData.id} is still running, current chunk will be stopped a new chunk will be started.`,\n );\n this.stop();\n }\n\n const traceId =\n getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;\n this._initializeChunk(traceId);\n this._startChunkProfiling(this._chunkData!);\n }\n\n /**\n * Stops the current chunk and flushes the profile to Sentry.\n * @returns void\n */\n public stop(): void {\n if (this._chunkData?.timer) {\n global.clearTimeout(this._chunkData.timer);\n this._chunkData.timer = undefined;\n DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${this._chunkData.id}`);\n }\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n if (!this._chunkData?.id) {\n DEBUG_BUILD &&\n logger.log(`[Profiling] Failed to collect profile for: ${this._chunkData?.id}, the chunk_id is missing.`);\n return;\n }\n const profile = CpuProfilerBindings.stopProfiling(this._chunkData.id, ProfileFormat.CHUNK);\n if (!profile || !this._chunkData.startTimestampMS) {\n DEBUG_BUILD && logger.log(`[Profiling] _chunkiledStartTraceID to collect profile for: ${this._chunkData.id}`);\n return;\n }\n if (profile) {\n DEBUG_BUILD && logger.log(`[Profiling] Sending profile chunk ${this._chunkData.id}.`);\n }\n\n DEBUG_BUILD && logger.log(`[Profiling] Profile chunk ${this._chunkData.id} sent to Sentry.`);\n const chunk = createProfilingChunkEvent(\n this._chunkData.startTimestampMS,\n this._client,\n this._client.getOptions(),\n profile,\n {\n chunk_id: this._chunkData.id,\n trace_id: this._chunkData.startTraceID,\n profiler_id: this._profilerId,\n },\n );\n\n if (!chunk) {\n DEBUG_BUILD && logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`);\n this._reset();\n return;\n }\n\n this._flush(chunk);\n // Depending on the profile and stack sizes, stopping the profile and converting\n // the format may negatively impact the performance of the application. To avoid\n // blocking for too long, enqueue the next chunk start inside the next macrotask.\n // clear current chunk\n this._reset();\n }\n\n /**\n * Flushes the profile chunk to Sentry.\n * @param chunk\n */\n private _flush(chunk: ProfileChunk): void {\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n\n const transport = this._client.getTransport();\n if (!transport) {\n DEBUG_BUILD && logger.log('[Profiling] No transport available to send profile chunk.');\n return;\n }\n\n const dsn = this._client.getDsn();\n const metadata = this._client.getSdkMetadata();\n const tunnel = this._client.getOptions().tunnel;\n\n const envelope = makeProfileChunkEnvelope(chunk, metadata?.sdk, tunnel, dsn);\n transport.send(envelope).then(null, reason => {\n DEBUG_BUILD && logger.error('Error while sending profile chunk envelope:', reason);\n });\n }\n\n /**\n * Starts the profiler and registers the flush timer for a given chunk.\n * @param chunk\n */\n private _startChunkProfiling(chunk: ChunkData): void {\n CpuProfilerBindings.startProfiling(chunk.id!);\n DEBUG_BUILD && logger.log(`[Profiling] starting profiling chunk: ${chunk.id}`);\n\n chunk.timer = global.setTimeout(() => {\n DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${chunk.id}`);\n this.stop();\n DEBUG_BUILD && logger.log('[Profiling] Starting new profiling chunk.');\n setImmediate(this.start.bind(this));\n }, CHUNK_INTERVAL_MS);\n\n // Unref timeout so it doesn't keep the process alive.\n chunk.timer.unref();\n }\n\n /**\n * Initializes new profile chunk metadata\n */\n private _initializeChunk(traceId: string): void {\n this._chunkData = {\n id: uuid4(),\n startTraceID: traceId,\n startTimestampMS: timestampInSeconds(),\n timer: undefined,\n };\n }\n\n /**\n * Resets the current chunk state.\n */\n private _reset(): void {\n this._chunkData = undefined;\n }\n}\n\nexport interface ProfilingIntegration extends Integration {\n _profiler: ContinuousProfiler;\n}\n\n/** Exported only for tests. */\nexport const _nodeProfilingIntegration = ((): ProfilingIntegration => {\n if (DEBUG_BUILD && ![16, 18, 20, 22].includes(NODE_MAJOR)) {\n logger.warn(\n `[Profiling] You are using a Node.js version that does not have prebuilt binaries (${NODE_VERSION}).`,\n 'The @sentry/profiling-node package only has prebuilt support for the following LTS versions of Node.js: 16, 18, 20, 22.',\n 'To use the @sentry/profiling-node package with this version of Node.js, you will need to compile the native addon from source.',\n 'See: https://github.com/getsentry/sentry-javascript/tree/develop/packages/profiling-node#building-the-package-from-source',\n );\n }\n\n return {\n name: 'ProfilingIntegration',\n _profiler: new ContinuousProfiler(),\n setup(client: NodeClient) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling integration setup.');\n const options = client.getOptions();\n\n const mode =\n (options.profilesSampleRate === undefined || options.profilesSampleRate === 0) && !options.profilesSampler\n ? 'continuous'\n : 'span';\n switch (mode) {\n case 'continuous': {\n DEBUG_BUILD && logger.log('[Profiling] Continuous profiler mode enabled.');\n this._profiler.initialize(client);\n break;\n }\n // Default to span profiling when no mode profiler mode is set\n case 'span':\n case undefined: {\n DEBUG_BUILD && logger.log('[Profiling] Span profiler mode enabled.');\n setupAutomatedSpanProfiling(client);\n break;\n }\n default: {\n DEBUG_BUILD && logger.warn(`[Profiling] Unknown profiler mode: ${mode}, profiler was not initialized`);\n }\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * We need this integration in order to send data to Sentry. We hook into the event processor\n * and inspect each event to see if it is a transaction event and if that transaction event\n * contains a profile on it's metadata. If that is the case, we create a profiling event envelope\n * and delete the profile from the transaction metadata.\n */\nexport const nodeProfilingIntegration = defineIntegration(_nodeProfilingIntegration);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEA;AACA;AACA;;;AAGO;;ACUP;AACA;AACA;AACA;AACA;;AAEA;;AAE4F;;;AAGA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;;;AAMA;;AAEA;;;;AAIA;;;;AAIA;AACA;;;AAGA;AACA;;AAEA;;AC7LrF;AACA;;ACHP;;AA4BA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACE;AACF;AACE;AACF;;AAEA;;AAEA;AACA;;;;AAIO;AACL;AACF;AACE;;AAEA;;AAEA;;AAEE;AACA;AACA;AACE;AACE;;;;AAIR;;AAEA;AACA;;;;;AAKO;;;AAGL;;AAEA;;;;;AAKE;AACA;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACE;;AAEA;AACE;;AAEA;;AAEA;AACA;;AAED;;AAQD;AACF;;AAEA;;AAEE;AACE;AACF;;AAEA;;;AAGE;;AAEA;;AAEA;;AAEA;AACA;;;;AAIA;;AAEE;AACA;;AAEF;AACE;;AAEA;AACA;AACA;;;;;;;AAOA;;AAEA;AACA;;;;;AAKN;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACE;;AAEA;AACE;;AAEA;AACA;;AAEA;AACD;;AAOD;AACF;;AAEA;;AAEE;AACE;AACF;;AAEA;;;AAGE;;;AAGA;AACA;AACA;;AAEA;;;;;;;;AAQJ;;AAEA;AACA;;AAEO;AACL;AACA;AACA;AACA;;AAEF;AACE;;AAEA;;;;;AAKE;;;AAGA;AACJ;AACA;;AAEA;AACA;AACA;AACA;;AAEO;;AAEL;;;;;AAKF;;;AAGE;;AAEF;;;AAGE;;AAEF;AACE;;;AAGA;;AAEF;;AAEA;;AAEA;AACA;;AAEO;;;;AAIP;;AAEM;;AAEJ;;;;AAIA;;;AAGF;;AAEA;;;AAGA;;AAEO;;;;AAIP;;AAEM;;AAEJ;;;AAGF;;AAEA;AACA;;;AAGA;;AAEO;AACL;AACE;AACF;;;AAGF;AACI;AACF;AACA;AACF;;AAEA;;;AAGA;;AAEO;AACL;;AAEA;;AAEI;AACF;;;;AAIE;;;;AAIE;AACF;;;;;AAKA;AACE;AACF;AACF;AACJ;;;AAGA;;AAEA;AACA;;;AAGO;AACL;AACA;AACA;AACF;AACE;AACE;AACA;;AAEA;;AAEJ;;AAEA;AACA;;AAEO;;AAEL;AACA;AACA;AACF;;AAEI;;;AAGF;;AAEF;AACA;;AAEA;;AAEA;AACA;AACA;;;AAGO;AACL;AACA;AACE;AACF;;AAEA;;AAEA;AACE;AACF;;;AAGA;AACA;;;AAGE;AACA;AACF;;AAEF;AACE;AACE;;AAEA;AACA;;;;;AAKA;;AAEA;AACE;AACA;;AAEA;AACE;;AAEF;AACF;AACA;;;AAGF;;AAEA;AACE;;AAEI;AACA;AACA;AACR;AACI;AACF;;;AAGF;;ACrdO;;AAEP;AACA;AACA;;AAEO;AACL;;AAEA;AACF;AACA;AACA;;;AAGI;AACF;;AAEF;;AAEI;AACA;AACF;;AAEA;;AAEE;AACA;AACF;;AAEA;;;AAGF;AACE;;AAEF;;;AAGI;;AAEE;AACA;;;;;;AAMN;AACE;;AAEF;;AAEE;AACE;AACA;AACF;;;;;;AAMM;AACE;AACV;AACA;AACA;;AAES;AACA;;AAEA;AACA;AACA;AACA;;;;AAIA;AACA;;;AAGA;AACA;;;;;;AAMA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;;;;AAMA;;;;AAIA;AACA;;;AAGA;;;;;AAKA;;AC5DiB;AACxB;AACA;AACF;;ACvDA;AACA;AACA;;AAEA;AACE;AACF;;AAEA;AACE;AACA;;AAEF;;AAEA;AACA;;;AAGA;AACE;;;;AAII;AACF;;AAEA;;AAEA;AACE;AACN;;;AAGQ;;AAEF;;;AAGE;AACF;;;AAGA;;;;AAIE;;AAEE;AACF;;;AAGR;AACM;;;AAGA;AACF;AACJ;;;AAGI;;AAEA;AACE;;;AAGE;AACF;AACA;;;AAGE;AACF;AACF;AACJ;;AAEE;;AAEE;AACE;AACF;;AAEA;AACA;AACE;AACF;;AAEA;;;;AAIE;;AAEA;AACE;AACF;;AAEN;AACM;;AAEA;;;AAGA;AACE;AACgG;AACA;;AAEA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;;AAGA;AACA;;AAQA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AAMA;;;;AAIA;AACA;AACA;;AAEA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;;;;;;AAMA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;;;AAIA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;;;;;AAKA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA;;AAEA;AACA;AACA;;AAEA;;AAEA;;;AAGA;;AAEA;AACA;;AAMA;AACA;;;AAGA;;;;;AAKA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;;AAGA;;AAEA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;;;AAGA;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../core/src/session.ts","../../../core/src/utils/spanOnScope.ts","../../../core/src/scope.ts","../../../core/src/currentScopes.ts","../../src/debug-build.ts","../../src/cpu_profiler.ts","../../src/nodeVersion.ts","../../src/utils.ts","../../src/spanProfileUtils.ts","../../src/types.ts","../../src/integration.ts"],"sourcesContent":["import type { SerializedSession, Session, SessionContext, SessionStatus } from '@sentry/types';\nimport { dropUndefinedKeys, timestampInSeconds, uuid4 } from '@sentry/utils';\n/**\n * Creates a new `Session` object by setting certain default parameters. If optional @param context\n * is passed, the passed properties are applied to the session object.\n *\n * @param context (optional) additional properties to be applied to the returned session object\n *\n * @returns a new `Session` object\n */\nexport function makeSession(context?: Omit<SessionContext, 'started' | 'status'>): Session {\n // Both timestamp and started are in seconds since the UNIX epoch.\n const startingTime = timestampInSeconds();\n\n const session: Session = {\n sid: uuid4(),\n init: true,\n timestamp: startingTime,\n started: startingTime,\n duration: 0,\n status: 'ok',\n errors: 0,\n ignoreDuration: false,\n toJSON: () => sessionToJSON(session),\n };\n\n if (context) {\n updateSession(session, context);\n }\n\n return session;\n}\n\n/**\n * Updates a session object with the properties passed in the context.\n *\n * Note that this function mutates the passed object and returns void.\n * (Had to do this instead of returning a new and updated session because closing and sending a session\n * makes an update to the session after it was passed to the sending logic.\n * @see BaseClient.captureSession )\n *\n * @param session the `Session` to update\n * @param context the `SessionContext` holding the properties that should be updated in @param session\n */\n// eslint-disable-next-line complexity\nexport function updateSession(session: Session, context: SessionContext = {}): void {\n if (context.user) {\n if (!session.ipAddress && context.user.ip_address) {\n session.ipAddress = context.user.ip_address;\n }\n\n if (!session.did && !context.did) {\n session.did = context.user.id || context.user.email || context.user.username;\n }\n }\n\n session.timestamp = context.timestamp || timestampInSeconds();\n\n if (context.abnormal_mechanism) {\n session.abnormal_mechanism = context.abnormal_mechanism;\n }\n\n if (context.ignoreDuration) {\n session.ignoreDuration = context.ignoreDuration;\n }\n if (context.sid) {\n // Good enough uuid validation. — Kamil\n session.sid = context.sid.length === 32 ? context.sid : uuid4();\n }\n if (context.init !== undefined) {\n session.init = context.init;\n }\n if (!session.did && context.did) {\n session.did = `${context.did}`;\n }\n if (typeof context.started === 'number') {\n session.started = context.started;\n }\n if (session.ignoreDuration) {\n session.duration = undefined;\n } else if (typeof context.duration === 'number') {\n session.duration = context.duration;\n } else {\n const duration = session.timestamp - session.started;\n session.duration = duration >= 0 ? duration : 0;\n }\n if (context.release) {\n session.release = context.release;\n }\n if (context.environment) {\n session.environment = context.environment;\n }\n if (!session.ipAddress && context.ipAddress) {\n session.ipAddress = context.ipAddress;\n }\n if (!session.userAgent && context.userAgent) {\n session.userAgent = context.userAgent;\n }\n if (typeof context.errors === 'number') {\n session.errors = context.errors;\n }\n if (context.status) {\n session.status = context.status;\n }\n}\n\n/**\n * Closes a session by setting its status and updating the session object with it.\n * Internally calls `updateSession` to update the passed session object.\n *\n * Note that this function mutates the passed session (@see updateSession for explanation).\n *\n * @param session the `Session` object to be closed\n * @param status the `SessionStatus` with which the session was closed. If you don't pass a status,\n * this function will keep the previously set status, unless it was `'ok'` in which case\n * it is changed to `'exited'`.\n */\nexport function closeSession(session: Session, status?: Exclude<SessionStatus, 'ok'>): void {\n let context = {};\n if (status) {\n context = { status };\n } else if (session.status === 'ok') {\n context = { status: 'exited' };\n }\n\n updateSession(session, context);\n}\n\n/**\n * Serializes a passed session object to a JSON object with a slightly different structure.\n * This is necessary because the Sentry backend requires a slightly different schema of a session\n * than the one the JS SDKs use internally.\n *\n * @param session the session to be converted\n *\n * @returns a JSON object of the passed session\n */\nfunction sessionToJSON(session: Session): SerializedSession {\n return dropUndefinedKeys({\n sid: `${session.sid}`,\n init: session.init,\n // Make sure that sec is converted to ms for date constructor\n started: new Date(session.started * 1000).toISOString(),\n timestamp: new Date(session.timestamp * 1000).toISOString(),\n status: session.status,\n errors: session.errors,\n did: typeof session.did === 'number' || typeof session.did === 'string' ? `${session.did}` : undefined,\n duration: session.duration,\n abnormal_mechanism: session.abnormal_mechanism,\n attrs: {\n release: session.release,\n environment: session.environment,\n ip_address: session.ipAddress,\n user_agent: session.userAgent,\n },\n });\n}\n","import type { Scope, Span } from '@sentry/types';\nimport { addNonEnumerableProperty } from '@sentry/utils';\n\nconst SCOPE_SPAN_FIELD = '_sentrySpan';\n\ntype ScopeWithMaybeSpan = Scope & {\n [SCOPE_SPAN_FIELD]?: Span;\n};\n\n/**\n * Set the active span for a given scope.\n * NOTE: This should NOT be used directly, but is only used internally by the trace methods.\n */\nexport function _setSpanForScope(scope: Scope, span: Span | undefined): void {\n if (span) {\n addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);\n } else {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];\n }\n}\n\n/**\n * Get the active span for a given scope.\n * NOTE: This should NOT be used directly, but is only used internally by the trace methods.\n */\nexport function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {\n return scope[SCOPE_SPAN_FIELD];\n}\n","/* eslint-disable max-lines */\nimport type {\n Attachment,\n Breadcrumb,\n CaptureContext,\n Client,\n Context,\n Contexts,\n Event,\n EventHint,\n EventProcessor,\n Extra,\n Extras,\n Primitive,\n PropagationContext,\n RequestSession,\n Scope as ScopeInterface,\n ScopeContext,\n ScopeData,\n Session,\n SeverityLevel,\n User,\n} from '@sentry/types';\nimport { dateTimestampInSeconds, generatePropagationContext, isPlainObject, logger, uuid4 } from '@sentry/utils';\n\nimport { updateSession } from './session';\nimport { _getSpanForScope, _setSpanForScope } from './utils/spanOnScope';\n\n/**\n * Default value for maximum number of breadcrumbs added to an event.\n */\nconst DEFAULT_MAX_BREADCRUMBS = 100;\n\n/**\n * Holds additional event information.\n */\nclass ScopeClass implements ScopeInterface {\n /** Flag if notifying is happening. */\n protected _notifyingListeners: boolean;\n\n /** Callback for client to receive scope changes. */\n protected _scopeListeners: Array<(scope: Scope) => void>;\n\n /** Callback list that will be called during event processing. */\n protected _eventProcessors: EventProcessor[];\n\n /** Array of breadcrumbs. */\n protected _breadcrumbs: Breadcrumb[];\n\n /** User */\n protected _user: User;\n\n /** Tags */\n protected _tags: { [key: string]: Primitive };\n\n /** Extra */\n protected _extra: Extras;\n\n /** Contexts */\n protected _contexts: Contexts;\n\n /** Attachments */\n protected _attachments: Attachment[];\n\n /** Propagation Context for distributed tracing */\n protected _propagationContext: PropagationContext;\n\n /**\n * A place to stash data which is needed at some point in the SDK's event processing pipeline but which shouldn't get\n * sent to Sentry\n */\n protected _sdkProcessingMetadata: { [key: string]: unknown };\n\n /** Fingerprint */\n protected _fingerprint?: string[];\n\n /** Severity */\n protected _level?: SeverityLevel;\n\n /**\n * Transaction Name\n *\n * IMPORTANT: The transaction name on the scope has nothing to do with root spans/transaction objects.\n * It's purpose is to assign a transaction to the scope that's added to non-transaction events.\n */\n protected _transactionName?: string;\n\n /** Session */\n protected _session?: Session;\n\n /** Request Mode Session Status */\n protected _requestSession?: RequestSession;\n\n /** The client on this scope */\n protected _client?: Client;\n\n /** Contains the last event id of a captured event. */\n protected _lastEventId?: string;\n\n // NOTE: Any field which gets added here should get added not only to the constructor but also to the `clone` method.\n\n public constructor() {\n this._notifyingListeners = false;\n this._scopeListeners = [];\n this._eventProcessors = [];\n this._breadcrumbs = [];\n this._attachments = [];\n this._user = {};\n this._tags = {};\n this._extra = {};\n this._contexts = {};\n this._sdkProcessingMetadata = {};\n this._propagationContext = generatePropagationContext();\n }\n\n /**\n * @inheritDoc\n */\n public clone(): ScopeClass {\n const newScope = new ScopeClass();\n newScope._breadcrumbs = [...this._breadcrumbs];\n newScope._tags = { ...this._tags };\n newScope._extra = { ...this._extra };\n newScope._contexts = { ...this._contexts };\n newScope._user = this._user;\n newScope._level = this._level;\n newScope._session = this._session;\n newScope._transactionName = this._transactionName;\n newScope._fingerprint = this._fingerprint;\n newScope._eventProcessors = [...this._eventProcessors];\n newScope._requestSession = this._requestSession;\n newScope._attachments = [...this._attachments];\n newScope._sdkProcessingMetadata = { ...this._sdkProcessingMetadata };\n newScope._propagationContext = { ...this._propagationContext };\n newScope._client = this._client;\n newScope._lastEventId = this._lastEventId;\n\n _setSpanForScope(newScope, _getSpanForScope(this));\n\n return newScope;\n }\n\n /**\n * @inheritDoc\n */\n public setClient(client: Client | undefined): void {\n this._client = client;\n }\n\n /**\n * @inheritDoc\n */\n public setLastEventId(lastEventId: string | undefined): void {\n this._lastEventId = lastEventId;\n }\n\n /**\n * @inheritDoc\n */\n public getClient<C extends Client>(): C | undefined {\n return this._client as C | undefined;\n }\n\n /**\n * @inheritDoc\n */\n public lastEventId(): string | undefined {\n return this._lastEventId;\n }\n\n /**\n * @inheritDoc\n */\n public addScopeListener(callback: (scope: Scope) => void): void {\n this._scopeListeners.push(callback);\n }\n\n /**\n * @inheritDoc\n */\n public addEventProcessor(callback: EventProcessor): this {\n this._eventProcessors.push(callback);\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setUser(user: User | null): this {\n // If null is passed we want to unset everything, but still define keys,\n // so that later down in the pipeline any existing values are cleared.\n this._user = user || {\n email: undefined,\n id: undefined,\n ip_address: undefined,\n username: undefined,\n };\n\n if (this._session) {\n updateSession(this._session, { user });\n }\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public getUser(): User | undefined {\n return this._user;\n }\n\n /**\n * @inheritDoc\n */\n public getRequestSession(): RequestSession | undefined {\n return this._requestSession;\n }\n\n /**\n * @inheritDoc\n */\n public setRequestSession(requestSession?: RequestSession): this {\n this._requestSession = requestSession;\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setTags(tags: { [key: string]: Primitive }): this {\n this._tags = {\n ...this._tags,\n ...tags,\n };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setTag(key: string, value: Primitive): this {\n this._tags = { ...this._tags, [key]: value };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setExtras(extras: Extras): this {\n this._extra = {\n ...this._extra,\n ...extras,\n };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setExtra(key: string, extra: Extra): this {\n this._extra = { ...this._extra, [key]: extra };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setFingerprint(fingerprint: string[]): this {\n this._fingerprint = fingerprint;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setLevel(level: SeverityLevel): this {\n this._level = level;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setTransactionName(name?: string): this {\n this._transactionName = name;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setContext(key: string, context: Context | null): this {\n if (context === null) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete this._contexts[key];\n } else {\n this._contexts[key] = context;\n }\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setSession(session?: Session): this {\n if (!session) {\n delete this._session;\n } else {\n this._session = session;\n }\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public getSession(): Session | undefined {\n return this._session;\n }\n\n /**\n * @inheritDoc\n */\n public update(captureContext?: CaptureContext): this {\n if (!captureContext) {\n return this;\n }\n\n const scopeToMerge = typeof captureContext === 'function' ? captureContext(this) : captureContext;\n\n const [scopeInstance, requestSession] =\n scopeToMerge instanceof Scope\n ? [scopeToMerge.getScopeData(), scopeToMerge.getRequestSession()]\n : isPlainObject(scopeToMerge)\n ? [captureContext as ScopeContext, (captureContext as ScopeContext).requestSession]\n : [];\n\n const { tags, extra, user, contexts, level, fingerprint = [], propagationContext } = scopeInstance || {};\n\n this._tags = { ...this._tags, ...tags };\n this._extra = { ...this._extra, ...extra };\n this._contexts = { ...this._contexts, ...contexts };\n\n if (user && Object.keys(user).length) {\n this._user = user;\n }\n\n if (level) {\n this._level = level;\n }\n\n if (fingerprint.length) {\n this._fingerprint = fingerprint;\n }\n\n if (propagationContext) {\n this._propagationContext = propagationContext;\n }\n\n if (requestSession) {\n this._requestSession = requestSession;\n }\n\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public clear(): this {\n // client is not cleared here on purpose!\n this._breadcrumbs = [];\n this._tags = {};\n this._extra = {};\n this._user = {};\n this._contexts = {};\n this._level = undefined;\n this._transactionName = undefined;\n this._fingerprint = undefined;\n this._requestSession = undefined;\n this._session = undefined;\n _setSpanForScope(this, undefined);\n this._attachments = [];\n this._propagationContext = generatePropagationContext();\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this {\n const maxCrumbs = typeof maxBreadcrumbs === 'number' ? maxBreadcrumbs : DEFAULT_MAX_BREADCRUMBS;\n\n // No data has been changed, so don't notify scope listeners\n if (maxCrumbs <= 0) {\n return this;\n }\n\n const mergedBreadcrumb = {\n timestamp: dateTimestampInSeconds(),\n ...breadcrumb,\n };\n\n const breadcrumbs = this._breadcrumbs;\n breadcrumbs.push(mergedBreadcrumb);\n this._breadcrumbs = breadcrumbs.length > maxCrumbs ? breadcrumbs.slice(-maxCrumbs) : breadcrumbs;\n\n this._notifyScopeListeners();\n\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public getLastBreadcrumb(): Breadcrumb | undefined {\n return this._breadcrumbs[this._breadcrumbs.length - 1];\n }\n\n /**\n * @inheritDoc\n */\n public clearBreadcrumbs(): this {\n this._breadcrumbs = [];\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public addAttachment(attachment: Attachment): this {\n this._attachments.push(attachment);\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public clearAttachments(): this {\n this._attachments = [];\n return this;\n }\n\n /** @inheritDoc */\n public getScopeData(): ScopeData {\n return {\n breadcrumbs: this._breadcrumbs,\n attachments: this._attachments,\n contexts: this._contexts,\n tags: this._tags,\n extra: this._extra,\n user: this._user,\n level: this._level,\n fingerprint: this._fingerprint || [],\n eventProcessors: this._eventProcessors,\n propagationContext: this._propagationContext,\n sdkProcessingMetadata: this._sdkProcessingMetadata,\n transactionName: this._transactionName,\n span: _getSpanForScope(this),\n };\n }\n\n /**\n * @inheritDoc\n */\n public setSDKProcessingMetadata(newData: { [key: string]: unknown }): this {\n this._sdkProcessingMetadata = { ...this._sdkProcessingMetadata, ...newData };\n\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public setPropagationContext(context: PropagationContext): this {\n this._propagationContext = context;\n return this;\n }\n\n /**\n * @inheritDoc\n */\n public getPropagationContext(): PropagationContext {\n return this._propagationContext;\n }\n\n /**\n * @inheritDoc\n */\n public captureException(exception: unknown, hint?: EventHint): string {\n const eventId = hint && hint.event_id ? hint.event_id : uuid4();\n\n if (!this._client) {\n logger.warn('No client configured on scope - will not capture exception!');\n return eventId;\n }\n\n const syntheticException = new Error('Sentry syntheticException');\n\n this._client.captureException(\n exception,\n {\n originalException: exception,\n syntheticException,\n ...hint,\n event_id: eventId,\n },\n this,\n );\n\n return eventId;\n }\n\n /**\n * @inheritDoc\n */\n public captureMessage(message: string, level?: SeverityLevel, hint?: EventHint): string {\n const eventId = hint && hint.event_id ? hint.event_id : uuid4();\n\n if (!this._client) {\n logger.warn('No client configured on scope - will not capture message!');\n return eventId;\n }\n\n const syntheticException = new Error(message);\n\n this._client.captureMessage(\n message,\n level,\n {\n originalException: message,\n syntheticException,\n ...hint,\n event_id: eventId,\n },\n this,\n );\n\n return eventId;\n }\n\n /**\n * @inheritDoc\n */\n public captureEvent(event: Event, hint?: EventHint): string {\n const eventId = hint && hint.event_id ? hint.event_id : uuid4();\n\n if (!this._client) {\n logger.warn('No client configured on scope - will not capture event!');\n return eventId;\n }\n\n this._client.captureEvent(event, { ...hint, event_id: eventId }, this);\n\n return eventId;\n }\n\n /**\n * This will be called on every set call.\n */\n protected _notifyScopeListeners(): void {\n // We need this check for this._notifyingListeners to be able to work on scope during updates\n // If this check is not here we'll produce endless recursion when something is done with the scope\n // during the callback.\n if (!this._notifyingListeners) {\n this._notifyingListeners = true;\n this._scopeListeners.forEach(callback => {\n callback(this);\n });\n this._notifyingListeners = false;\n }\n }\n}\n\n// NOTE: By exporting this here as const & type, instead of doing `export class`,\n// We can get the correct class when importing from `@sentry/core`, but the original type (from `@sentry/types`)\n// This is helpful for interop, e.g. when doing `import type { Scope } from '@sentry/node';` (which re-exports this)\n\n/**\n * Holds additional event information.\n */\nexport const Scope = ScopeClass;\n\n/**\n * Holds additional event information.\n */\nexport type Scope = ScopeInterface;\n","import type { Scope } from '@sentry/types';\nimport type { Client } from '@sentry/types';\nimport { getGlobalSingleton } from '@sentry/utils';\nimport { getAsyncContextStrategy } from './asyncContext';\nimport { getMainCarrier } from './carrier';\nimport { Scope as ScopeClass } from './scope';\n\n/**\n * Get the currently active scope.\n */\nexport function getCurrentScope(): Scope {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n return acs.getCurrentScope();\n}\n\n/**\n * Get the currently active isolation scope.\n * The isolation scope is active for the current exection context.\n */\nexport function getIsolationScope(): Scope {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n return acs.getIsolationScope();\n}\n\n/**\n * Get the global scope.\n * This scope is applied to _all_ events.\n */\nexport function getGlobalScope(): Scope {\n return getGlobalSingleton('globalScope', () => new ScopeClass());\n}\n\n/**\n * Creates a new scope with and executes the given operation within.\n * The scope is automatically removed once the operation\n * finishes or throws.\n */\nexport function withScope<T>(callback: (scope: Scope) => T): T;\n/**\n * Set the given scope as the active scope in the callback.\n */\nexport function withScope<T>(scope: Scope | undefined, callback: (scope: Scope) => T): T;\n/**\n * Either creates a new active scope, or sets the given scope as active scope in the given callback.\n */\nexport function withScope<T>(\n ...rest: [callback: (scope: Scope) => T] | [scope: Scope | undefined, callback: (scope: Scope) => T]\n): T {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n\n // If a scope is defined, we want to make this the active scope instead of the default one\n if (rest.length === 2) {\n const [scope, callback] = rest;\n\n if (!scope) {\n return acs.withScope(callback);\n }\n\n return acs.withSetScope(scope, callback);\n }\n\n return acs.withScope(rest[0]);\n}\n\n/**\n * Attempts to fork the current isolation scope and the current scope based on the current async context strategy. If no\n * async context strategy is set, the isolation scope and the current scope will not be forked (this is currently the\n * case, for example, in the browser).\n *\n * Usage of this function in environments without async context strategy is discouraged and may lead to unexpected behaviour.\n *\n * This function is intended for Sentry SDK and SDK integration development. It is not recommended to be used in \"normal\"\n * applications directly because it comes with pitfalls. Use at your own risk!\n */\nexport function withIsolationScope<T>(callback: (isolationScope: Scope) => T): T;\n/**\n * Set the provided isolation scope as active in the given callback. If no\n * async context strategy is set, the isolation scope and the current scope will not be forked (this is currently the\n * case, for example, in the browser).\n *\n * Usage of this function in environments without async context strategy is discouraged and may lead to unexpected behaviour.\n *\n * This function is intended for Sentry SDK and SDK integration development. It is not recommended to be used in \"normal\"\n * applications directly because it comes with pitfalls. Use at your own risk!\n *\n * If you pass in `undefined` as a scope, it will fork a new isolation scope, the same as if no scope is passed.\n */\nexport function withIsolationScope<T>(isolationScope: Scope | undefined, callback: (isolationScope: Scope) => T): T;\n/**\n * Either creates a new active isolation scope, or sets the given isolation scope as active scope in the given callback.\n */\nexport function withIsolationScope<T>(\n ...rest:\n | [callback: (isolationScope: Scope) => T]\n | [isolationScope: Scope | undefined, callback: (isolationScope: Scope) => T]\n): T {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n\n // If a scope is defined, we want to make this the active scope instead of the default one\n if (rest.length === 2) {\n const [isolationScope, callback] = rest;\n\n if (!isolationScope) {\n return acs.withIsolationScope(callback);\n }\n\n return acs.withSetIsolationScope(isolationScope, callback);\n }\n\n return acs.withIsolationScope(rest[0]);\n}\n\n/**\n * Get the currently active client.\n */\nexport function getClient<C extends Client>(): C | undefined {\n return getCurrentScope().getClient<C>();\n}\n","declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n","import { arch as _arch, platform as _platform } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { env, versions } from 'node:process';\nimport { threadId } from 'node:worker_threads';\nimport { familySync } from 'detect-libc';\nimport { getAbi } from 'node-abi';\n\nimport { GLOBAL_OBJ, logger } from '@sentry/utils';\nimport { DEBUG_BUILD } from './debug-build';\nimport type {\n PrivateV8CpuProfilerBindings,\n RawChunkCpuProfile,\n RawThreadCpuProfile,\n V8CpuProfilerBindings,\n} from './types';\nimport type { ProfileFormat } from './types';\n\nconst stdlib = familySync();\nconst platform = process.env['BUILD_PLATFORM'] || _platform();\nconst arch = process.env['BUILD_ARCH'] || _arch();\nconst abi = getAbi(versions.node, 'node');\nconst identifier = [platform, arch, stdlib, abi].filter(c => c !== undefined && c !== null).join('-');\n\nconst built_from_source_path = resolve(__dirname, '..', `./sentry_cpu_profiler-${identifier}`);\n\n/**\n * Imports cpp bindings based on the current platform and architecture.\n */\n// eslint-disable-next-line complexity\nexport function importCppBindingsModule(): PrivateV8CpuProfilerBindings {\n // If a binary path is specified, use that.\n if (env['SENTRY_PROFILER_BINARY_PATH']) {\n const envPath = env['SENTRY_PROFILER_BINARY_PATH'];\n return require(envPath);\n }\n\n // If a user specifies a different binary dir, they are in control of the binaries being moved there\n if (env['SENTRY_PROFILER_BINARY_DIR']) {\n const binaryPath = join(resolve(env['SENTRY_PROFILER_BINARY_DIR']), `sentry_cpu_profiler-${identifier}`);\n return require(`${binaryPath}.node`);\n }\n\n // We need the fallthrough so that in the end, we can fallback to the require dynamice require.\n // This is for cases where precompiled binaries were not provided, but may have been compiled from source.\n if (platform === 'darwin') {\n if (arch === 'x64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-darwin-x64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-darwin-x64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-darwin-x64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-darwin-x64-127.node');\n }\n }\n\n if (arch === 'arm64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-darwin-arm64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-darwin-arm64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-darwin-arm64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-darwin-arm64-127.node');\n }\n }\n }\n\n if (platform === 'win32') {\n if (arch === 'x64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-win32-x64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-win32-x64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-win32-x64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-win32-x64-127.node');\n }\n }\n }\n\n if (platform === 'linux') {\n if (arch === 'x64') {\n if (stdlib === 'musl') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-x64-musl-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-x64-musl-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-x64-musl-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-x64-musl-127.node');\n }\n }\n if (stdlib === 'glibc') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-127.node');\n }\n }\n }\n if (arch === 'arm64') {\n if (stdlib === 'musl') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-127.node');\n }\n }\n if (stdlib === 'glibc') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-127.node');\n }\n }\n }\n }\n return require(`${built_from_source_path}.node`);\n}\n\nconst PrivateCpuProfilerBindings: PrivateV8CpuProfilerBindings = importCppBindingsModule();\n\nclass Bindings implements V8CpuProfilerBindings {\n public startProfiling(name: string): void {\n if (!PrivateCpuProfilerBindings) {\n DEBUG_BUILD && logger.log('[Profiling] Bindings not loaded, ignoring call to startProfiling.');\n return;\n }\n\n return PrivateCpuProfilerBindings.startProfiling(name);\n }\n\n public stopProfiling(name: string, format: ProfileFormat.THREAD): RawThreadCpuProfile | null;\n public stopProfiling(name: string, format: ProfileFormat.CHUNK): RawChunkCpuProfile | null;\n public stopProfiling(\n name: string,\n format: ProfileFormat.CHUNK | ProfileFormat.THREAD,\n ): RawThreadCpuProfile | RawChunkCpuProfile | null {\n if (!PrivateCpuProfilerBindings) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Bindings not loaded or profile was never started, ignoring call to stopProfiling.');\n return null;\n }\n\n return PrivateCpuProfilerBindings.stopProfiling(\n name,\n format as unknown as any,\n threadId,\n !!GLOBAL_OBJ._sentryDebugIds,\n );\n }\n}\n\nconst CpuProfilerBindings = new Bindings();\n\nexport { PrivateCpuProfilerBindings };\nexport { CpuProfilerBindings };\n","import { parseSemver } from '@sentry/utils';\n\nexport const NODE_VERSION = parseSemver(process.versions.node) as { major: number; minor: number; patch: number };\nexport const NODE_MAJOR = NODE_VERSION.major;\n","/* eslint-disable max-lines */\nimport * as os from 'os';\nimport type {\n Client,\n Context,\n ContinuousThreadCpuProfile,\n DebugImage,\n DsnComponents,\n Envelope,\n Event,\n EventEnvelopeHeaders,\n Profile,\n ProfileChunk,\n ProfileChunkEnvelope,\n ProfileChunkItem,\n SdkInfo,\n StackFrame,\n StackParser,\n ThreadCpuProfile,\n} from '@sentry/types';\nimport { GLOBAL_OBJ, createEnvelope, dsnToString, forEachEnvelopeItem, logger, uuid4 } from '@sentry/utils';\n\nimport { env, versions } from 'process';\nimport { isMainThread, threadId } from 'worker_threads';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport type { RawChunkCpuProfile, RawThreadCpuProfile } from './types';\n\n// We require the file because if we import it, it will be included in the bundle.\n// I guess tsc does not check file contents when it's imported.\nexport const PROFILER_THREAD_ID_STRING = String(threadId);\nexport const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker';\nconst FORMAT_VERSION = '1';\nconst CONTINUOUS_FORMAT_VERSION = '2';\n\n// Os machine was backported to 16.18, but this was not reflected in the types\n// @ts-expect-error ignore missing\nconst machine = typeof os.machine === 'function' ? os.machine() : os.arch();\n\n// Machine properties (eval only once)\nconst PLATFORM = os.platform();\nconst RELEASE = os.release();\nconst VERSION = os.version();\nconst TYPE = os.type();\nconst MODEL = machine;\nconst ARCH = os.arch();\n\n/**\n * Checks if the profile is a raw profile or a profile enriched with thread information.\n * @param {ThreadCpuProfile | RawThreadCpuProfile} profile\n * @returns {boolean}\n */\nfunction isRawThreadCpuProfile(\n profile: ThreadCpuProfile | RawThreadCpuProfile | ContinuousThreadCpuProfile | RawChunkCpuProfile,\n): profile is RawThreadCpuProfile | RawChunkCpuProfile {\n return !('thread_metadata' in profile);\n}\n\n/**\n * Enriches the profile with threadId of the current thread.\n * This is done in node as we seem to not be able to get the info from C native code.\n *\n * @param {ThreadCpuProfile | RawThreadCpuProfile} profile\n * @returns {ThreadCpuProfile}\n */\nexport function enrichWithThreadInformation(\n profile: ThreadCpuProfile | RawThreadCpuProfile | ContinuousThreadCpuProfile | RawChunkCpuProfile,\n): ThreadCpuProfile | ContinuousThreadCpuProfile {\n if (!isRawThreadCpuProfile(profile)) {\n return profile;\n }\n\n return {\n samples: profile.samples,\n frames: profile.frames,\n stacks: profile.stacks,\n thread_metadata: {\n [PROFILER_THREAD_ID_STRING]: {\n name: PROFILER_THREAD_NAME,\n },\n },\n } as ThreadCpuProfile | ContinuousThreadCpuProfile;\n}\n\n/**\n * Creates a profiling envelope item, if the profile does not pass validation, returns null.\n * @param {RawThreadCpuProfile}\n * @param {Event}\n * @returns {Profile | null}\n */\nexport function createProfilingEvent(client: Client, profile: RawThreadCpuProfile, event: Event): Profile | null {\n if (!isValidProfile(profile)) {\n return null;\n }\n\n return createProfilePayload(client, profile, {\n release: event.release ?? '',\n environment: event.environment ?? '',\n event_id: event.event_id ?? '',\n transaction: event.transaction ?? '',\n start_timestamp: event.start_timestamp ? event.start_timestamp * 1000 : Date.now(),\n trace_id: event.contexts?.['trace']?.['trace_id'] ?? '',\n profile_id: profile.profile_id,\n });\n}\n\n/**\n * Create a profile\n * @param {RawThreadCpuProfile} cpuProfile\n * @param {options}\n * @returns {Profile}\n */\nfunction createProfilePayload(\n client: Client,\n cpuProfile: RawThreadCpuProfile,\n {\n release,\n environment,\n event_id,\n transaction,\n start_timestamp,\n trace_id,\n profile_id,\n }: {\n release: string;\n environment: string;\n event_id: string;\n transaction: string;\n start_timestamp: number;\n trace_id: string | undefined;\n profile_id: string;\n },\n): Profile {\n // Log a warning if the profile has an invalid traceId (should be uuidv4).\n // All profiles and transactions are rejected if this is the case and we want to\n // warn users that this is happening if they enable debug flag\n if (trace_id && trace_id.length !== 32) {\n DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);\n }\n\n const enrichedThreadProfile = enrichWithThreadInformation(cpuProfile);\n\n const profile: Profile = {\n event_id: profile_id,\n timestamp: new Date(start_timestamp).toISOString(),\n platform: 'node',\n version: FORMAT_VERSION,\n release: release,\n environment: environment,\n measurements: cpuProfile.measurements,\n runtime: {\n name: 'node',\n version: versions.node || '',\n },\n os: {\n name: PLATFORM,\n version: RELEASE,\n build_number: VERSION,\n },\n device: {\n locale: env['LC_ALL'] || env['LC_MESSAGES'] || env['LANG'] || env['LANGUAGE'] || '',\n model: MODEL,\n manufacturer: TYPE,\n architecture: ARCH,\n is_emulator: false,\n },\n debug_meta: {\n images: applyDebugMetadata(client, cpuProfile.resources),\n },\n profile: enrichedThreadProfile as ThreadCpuProfile,\n transaction: {\n name: transaction,\n id: event_id,\n trace_id: trace_id || '',\n active_thread_id: PROFILER_THREAD_ID_STRING,\n },\n };\n\n return profile;\n}\n\n/**\n * Create a profile chunk from raw thread profile\n * @param {RawThreadCpuProfile} cpuProfile\n * @param {options}\n * @returns {Profile}\n */\nfunction createProfileChunkPayload(\n client: Client,\n cpuProfile: RawChunkCpuProfile,\n {\n release,\n environment,\n trace_id,\n profiler_id,\n chunk_id,\n }: {\n release: string;\n environment: string;\n trace_id: string | undefined;\n chunk_id: string;\n profiler_id: string;\n },\n): ProfileChunk {\n // Log a warning if the profile has an invalid traceId (should be uuidv4).\n // All profiles and transactions are rejected if this is the case and we want to\n // warn users that this is happening if they enable debug flag\n if (trace_id && trace_id.length !== 32) {\n DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);\n }\n\n const enrichedThreadProfile = enrichWithThreadInformation(cpuProfile);\n\n const profile: ProfileChunk = {\n chunk_id: chunk_id,\n profiler_id: profiler_id,\n platform: 'node',\n version: CONTINUOUS_FORMAT_VERSION,\n release: release,\n environment: environment,\n measurements: cpuProfile.measurements,\n debug_meta: {\n images: applyDebugMetadata(client, cpuProfile.resources),\n },\n profile: enrichedThreadProfile as ContinuousThreadCpuProfile,\n };\n\n return profile;\n}\n\n/**\n * Creates a profiling chunk envelope item, if the profile does not pass validation, returns null.\n */\nexport function createProfilingChunkEvent(\n client: Client,\n options: { release?: string; environment?: string },\n profile: RawChunkCpuProfile,\n identifiers: { trace_id: string | undefined; chunk_id: string; profiler_id: string },\n): ProfileChunk | null {\n if (!isValidProfileChunk(profile)) {\n return null;\n }\n\n return createProfileChunkPayload(client, profile, {\n release: options.release ?? '',\n environment: options.environment ?? '',\n trace_id: identifiers.trace_id ?? '',\n chunk_id: identifiers.chunk_id,\n profiler_id: identifiers.profiler_id,\n });\n}\n\n/**\n * Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1).\n * @param {unknown} rate\n * @returns {boolean}\n */\nexport function isValidSampleRate(rate: unknown): boolean {\n // we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck\n if ((typeof rate !== 'number' && typeof rate !== 'boolean') || (typeof rate === 'number' && isNaN(rate))) {\n DEBUG_BUILD &&\n logger.warn(\n `[Profiling] Invalid sample rate. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify(\n rate,\n )} of type ${JSON.stringify(typeof rate)}.`,\n );\n return false;\n }\n\n // Boolean sample rates are always valid\n if (rate === true || rate === false) {\n return true;\n }\n\n // in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false\n if (rate < 0 || rate > 1) {\n DEBUG_BUILD && logger.warn(`[Profiling] Invalid sample rate. Sample rate must be between 0 and 1. Got ${rate}.`);\n return false;\n }\n return true;\n}\n\n/**\n * Checks if the profile is valid and can be sent to Sentry.\n * @param {RawThreadCpuProfile} profile\n * @returns {boolean}\n */\nexport function isValidProfile(profile: RawThreadCpuProfile): profile is RawThreadCpuProfile & { profile_id: string } {\n if (profile.samples.length <= 1) {\n DEBUG_BUILD &&\n // Log a warning if the profile has less than 2 samples so users can know why\n // they are not seeing any profiling data and we cant avoid the back and forth\n // of asking them to provide us with a dump of the profile data.\n logger.log('[Profiling] Discarding profile because it contains less than 2 samples');\n return false;\n }\n\n if (!profile.profile_id) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Checks if the profile chunk is valid and can be sent to Sentry.\n * @param profile\n * @returns\n */\nexport function isValidProfileChunk(profile: RawChunkCpuProfile): profile is RawChunkCpuProfile {\n if (profile.samples.length <= 1) {\n DEBUG_BUILD &&\n // Log a warning if the profile has less than 2 samples so users can know why\n // they are not seeing any profiling data and we cant avoid the back and forth\n // of asking them to provide us with a dump of the profile data.\n logger.log('[Profiling] Discarding profile chunk because it contains less than 2 samples');\n return false;\n }\n\n return true;\n}\n\n/**\n * Adds items to envelope if they are not already present - mutates the envelope.\n * @param {Envelope} envelope\n * @param {Profile[]} profiles\n * @returns {Envelope}\n */\nexport function addProfilesToEnvelope(envelope: Envelope, profiles: Profile[]): Envelope {\n if (!profiles.length) {\n return envelope;\n }\n\n for (const profile of profiles) {\n // @ts-expect-error untyped envelope\n envelope[1].push([{ type: 'profile' }, profile]);\n }\n return envelope;\n}\n\n/**\n * Finds transactions with profile_id context in the envelope\n * @param {Envelope} envelope\n * @returns {Event[]}\n */\nexport function findProfiledTransactionsFromEnvelope(envelope: Envelope): Event[] {\n const events: Event[] = [];\n\n forEachEnvelopeItem(envelope, (item, type) => {\n if (type !== 'transaction') {\n return;\n }\n\n // First item is the type, so we can skip it, everything else is an event\n for (let j = 1; j < item.length; j++) {\n const event = item[j];\n\n if (!event) {\n // Shouldnt happen, but lets be safe\n continue;\n }\n\n // @ts-expect-error profile_id is not part of the metadata type\n const profile_id = (event.contexts as Context)?.['profile']?.['profile_id'];\n\n if (event && profile_id) {\n events.push(item[j] as Event);\n }\n }\n });\n\n return events;\n}\n\n/**\n * Creates event envelope headers for a profile chunk. This is separate from createEventEnvelopeHeaders util\n * as the profile chunk does not conform to the sentry event type\n */\nexport function createEventEnvelopeHeaders(\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): EventEnvelopeHeaders {\n return {\n event_id: uuid4(),\n sent_at: new Date().toISOString(),\n ...(sdkInfo && { sdk: sdkInfo }),\n ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),\n };\n}\n\n/**\n * Creates a standalone profile_chunk envelope.\n */\nexport function makeProfileChunkEnvelope(\n chunk: ProfileChunk,\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): ProfileChunkEnvelope {\n const profileChunkHeader: ProfileChunkItem[0] = {\n type: 'profile_chunk',\n };\n\n return createEnvelope<ProfileChunkEnvelope>(createEventEnvelopeHeaders(sdkInfo, tunnel, dsn), [\n [profileChunkHeader, chunk],\n ]);\n}\n\nconst debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();\n\n/**\n * Cross reference profile collected resources with debug_ids and return a list of debug images.\n * @param {string[]} resource_paths\n * @returns {DebugImage[]}\n */\nexport function applyDebugMetadata(client: Client, resource_paths: ReadonlyArray<string>): DebugImage[] {\n const debugIdMap = GLOBAL_OBJ._sentryDebugIds;\n if (!debugIdMap) {\n return [];\n }\n\n const options = client.getOptions();\n\n if (!options || !options.stackParser) {\n return [];\n }\n\n let debugIdStackFramesCache: Map<string, StackFrame[]>;\n const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(options.stackParser);\n if (cachedDebugIdStackFrameCache) {\n debugIdStackFramesCache = cachedDebugIdStackFrameCache;\n } else {\n debugIdStackFramesCache = new Map<string, StackFrame[]>();\n debugIdStackParserCache.set(options.stackParser, debugIdStackFramesCache);\n }\n\n // Build a map of filename -> debug_id.\n const filenameDebugIdMap = Object.keys(debugIdMap).reduce<Record<string, string>>((acc, debugIdStackTrace) => {\n let parsedStack: StackFrame[];\n\n const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);\n if (cachedParsedStack) {\n parsedStack = cachedParsedStack;\n } else {\n parsedStack = options.stackParser(debugIdStackTrace);\n debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);\n }\n\n for (let i = parsedStack.length - 1; i >= 0; i--) {\n const stackFrame = parsedStack[i];\n const file = stackFrame && stackFrame.filename;\n\n if (stackFrame && file) {\n acc[file] = debugIdMap[debugIdStackTrace] as string;\n break;\n }\n }\n return acc;\n }, {});\n\n const images: DebugImage[] = [];\n\n for (const resource of resource_paths) {\n if (resource && filenameDebugIdMap[resource]) {\n images.push({\n type: 'sourcemap',\n code_file: resource,\n debug_id: filenameDebugIdMap[resource] as string,\n });\n }\n }\n\n return images;\n}\n","import { spanIsSampled, spanToJSON } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport type { CustomSamplingContext, Span } from '@sentry/types';\nimport { logger, uuid4 } from '@sentry/utils';\n\nimport { CpuProfilerBindings } from './cpu_profiler';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { RawThreadCpuProfile } from './types';\nimport { isValidSampleRate } from './utils';\n\nexport const MAX_PROFILE_DURATION_MS = 30 * 1000;\n\n/**\n * Takes a transaction and determines if it should be profiled or not. If it should be profiled, it returns the\n * profile_id, otherwise returns undefined. Takes care of setting profile context on transaction as well\n */\nexport function maybeProfileSpan(\n client: NodeClient | undefined,\n span: Span,\n customSamplingContext?: CustomSamplingContext,\n): string | undefined {\n // profilesSampleRate is multiplied with tracesSampleRate to get the final sampling rate. We dont perform\n // the actual multiplication to get the final rate, but we discard the profile if the span was sampled,\n // so anything after this block from here is based on the span sampling.\n if (!spanIsSampled(span)) {\n return;\n }\n\n // Client and options are required for profiling\n if (!client) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling disabled, no client found.');\n return;\n }\n\n const options = client.getOptions();\n if (!options) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling disabled, no options found.');\n return;\n }\n\n const profilesSampler = options.profilesSampler;\n let profilesSampleRate: number | boolean | undefined = options.profilesSampleRate;\n\n // Prefer sampler to sample rate if both are provided.\n if (typeof profilesSampler === 'function') {\n const { description: spanName = '<unknown>', data } = spanToJSON(span);\n // We bail out early if that is not the case\n const parentSampled = true;\n\n profilesSampleRate = profilesSampler({\n name: spanName,\n attributes: data,\n transactionContext: {\n name: spanName,\n parentSampled,\n },\n parentSampled,\n ...customSamplingContext,\n });\n }\n\n // Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The\n // only valid values are booleans or numbers between 0 and 1.)\n if (!isValidSampleRate(profilesSampleRate)) {\n DEBUG_BUILD && logger.warn('[Profiling] Discarding profile because of invalid sample rate.');\n return;\n }\n\n // if the function returned 0 (or false), or if `profileSampleRate` is 0, it's a sign the profile should be dropped\n if (!profilesSampleRate) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Discarding profile because ${\n typeof profilesSampler === 'function'\n ? 'profileSampler returned 0 or false'\n : 'a negative sampling decision was inherited or profileSampleRate is set to 0'\n }`,\n );\n return;\n }\n\n // Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is\n // a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false.\n const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate;\n // Check if we should sample this profile\n if (!sampled) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(\n profilesSampleRate,\n )})`,\n );\n return;\n }\n\n const profile_id = uuid4();\n CpuProfilerBindings.startProfiling(profile_id);\n DEBUG_BUILD && logger.log(`[Profiling] started profiling transaction: ${spanToJSON(span).description}`);\n\n // set transaction context - do this regardless if profiling fails down the line\n // so that we can still see the profile_id in the transaction context\n return profile_id;\n}\n\n/**\n * Stops the profiler for profile_id and returns the profile\n * @param transaction\n * @param profile_id\n * @returns\n */\nexport function stopSpanProfile(span: Span, profile_id: string | undefined): RawThreadCpuProfile | null {\n // Should not happen, but satisfy the type checker and be safe regardless.\n if (!profile_id) {\n return null;\n }\n\n const profile = CpuProfilerBindings.stopProfiling(profile_id, 0);\n DEBUG_BUILD && logger.log(`[Profiling] stopped profiling of transaction: ${spanToJSON(span).description}`);\n\n // In case of an overlapping span, stopProfiling may return null and silently ignore the overlapping profile.\n if (!profile) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] profiler returned null profile for: ${spanToJSON(span).description}`,\n 'this may indicate an overlapping span or a call to stopProfiling with a profile title that was never started',\n );\n return null;\n }\n\n // Assign profile_id to the profile\n profile.profile_id = profile_id;\n return profile;\n}\n","import type { Event } from '@sentry/types';\n\ninterface Sample {\n stack_id: number;\n thread_id: string;\n elapsed_since_start_ns: string;\n}\n\ninterface ChunkSample {\n stack_id: number;\n thread_id: string;\n timestamp: number;\n}\n\ntype Frame = {\n function: string;\n file: string;\n lineno: number;\n colno: number;\n};\n\ninterface Measurement {\n unit: string;\n values: {\n elapsed_since_start_ns: number;\n value: number;\n }[];\n}\n\n// Profile is marked as optional because it is deleted from the metadata\n// by the integration before the event is processed by other integrations.\nexport interface ProfiledEvent extends Event {\n sdkProcessingMetadata: {\n profile?: RawThreadCpuProfile;\n };\n}\n\ninterface BaseProfile {\n profile_id?: string;\n stacks: number[][];\n frames: Frame[];\n resources: string[];\n profiler_logging_mode: 'eager' | 'lazy';\n measurements: Record<string, Measurement>;\n}\nexport interface RawThreadCpuProfile extends BaseProfile {\n samples: Sample[];\n}\n\nexport interface RawChunkCpuProfile extends BaseProfile {\n samples: ChunkSample[];\n}\n\nexport interface PrivateV8CpuProfilerBindings {\n startProfiling(name: string): void;\n\n stopProfiling(\n name: string,\n format: ProfileFormat.THREAD,\n threadId: number,\n collectResources: boolean,\n ): RawThreadCpuProfile | null;\n stopProfiling(\n name: string,\n format: ProfileFormat.CHUNK,\n threadId: number,\n collectResources: boolean,\n ): RawChunkCpuProfile | null;\n\n // Helper methods exposed for testing\n getFrameModule(abs_path: string): string;\n}\n\nexport enum ProfileFormat {\n THREAD = 0,\n CHUNK = 1,\n}\n\nexport interface V8CpuProfilerBindings {\n startProfiling(name: string): void;\n\n stopProfiling(name: string, format: ProfileFormat.THREAD): RawThreadCpuProfile | null;\n stopProfiling(name: string, format: ProfileFormat.CHUNK): RawChunkCpuProfile | null;\n}\n","import { defineIntegration, getCurrentScope, getIsolationScope, getRootSpan, spanToJSON } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport type { Event, Integration, IntegrationFn, Profile, ProfileChunk, Span } from '@sentry/types';\n\nimport { LRUMap, logger, uuid4 } from '@sentry/utils';\n\nimport { getGlobalScope } from '../../core/src/currentScopes';\nimport { CpuProfilerBindings } from './cpu_profiler';\nimport { DEBUG_BUILD } from './debug-build';\nimport { NODE_MAJOR, NODE_VERSION } from './nodeVersion';\nimport { MAX_PROFILE_DURATION_MS, maybeProfileSpan, stopSpanProfile } from './spanProfileUtils';\nimport type { RawChunkCpuProfile, RawThreadCpuProfile } from './types';\nimport { ProfileFormat } from './types';\nimport { PROFILER_THREAD_NAME } from './utils';\n\nimport {\n PROFILER_THREAD_ID_STRING,\n addProfilesToEnvelope,\n createProfilingChunkEvent,\n createProfilingEvent,\n findProfiledTransactionsFromEnvelope,\n makeProfileChunkEnvelope,\n} from './utils';\n\nconst CHUNK_INTERVAL_MS = 5000;\nconst PROFILE_MAP = new LRUMap<string, RawThreadCpuProfile>(50);\nconst PROFILE_TIMEOUTS: Record<string, NodeJS.Timeout> = {};\n\nfunction addToProfileQueue(profile_id: string, profile: RawThreadCpuProfile): void {\n PROFILE_MAP.set(profile_id, profile);\n}\n\nfunction takeFromProfileQueue(profile_id: string): RawThreadCpuProfile | undefined {\n const profile = PROFILE_MAP.get(profile_id);\n PROFILE_MAP.remove(profile_id);\n return profile;\n}\n\n/**\n * Instruments the client to automatically invoke the profiler on span start and stop events.\n * @param client\n */\nfunction setupAutomatedSpanProfiling(client: NodeClient): void {\n const spanToProfileIdMap = new WeakMap<Span, string>();\n\n client.on('spanStart', span => {\n if (span !== getRootSpan(span)) {\n return;\n }\n\n const profile_id = maybeProfileSpan(client, span);\n\n if (profile_id) {\n const options = client.getOptions();\n // Not intended for external use, hence missing types, but we want to profile a couple of things at Sentry that\n // currently exceed the default timeout set by the SDKs.\n const maxProfileDurationMs =\n (options._experiments && options._experiments['maxProfileDurationMs']) || MAX_PROFILE_DURATION_MS;\n\n if (PROFILE_TIMEOUTS[profile_id]) {\n global.clearTimeout(PROFILE_TIMEOUTS[profile_id]);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete PROFILE_TIMEOUTS[profile_id];\n }\n\n // Enqueue a timeout to prevent profiles from running over max duration.\n const timeout = global.setTimeout(() => {\n DEBUG_BUILD &&\n logger.log('[Profiling] max profile duration elapsed, stopping profiling for:', spanToJSON(span).description);\n\n const profile = stopSpanProfile(span, profile_id);\n if (profile) {\n addToProfileQueue(profile_id, profile);\n }\n }, maxProfileDurationMs);\n\n // Unref timeout so it doesn't keep the process alive.\n timeout.unref();\n\n getCurrentScope().setContext('profile', { profile_id });\n spanToProfileIdMap.set(span, profile_id);\n }\n });\n\n client.on('spanEnd', span => {\n const profile_id = spanToProfileIdMap.get(span);\n\n if (profile_id) {\n if (PROFILE_TIMEOUTS[profile_id]) {\n global.clearTimeout(PROFILE_TIMEOUTS[profile_id]);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete PROFILE_TIMEOUTS[profile_id];\n }\n const profile = stopSpanProfile(span, profile_id);\n\n if (profile) {\n addToProfileQueue(profile_id, profile);\n }\n }\n });\n\n client.on('beforeEnvelope', (envelope): void => {\n // if not profiles are in queue, there is nothing to add to the envelope.\n if (!PROFILE_MAP.size) {\n return;\n }\n\n const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);\n if (!profiledTransactionEvents.length) {\n return;\n }\n\n const profilesToAddToEnvelope: Profile[] = [];\n\n for (const profiledTransaction of profiledTransactionEvents) {\n const profileContext = profiledTransaction.contexts?.['profile'];\n const profile_id = profileContext?.['profile_id'];\n\n if (!profile_id) {\n throw new TypeError('[Profiling] cannot find profile for a transaction without a profile context');\n }\n\n // Remove the profile from the transaction context before sending, relay will take care of the rest.\n if (profileContext) {\n delete profiledTransaction.contexts?.['profile'];\n }\n\n const cpuProfile = takeFromProfileQueue(profile_id);\n if (!cpuProfile) {\n DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);\n continue;\n }\n\n const profile = createProfilingEvent(client, cpuProfile, profiledTransaction);\n if (!profile) return;\n\n profilesToAddToEnvelope.push(profile);\n\n // @ts-expect-error profile does not inherit from Event\n client.emit('preprocessEvent', profile, {\n event_id: profiledTransaction.event_id,\n });\n }\n\n addProfilesToEnvelope(envelope, profilesToAddToEnvelope);\n });\n}\n\ninterface ChunkData {\n id: string;\n timer: NodeJS.Timeout | undefined;\n startTraceID: string;\n}\nclass ContinuousProfiler {\n private _profilerId = uuid4();\n private _client: NodeClient | undefined = undefined;\n private _chunkData: ChunkData | undefined = undefined;\n\n /**\n * Called when the profiler is attached to the client (continuous mode is enabled). If of the profiler\n * methods called before the profiler is initialized will result in a noop action with debug logs.\n * @param client\n */\n public initialize(client: NodeClient): void {\n this._client = client;\n }\n\n /**\n * Recursively schedules chunk profiling to start and stop at a set interval.\n * Once the user calls stop(), the current chunk will be stopped and flushed to Sentry and no new chunks will\n * will be started. To restart continuous mode after calling stop(), the user must call start() again.\n * @returns void\n */\n public start(): void {\n if (!this._client) {\n // The client is not attached to the profiler if the user has not enabled continuous profiling.\n // In this case, calling start() and stop() is a noop action.The reason this exists is because\n // it makes the types easier to work with and avoids users having to do null checks.\n DEBUG_BUILD && logger.log('[Profiling] Profiler was never attached to the client.');\n return;\n }\n if (this._chunkData) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Chunk with chunk_id ${this._chunkData.id} is still running, current chunk will be stopped a new chunk will be started.`,\n );\n this.stop();\n }\n\n const traceId =\n getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;\n this._initializeChunk(traceId);\n this._startChunkProfiling(this._chunkData!);\n }\n\n /**\n * Stops the current chunk and flushes the profile to Sentry.\n * @returns void\n */\n public stop(): void {\n if (this._chunkData?.timer) {\n global.clearTimeout(this._chunkData.timer);\n this._chunkData.timer = undefined;\n DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${this._chunkData.id}`);\n }\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n if (!this._chunkData?.id) {\n DEBUG_BUILD &&\n logger.log(`[Profiling] Failed to collect profile for: ${this._chunkData?.id}, the chunk_id is missing.`);\n return;\n }\n\n const profile = this._stopChunkProfiling(this._chunkData);\n\n if (!profile) {\n DEBUG_BUILD && logger.log(`[Profiling] _chunkiledStartTraceID to collect profile for: ${this._chunkData.id}`);\n return;\n }\n if (profile) {\n DEBUG_BUILD && logger.log(`[Profiling] Sending profile chunk ${this._chunkData.id}.`);\n }\n\n DEBUG_BUILD && logger.log(`[Profiling] Profile chunk ${this._chunkData.id} sent to Sentry.`);\n const chunk = createProfilingChunkEvent(this._client, this._client.getOptions(), profile, {\n chunk_id: this._chunkData.id,\n trace_id: this._chunkData.startTraceID,\n profiler_id: this._profilerId,\n });\n\n if (!chunk) {\n DEBUG_BUILD && logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`);\n this._reset();\n return;\n }\n\n this._flush(chunk);\n // Depending on the profile and stack sizes, stopping the profile and converting\n // the format may negatively impact the performance of the application. To avoid\n // blocking for too long, enqueue the next chunk start inside the next macrotask.\n // clear current chunk\n this._reset();\n }\n\n /**\n * Flushes the profile chunk to Sentry.\n * @param chunk\n */\n private _flush(chunk: ProfileChunk): void {\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n\n const transport = this._client.getTransport();\n if (!transport) {\n DEBUG_BUILD && logger.log('[Profiling] No transport available to send profile chunk.');\n return;\n }\n\n const dsn = this._client.getDsn();\n const metadata = this._client.getSdkMetadata();\n const tunnel = this._client.getOptions().tunnel;\n\n const envelope = makeProfileChunkEnvelope(chunk, metadata?.sdk, tunnel, dsn);\n transport.send(envelope).then(null, reason => {\n DEBUG_BUILD && logger.error('Error while sending profile chunk envelope:', reason);\n });\n }\n\n /**\n * Stops the profile and clears chunk instrumentation from global scope\n * @returns void\n */\n private _stopChunkProfiling(chunk: ChunkData): RawChunkCpuProfile | null {\n this._teardownSpanChunkInstrumentation();\n return CpuProfilerBindings.stopProfiling(chunk.id, ProfileFormat.CHUNK);\n }\n\n /**\n * Starts the profiler and registers the flush timer for a given chunk.\n * @param chunk\n */\n private _startChunkProfiling(chunk: ChunkData): void {\n this._setupSpanChunkInstrumentation();\n CpuProfilerBindings.startProfiling(chunk.id);\n DEBUG_BUILD && logger.log(`[Profiling] starting profiling chunk: ${chunk.id}`);\n\n chunk.timer = global.setTimeout(() => {\n DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${chunk.id}`);\n this.stop();\n DEBUG_BUILD && logger.log('[Profiling] Starting new profiling chunk.');\n setImmediate(this.start.bind(this));\n }, CHUNK_INTERVAL_MS);\n\n // Unref timeout so it doesn't keep the process alive.\n chunk.timer.unref();\n }\n\n /**\n * Attaches profiling information to spans that were started\n * during a profiling session.\n */\n private _setupSpanChunkInstrumentation(): void {\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n\n getGlobalScope().setContext('profile', {\n profiler_id: this._profilerId,\n });\n\n this._client.on('beforeSendEvent', e => this._assignThreadIdContext(e));\n }\n\n /**\n * Clear profiling information from global context when a profile is not running.\n */\n private _teardownSpanChunkInstrumentation(): void {\n const globalScope = getGlobalScope();\n globalScope.setContext('profile', {});\n }\n\n /**\n * Initializes new profile chunk metadata\n */\n private _initializeChunk(traceId: string): void {\n this._chunkData = {\n id: uuid4(),\n startTraceID: traceId,\n timer: undefined,\n };\n }\n\n /**\n * Assigns thread_id and thread name context to a profiled event.\n */\n private _assignThreadIdContext(event: Event): any {\n if (!event?.['contexts']?.['profile']) {\n return;\n }\n\n if (!event.contexts) {\n return;\n }\n\n // @ts-expect-error the trace fallback value is wrong, though it should never happen\n // and in case it does, we dont want to override whatever was passed initially.\n event.contexts['trace'] = {\n ...(event.contexts?.['trace'] ?? {}),\n data: {\n ...(event.contexts?.['trace']?.['data'] ?? {}),\n ['thread.id']: PROFILER_THREAD_ID_STRING,\n ['thread.name']: PROFILER_THREAD_NAME,\n },\n };\n }\n\n /**\n * Resets the current chunk state.\n */\n private _reset(): void {\n this._chunkData = undefined;\n }\n}\n\nexport interface ProfilingIntegration extends Integration {\n _profiler: ContinuousProfiler;\n}\n\n/** Exported only for tests. */\nexport const _nodeProfilingIntegration = ((): ProfilingIntegration => {\n if (DEBUG_BUILD && ![16, 18, 20, 22].includes(NODE_MAJOR)) {\n logger.warn(\n `[Profiling] You are using a Node.js version that does not have prebuilt binaries (${NODE_VERSION}).`,\n 'The @sentry/profiling-node package only has prebuilt support for the following LTS versions of Node.js: 16, 18, 20, 22.',\n 'To use the @sentry/profiling-node package with this version of Node.js, you will need to compile the native addon from source.',\n 'See: https://github.com/getsentry/sentry-javascript/tree/develop/packages/profiling-node#building-the-package-from-source',\n );\n }\n\n return {\n name: 'ProfilingIntegration',\n _profiler: new ContinuousProfiler(),\n setup(client: NodeClient) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling integration setup.');\n const options = client.getOptions();\n\n const mode =\n (options.profilesSampleRate === undefined || options.profilesSampleRate === 0) && !options.profilesSampler\n ? 'continuous'\n : 'span';\n switch (mode) {\n case 'continuous': {\n DEBUG_BUILD && logger.log('[Profiling] Continuous profiler mode enabled.');\n this._profiler.initialize(client);\n break;\n }\n // Default to span profiling when no mode profiler mode is set\n case 'span':\n case undefined: {\n DEBUG_BUILD && logger.log('[Profiling] Span profiler mode enabled.');\n setupAutomatedSpanProfiling(client);\n break;\n }\n default: {\n DEBUG_BUILD && logger.warn(`[Profiling] Unknown profiler mode: ${mode}, profiler was not initialized`);\n }\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * We need this integration in order to send data to Sentry. We hook into the event processor\n * and inspect each event to see if it is a transaction event and if that transaction event\n * contains a profile on it's metadata. If that is the case, we create a profiling event envelope\n * and delete the profile from the transaction metadata.\n */\nexport const nodeProfilingIntegration = defineIntegration(_nodeProfilingIntegration);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiCA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACO;AACL;;AAEI;AACF;;AAEA;AACE;AACF;AACF;;;;AAIA;;AAEA;;;AAGE;AACF;AACA;AACF;;AAEE;;;AAGA;;;AAGiB;AACA;AACA;AACA;;;AAGA;AACA;;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;ACrGnB;;AAMA;AACA;AACA;;AAEO;AACL;;;;AAIE;AACF;AACF;;AAEA;AACA;AACA;;AAEO;;AAEP;;ACAA;;;AAGA;;AAEA;AACA;;AAEA;AACA;;AAGA;;;;;;AASA;;AAGA;;AAGA;;;;AAMA;;AAGA;;AAGA;;;;;AAMA;;;;AAMA;AACA;AACA;AACA;AACA;;;;;;;;;AAaA;;;;;AAMI;;;AAGA;AACA;;;AAGA;AACA;AACA;;AAEF;;AAEF;;;AAGS;;AAEL;AACA;AACA;AACA;;;AAGA;;AAEA;;AAEA;AACA;AACA;;;AAGA;;;;AAIA;AACF;;AAEF;;;AAGS;AACL;AACF;;AAEF;;;;;AAKE;;AAEF;;;;AAII;AACF;;AAEF;;;;;AAKE;;AAEF;;;;AAII;AACF;;AAEF;;;;AAII;;AAEF;;AAEF;;;;;;AAMI;AACE;;AAEA;AACA;;;AAGF;AACE;AACF;;;;AAIF;;AAEF;;;AAGS;AACL;AACF;;AAEF;;;AAGS;;AAEP;;AAEF;;;AAGS;AACL;;AAEF;;AAEF;;;;;;AAMM;;;;AAIJ;;AAEF;;;AAGS;AACL;;;AAGF;;AAEF;;;AAGS;;AAEH;AACA;;;;AAIJ;;AAEF;;;AAGS;AACL;;;AAGF;;AAEF;;;;;;;AAOE;;AAEF;;;AAGS;AACL;;;AAGF;;AAEF;;;;;;;AAOE;;AAEF;;;;AAII;;;;;AAKA;;;;AAIF;;AAEF;;;AAGS;;AAEH;;AAEA;AACF;;;AAGF;;AAEF;;;;AAII;AACF;;AAEF;;;;AAII;;AAEA;;AAEA;;AAEA;;AAEM;;;AAGV;;AAEI;;AAEA;AACA;;;AAGA;AACE;AACF;;AAEA;AACE;AACF;;;;AAIA;;;AAGE;AACF;;AAEA;AACE;AACF;;;AAGF;;AAEF;;;AAGS;AACT;AACI;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;;;;AAKF;;AAEF;;;AAGS;AACL;;;AAGA;;AAEA;;;AAGE;;;;AAIF;AACA;AACA;;;;;AAKF;;AAEF;;;AAGS;;AAEP;;AAEF;;;AAGS;AACL;;;AAGF;;AAEF;;;;AAII;;AAEF;;AAEF;;;AAGS;AACL;;AAEF;;AAEF;AACS;AACL;;;;AAIE;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGJ;;AAEF;;;AAGS;AACL;;;AAGF;;AAEF;;;AAGS;AACL;;AAEF;;AAEF;;;;AAII;AACF;;AAEF;;;AAGS;;;AAGL;AACE;;AAEF;;;;;AAKE;AACA;;AAEE;AACA;AACA;;;;;;AAMN;;AAEF;;;AAGS;;;AAGL;AACE;;AAEF;;AAEA;;;AAGE;;AAEA;;AAEE;AACA;AACA;;;;;;AAMN;;AAEF;;;;;;AAMI;;;AAGA;;AAEA;;;AAGF;;AAEF;AACA;;;AAGA;AACA;AACA;;;AAGM;AACE;AACR;AACM;AACF;AACF;AACF;;AAEA;AACA;AACA;;AAEA;AACA;;AAEO;;AAEP;AACA;;;AC7jBA;AACA;AACA;;AAEO;;AAEP;;AC9BA;AACA;AACA;;;AAGO;;ACUP;AACA;AACA;AACA;AACA;;AAEA;;AAE4F;;;AAGA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;;;AAMA;;AAEA;;;;AAIA;;;;AAIA;AACA;;;AAGA;AACA;;AAEA;;AC7LrF;AACA;;ACHP;;AA4BA;AACA;AACO;AACA;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACE;AACF;AACE;AACF;;AAEA;;AAEA;AACA;;;;AAIO;AACL;AACF;AACE;;AAEA;;AAEA;;AAEE;AACA;AACA;;;;;;AAMJ;;AAEA;AACA;;;;;AAKO;;;AAGL;;AAEA;;;;;AAKE;AACA;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACE;;AAEA;AACE;;AAEA;;AAEA;AACA;;AAED;;AAQD;AACF;;AAEA;;AAEE;AACE;AACF;;AAEA;;;AAGE;;AAEA;;AAEA;;AAEA;AACA;;;;AAIA;;AAEE;AACA;;AAEF;AACE;;AAEA;AACA;AACA;;;;;;;AAOA;;AAEA;AACA;;;;;AAKN;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACE;;AAEA;AACE;;AAEA;;AAEA;AACD;;AAMD;AACF;;AAEA;;AAEE;AACE;AACF;;AAEA;;;AAGE;;AAEA;AACA;AACA;;AAEA;;;;;;;;AAQJ;;AAEA;AACA;;AAEO;AACL;AACA;AACA;;AAEF;AACE;;AAEA;;;;;;;AAOE;AACJ;AACA;;AAEA;AACA;AACA;AACA;;AAEO;;AAEL;;;;;AAKF;;;AAGE;;AAEF;;;AAGE;;AAEF;AACE;;;AAGA;;AAEF;;AAEA;;AAEA;AACA;;AAEO;;;;AAIP;;AAEM;;AAEJ;;;;AAIA;;;AAGF;;AAEA;;;AAGA;;AAEO;;;;AAIP;;AAEM;;AAEJ;;;AAGF;;AAEA;AACA;;;AAGA;;AAEO;AACL;AACE;AACF;;;AAGF;AACI;AACF;AACA;AACF;;AAEA;;;AAGA;;AAEO;AACL;;AAEA;;AAEI;AACF;;;;AAIE;;;;AAIE;AACF;;;;;AAKA;AACE;AACF;AACF;AACJ;;;AAGA;;AAEA;AACA;;;AAGO;AACL;AACA;AACA;AACF;AACE;AACE;AACA;;AAEA;;AAEJ;;AAEA;AACA;;AAEO;;AAEL;AACA;AACA;AACF;;AAEI;;;AAGF;;AAEF;AACA;;AAEA;;AAEA;AACA;AACA;;;AAGO;AACL;AACA;AACE;AACF;;AAEA;;AAEA;AACE;AACF;;;AAGA;AACA;;;AAGE;AACA;AACF;;AAEF;AACE;AACE;;AAEA;AACA;;;;;AAKA;;AAEA;AACE;AACA;;AAEA;AACE;;AAEF;AACF;AACA;;;AAGF;;AAEA;AACE;;AAEI;AACA;AACA;AACR;AACI;AACF;;;AAGF;;AChdO;;AAEP;AACA;AACA;;AAEO;AACL;;AAEA;AACF;AACA;AACA;;;AAGI;AACF;;AAEF;;AAEI;AACA;AACF;;AAEA;;AAEE;AACA;AACF;;AAEA;;;AAGF;AACE;;AAEF;;;AAGI;;AAEE;AACA;;;;;;AAMN;AACE;;AAEF;;AAEE;AACE;AACA;AACF;;;;;;AAMM;AACE;AACV;AACA;AACA;;AAES;AACA;;AAEA;AACA;AACA;AACA;;;;AAIA;AACA;;;AAGA;AACA;;;;;;AAMA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;;;AAKA;;;;AAIA;AACA;;;AAGA;;;;;AAKA;;AC3DiB;AACxB;AACA;AACF;;ACpDA;AACA;AACA;;AAEA;AACE;AACF;;AAEA;AACE;AACA;;AAEF;;AAEA;AACA;;;AAGA;AACE;;;;AAII;AACF;;AAEA;;AAEA;AACE;AACN;;;AAGQ;;AAEF;;;AAGE;AACF;;;AAGA;;;;AAIE;;AAEE;AACF;;;AAGR;AACM;;;AAGA;AACF;AACJ;;;AAGI;;AAEA;AACE;;;AAGE;AACF;AACA;;;AAGE;AACF;AACF;AACJ;;AAEE;;AAEE;AACE;AACF;;AAEA;AACA;AACE;AACF;;AAEA;;;;AAIE;;AAEA;AACE;AACF;;AAEN;AACM;;AAEA;;;AAGA;AACE;AACgG;AACA;;AAEA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;;AAGA;AACA;;AAOA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AAMA;;;;AAIA;AACA;AACA;;AAEA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;AAMA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;;AAGA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;;;AAIA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;;;;;AAKA;AACA;AACA;;AAEA;;;;;AAKA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;;;AAIA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;;AAEA;AACA;;AAEA;;AAEA;;;;;AAKA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;;;AAIA;AACA;AACA;;;AAGA;;AAEA;;;AAGA;;AAEA;AACA;;AAMA;AACA;;;AAGA;;;;;AAKA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;;AAGA;;AAEA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;;;AAGA;;"}
@@ -0,0 +1,14 @@
1
+ import type { Carrier } from './../carrier';
2
+ import type { AsyncContextStrategy } from './types';
3
+ /**
4
+ * @private Private API with no semver guarantees!
5
+ *
6
+ * Sets the global async context strategy
7
+ */
8
+ export declare function setAsyncContextStrategy(strategy: AsyncContextStrategy | undefined): void;
9
+ /**
10
+ * Get the current async context strategy.
11
+ * If none has been setup, the default will be used.
12
+ */
13
+ export declare function getAsyncContextStrategy(carrier: Carrier): AsyncContextStrategy;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../core/src/asyncContext/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GAAG,IAAI,CAKxF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,CAS9E"}
@@ -0,0 +1,52 @@
1
+ import type { Client, Scope as ScopeInterface } from '@sentry/types';
2
+ import type { AsyncContextStrategy } from './types';
3
+ interface Layer {
4
+ client?: Client;
5
+ scope: ScopeInterface;
6
+ }
7
+ /**
8
+ * This is an object that holds a stack of scopes.
9
+ */
10
+ export declare class AsyncContextStack {
11
+ private readonly _stack;
12
+ private _isolationScope;
13
+ constructor(scope?: ScopeInterface, isolationScope?: ScopeInterface);
14
+ /**
15
+ * Fork a scope for the stack.
16
+ */
17
+ withScope<T>(callback: (scope: ScopeInterface) => T): T;
18
+ /**
19
+ * Get the client of the stack.
20
+ */
21
+ getClient<C extends Client>(): C | undefined;
22
+ /**
23
+ * Returns the scope of the top stack.
24
+ */
25
+ getScope(): ScopeInterface;
26
+ /**
27
+ * Get the isolation scope for the stack.
28
+ */
29
+ getIsolationScope(): ScopeInterface;
30
+ /**
31
+ * Returns the scope stack for domains or the process.
32
+ */
33
+ getStack(): Layer[];
34
+ /**
35
+ * Returns the topmost scope layer in the order domain > local > process.
36
+ */
37
+ getStackTop(): Layer;
38
+ /**
39
+ * Push a scope to the stack.
40
+ */
41
+ private _pushScope;
42
+ /**
43
+ * Pop a scope from the stack.
44
+ */
45
+ private _popScope;
46
+ }
47
+ /**
48
+ * Get the stack-based async context strategy.
49
+ */
50
+ export declare function getStackAsyncContextStrategy(): AsyncContextStrategy;
51
+ export {};
52
+ //# sourceMappingURL=stackStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackStrategy.d.ts","sourceRoot":"","sources":["../../../../../../core/src/asyncContext/stackStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAMrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,cAAc,CAAC;CACvB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,eAAe,CAAiB;gBAErB,KAAK,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,cAAc;IAmB1E;;OAEG;IACI,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,CAAC,GAAG,CAAC;IA6B9D;;OAEG;IACI,SAAS,CAAC,CAAC,SAAS,MAAM,KAAK,CAAC,GAAG,SAAS;IAInD;;OAEG;IACI,QAAQ,IAAI,cAAc;IAIjC;;OAEG;IACI,iBAAiB,IAAI,cAAc;IAI1C;;OAEG;IACI,QAAQ,IAAI,KAAK,EAAE;IAI1B;;OAEG;IACI,WAAW,IAAI,KAAK;IAI3B;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACH,OAAO,CAAC,SAAS;CAIlB;AA+BD;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,oBAAoB,CAWnE"}
@@ -0,0 +1,47 @@
1
+ import type { Scope } from '@sentry/types';
2
+ import type { startInactiveSpan, startSpan, startSpanManual, suppressTracing, withActiveSpan } from './../tracing/trace';
3
+ import type { getActiveSpan } from './../utils/spanUtils';
4
+ /**
5
+ * @private Private API with no semver guarantees!
6
+ *
7
+ * Strategy used to track async context.
8
+ */
9
+ export interface AsyncContextStrategy {
10
+ /**
11
+ * Fork the isolation scope inside of the provided callback.
12
+ */
13
+ withIsolationScope: <T>(callback: (isolationScope: Scope) => T) => T;
14
+ /**
15
+ * Fork the current scope inside of the provided callback.
16
+ */
17
+ withScope: <T>(callback: (isolationScope: Scope) => T) => T;
18
+ /**
19
+ * Set the provided scope as the current scope inside of the provided callback.
20
+ */
21
+ withSetScope: <T>(scope: Scope, callback: (scope: Scope) => T) => T;
22
+ /**
23
+ * Set the provided isolation as the current isolation scope inside of the provided callback.
24
+ */
25
+ withSetIsolationScope: <T>(isolationScope: Scope, callback: (isolationScope: Scope) => T) => T;
26
+ /**
27
+ * Get the currently active scope.
28
+ */
29
+ getCurrentScope: () => Scope;
30
+ /**
31
+ * Get the currently active isolation scope.
32
+ */
33
+ getIsolationScope: () => Scope;
34
+ /** Start an active span. */
35
+ startSpan?: typeof startSpan;
36
+ /** Start an inactive span. */
37
+ startInactiveSpan?: typeof startInactiveSpan;
38
+ /** Start an active manual span. */
39
+ startSpanManual?: typeof startSpanManual;
40
+ /** Get the currently active span. */
41
+ getActiveSpan?: typeof getActiveSpan;
42
+ /** Make a span the active span in the context of the callback. */
43
+ withActiveSpan?: typeof withActiveSpan;
44
+ /** Suppress tracing in the given callback, ensuring no spans are generated inside of it. */
45
+ suppressTracing?: typeof suppressTracing;
46
+ }
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../core/src/asyncContext/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EACV,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,eAAe,EACf,cAAc,EACf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,kBAAkB,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC;IAErE;;OAEG;IACH,SAAS,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC;IAE5D;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC;IAEpE;;OAEG;IACH,qBAAqB,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC;IAE/F;;OAEG;IACH,eAAe,EAAE,MAAM,KAAK,CAAC;IAE7B;;OAEG;IACH,iBAAiB,EAAE,MAAM,KAAK,CAAC;IAK/B,4BAA4B;IAC5B,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAE7B,8BAA8B;IAC9B,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;IAE7C,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;IAEzC,qCAAqC;IACrC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;IAErC,kEAAkE;IAClE,cAAc,CAAC,EAAE,OAAO,cAAc,CAAC;IAEvC,6FAA6F;IAC7F,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;CAC1C"}
@@ -0,0 +1,37 @@
1
+ import type { Client, Integration, MetricsAggregator, Scope } from '@sentry/types';
2
+ import type { AsyncContextStack } from './asyncContext/stackStrategy';
3
+ import type { AsyncContextStrategy } from './asyncContext/types';
4
+ /**
5
+ * An object that contains globally accessible properties and maintains a scope stack.
6
+ * @hidden
7
+ */
8
+ export interface Carrier {
9
+ __SENTRY__?: VersionedCarrier;
10
+ }
11
+ type VersionedCarrier = {
12
+ version?: string;
13
+ } & Record<Exclude<string, 'version'>, SentryCarrier>;
14
+ interface SentryCarrier {
15
+ acs?: AsyncContextStrategy;
16
+ stack?: AsyncContextStack;
17
+ globalScope?: Scope;
18
+ defaultIsolationScope?: Scope;
19
+ defaultCurrentScope?: Scope;
20
+ globalMetricsAggregators?: WeakMap<Client, MetricsAggregator> | undefined;
21
+ integrations?: Integration[];
22
+ extensions?: {
23
+ [key: string]: Function;
24
+ };
25
+ }
26
+ /**
27
+ * Returns the global shim registry.
28
+ *
29
+ * FIXME: This function is problematic, because despite always returning a valid Carrier,
30
+ * it has an optional `__SENTRY__` property, which then in turn requires us to always perform an unnecessary check
31
+ * at the call-site. We always access the carrier through this function, so we can guarantee that `__SENTRY__` is there.
32
+ **/
33
+ export declare function getMainCarrier(): Carrier;
34
+ /** Will either get the existing sentry carrier, or create a new one. */
35
+ export declare function getSentryCarrier(carrier: Carrier): SentryCarrier;
36
+ export {};
37
+ //# sourceMappingURL=carrier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carrier.d.ts","sourceRoot":"","sources":["../../../../../core/src/carrier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEnF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,aAAa,CAAC,CAAC;AAEtD,UAAU,aAAa;IACrB,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAC3B,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAE1B,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,qBAAqB,CAAC,EAAE,KAAK,CAAC;IAC9B,mBAAmB,CAAC,EAAE,KAAK,CAAC;IAC5B,wBAAwB,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAG1E,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE;QAEX,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;KACzB,CAAC;CACH;AAED;;;;;;IAMI;AACJ,wBAAgB,cAAc,IAAI,OAAO,CAIxC;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAShE"}
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_ENVIRONMENT = "production";
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../core/src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,eAAe,CAAC"}