@sentry/browser 11.4.0 → 11.6.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 (39) hide show
  1. package/build/npm/cjs/dev/client.js +34 -10
  2. package/build/npm/cjs/dev/client.js.map +1 -1
  3. package/build/npm/cjs/dev/integrations/fetchStreamPerformance.js +1 -1
  4. package/build/npm/cjs/dev/integrations/fetchStreamPerformance.js.map +1 -1
  5. package/build/npm/cjs/dev/profiling/utils.js +1 -4
  6. package/build/npm/cjs/dev/profiling/utils.js.map +1 -1
  7. package/build/npm/cjs/dev/tracing/request.js +1 -1
  8. package/build/npm/cjs/dev/tracing/request.js.map +1 -1
  9. package/build/npm/cjs/prod/client.js +34 -10
  10. package/build/npm/cjs/prod/client.js.map +1 -1
  11. package/build/npm/cjs/prod/integrations/fetchStreamPerformance.js +1 -1
  12. package/build/npm/cjs/prod/integrations/fetchStreamPerformance.js.map +1 -1
  13. package/build/npm/cjs/prod/profiling/utils.js +1 -4
  14. package/build/npm/cjs/prod/profiling/utils.js.map +1 -1
  15. package/build/npm/cjs/prod/tracing/request.js +1 -1
  16. package/build/npm/cjs/prod/tracing/request.js.map +1 -1
  17. package/build/npm/esm/dev/client.js +35 -11
  18. package/build/npm/esm/dev/client.js.map +1 -1
  19. package/build/npm/esm/dev/integrations/fetchStreamPerformance.js +3 -3
  20. package/build/npm/esm/dev/integrations/fetchStreamPerformance.js.map +1 -1
  21. package/build/npm/esm/dev/package.json +1 -1
  22. package/build/npm/esm/dev/profiling/utils.js +2 -5
  23. package/build/npm/esm/dev/profiling/utils.js.map +1 -1
  24. package/build/npm/esm/dev/tracing/request.js +3 -3
  25. package/build/npm/esm/dev/tracing/request.js.map +1 -1
  26. package/build/npm/esm/prod/client.js +35 -11
  27. package/build/npm/esm/prod/client.js.map +1 -1
  28. package/build/npm/esm/prod/integrations/fetchStreamPerformance.js +3 -3
  29. package/build/npm/esm/prod/integrations/fetchStreamPerformance.js.map +1 -1
  30. package/build/npm/esm/prod/package.json +1 -1
  31. package/build/npm/esm/prod/profiling/utils.js +2 -5
  32. package/build/npm/esm/prod/profiling/utils.js.map +1 -1
  33. package/build/npm/esm/prod/tracing/request.js +3 -3
  34. package/build/npm/esm/prod/tracing/request.js.map +1 -1
  35. package/build/npm/types/client.d.ts.map +1 -1
  36. package/build/npm/types/exports.d.ts.map +1 -1
  37. package/build/npm/types/integrations/fetchStreamPerformance.d.ts.map +1 -1
  38. package/build/npm/types/profiling/utils.d.ts.map +1 -1
  39. package/package.json +8 -8
@@ -95,16 +95,13 @@ function convertToContinuousProfile(input) {
95
95
  }
96
96
  stacks[i] = list;
97
97
  }
98
- const perfOrigin = core.browserPerformanceTimeOrigin();
99
- const origin = typeof performance.timeOrigin === "number" ? performance.timeOrigin : perfOrigin || 0;
100
- const adjustForOriginChange = origin - (perfOrigin || origin);
101
98
  const samples = [];
102
99
  for (let i = 0; i < input.samples.length; i++) {
103
100
  const sample = input.samples[i];
104
101
  if (!sample) {
105
102
  continue;
106
103
  }
107
- const timestampSeconds = (origin + (sample.timestamp - adjustForOriginChange)) / 1e3;
104
+ const timestampSeconds = core._INTERNAL_performanceTimeToSeconds(sample.timestamp);
108
105
  samples[i] = {
109
106
  stack_id: sample.stackId ?? 0,
110
107
  thread_id: PROFILER_THREAD_ID_STRING,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../../src/profiling/utils.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, ContinuousThreadCpuProfile, DebugImage, ProfileChunk, Span } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getClient,\n getDebugImagesForResources,\n GLOBAL_OBJ,\n uuid4,\n} from '@sentry/core';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport type { JSSelfProfile, JSSelfProfiler, JSSelfProfilerConstructor } from './jsSelfProfiling';\n\n// Checking if we are in Main or Worker thread: `self` (not `window`) is the `globalThis` in Web Workers and `importScripts` are only available in Web Workers\nconst isMainThread = 'window' in GLOBAL_OBJ && GLOBAL_OBJ.window === GLOBAL_OBJ && typeof importScripts === 'undefined';\n\n// Setting ID to 0 as we cannot get an ID from Web Workers\nexport const PROFILER_THREAD_ID_STRING = String(0);\nexport const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker';\n\n/**\n * Create a profile chunk envelope item\n */\nexport function createProfileChunkPayload(\n jsSelfProfile: JSSelfProfile,\n client: Client,\n profilerId?: string,\n): ProfileChunk {\n // only == to catch null and undefined\n if (jsSelfProfile == null) {\n throw new TypeError(\n `Cannot construct profiling event envelope without a valid profile. Got ${jsSelfProfile} instead.`,\n );\n }\n\n const continuousProfile = convertToContinuousProfile(jsSelfProfile);\n\n const options = client.getOptions();\n const sdk = client.getSdkMetadata?.()?.sdk;\n\n return {\n chunk_id: uuid4(),\n client_sdk: {\n name: sdk?.name ?? 'sentry.javascript.browser',\n version: sdk?.version ?? '0.0.0',\n },\n profiler_id: profilerId || uuid4(),\n platform: 'javascript',\n version: '2',\n release: options.release ?? '',\n environment: options.environment ?? 'production',\n debug_meta: {\n // function name obfuscation\n images: applyDebugMetadata(jsSelfProfile.resources),\n },\n profile: continuousProfile,\n };\n}\n\n/**\n * Validate a profile chunk against the Sample Format V2 requirements.\n * https://develop.sentry.dev/sdk/telemetry/profiles/sample-format-v2/\n * - Presence of samples, stacks, frames\n * - Required metadata fields\n */\nexport function validateProfileChunk(chunk: ProfileChunk): { valid: true } | { reason: string } {\n try {\n // Required metadata\n if (!chunk || typeof chunk !== 'object') {\n return { reason: 'chunk is not an object' };\n }\n\n // profiler_id and chunk_id must be 32 lowercase hex chars\n const isHex32 = (val: unknown): boolean => typeof val === 'string' && /^[a-f0-9]{32}$/.test(val);\n if (!isHex32(chunk.profiler_id)) {\n return { reason: 'missing or invalid profiler_id' };\n }\n if (!isHex32(chunk.chunk_id)) {\n return { reason: 'missing or invalid chunk_id' };\n }\n\n if (!chunk.client_sdk) {\n return { reason: 'missing client_sdk metadata' };\n }\n\n // Profile data must have frames, stacks, samples\n const profile = chunk.profile as { frames?: unknown[]; stacks?: unknown[]; samples?: unknown[] } | undefined;\n if (!profile) {\n return { reason: 'missing profile data' };\n }\n\n if (!Array.isArray(profile.frames) || !profile.frames.length) {\n return { reason: 'profile has no frames' };\n }\n if (!Array.isArray(profile.stacks) || !profile.stacks.length) {\n return { reason: 'profile has no stacks' };\n }\n if (!Array.isArray(profile.samples) || !profile.samples.length) {\n return { reason: 'profile has no samples' };\n }\n\n return { valid: true };\n } catch (e) {\n return { reason: `unknown validation error: ${e}` };\n }\n}\n\n/**\n * Convert from JSSelfProfile format to ContinuousThreadCpuProfile format.\n */\nfunction convertToContinuousProfile(input: {\n frames: { name: string; resourceId?: number; line?: number; column?: number }[];\n stacks: { frameId: number; parentId?: number }[];\n samples: { timestamp: number; stackId?: number }[];\n resources: string[];\n}): ContinuousThreadCpuProfile {\n // Frames map 1:1 by index; fill only when present to avoid sparse writes\n const frames: ContinuousThreadCpuProfile['frames'] = [];\n for (let i = 0; i < input.frames.length; i++) {\n const frame = input.frames[i];\n if (!frame) {\n continue;\n }\n frames[i] = {\n function: frame.name,\n abs_path: typeof frame.resourceId === 'number' ? input.resources[frame.resourceId] : undefined,\n lineno: frame.line,\n colno: frame.column,\n };\n }\n\n // Build stacks by following parent links, top->down order (root last)\n const stacks: ContinuousThreadCpuProfile['stacks'] = [];\n for (let i = 0; i < input.stacks.length; i++) {\n const stackHead = input.stacks[i];\n if (!stackHead) {\n continue;\n }\n const list: number[] = [];\n let current: { frameId: number; parentId?: number } | undefined = stackHead;\n while (current) {\n list.push(current.frameId);\n current = current.parentId === undefined ? undefined : input.stacks[current.parentId];\n }\n stacks[i] = list;\n }\n\n // Align timestamps to SDK time origin to match span/event timelines\n const perfOrigin = browserPerformanceTimeOrigin();\n const origin = typeof performance.timeOrigin === 'number' ? performance.timeOrigin : perfOrigin || 0;\n const adjustForOriginChange = origin - (perfOrigin || origin);\n\n const samples: ContinuousThreadCpuProfile['samples'] = [];\n for (let i = 0; i < input.samples.length; i++) {\n const sample = input.samples[i];\n if (!sample) {\n continue;\n }\n // Convert ms to seconds epoch-based timestamp\n const timestampSeconds = (origin + (sample.timestamp - adjustForOriginChange)) / 1000;\n samples[i] = {\n stack_id: sample.stackId ?? 0,\n thread_id: PROFILER_THREAD_ID_STRING,\n timestamp: timestampSeconds,\n };\n }\n\n return {\n frames,\n stacks,\n samples,\n thread_metadata: { [PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME } },\n };\n}\n\n/**\n * Applies debug meta data to an event from a list of paths to resources (sourcemaps)\n */\nexport function applyDebugMetadata(resource_paths: ReadonlyArray<string>): DebugImage[] {\n const client = getClient();\n const options = client?.getOptions();\n const stackParser = options?.stackParser;\n\n if (!stackParser) {\n return [];\n }\n\n return getDebugImagesForResources(stackParser, resource_paths);\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 */\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 debug.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 && debug.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// Keep a flag value to avoid re-initializing the profiler constructor. If it fails\n// once, it will always fail and this allows us to early return.\nlet PROFILING_CONSTRUCTOR_FAILED: boolean = false;\nexport const MAX_PROFILE_DURATION_MS = 30_000;\n\n/**\n * Check if profiler constructor is available.\n * @param maybeProfiler\n */\nfunction isJSProfilerSupported(maybeProfiler: unknown): maybeProfiler is typeof JSSelfProfilerConstructor {\n return typeof maybeProfiler === 'function';\n}\n\n/**\n * Starts the profiler and returns the profiler instance.\n */\nexport function startJSSelfProfile(): JSSelfProfiler | undefined {\n // Feature support check first\n const JSProfilerConstructor = WINDOW.Profiler;\n\n if (!isJSProfilerSupported(JSProfilerConstructor)) {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.');\n }\n return;\n }\n\n // From initial testing, it seems that the minimum value for sampleInterval is 10ms.\n const samplingIntervalMS = 10;\n // Start the profiler\n const maxSamples = Math.floor(MAX_PROFILE_DURATION_MS / samplingIntervalMS);\n\n // Attempt to initialize the profiler constructor, if it fails, we disable profiling for the current user session.\n // This is likely due to a missing 'Document-Policy': 'js-profiling' header. We do not want to throw an error if this happens\n // as we risk breaking the user's application, so just disable profiling and log an error.\n try {\n return new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples });\n } catch {\n if (DEBUG_BUILD) {\n debug.log(\n \"[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.\",\n );\n debug.log('[Profiling] Disabling profiling for current user session.');\n }\n PROFILING_CONSTRUCTOR_FAILED = true;\n }\n\n return;\n}\n\n/**\n * Determine if a profile should be created for the current session.\n */\nexport function shouldProfileSession(options: BrowserOptions): boolean {\n // If constructor failed once, it will always fail, so we can early return.\n if (PROFILING_CONSTRUCTOR_FAILED) {\n if (DEBUG_BUILD) {\n debug.log(\n '[Profiling] Profiling has been disabled for the duration of the current user session as the JS Profiler could not be started.',\n );\n }\n return false;\n }\n\n if (options.profileLifecycle !== 'trace' && options.profileLifecycle !== 'manual') {\n DEBUG_BUILD && debug.warn('[Profiling] Session not sampled. Invalid `profileLifecycle` option.');\n return false;\n }\n\n // Session sampling: profileSessionSampleRate gates whether profiling is enabled for this session\n const profileSessionSampleRate = options.profileSessionSampleRate;\n\n if (!isValidSampleRate(profileSessionSampleRate)) {\n DEBUG_BUILD && debug.warn('[Profiling] Discarding profile because of invalid profileSessionSampleRate.');\n return false;\n }\n\n if (!profileSessionSampleRate) {\n DEBUG_BUILD &&\n debug.log('[Profiling] Discarding profile because profileSessionSampleRate is not defined or set to 0');\n return false;\n }\n\n return Math.random() <= profileSessionSampleRate;\n}\n\nexport function setThreadAttributes(span: Span): void {\n span.setAttribute('thread.id', PROFILER_THREAD_ID_STRING);\n span.setAttribute('thread.name', PROFILER_THREAD_NAME);\n}\n"],"names":["GLOBAL_OBJ","uuid4","browserPerformanceTimeOrigin","getClient","getDebugImagesForResources","DEBUG_BUILD","debug","WINDOW"],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../../src/profiling/utils.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, ContinuousThreadCpuProfile, DebugImage, ProfileChunk, Span } from '@sentry/core';\nimport {\n debug,\n getClient,\n getDebugImagesForResources,\n GLOBAL_OBJ,\n _INTERNAL_performanceTimeToSeconds,\n uuid4,\n} from '@sentry/core';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport type { JSSelfProfile, JSSelfProfiler, JSSelfProfilerConstructor } from './jsSelfProfiling';\n\n// Checking if we are in Main or Worker thread: `self` (not `window`) is the `globalThis` in Web Workers and `importScripts` are only available in Web Workers\nconst isMainThread = 'window' in GLOBAL_OBJ && GLOBAL_OBJ.window === GLOBAL_OBJ && typeof importScripts === 'undefined';\n\n// Setting ID to 0 as we cannot get an ID from Web Workers\nexport const PROFILER_THREAD_ID_STRING = String(0);\nexport const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker';\n\n/**\n * Create a profile chunk envelope item\n */\nexport function createProfileChunkPayload(\n jsSelfProfile: JSSelfProfile,\n client: Client,\n profilerId?: string,\n): ProfileChunk {\n // only == to catch null and undefined\n if (jsSelfProfile == null) {\n throw new TypeError(\n `Cannot construct profiling event envelope without a valid profile. Got ${jsSelfProfile} instead.`,\n );\n }\n\n const continuousProfile = convertToContinuousProfile(jsSelfProfile);\n\n const options = client.getOptions();\n const sdk = client.getSdkMetadata?.()?.sdk;\n\n return {\n chunk_id: uuid4(),\n client_sdk: {\n name: sdk?.name ?? 'sentry.javascript.browser',\n version: sdk?.version ?? '0.0.0',\n },\n profiler_id: profilerId || uuid4(),\n platform: 'javascript',\n version: '2',\n release: options.release ?? '',\n environment: options.environment ?? 'production',\n debug_meta: {\n // function name obfuscation\n images: applyDebugMetadata(jsSelfProfile.resources),\n },\n profile: continuousProfile,\n };\n}\n\n/**\n * Validate a profile chunk against the Sample Format V2 requirements.\n * https://develop.sentry.dev/sdk/telemetry/profiles/sample-format-v2/\n * - Presence of samples, stacks, frames\n * - Required metadata fields\n */\nexport function validateProfileChunk(chunk: ProfileChunk): { valid: true } | { reason: string } {\n try {\n // Required metadata\n if (!chunk || typeof chunk !== 'object') {\n return { reason: 'chunk is not an object' };\n }\n\n // profiler_id and chunk_id must be 32 lowercase hex chars\n const isHex32 = (val: unknown): boolean => typeof val === 'string' && /^[a-f0-9]{32}$/.test(val);\n if (!isHex32(chunk.profiler_id)) {\n return { reason: 'missing or invalid profiler_id' };\n }\n if (!isHex32(chunk.chunk_id)) {\n return { reason: 'missing or invalid chunk_id' };\n }\n\n if (!chunk.client_sdk) {\n return { reason: 'missing client_sdk metadata' };\n }\n\n // Profile data must have frames, stacks, samples\n const profile = chunk.profile as { frames?: unknown[]; stacks?: unknown[]; samples?: unknown[] } | undefined;\n if (!profile) {\n return { reason: 'missing profile data' };\n }\n\n if (!Array.isArray(profile.frames) || !profile.frames.length) {\n return { reason: 'profile has no frames' };\n }\n if (!Array.isArray(profile.stacks) || !profile.stacks.length) {\n return { reason: 'profile has no stacks' };\n }\n if (!Array.isArray(profile.samples) || !profile.samples.length) {\n return { reason: 'profile has no samples' };\n }\n\n return { valid: true };\n } catch (e) {\n return { reason: `unknown validation error: ${e}` };\n }\n}\n\n/**\n * Convert from JSSelfProfile format to ContinuousThreadCpuProfile format.\n */\nfunction convertToContinuousProfile(input: {\n frames: { name: string; resourceId?: number; line?: number; column?: number }[];\n stacks: { frameId: number; parentId?: number }[];\n samples: { timestamp: number; stackId?: number }[];\n resources: string[];\n}): ContinuousThreadCpuProfile {\n // Frames map 1:1 by index; fill only when present to avoid sparse writes\n const frames: ContinuousThreadCpuProfile['frames'] = [];\n for (let i = 0; i < input.frames.length; i++) {\n const frame = input.frames[i];\n if (!frame) {\n continue;\n }\n frames[i] = {\n function: frame.name,\n abs_path: typeof frame.resourceId === 'number' ? input.resources[frame.resourceId] : undefined,\n lineno: frame.line,\n colno: frame.column,\n };\n }\n\n // Build stacks by following parent links, top->down order (root last)\n const stacks: ContinuousThreadCpuProfile['stacks'] = [];\n for (let i = 0; i < input.stacks.length; i++) {\n const stackHead = input.stacks[i];\n if (!stackHead) {\n continue;\n }\n const list: number[] = [];\n let current: { frameId: number; parentId?: number } | undefined = stackHead;\n while (current) {\n list.push(current.frameId);\n current = current.parentId === undefined ? undefined : input.stacks[current.parentId];\n }\n stacks[i] = list;\n }\n\n const samples: ContinuousThreadCpuProfile['samples'] = [];\n for (let i = 0; i < input.samples.length; i++) {\n const sample = input.samples[i];\n if (!sample) {\n continue;\n }\n // Sample timestamps are relative to `performance.timeOrigin`, so we convert them like performance entries.\n // The cast is safe: the JS Self-Profiling API only exists if the Performance API does.\n const timestampSeconds = _INTERNAL_performanceTimeToSeconds(sample.timestamp) as number;\n samples[i] = {\n stack_id: sample.stackId ?? 0,\n thread_id: PROFILER_THREAD_ID_STRING,\n timestamp: timestampSeconds,\n };\n }\n\n return {\n frames,\n stacks,\n samples,\n thread_metadata: { [PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME } },\n };\n}\n\n/**\n * Applies debug meta data to an event from a list of paths to resources (sourcemaps)\n */\nexport function applyDebugMetadata(resource_paths: ReadonlyArray<string>): DebugImage[] {\n const client = getClient();\n const options = client?.getOptions();\n const stackParser = options?.stackParser;\n\n if (!stackParser) {\n return [];\n }\n\n return getDebugImagesForResources(stackParser, resource_paths);\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 */\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 debug.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 && debug.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// Keep a flag value to avoid re-initializing the profiler constructor. If it fails\n// once, it will always fail and this allows us to early return.\nlet PROFILING_CONSTRUCTOR_FAILED: boolean = false;\nexport const MAX_PROFILE_DURATION_MS = 30_000;\n\n/**\n * Check if profiler constructor is available.\n * @param maybeProfiler\n */\nfunction isJSProfilerSupported(maybeProfiler: unknown): maybeProfiler is typeof JSSelfProfilerConstructor {\n return typeof maybeProfiler === 'function';\n}\n\n/**\n * Starts the profiler and returns the profiler instance.\n */\nexport function startJSSelfProfile(): JSSelfProfiler | undefined {\n // Feature support check first\n const JSProfilerConstructor = WINDOW.Profiler;\n\n if (!isJSProfilerSupported(JSProfilerConstructor)) {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.');\n }\n return;\n }\n\n // From initial testing, it seems that the minimum value for sampleInterval is 10ms.\n const samplingIntervalMS = 10;\n // Start the profiler\n const maxSamples = Math.floor(MAX_PROFILE_DURATION_MS / samplingIntervalMS);\n\n // Attempt to initialize the profiler constructor, if it fails, we disable profiling for the current user session.\n // This is likely due to a missing 'Document-Policy': 'js-profiling' header. We do not want to throw an error if this happens\n // as we risk breaking the user's application, so just disable profiling and log an error.\n try {\n return new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples });\n } catch {\n if (DEBUG_BUILD) {\n debug.log(\n \"[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.\",\n );\n debug.log('[Profiling] Disabling profiling for current user session.');\n }\n PROFILING_CONSTRUCTOR_FAILED = true;\n }\n\n return;\n}\n\n/**\n * Determine if a profile should be created for the current session.\n */\nexport function shouldProfileSession(options: BrowserOptions): boolean {\n // If constructor failed once, it will always fail, so we can early return.\n if (PROFILING_CONSTRUCTOR_FAILED) {\n if (DEBUG_BUILD) {\n debug.log(\n '[Profiling] Profiling has been disabled for the duration of the current user session as the JS Profiler could not be started.',\n );\n }\n return false;\n }\n\n if (options.profileLifecycle !== 'trace' && options.profileLifecycle !== 'manual') {\n DEBUG_BUILD && debug.warn('[Profiling] Session not sampled. Invalid `profileLifecycle` option.');\n return false;\n }\n\n // Session sampling: profileSessionSampleRate gates whether profiling is enabled for this session\n const profileSessionSampleRate = options.profileSessionSampleRate;\n\n if (!isValidSampleRate(profileSessionSampleRate)) {\n DEBUG_BUILD && debug.warn('[Profiling] Discarding profile because of invalid profileSessionSampleRate.');\n return false;\n }\n\n if (!profileSessionSampleRate) {\n DEBUG_BUILD &&\n debug.log('[Profiling] Discarding profile because profileSessionSampleRate is not defined or set to 0');\n return false;\n }\n\n return Math.random() <= profileSessionSampleRate;\n}\n\nexport function setThreadAttributes(span: Span): void {\n span.setAttribute('thread.id', PROFILER_THREAD_ID_STRING);\n span.setAttribute('thread.name', PROFILER_THREAD_NAME);\n}\n"],"names":["GLOBAL_OBJ","uuid4","_INTERNAL_performanceTimeToSeconds","getClient","getDebugImagesForResources","DEBUG_BUILD","debug","WINDOW"],"mappings":"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"}
@@ -178,7 +178,7 @@ function xhrCallback(handlerData, shouldCreateSpan, shouldAttachHeaders2, spans,
178
178
  [attributes.URL_FULL]: core.filterCollectedUrl(sanitizedFullUrl),
179
179
  [attributes.SERVER_ADDRESS]: host,
180
180
  [attributes.URL_DOMAIN]: domain,
181
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser",
181
+ [attributes.SENTRY_ORIGIN]: "auto.http.browser",
182
182
  [attributes.SENTRY_OP]: op.HTTP_CLIENT,
183
183
  [attributes.URL_QUERY]: core.filterCollectedUrlQuery(core.getUrlQuery(parsedUrl?.search)),
184
184
  [attributes.URL_FRAGMENT]: core.getUrlFragment(parsedUrl?.hash)
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sources":["../../../../../src/tracing/request.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, RequestHookInfo, ResponseHookInfo, Span, SpanTimeInput } from '@sentry/core';\nimport {\n addFetchInstrumentationHandler,\n getActiveSpan,\n getClient,\n getTraceData,\n getUrlDomain,\n getUrlFragment,\n getUrlQuery,\n hasSpansEnabled,\n hasSpanStreamingEnabled,\n instrumentFetchRequest,\n matchesTracePropagationTargets,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SentryNonRecordingSpan,\n setHttpStatus,\n spanIsIgnored,\n spanToJSON,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport type { HandlerDataXhr, SentryWrappedXMLHttpRequest, XhrHint } from '@sentry/browser-utils';\nimport { filterCollectedUrl, filterCollectedUrlQuery } from '@sentry/core';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n getLocationHref,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/browser-utils';\nimport type { BrowserClient } from '../client';\nimport { WINDOW } from '../helpers';\nimport { baggageHeaderHasSentryValues, createHeadersSafely, getFullURL, isPerformanceResourceTiming } from './utils';\nimport {\n HTTP_REQUEST_METHOD,\n SENTRY_OP,\n SERVER_ADDRESS,\n URL_DOMAIN,\n URL_FRAGMENT,\n URL_FULL,\n URL_QUERY,\n} from '@sentry/conventions/attributes';\nimport { HTTP_CLIENT } from '@sentry/conventions/op';\n\n/** Options for Request Instrumentation */\nexport interface RequestInstrumentationOptions {\n /**\n * List of strings and/or Regular Expressions used to determine which outgoing requests will have `sentry-trace` and `baggage`\n * headers attached.\n *\n * **Default:** If this option is not provided, tracing headers will be attached to all outgoing requests.\n * If you are using a browser SDK, by default, tracing headers will only be attached to outgoing requests to the same origin.\n *\n * **Disclaimer:** Carelessly setting this option in browser environments may result into CORS errors!\n * Only attach tracing headers to requests to the same origin, or to requests to services you can control CORS headers of.\n * Cross-origin requests, meaning requests to a different domain, for example a request to `https://api.example.com/` while you're on `https://example.com/`, take special care.\n * If you are attaching headers to cross-origin requests, make sure the backend handling the request returns a `\"Access-Control-Allow-Headers: sentry-trace, baggage\"` header to ensure your requests aren't blocked.\n *\n * If you provide a `tracePropagationTargets` array, the entries you provide will be matched against the entire URL of the outgoing request.\n * If you are using a browser SDK, the entries will also be matched against the pathname of the outgoing requests.\n * This is so you can have matchers for relative requests, for example, `/^\\/api/` if you want to trace requests to your `/api` routes on the same domain.\n *\n * If any of the two match any of the provided values, tracing headers will be attached to the outgoing request.\n * Both, the string values, and the RegExes you provide in the array will match if they partially match the URL or pathname.\n * Matching is case-insensitive, so `'myApi.com'` and `/^myApi\\.com/` both match a request to `https://myapi.com`.\n *\n * Examples:\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://same-origin.com/api/posts`:\n * - Tracing headers will be attached because the request is sent to the same origin and the regex matches the pathname \"/api/posts\".\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://different-origin.com/api/posts`:\n * - Tracing headers will not be attached because the pathname will only be compared when the request target lives on the same origin.\n * - `tracePropagationTargets: [/^\\/api/, 'https://external-api.com']` and request to `https://external-api.com/v1/data`:\n * - Tracing headers will be attached because the request URL matches the string `'https://external-api.com'`.\n */\n tracePropagationTargets?: Array<string | RegExp>;\n\n /**\n * Flag to disable patching all together for fetch requests.\n *\n * Default: true\n */\n traceFetch: boolean;\n\n /**\n * Flag to disable patching all together for xhr requests.\n *\n * Default: true\n */\n traceXHR: boolean;\n\n /**\n * If true, Sentry will capture http timings and add them to the corresponding http spans.\n *\n * Default: true\n */\n enableHTTPTimings: boolean;\n\n /**\n * This function will be called before creating a span for a request with the given url.\n * Return false if you don't want a span for the given url.\n *\n * Default: (url: string) => true\n */\n shouldCreateSpanForRequest?(this: void, url: string): boolean;\n\n /**\n * Is called when spans are started for outgoing requests.\n */\n onRequestSpanStart?(span: Span, requestInformation: RequestHookInfo): void;\n\n /**\n * Is called when spans end for outgoing requests, providing access to response headers.\n */\n onRequestSpanEnd?(span: Span, responseInformation: ResponseHookInfo): void;\n}\n\nexport const defaultRequestInstrumentationOptions: RequestInstrumentationOptions = {\n traceFetch: true,\n traceXHR: true,\n enableHTTPTimings: true,\n};\n\n/** Registers span creators for xhr and fetch requests */\nexport function instrumentOutgoingRequests(client: Client, _options?: Partial<RequestInstrumentationOptions>): void {\n const {\n traceFetch,\n traceXHR,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n tracePropagationTargets,\n onRequestSpanStart,\n onRequestSpanEnd,\n } = {\n ...defaultRequestInstrumentationOptions,\n ..._options,\n };\n\n const shouldCreateSpan =\n typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_: string) => true;\n\n const shouldAttachHeadersWithTargets = (url: string): boolean => shouldAttachHeaders(url, tracePropagationTargets);\n\n const spans: Record<string, Span> = {};\n\n const propagateTraceparent = (client as BrowserClient).getOptions().propagateTraceparent;\n\n if (traceFetch) {\n addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\n // The generic fetch instrumentation has no page origin to resolve relative URLs against.\n urlBase: WINDOW.location?.origin,\n });\n\n // We cannot use `window.location` in the generic fetch instrumentation,\n // but we need it for reliable `server.address` attribute.\n // so we extend this in here\n if (createdSpan) {\n const fullUrl = getFullURL(handlerData.fetchData.url);\n // `parseUrl` returns the raw authority — userinfo credentials must never reach an attribute.\n const host = fullUrl ? parseUrl(fullUrl).host?.replace(/^.*@/, '') : undefined;\n const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n [URL_FULL]: filterCollectedUrl(sanitizedFullUrl),\n [SERVER_ADDRESS]: host,\n });\n\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan, client);\n }\n\n onRequestSpanStart?.(createdSpan, { headers: handlerData.headers });\n }\n });\n }\n\n if (traceXHR) {\n addXhrInstrumentationHandler(handlerData => {\n const createdSpan = xhrCallback(\n handlerData,\n shouldCreateSpan,\n shouldAttachHeadersWithTargets,\n spans,\n propagateTraceparent,\n onRequestSpanEnd,\n );\n\n if (createdSpan) {\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan, client);\n }\n\n onRequestSpanStart?.(createdSpan, {\n headers: createHeadersSafely(handlerData.xhr.__sentry_xhr_v3__?.request_headers),\n });\n }\n });\n }\n}\n\n/**\n * The maximum time (ms) to wait for PerformanceResourceTiming data before ending the span.\n * Same approach is used by OTel's browser fetch instrumentation:\n * See {@link https://github.com/open-telemetry/opentelemetry-js/blob/30f94fe99339287b1e4d3c8bb90172c2523f06f4/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L352-L372}\n */\nconst HTTP_TIMING_WAIT_MS = 300;\n\n/**\n * Creates a temporary observer to listen to the next fetch/xhr resourcing timings,\n * so that when timings hit their per-browser limit they don't need to be removed.\n *\n * @param span A span that has yet to be finished, must contain `url.full` on data.\n */\nfunction addHTTPTimings(span: Span, client: Client): void {\n const url = spanToJSON(span).attributes[URL_FULL];\n\n if (!url || typeof url !== 'string') {\n return;\n }\n\n // Clean up the performance observer and other resources\n // We have to wait here because otherwise this cleans itself up before it is fully done.\n // Default (non-streaming): just deregister the observer.\n let onEntryFound = (): void => void setTimeout(unsubscribePerformanceObsever);\n\n // For streamed spans, we have to artificially delay the ending of the span until we\n // either receive the timing data, or HTTP_TIMING_WAIT_MS elapses.\n if (hasSpanStreamingEnabled(client)) {\n const originalEnd = span.end.bind(span);\n\n span.end = (endTimestamp?: SpanTimeInput) => {\n const capturedEndTimestamp = endTimestamp ?? timestampInSeconds();\n let isEnded = false;\n\n const endSpanAndCleanup = (): void => {\n if (isEnded) {\n return;\n }\n isEnded = true;\n setTimeout(unsubscribePerformanceObsever);\n originalEnd(capturedEndTimestamp);\n clearTimeout(fallbackTimeout);\n };\n\n onEntryFound = endSpanAndCleanup;\n\n // Fallback: always end the span after HTTP_TIMING_WAIT_MS even if no\n // PerformanceResourceTiming entry arrives (e.g. cross-origin without\n // Timing-Allow-Origin, or the browser didn't fire the observer in time).\n const fallbackTimeout = setTimeout(endSpanAndCleanup, HTTP_TIMING_WAIT_MS);\n };\n }\n\n const unsubscribePerformanceObsever = addPerformanceInstrumentationHandler('resource', ({ entries }) => {\n entries.forEach(entry => {\n if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) {\n span.setAttributes(resourceTimingToSpanAttributes(entry));\n onEntryFound();\n }\n });\n });\n}\n\n/**\n * A function that determines whether to attach tracing headers to a request.\n * We only export this function for testing purposes.\n */\nexport function shouldAttachHeaders(\n targetUrl: string,\n tracePropagationTargets: (string | RegExp)[] | undefined,\n): boolean {\n // window.location.href not being defined is an edge case in the browser but we need to handle it.\n // Potentially dangerous situations where it may not be defined: Browser Extensions, Web Workers, patching of the location obj\n const href = getLocationHref();\n\n if (!href) {\n // If there is no window.location.origin, we default to only attaching tracing headers to relative requests, i.e. ones that start with `/`\n // BIG DISCLAIMER: Users can call URLs with a double slash (fetch(\"//example.com/api\")), this is a shorthand for \"send to the same protocol\",\n // so we need a to exclude those requests, because they might be cross origin.\n const isRelativeSameOriginRequest = !!targetUrl.match(/^\\/(?!\\/)/);\n if (!tracePropagationTargets) {\n return isRelativeSameOriginRequest;\n } else {\n return matchesTracePropagationTargets(targetUrl, tracePropagationTargets);\n }\n } else {\n let resolvedUrl;\n let currentOrigin;\n\n // URL parsing may fail, we default to not attaching trace headers in that case.\n try {\n resolvedUrl = new URL(targetUrl, href);\n currentOrigin = new URL(href).origin;\n } catch {\n return false;\n }\n\n const isSameOriginRequest = resolvedUrl.origin === currentOrigin;\n if (!tracePropagationTargets) {\n return isSameOriginRequest;\n } else {\n return (\n matchesTracePropagationTargets(resolvedUrl.toString(), tracePropagationTargets) ||\n (isSameOriginRequest && matchesTracePropagationTargets(resolvedUrl.pathname, tracePropagationTargets))\n );\n }\n }\n}\n\n/**\n * Create and track xhr request spans\n *\n * @returns Span if a span was created, otherwise void.\n */\n// oxlint-disable-next-line complexity\nfunction xhrCallback(\n handlerData: HandlerDataXhr,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n propagateTraceparent?: boolean,\n onRequestSpanEnd?: RequestInstrumentationOptions['onRequestSpanEnd'],\n): Span | undefined {\n const xhr = handlerData.xhr;\n const sentryXhrData = xhr?.[SENTRY_XHR_DATA_KEY];\n\n if (!xhr || xhr.__sentry_own_request__ || !sentryXhrData) {\n return undefined;\n }\n\n const { url, method } = sentryXhrData;\n\n const shouldCreateSpanResult = hasSpansEnabled() && shouldCreateSpan(url);\n\n // Handle XHR completion - clean up spans from the record\n if (handlerData.endTimestamp) {\n const spanId = xhr.__sentry_xhr_span_id__;\n if (!spanId) return;\n\n const span = spans[spanId];\n\n if (span) {\n if (shouldCreateSpanResult && sentryXhrData.status_code !== undefined) {\n setHttpStatus(span, sentryXhrData.status_code);\n span.end();\n\n onRequestSpanEnd?.(span, {\n headers: createHeadersSafely(parseXhrResponseHeaders(xhr as XMLHttpRequest & SentryWrappedXMLHttpRequest)),\n error: handlerData.error,\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n\n return undefined;\n }\n\n const fullUrl = getFullURL(url);\n const parsedUrl = fullUrl ? parseUrl(fullUrl) : parseUrl(url);\n const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n // `parseUrl` returns the raw authority — userinfo credentials must never reach an attribute.\n const host = parsedUrl?.host?.replace(/^.*@/, '');\n // `getFullURL` already resolved relative URLs against the page origin; only data URLs have no domain.\n const domain = getUrlDomain(fullUrl || url);\n\n // With span streaming, span names have to be low cardinality, so only the domain is kept.\n const streamedName = domain ? `${method} ${domain}` : method;\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: !!client && hasSpanStreamingEnabled(client) ? streamedName : `${method} ${urlForSpanName}`,\n attributes: {\n type: 'xhr',\n // eslint-disable-next-line typescript/no-deprecated\n [HTTP_REQUEST_METHOD]: method,\n [URL_FULL]: filterCollectedUrl(sanitizedFullUrl),\n [SERVER_ADDRESS]: host,\n [URL_DOMAIN]: domain,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',\n [SENTRY_OP]: HTTP_CLIENT,\n [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl?.search)),\n [URL_FRAGMENT]: getUrlFragment(parsedUrl?.hash),\n },\n })\n : new SentryNonRecordingSpan();\n\n // If the span is ignored, we don't want to continue the trace from it (NonRecordingSpan) but rather\n // from the active span. Passing `undefined` here will make `getTraceData` use the active span instead.\n const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? undefined : span;\n\n if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\n\n xhr.__sentry_xhr_span_id__ = span.spanContext().spanId;\n spans[xhr.__sentry_xhr_span_id__] = span;\n\n if (shouldAttachHeaders(url)) {\n addTracingHeadersToXhrRequest(\n xhr,\n // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction),\n // we do not want to use the span as base for the trace headers,\n // which means that the headers will be generated from the scope and the sampling decision is deferred\n hasSpansEnabled() && shouldEmitSpan ? spanForTraceHeaders : undefined,\n propagateTraceparent,\n );\n }\n\n if (client) {\n client.emit('beforeOutgoingRequestSpan', span, handlerData as XhrHint);\n }\n\n return span;\n}\n\nfunction addTracingHeadersToXhrRequest(\n xhr: SentryWrappedXMLHttpRequest,\n span?: Span,\n propagateTraceparent?: boolean,\n): void {\n const { 'sentry-trace': sentryTrace, baggage, traceparent } = getTraceData({ span, propagateTraceparent });\n\n if (sentryTrace) {\n setHeaderOnXhr(xhr, sentryTrace, baggage, traceparent);\n }\n}\n\nfunction setHeaderOnXhr(\n xhr: SentryWrappedXMLHttpRequest,\n sentryTraceHeader: string,\n sentryBaggageHeader: string | undefined,\n traceparentHeader: string | undefined,\n): void {\n const originalHeaders = xhr.__sentry_xhr_v3__?.request_headers;\n\n if (originalHeaders?.['sentry-trace'] || !xhr.setRequestHeader) {\n // bail if a sentry-trace header is already set\n return;\n }\n\n try {\n xhr.setRequestHeader('sentry-trace', sentryTraceHeader);\n\n if (traceparentHeader && !originalHeaders?.['traceparent']) {\n xhr.setRequestHeader('traceparent', traceparentHeader);\n }\n\n if (sentryBaggageHeader) {\n // only add our headers if\n // - no pre-existing baggage header exists\n // - or it is set and doesn't yet contain sentry values\n const originalBaggageHeader = originalHeaders?.['baggage'];\n if (!originalBaggageHeader || !baggageHeaderHasSentryValues(originalBaggageHeader)) {\n // From MDN: \"If this method is called several times with the same header, the values are merged into one single request header.\"\n // We can therefore simply set a baggage header without checking what was there before\n // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader\n xhr.setRequestHeader('baggage', sentryBaggageHeader);\n }\n }\n } catch {\n // Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.\n }\n}\n"],"names":["addFetchInstrumentationHandler","instrumentFetchRequest","WINDOW","getFullURL","parseUrl","stripDataUrlContent","URL_FULL","filterCollectedUrl","SERVER_ADDRESS","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","matchesTracePropagationTargets","shouldAttachHeaders","SENTRY_XHR_DATA_KEY","hasSpansEnabled","span","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getClient","getActiveSpan","getUrlDomain","startInactiveSpan","HTTP_REQUEST_METHOD","URL_DOMAIN","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SENTRY_OP","HTTP_CLIENT","URL_QUERY","filterCollectedUrlQuery","getUrlQuery","URL_FRAGMENT","getUrlFragment","SentryNonRecordingSpan","spanIsIgnored","getTraceData","baggageHeaderHasSentryValues"],"mappings":";;;;;;;;;;AAyHO,MAAM,oCAAA,GAAsE;AAAA,EACjF,UAAA,EAAY,IAAA;AAAA,EACZ,QAAA,EAAU,IAAA;AAAA,EACV,iBAAA,EAAmB;AACrB;AAGO,SAAS,0BAAA,CAA2B,QAAgB,QAAA,EAAyD;AAClH,EAAA,MAAM;AAAA,IACJ,UAAA;AAAA,IACA,QAAA;AAAA,IACA,0BAAA;AAAA,IACA,iBAAA;AAAA,IACA,uBAAA;AAAA,IACA,kBAAA;AAAA,IACA;AAAA,GACF,GAAI;AAAA,IACF,GAAG,oCAAA;AAAA,IACH,GAAG;AAAA,GACL;AAEA,EAAA,MAAM,mBACJ,OAAO,0BAAA,KAA+B,UAAA,GAAa,0BAAA,GAA6B,CAAC,CAAA,KAAc,IAAA;AAEjG,EAAA,MAAM,8BAAA,GAAiC,CAAC,GAAA,KAAyB,mBAAA,CAAoB,KAAK,uBAAuB,CAAA;AAEjH,EAAA,MAAM,QAA8B,EAAC;AAErC,EAAA,MAAM,oBAAA,GAAwB,MAAA,CAAyB,UAAA,EAAW,CAAE,oBAAA;AAEpE,EAAA,IAAI,UAAA,EAAY;AACd,IAAAA,mCAAA,CAA+B,CAAA,WAAA,KAAe;AAC5C,MAAA,MAAM,WAAA,GAAcC,2BAAA,CAAuB,WAAA,EAAa,gBAAA,EAAkB,gCAAgC,KAAA,EAAO;AAAA,QAC/G,oBAAA;AAAA,QACA,gBAAA;AAAA;AAAA,QAEA,OAAA,EAASC,eAAO,QAAA,EAAU;AAAA,OAC3B,CAAA;AAKD,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,MAAM,OAAA,GAAUC,gBAAA,CAAW,WAAA,CAAY,SAAA,CAAU,GAAG,CAAA;AAEpD,QAAA,MAAM,IAAA,GAAO,UAAUC,aAAA,CAAS,OAAO,EAAE,IAAA,EAAM,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA,GAAI,MAAA;AACrE,QAAA,MAAM,gBAAA,GAAmB,OAAA,GAAUC,wBAAA,CAAoB,OAAO,CAAA,GAAI,MAAA;AAClE,QAAA,WAAA,CAAY,aAAA,CAAc;AAAA,UACxB,CAACC,mBAAQ,GAAGC,uBAAA,CAAmB,gBAAgB,CAAA;AAAA,UAC/C,CAACC,yBAAc,GAAG;AAAA,SACnB,CAAA;AAED,QAAA,IAAI,iBAAA,EAAmB;AACrB,UAAA,cAAA,CAAe,aAAa,MAAM,CAAA;AAAA,QACpC;AAEA,QAAA,kBAAA,GAAqB,WAAA,EAAa,EAAE,OAAA,EAAS,WAAA,CAAY,SAAS,CAAA;AAAA,MACpE;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAAC,yCAAA,CAA6B,CAAA,WAAA,KAAe;AAC1C,MAAA,MAAM,WAAA,GAAc,WAAA;AAAA,QAClB,WAAA;AAAA,QACA,gBAAA;AAAA,QACA,8BAAA;AAAA,QACA,KAAA;AAAA,QACA,oBAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,IAAI,iBAAA,EAAmB;AACrB,UAAA,cAAA,CAAe,aAAa,MAAM,CAAA;AAAA,QACpC;AAEA,QAAA,kBAAA,GAAqB,WAAA,EAAa;AAAA,UAChC,OAAA,EAASC,yBAAA,CAAoB,WAAA,CAAY,GAAA,CAAI,mBAAmB,eAAe;AAAA,SAChF,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AACF;AAOA,MAAM,mBAAA,GAAsB,GAAA;AAQ5B,SAAS,cAAA,CAAe,MAAY,MAAA,EAAsB;AACxD,EAAA,MAAM,GAAA,GAAMC,eAAA,CAAW,IAAI,CAAA,CAAE,WAAWL,mBAAQ,CAAA;AAEhD,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AACnC,IAAA;AAAA,EACF;AAKA,EAAA,IAAI,YAAA,GAAe,MAAY,KAAK,UAAA,CAAW,6BAA6B,CAAA;AAI5E,EAAA,IAAIM,4BAAA,CAAwB,MAAM,CAAA,EAAG;AACnC,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AAEtC,IAAA,IAAA,CAAK,GAAA,GAAM,CAAC,YAAA,KAAiC;AAC3C,MAAA,MAAM,oBAAA,GAAuB,gBAAgBC,uBAAA,EAAmB;AAChE,MAAA,IAAI,OAAA,GAAU,KAAA;AAEd,MAAA,MAAM,oBAAoB,MAAY;AACpC,QAAA,IAAI,OAAA,EAAS;AACX,UAAA;AAAA,QACF;AACA,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,UAAA,CAAW,6BAA6B,CAAA;AACxC,QAAA,WAAA,CAAY,oBAAoB,CAAA;AAChC,QAAA,YAAA,CAAa,eAAe,CAAA;AAAA,MAC9B,CAAA;AAEA,MAAA,YAAA,GAAe,iBAAA;AAKf,MAAA,MAAM,eAAA,GAAkB,UAAA,CAAW,iBAAA,EAAmB,mBAAmB,CAAA;AAAA,IAC3E,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,gCAAgCC,iDAAA,CAAqC,UAAA,EAAY,CAAC,EAAE,SAAQ,KAAM;AACtG,IAAA,OAAA,CAAQ,QAAQ,CAAA,KAAA,KAAS;AACvB,MAAA,IAAIC,kCAA4B,KAAK,CAAA,IAAK,MAAM,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAAG;AAClE,QAAA,IAAA,CAAK,aAAA,CAAcC,2CAAA,CAA+B,KAAK,CAAC,CAAA;AACxD,QAAA,YAAA,EAAa;AAAA,MACf;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAMO,SAAS,mBAAA,CACd,WACA,uBAAA,EACS;AAGT,EAAA,MAAM,OAAOC,4BAAA,EAAgB;AAE7B,EAAA,IAAI,CAAC,IAAA,EAAM;AAIT,IAAA,MAAM,2BAAA,GAA8B,CAAC,CAAC,SAAA,CAAU,MAAM,WAAW,CAAA;AACjE,IAAA,IAAI,CAAC,uBAAA,EAAyB;AAC5B,MAAA,OAAO,2BAAA;AAAA,IACT,CAAA,MAAO;AACL,MAAA,OAAOC,mCAAA,CAA+B,WAAW,uBAAuB,CAAA;AAAA,IAC1E;AAAA,EACF,CAAA,MAAO;AACL,IAAA,IAAI,WAAA;AACJ,IAAA,IAAI,aAAA;AAGJ,IAAA,IAAI;AACF,MAAA,WAAA,GAAc,IAAI,GAAA,CAAI,SAAA,EAAW,IAAI,CAAA;AACrC,MAAA,aAAA,GAAgB,IAAI,GAAA,CAAI,IAAI,CAAA,CAAE,MAAA;AAAA,IAChC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,mBAAA,GAAsB,YAAY,MAAA,KAAW,aAAA;AACnD,IAAA,IAAI,CAAC,uBAAA,EAAyB;AAC5B,MAAA,OAAO,mBAAA;AAAA,IACT,CAAA,MAAO;AACL,MAAA,OACEA,mCAAA,CAA+B,WAAA,CAAY,QAAA,EAAS,EAAG,uBAAuB,KAC7E,mBAAA,IAAuBA,mCAAA,CAA+B,WAAA,CAAY,QAAA,EAAU,uBAAuB,CAAA;AAAA,IAExG;AAAA,EACF;AACF;AAQA,SAAS,YACP,WAAA,EACA,gBAAA,EACAC,oBAAAA,EACA,KAAA,EACA,sBACA,gBAAA,EACkB;AAClB,EAAA,MAAM,MAAM,WAAA,CAAY,GAAA;AACxB,EAAA,MAAM,aAAA,GAAgB,MAAMC,gCAAmB,CAAA;AAE/C,EAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,sBAAA,IAA0B,CAAC,aAAA,EAAe;AACxD,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAE,GAAA,EAAK,MAAA,EAAO,GAAI,aAAA;AAExB,EAAA,MAAM,sBAAA,GAAyBC,oBAAA,EAAgB,IAAK,gBAAA,CAAiB,GAAG,CAAA;AAGxE,EAAA,IAAI,YAAY,YAAA,EAAc;AAC5B,IAAA,MAAM,SAAS,GAAA,CAAI,sBAAA;AACnB,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,MAAMC,KAAAA,GAAO,MAAM,MAAM,CAAA;AAEzB,IAAA,IAAIA,KAAAA,EAAM;AACR,MAAA,IAAI,sBAAA,IAA0B,aAAA,CAAc,WAAA,KAAgB,MAAA,EAAW;AACrE,QAAAC,kBAAA,CAAcD,KAAAA,EAAM,cAAc,WAAW,CAAA;AAC7C,QAAAA,MAAK,GAAA,EAAI;AAET,QAAA,gBAAA,GAAmBA,KAAAA,EAAM;AAAA,UACvB,OAAA,EAASZ,yBAAA,CAAoBc,oCAAA,CAAwB,GAAmD,CAAC,CAAA;AAAA,UACzG,OAAO,WAAA,CAAY;AAAA,SACpB,CAAA;AAAA,MACH;AAGA,MAAA,OAAO,MAAM,MAAM,CAAA;AAAA,IACrB;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAUrB,iBAAW,GAAG,CAAA;AAC9B,EAAA,MAAM,YAAY,OAAA,GAAUC,aAAA,CAAS,OAAO,CAAA,GAAIA,cAAS,GAAG,CAAA;AAC5D,EAAA,MAAM,gBAAA,GAAmB,OAAA,GAAUC,wBAAA,CAAoB,OAAO,CAAA,GAAI,MAAA;AAElE,EAAA,MAAM,cAAA,GAAiBA,wBAAA,CAAoBoB,6BAAA,CAAyB,GAAG,CAAC,CAAA;AAExE,EAAA,MAAM,SAASC,cAAA,EAAU;AACzB,EAAA,MAAM,SAAA,GAAY,CAAC,CAACC,kBAAA,EAAc;AAElC,EAAA,MAAM,iBAAiB,SAAA,IAAc,CAAC,CAAC,MAAA,IAAUf,6BAAwB,MAAM,CAAA;AAG/E,EAAA,MAAM,IAAA,GAAO,SAAA,EAAW,IAAA,EAAM,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAEhD,EAAA,MAAM,MAAA,GAASgB,iBAAA,CAAa,OAAA,IAAW,GAAG,CAAA;AAG1C,EAAA,MAAM,eAAe,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,GAAK,MAAA;AAEtD,EAAA,MAAM,IAAA,GACJ,sBAAA,IAA0B,cAAA,GACtBC,yBAAA,CAAkB;AAAA,IAChB,IAAA,EAAM,CAAC,CAAC,MAAA,IAAUjB,4BAAA,CAAwB,MAAM,CAAA,GAAI,YAAA,GAAe,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,cAAc,CAAA,CAAA;AAAA,IAC9F,UAAA,EAAY;AAAA,MACV,IAAA,EAAM,KAAA;AAAA;AAAA,MAEN,CAACkB,8BAAmB,GAAG,MAAA;AAAA,MACvB,CAACxB,mBAAQ,GAAGC,uBAAA,CAAmB,gBAAgB,CAAA;AAAA,MAC/C,CAACC,yBAAc,GAAG,IAAA;AAAA,MAClB,CAACuB,qBAAU,GAAG,MAAA;AAAA,MACd,CAACC,qCAAgC,GAAG,mBAAA;AAAA,MACpC,CAACC,oBAAS,GAAGC,cAAA;AAAA,MACb,CAACC,oBAAS,GAAGC,6BAAwBC,gBAAA,CAAY,SAAA,EAAW,MAAM,CAAC,CAAA;AAAA,MACnE,CAACC,uBAAY,GAAGC,mBAAA,CAAe,WAAW,IAAI;AAAA;AAChD,GACD,CAAA,GACD,IAAIC,2BAAA,EAAuB;AAIjC,EAAA,MAAM,mBAAA,GAAsBC,kBAAA,CAAc,IAAI,CAAA,IAAK,YAAY,MAAA,GAAY,IAAA;AAE3E,EAAA,IAAI,sBAAA,IAA0B,CAAC,cAAA,EAAgB;AAC7C,IAAA,MAAA,EAAQ,kBAAA,CAAmB,kBAAkB,MAAM,CAAA;AAAA,EACrD;AAEA,EAAA,GAAA,CAAI,sBAAA,GAAyB,IAAA,CAAK,WAAA,EAAY,CAAE,MAAA;AAChD,EAAA,KAAA,CAAM,GAAA,CAAI,sBAAsB,CAAA,GAAI,IAAA;AAEpC,EAAA,IAAItB,oBAAAA,CAAoB,GAAG,CAAA,EAAG;AAC5B,IAAA,6BAAA;AAAA,MACE,GAAA;AAAA;AAAA;AAAA;AAAA,MAIAE,oBAAA,EAAgB,IAAK,cAAA,GAAiB,mBAAA,GAAsB,MAAA;AAAA,MAC5D;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAA,CAAO,IAAA,CAAK,2BAAA,EAA6B,IAAA,EAAM,WAAsB,CAAA;AAAA,EACvE;AAEA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,6BAAA,CACP,GAAA,EACA,IAAA,EACA,oBAAA,EACM;AACN,EAAA,MAAM,EAAE,cAAA,EAAgB,WAAA,EAAa,OAAA,EAAS,WAAA,KAAgBqB,iBAAA,CAAa,EAAE,IAAA,EAAM,oBAAA,EAAsB,CAAA;AAEzG,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,cAAA,CAAe,GAAA,EAAK,WAAA,EAAa,OAAA,EAAS,WAAW,CAAA;AAAA,EACvD;AACF;AAEA,SAAS,cAAA,CACP,GAAA,EACA,iBAAA,EACA,mBAAA,EACA,iBAAA,EACM;AACN,EAAA,MAAM,eAAA,GAAkB,IAAI,iBAAA,EAAmB,eAAA;AAE/C,EAAA,IAAI,eAAA,GAAkB,cAAc,CAAA,IAAK,CAAC,IAAI,gBAAA,EAAkB;AAE9D,IAAA;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,GAAA,CAAI,gBAAA,CAAiB,gBAAgB,iBAAiB,CAAA;AAEtD,IAAA,IAAI,iBAAA,IAAqB,CAAC,eAAA,GAAkB,aAAa,CAAA,EAAG;AAC1D,MAAA,GAAA,CAAI,gBAAA,CAAiB,eAAe,iBAAiB,CAAA;AAAA,IACvD;AAEA,IAAA,IAAI,mBAAA,EAAqB;AAIvB,MAAA,MAAM,qBAAA,GAAwB,kBAAkB,SAAS,CAAA;AACzD,MAAA,IAAI,CAAC,qBAAA,IAAyB,CAACC,kCAAA,CAA6B,qBAAqB,CAAA,EAAG;AAIlF,QAAA,GAAA,CAAI,gBAAA,CAAiB,WAAW,mBAAmB,CAAA;AAAA,MACrD;AAAA,IACF;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;;;;"}
1
+ {"version":3,"file":"request.js","sources":["../../../../../src/tracing/request.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, RequestHookInfo, ResponseHookInfo, Span, SpanTimeInput } from '@sentry/core';\nimport {\n addFetchInstrumentationHandler,\n getActiveSpan,\n getClient,\n getTraceData,\n getUrlDomain,\n getUrlFragment,\n getUrlQuery,\n hasSpansEnabled,\n hasSpanStreamingEnabled,\n instrumentFetchRequest,\n matchesTracePropagationTargets,\n parseUrl,\n SentryNonRecordingSpan,\n setHttpStatus,\n spanIsIgnored,\n spanToJSON,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport type { HandlerDataXhr, SentryWrappedXMLHttpRequest, XhrHint } from '@sentry/browser-utils';\nimport { filterCollectedUrl, filterCollectedUrlQuery } from '@sentry/core';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n getLocationHref,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/browser-utils';\nimport type { BrowserClient } from '../client';\nimport { WINDOW } from '../helpers';\nimport { baggageHeaderHasSentryValues, createHeadersSafely, getFullURL, isPerformanceResourceTiming } from './utils';\nimport {\n HTTP_REQUEST_METHOD,\n SENTRY_OP,\n SERVER_ADDRESS,\n URL_DOMAIN,\n URL_FRAGMENT,\n URL_FULL,\n URL_QUERY,\n SENTRY_ORIGIN,\n} from '@sentry/conventions/attributes';\nimport { HTTP_CLIENT } from '@sentry/conventions/op';\n\n/** Options for Request Instrumentation */\nexport interface RequestInstrumentationOptions {\n /**\n * List of strings and/or Regular Expressions used to determine which outgoing requests will have `sentry-trace` and `baggage`\n * headers attached.\n *\n * **Default:** If this option is not provided, tracing headers will be attached to all outgoing requests.\n * If you are using a browser SDK, by default, tracing headers will only be attached to outgoing requests to the same origin.\n *\n * **Disclaimer:** Carelessly setting this option in browser environments may result into CORS errors!\n * Only attach tracing headers to requests to the same origin, or to requests to services you can control CORS headers of.\n * Cross-origin requests, meaning requests to a different domain, for example a request to `https://api.example.com/` while you're on `https://example.com/`, take special care.\n * If you are attaching headers to cross-origin requests, make sure the backend handling the request returns a `\"Access-Control-Allow-Headers: sentry-trace, baggage\"` header to ensure your requests aren't blocked.\n *\n * If you provide a `tracePropagationTargets` array, the entries you provide will be matched against the entire URL of the outgoing request.\n * If you are using a browser SDK, the entries will also be matched against the pathname of the outgoing requests.\n * This is so you can have matchers for relative requests, for example, `/^\\/api/` if you want to trace requests to your `/api` routes on the same domain.\n *\n * If any of the two match any of the provided values, tracing headers will be attached to the outgoing request.\n * Both, the string values, and the RegExes you provide in the array will match if they partially match the URL or pathname.\n * Matching is case-insensitive, so `'myApi.com'` and `/^myApi\\.com/` both match a request to `https://myapi.com`.\n *\n * Examples:\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://same-origin.com/api/posts`:\n * - Tracing headers will be attached because the request is sent to the same origin and the regex matches the pathname \"/api/posts\".\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://different-origin.com/api/posts`:\n * - Tracing headers will not be attached because the pathname will only be compared when the request target lives on the same origin.\n * - `tracePropagationTargets: [/^\\/api/, 'https://external-api.com']` and request to `https://external-api.com/v1/data`:\n * - Tracing headers will be attached because the request URL matches the string `'https://external-api.com'`.\n */\n tracePropagationTargets?: Array<string | RegExp>;\n\n /**\n * Flag to disable patching all together for fetch requests.\n *\n * Default: true\n */\n traceFetch: boolean;\n\n /**\n * Flag to disable patching all together for xhr requests.\n *\n * Default: true\n */\n traceXHR: boolean;\n\n /**\n * If true, Sentry will capture http timings and add them to the corresponding http spans.\n *\n * Default: true\n */\n enableHTTPTimings: boolean;\n\n /**\n * This function will be called before creating a span for a request with the given url.\n * Return false if you don't want a span for the given url.\n *\n * Default: (url: string) => true\n */\n shouldCreateSpanForRequest?(this: void, url: string): boolean;\n\n /**\n * Is called when spans are started for outgoing requests.\n */\n onRequestSpanStart?(span: Span, requestInformation: RequestHookInfo): void;\n\n /**\n * Is called when spans end for outgoing requests, providing access to response headers.\n */\n onRequestSpanEnd?(span: Span, responseInformation: ResponseHookInfo): void;\n}\n\nexport const defaultRequestInstrumentationOptions: RequestInstrumentationOptions = {\n traceFetch: true,\n traceXHR: true,\n enableHTTPTimings: true,\n};\n\n/** Registers span creators for xhr and fetch requests */\nexport function instrumentOutgoingRequests(client: Client, _options?: Partial<RequestInstrumentationOptions>): void {\n const {\n traceFetch,\n traceXHR,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n tracePropagationTargets,\n onRequestSpanStart,\n onRequestSpanEnd,\n } = {\n ...defaultRequestInstrumentationOptions,\n ..._options,\n };\n\n const shouldCreateSpan =\n typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_: string) => true;\n\n const shouldAttachHeadersWithTargets = (url: string): boolean => shouldAttachHeaders(url, tracePropagationTargets);\n\n const spans: Record<string, Span> = {};\n\n const propagateTraceparent = (client as BrowserClient).getOptions().propagateTraceparent;\n\n if (traceFetch) {\n addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\n // The generic fetch instrumentation has no page origin to resolve relative URLs against.\n urlBase: WINDOW.location?.origin,\n });\n\n // We cannot use `window.location` in the generic fetch instrumentation,\n // but we need it for reliable `server.address` attribute.\n // so we extend this in here\n if (createdSpan) {\n const fullUrl = getFullURL(handlerData.fetchData.url);\n // `parseUrl` returns the raw authority — userinfo credentials must never reach an attribute.\n const host = fullUrl ? parseUrl(fullUrl).host?.replace(/^.*@/, '') : undefined;\n const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n [URL_FULL]: filterCollectedUrl(sanitizedFullUrl),\n [SERVER_ADDRESS]: host,\n });\n\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan, client);\n }\n\n onRequestSpanStart?.(createdSpan, { headers: handlerData.headers });\n }\n });\n }\n\n if (traceXHR) {\n addXhrInstrumentationHandler(handlerData => {\n const createdSpan = xhrCallback(\n handlerData,\n shouldCreateSpan,\n shouldAttachHeadersWithTargets,\n spans,\n propagateTraceparent,\n onRequestSpanEnd,\n );\n\n if (createdSpan) {\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan, client);\n }\n\n onRequestSpanStart?.(createdSpan, {\n headers: createHeadersSafely(handlerData.xhr.__sentry_xhr_v3__?.request_headers),\n });\n }\n });\n }\n}\n\n/**\n * The maximum time (ms) to wait for PerformanceResourceTiming data before ending the span.\n * Same approach is used by OTel's browser fetch instrumentation:\n * See {@link https://github.com/open-telemetry/opentelemetry-js/blob/30f94fe99339287b1e4d3c8bb90172c2523f06f4/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L352-L372}\n */\nconst HTTP_TIMING_WAIT_MS = 300;\n\n/**\n * Creates a temporary observer to listen to the next fetch/xhr resourcing timings,\n * so that when timings hit their per-browser limit they don't need to be removed.\n *\n * @param span A span that has yet to be finished, must contain `url.full` on data.\n */\nfunction addHTTPTimings(span: Span, client: Client): void {\n const url = spanToJSON(span).attributes[URL_FULL];\n\n if (!url || typeof url !== 'string') {\n return;\n }\n\n // Clean up the performance observer and other resources\n // We have to wait here because otherwise this cleans itself up before it is fully done.\n // Default (non-streaming): just deregister the observer.\n let onEntryFound = (): void => void setTimeout(unsubscribePerformanceObsever);\n\n // For streamed spans, we have to artificially delay the ending of the span until we\n // either receive the timing data, or HTTP_TIMING_WAIT_MS elapses.\n if (hasSpanStreamingEnabled(client)) {\n const originalEnd = span.end.bind(span);\n\n span.end = (endTimestamp?: SpanTimeInput) => {\n const capturedEndTimestamp = endTimestamp ?? timestampInSeconds();\n let isEnded = false;\n\n const endSpanAndCleanup = (): void => {\n if (isEnded) {\n return;\n }\n isEnded = true;\n setTimeout(unsubscribePerformanceObsever);\n originalEnd(capturedEndTimestamp);\n clearTimeout(fallbackTimeout);\n };\n\n onEntryFound = endSpanAndCleanup;\n\n // Fallback: always end the span after HTTP_TIMING_WAIT_MS even if no\n // PerformanceResourceTiming entry arrives (e.g. cross-origin without\n // Timing-Allow-Origin, or the browser didn't fire the observer in time).\n const fallbackTimeout = setTimeout(endSpanAndCleanup, HTTP_TIMING_WAIT_MS);\n };\n }\n\n const unsubscribePerformanceObsever = addPerformanceInstrumentationHandler('resource', ({ entries }) => {\n entries.forEach(entry => {\n if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) {\n span.setAttributes(resourceTimingToSpanAttributes(entry));\n onEntryFound();\n }\n });\n });\n}\n\n/**\n * A function that determines whether to attach tracing headers to a request.\n * We only export this function for testing purposes.\n */\nexport function shouldAttachHeaders(\n targetUrl: string,\n tracePropagationTargets: (string | RegExp)[] | undefined,\n): boolean {\n // window.location.href not being defined is an edge case in the browser but we need to handle it.\n // Potentially dangerous situations where it may not be defined: Browser Extensions, Web Workers, patching of the location obj\n const href = getLocationHref();\n\n if (!href) {\n // If there is no window.location.origin, we default to only attaching tracing headers to relative requests, i.e. ones that start with `/`\n // BIG DISCLAIMER: Users can call URLs with a double slash (fetch(\"//example.com/api\")), this is a shorthand for \"send to the same protocol\",\n // so we need a to exclude those requests, because they might be cross origin.\n const isRelativeSameOriginRequest = !!targetUrl.match(/^\\/(?!\\/)/);\n if (!tracePropagationTargets) {\n return isRelativeSameOriginRequest;\n } else {\n return matchesTracePropagationTargets(targetUrl, tracePropagationTargets);\n }\n } else {\n let resolvedUrl;\n let currentOrigin;\n\n // URL parsing may fail, we default to not attaching trace headers in that case.\n try {\n resolvedUrl = new URL(targetUrl, href);\n currentOrigin = new URL(href).origin;\n } catch {\n return false;\n }\n\n const isSameOriginRequest = resolvedUrl.origin === currentOrigin;\n if (!tracePropagationTargets) {\n return isSameOriginRequest;\n } else {\n return (\n matchesTracePropagationTargets(resolvedUrl.toString(), tracePropagationTargets) ||\n (isSameOriginRequest && matchesTracePropagationTargets(resolvedUrl.pathname, tracePropagationTargets))\n );\n }\n }\n}\n\n/**\n * Create and track xhr request spans\n *\n * @returns Span if a span was created, otherwise void.\n */\n// oxlint-disable-next-line complexity\nfunction xhrCallback(\n handlerData: HandlerDataXhr,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n propagateTraceparent?: boolean,\n onRequestSpanEnd?: RequestInstrumentationOptions['onRequestSpanEnd'],\n): Span | undefined {\n const xhr = handlerData.xhr;\n const sentryXhrData = xhr?.[SENTRY_XHR_DATA_KEY];\n\n if (!xhr || xhr.__sentry_own_request__ || !sentryXhrData) {\n return undefined;\n }\n\n const { url, method } = sentryXhrData;\n\n const shouldCreateSpanResult = hasSpansEnabled() && shouldCreateSpan(url);\n\n // Handle XHR completion - clean up spans from the record\n if (handlerData.endTimestamp) {\n const spanId = xhr.__sentry_xhr_span_id__;\n if (!spanId) return;\n\n const span = spans[spanId];\n\n if (span) {\n if (shouldCreateSpanResult && sentryXhrData.status_code !== undefined) {\n setHttpStatus(span, sentryXhrData.status_code);\n span.end();\n\n onRequestSpanEnd?.(span, {\n headers: createHeadersSafely(parseXhrResponseHeaders(xhr as XMLHttpRequest & SentryWrappedXMLHttpRequest)),\n error: handlerData.error,\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n\n return undefined;\n }\n\n const fullUrl = getFullURL(url);\n const parsedUrl = fullUrl ? parseUrl(fullUrl) : parseUrl(url);\n const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n // `parseUrl` returns the raw authority — userinfo credentials must never reach an attribute.\n const host = parsedUrl?.host?.replace(/^.*@/, '');\n // `getFullURL` already resolved relative URLs against the page origin; only data URLs have no domain.\n const domain = getUrlDomain(fullUrl || url);\n\n // With span streaming, span names have to be low cardinality, so only the domain is kept.\n const streamedName = domain ? `${method} ${domain}` : method;\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: !!client && hasSpanStreamingEnabled(client) ? streamedName : `${method} ${urlForSpanName}`,\n attributes: {\n type: 'xhr',\n // eslint-disable-next-line typescript/no-deprecated\n [HTTP_REQUEST_METHOD]: method,\n [URL_FULL]: filterCollectedUrl(sanitizedFullUrl),\n [SERVER_ADDRESS]: host,\n [URL_DOMAIN]: domain,\n [SENTRY_ORIGIN]: 'auto.http.browser',\n [SENTRY_OP]: HTTP_CLIENT,\n [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl?.search)),\n [URL_FRAGMENT]: getUrlFragment(parsedUrl?.hash),\n },\n })\n : new SentryNonRecordingSpan();\n\n // If the span is ignored, we don't want to continue the trace from it (NonRecordingSpan) but rather\n // from the active span. Passing `undefined` here will make `getTraceData` use the active span instead.\n const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? undefined : span;\n\n if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\n\n xhr.__sentry_xhr_span_id__ = span.spanContext().spanId;\n spans[xhr.__sentry_xhr_span_id__] = span;\n\n if (shouldAttachHeaders(url)) {\n addTracingHeadersToXhrRequest(\n xhr,\n // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction),\n // we do not want to use the span as base for the trace headers,\n // which means that the headers will be generated from the scope and the sampling decision is deferred\n hasSpansEnabled() && shouldEmitSpan ? spanForTraceHeaders : undefined,\n propagateTraceparent,\n );\n }\n\n if (client) {\n client.emit('beforeOutgoingRequestSpan', span, handlerData as XhrHint);\n }\n\n return span;\n}\n\nfunction addTracingHeadersToXhrRequest(\n xhr: SentryWrappedXMLHttpRequest,\n span?: Span,\n propagateTraceparent?: boolean,\n): void {\n const { 'sentry-trace': sentryTrace, baggage, traceparent } = getTraceData({ span, propagateTraceparent });\n\n if (sentryTrace) {\n setHeaderOnXhr(xhr, sentryTrace, baggage, traceparent);\n }\n}\n\nfunction setHeaderOnXhr(\n xhr: SentryWrappedXMLHttpRequest,\n sentryTraceHeader: string,\n sentryBaggageHeader: string | undefined,\n traceparentHeader: string | undefined,\n): void {\n const originalHeaders = xhr.__sentry_xhr_v3__?.request_headers;\n\n if (originalHeaders?.['sentry-trace'] || !xhr.setRequestHeader) {\n // bail if a sentry-trace header is already set\n return;\n }\n\n try {\n xhr.setRequestHeader('sentry-trace', sentryTraceHeader);\n\n if (traceparentHeader && !originalHeaders?.['traceparent']) {\n xhr.setRequestHeader('traceparent', traceparentHeader);\n }\n\n if (sentryBaggageHeader) {\n // only add our headers if\n // - no pre-existing baggage header exists\n // - or it is set and doesn't yet contain sentry values\n const originalBaggageHeader = originalHeaders?.['baggage'];\n if (!originalBaggageHeader || !baggageHeaderHasSentryValues(originalBaggageHeader)) {\n // From MDN: \"If this method is called several times with the same header, the values are merged into one single request header.\"\n // We can therefore simply set a baggage header without checking what was there before\n // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader\n xhr.setRequestHeader('baggage', sentryBaggageHeader);\n }\n }\n } catch {\n // Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.\n }\n}\n"],"names":["addFetchInstrumentationHandler","instrumentFetchRequest","WINDOW","getFullURL","parseUrl","stripDataUrlContent","URL_FULL","filterCollectedUrl","SERVER_ADDRESS","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","matchesTracePropagationTargets","shouldAttachHeaders","SENTRY_XHR_DATA_KEY","hasSpansEnabled","span","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getClient","getActiveSpan","getUrlDomain","startInactiveSpan","HTTP_REQUEST_METHOD","URL_DOMAIN","SENTRY_ORIGIN","SENTRY_OP","HTTP_CLIENT","URL_QUERY","filterCollectedUrlQuery","getUrlQuery","URL_FRAGMENT","getUrlFragment","SentryNonRecordingSpan","spanIsIgnored","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { setRouteProvider } from '@sentry/browser-utils';
2
- import { Client, getSDKSource, applySdkMetadata, addAutoIpAddressToSession } from '@sentry/core';
2
+ import { Client, getSDKSource, applySdkMetadata, addAutoIpAddressToSession, timestampInSeconds } from '@sentry/core';
3
3
  import { eventFromException, eventFromMessage } from './eventbuilder.js';
4
4
  import { WINDOW } from './helpers.js';
5
5
 
@@ -28,18 +28,42 @@ class BrowserClient extends Client {
28
28
  };
29
29
  }
30
30
  const { sendClientReports } = this._options;
31
- if (WINDOW.document) {
32
- WINDOW.document.addEventListener("visibilitychange", () => {
33
- if (WINDOW.document.visibilityState === "hidden") {
34
- if (sendClientReports) {
35
- this._flushOutcomes();
31
+ const checkDrift = () => {
32
+ timestampInSeconds();
33
+ };
34
+ const listeners = [
35
+ // Flush buffered data when the page becomes hidden (e.g. tab switch, navigation, or the page
36
+ // being discarded). `flush()` emits the `flush` hook, which drains the span (streaming), log and
37
+ // metric buffers and hands the resulting envelopes to the transport (which uses `keepalive`).
38
+ // Client report outcomes don't listen to the `flush` hook, so we flush them separately.
39
+ [
40
+ WINDOW.document,
41
+ "visibilitychange",
42
+ () => {
43
+ checkDrift();
44
+ if (WINDOW.document.visibilityState === "hidden") {
45
+ if (sendClientReports) {
46
+ this._flushOutcomes();
47
+ }
48
+ queueMicrotask(() => {
49
+ void this.flush();
50
+ });
36
51
  }
37
- queueMicrotask(() => {
38
- void this.flush();
39
- });
40
52
  }
41
- });
42
- }
53
+ ],
54
+ // `freeze` and `resume` are only fired by Chromium browsers. Other browsers never fire them, so these listeners
55
+ // are no-ops there.
56
+ [WINDOW.document, "freeze", checkDrift],
57
+ [WINDOW.document, "resume", checkDrift],
58
+ // Pages restored from the back/forward cache were paused while they were cached.
59
+ [WINDOW, "pagehide", checkDrift],
60
+ [WINDOW, "pageshow", checkDrift]
61
+ ];
62
+ listeners.forEach(([target, name, listener]) => target?.addEventListener?.(name, listener));
63
+ this.on(
64
+ "close",
65
+ () => listeners.forEach(([target, name, listener]) => target?.removeEventListener?.(name, listener))
66
+ );
43
67
  if (userInfo) {
44
68
  this.on("beforeSendSession", addAutoIpAddressToSession);
45
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sources":["../../../../src/client.ts"],"sourcesContent":["import type {\n ClientOptions,\n Event,\n EventHint,\n Options as CoreOptions,\n ParameterizedString,\n Scope,\n SeverityLevel,\n} from '@sentry/core';\nimport type { BrowserClientReplayOptions } from '@sentry/core/browser';\nimport type { RouteProvider } from '@sentry/browser-utils';\nimport { setRouteProvider } from '@sentry/browser-utils';\nimport { addAutoIpAddressToSession, applySdkMetadata, Client, getSDKSource } from '@sentry/core';\nimport { eventFromException, eventFromMessage } from './eventbuilder';\nimport { WINDOW } from './helpers';\nimport type { BrowserTransportOptions } from './transports/types';\n\n/**\n * A magic string that build tooling can leverage in order to inject a release value into the SDK.\n */\ndeclare const __SENTRY_RELEASE__: string | undefined;\n\nexport type BrowserClientProfilingOptions = {\n /**\n * Sets profiling session sample rate for the entire profiling session.\n *\n * A profiling session corresponds to a user session, meaning it is set once at integration initialization and\n * persisted until the next page reload. This rate determines what percentage of user sessions will have profiling enabled.\n * @default 0\n */\n profileSessionSampleRate?: number;\n\n /**\n * Set the lifecycle mode of the profiler.\n * - **manual**: The profiler will be manually started and stopped via `startProfiler`/`stopProfiler`.\n * If a session is sampled, is dependent on the `profileSessionSampleRate`.\n * - **trace**: The profiler will be automatically started when a root span exists and stopped when there are no\n * more sampled root spans. Whether a session is sampled, is dependent on the `profileSessionSampleRate` and the\n * existing sampling configuration for tracing (`tracesSampleRate`/`tracesSampler`).\n *\n * @default 'manual'\n */\n profileLifecycle?: 'manual' | 'trace';\n};\n\ntype BrowserSpecificOptions = BrowserClientReplayOptions &\n BrowserClientProfilingOptions & {\n /** If configured, this URL will be used as base URL for lazy loading integration. */\n cdnBaseUrl?: string;\n\n /**\n * Important: Only set this option if you know what you are doing!\n *\n * By default, the SDK will check if `Sentry.init` is called in a browser extension.\n * In case it is, it will stop initialization and log a warning\n * because browser extensions require a different Sentry initialization process:\n * https://docs.sentry.io/platforms/javascript/best-practices/shared-environments/\n *\n * Setting up the SDK in a browser extension with global error monitoring is not recommended\n * and will likely flood you with errors from other web sites or extensions. This can heavily\n * impact your quota and cause interference with your and other Sentry SDKs in shared environments.\n *\n * If this check wrongfully flags your setup as a browser extension, you can set this\n * option to `true` to skip the check.\n *\n * @default false\n */\n skipBrowserExtensionCheck?: boolean;\n\n /**\n * If you use Spotlight by Sentry during development, use\n * this option to forward captured Sentry events to Spotlight.\n *\n * Either set it to true, or provide a specific Spotlight Sidecar URL.\n *\n * More details: https://spotlightjs.com/\n *\n * IMPORTANT: Only set this option to `true` while developing, not in production!\n */\n spotlight?: boolean | string;\n\n /**\n * Resolves URLs to low-cardinality route names, e.g. `/users/42` -> `/users/:id`.\n *\n * Framework SDKs set this for you. Set it yourself to name routes for a router the SDK has no\n * integration for. `setRouteProvider` replaces it at runtime.\n */\n routeProvider?: RouteProvider;\n };\n/**\n * Configuration options for the Sentry Browser SDK.\n * @see @sentry/core Options for more information.\n */\nexport type BrowserOptions = CoreOptions<BrowserTransportOptions> & BrowserSpecificOptions;\n\n/**\n * Configuration options for the Sentry Browser SDK Client class\n * @see BrowserClient for more information.\n */\nexport type BrowserClientOptions = ClientOptions<BrowserTransportOptions> & BrowserSpecificOptions;\n\n/**\n * The Sentry Browser SDK Client.\n *\n * @see BrowserOptions for documentation on configuration options.\n * @see SentryClient for usage documentation.\n */\nexport class BrowserClient extends Client<BrowserClientOptions> {\n /**\n * Creates a new Browser SDK instance.\n *\n * @param options Configuration options for this SDK.\n */\n public constructor(options: BrowserClientOptions) {\n const opts = applyDefaultOptions(options);\n const sdkSource = WINDOW.SENTRY_SDK_SOURCE || getSDKSource();\n applySdkMetadata(opts, 'browser', ['browser'], sdkSource);\n\n super(opts);\n\n if (opts.routeProvider) {\n setRouteProvider(opts.routeProvider, this);\n }\n\n // Unhandled errors don't actually crash the browser, so we report `unhandled` rather than `crashed`.\n this._unhandledSessionStatus = 'unhandled';\n\n const { userInfo } = this.getDataCollectionOptions();\n\n if (opts._metadata?.sdk) {\n opts._metadata.sdk.settings = {\n // Only allow IP inferral by Relay if the user opted in via dataCollection\n infer_ip: userInfo ? 'auto' : 'never',\n // purposefully allowing already passed settings to override the default\n ...opts._metadata.sdk.settings,\n };\n }\n\n const { sendClientReports } = this._options;\n\n // Flush buffered data when the page becomes hidden (e.g. tab switch, navigation, or the page\n // being discarded). `flush()` emits the `flush` hook, which drains the span (streaming), log and\n // metric buffers and hands the resulting envelopes to the transport (which uses `keepalive`).\n // Client report outcomes don't listen to the `flush` hook, so we flush them separately.\n if (WINDOW.document) {\n WINDOW.document.addEventListener('visibilitychange', () => {\n if (WINDOW.document.visibilityState === 'hidden') {\n if (sendClientReports) {\n this._flushOutcomes();\n }\n // Defer the flush to a microtask so that visibilitychange listeners registered after this\n // one have already run. In particular, browser tracing's background-tab detection ends the\n // active pageload/navigation (segment) span when the page is hidden. Deferring ensures that\n // segment span has been added to the streaming buffer before we flush, so it is sent\n // together with its child spans instead of being orphaned.\n queueMicrotask(() => {\n void this.flush();\n });\n }\n });\n }\n\n if (userInfo) {\n this.on('beforeSendSession', addAutoIpAddressToSession);\n }\n }\n\n /**\n * @inheritDoc\n */\n public eventFromException(exception: unknown, hint?: EventHint): PromiseLike<Event> {\n return eventFromException(this._options.stackParser, exception, hint, this._options.attachStacktrace);\n }\n\n /**\n * @inheritDoc\n */\n public eventFromMessage(\n message: ParameterizedString,\n level: SeverityLevel = 'info',\n hint?: EventHint,\n ): PromiseLike<Event> {\n return eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace);\n }\n\n /**\n * @inheritDoc\n */\n protected _prepareEvent(\n event: Event,\n hint: EventHint,\n currentScope: Scope,\n isolationScope: Scope,\n ): PromiseLike<Event | null> {\n event.platform = event.platform || 'javascript';\n\n return super._prepareEvent(event, hint, currentScope, isolationScope);\n }\n}\n\n/** Exported only for tests. */\nexport function applyDefaultOptions<T extends Partial<BrowserClientOptions>>(optionsArg: T): T {\n return {\n release:\n typeof __SENTRY_RELEASE__ === 'string' // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value\n ? __SENTRY_RELEASE__\n : WINDOW.SENTRY_RELEASE?.id, // This supports the variable that sentry-webpack-plugin injects\n sendClientReports: true,\n // We default this to true, as it is the safer scenario\n parentSpanIsAlwaysRootSpan: true,\n ...optionsArg,\n };\n}\n"],"names":[],"mappings":";;;;;AA2GO,MAAM,sBAAsB,MAAA,CAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvD,YAAY,OAAA,EAA+B;AAChD,IAAA,MAAM,IAAA,GAAO,oBAAoB,OAAO,CAAA;AACxC,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,iBAAA,IAAqB,YAAA,EAAa;AAC3D,IAAA,gBAAA,CAAiB,IAAA,EAAM,SAAA,EAAW,CAAC,SAAS,GAAG,SAAS,CAAA;AAExD,IAAA,KAAA,CAAM,IAAI,CAAA;AAEV,IAAA,IAAI,KAAK,aAAA,EAAe;AACtB,MAAA,gBAAA,CAAiB,IAAA,CAAK,eAAe,IAAI,CAAA;AAAA,IAC3C;AAGA,IAAA,IAAA,CAAK,uBAAA,GAA0B,WAAA;AAE/B,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,IAAA,CAAK,wBAAA,EAAyB;AAEnD,IAAA,IAAI,IAAA,CAAK,WAAW,GAAA,EAAK;AACvB,MAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAA,GAAW;AAAA;AAAA,QAE5B,QAAA,EAAU,WAAW,MAAA,GAAS,OAAA;AAAA;AAAA,QAE9B,GAAG,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI;AAAA,OACxB;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,iBAAA,EAAkB,GAAI,IAAA,CAAK,QAAA;AAMnC,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAA,CAAO,QAAA,CAAS,gBAAA,CAAiB,kBAAA,EAAoB,MAAM;AACzD,QAAA,IAAI,MAAA,CAAO,QAAA,CAAS,eAAA,KAAoB,QAAA,EAAU;AAChD,UAAA,IAAI,iBAAA,EAAmB;AACrB,YAAA,IAAA,CAAK,cAAA,EAAe;AAAA,UACtB;AAMA,UAAA,cAAA,CAAe,MAAM;AACnB,YAAA,KAAK,KAAK,KAAA,EAAM;AAAA,UAClB,CAAC,CAAA;AAAA,QACH;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,IAAA,CAAK,EAAA,CAAG,qBAAqB,yBAAyB,CAAA;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,kBAAA,CAAmB,WAAoB,IAAA,EAAsC;AAClF,IAAA,OAAO,kBAAA,CAAmB,KAAK,QAAA,CAAS,WAAA,EAAa,WAAW,IAAA,EAAM,IAAA,CAAK,SAAS,gBAAgB,CAAA;AAAA,EACtG;AAAA;AAAA;AAAA;AAAA,EAKO,gBAAA,CACL,OAAA,EACA,KAAA,GAAuB,MAAA,EACvB,IAAA,EACoB;AACpB,IAAA,OAAO,gBAAA,CAAiB,KAAK,QAAA,CAAS,WAAA,EAAa,SAAS,KAAA,EAAO,IAAA,EAAM,IAAA,CAAK,QAAA,CAAS,gBAAgB,CAAA;AAAA,EACzG;AAAA;AAAA;AAAA;AAAA,EAKU,aAAA,CACR,KAAA,EACA,IAAA,EACA,YAAA,EACA,cAAA,EAC2B;AAC3B,IAAA,KAAA,CAAM,QAAA,GAAW,MAAM,QAAA,IAAY,YAAA;AAEnC,IAAA,OAAO,KAAA,CAAM,aAAA,CAAc,KAAA,EAAO,IAAA,EAAM,cAAc,cAAc,CAAA;AAAA,EACtE;AACF;AAGO,SAAS,oBAA6D,UAAA,EAAkB;AAC7F,EAAA,OAAO;AAAA,IACL,SACE,OAAO,kBAAA,KAAuB,QAAA,GAC1B,kBAAA,GACA,OAAO,cAAA,EAAgB,EAAA;AAAA;AAAA,IAC7B,iBAAA,EAAmB,IAAA;AAAA;AAAA,IAEnB,0BAAA,EAA4B,IAAA;AAAA,IAC5B,GAAG;AAAA,GACL;AACF;;;;"}
1
+ {"version":3,"file":"client.js","sources":["../../../../src/client.ts"],"sourcesContent":["import type {\n ClientOptions,\n Event,\n EventHint,\n Options as CoreOptions,\n ParameterizedString,\n Scope,\n SeverityLevel,\n} from '@sentry/core';\nimport type { BrowserClientReplayOptions } from '@sentry/core/browser';\nimport type { RouteProvider } from '@sentry/browser-utils';\nimport { setRouteProvider } from '@sentry/browser-utils';\nimport { addAutoIpAddressToSession, applySdkMetadata, Client, getSDKSource, timestampInSeconds } from '@sentry/core';\nimport { eventFromException, eventFromMessage } from './eventbuilder';\nimport { WINDOW } from './helpers';\nimport type { BrowserTransportOptions } from './transports/types';\n\n/**\n * A magic string that build tooling can leverage in order to inject a release value into the SDK.\n */\ndeclare const __SENTRY_RELEASE__: string | undefined;\n\nexport type BrowserClientProfilingOptions = {\n /**\n * Sets profiling session sample rate for the entire profiling session.\n *\n * A profiling session corresponds to a user session, meaning it is set once at integration initialization and\n * persisted until the next page reload. This rate determines what percentage of user sessions will have profiling enabled.\n * @default 0\n */\n profileSessionSampleRate?: number;\n\n /**\n * Set the lifecycle mode of the profiler.\n * - **manual**: The profiler will be manually started and stopped via `startProfiler`/`stopProfiler`.\n * If a session is sampled, is dependent on the `profileSessionSampleRate`.\n * - **trace**: The profiler will be automatically started when a root span exists and stopped when there are no\n * more sampled root spans. Whether a session is sampled, is dependent on the `profileSessionSampleRate` and the\n * existing sampling configuration for tracing (`tracesSampleRate`/`tracesSampler`).\n *\n * @default 'manual'\n */\n profileLifecycle?: 'manual' | 'trace';\n};\n\ntype BrowserSpecificOptions = BrowserClientReplayOptions &\n BrowserClientProfilingOptions & {\n /** If configured, this URL will be used as base URL for lazy loading integration. */\n cdnBaseUrl?: string;\n\n /**\n * Important: Only set this option if you know what you are doing!\n *\n * By default, the SDK will check if `Sentry.init` is called in a browser extension.\n * In case it is, it will stop initialization and log a warning\n * because browser extensions require a different Sentry initialization process:\n * https://docs.sentry.io/platforms/javascript/best-practices/shared-environments/\n *\n * Setting up the SDK in a browser extension with global error monitoring is not recommended\n * and will likely flood you with errors from other web sites or extensions. This can heavily\n * impact your quota and cause interference with your and other Sentry SDKs in shared environments.\n *\n * If this check wrongfully flags your setup as a browser extension, you can set this\n * option to `true` to skip the check.\n *\n * @default false\n */\n skipBrowserExtensionCheck?: boolean;\n\n /**\n * If you use Spotlight by Sentry during development, use\n * this option to forward captured Sentry events to Spotlight.\n *\n * Either set it to true, or provide a specific Spotlight Sidecar URL.\n *\n * More details: https://spotlightjs.com/\n *\n * IMPORTANT: Only set this option to `true` while developing, not in production!\n */\n spotlight?: boolean | string;\n\n /**\n * Resolves URLs to low-cardinality route names, e.g. `/users/42` -> `/users/:id`.\n *\n * Framework SDKs set this for you. Set it yourself to name routes for a router the SDK has no\n * integration for. `setRouteProvider` replaces it at runtime.\n */\n routeProvider?: RouteProvider;\n };\n/**\n * Configuration options for the Sentry Browser SDK.\n * @see @sentry/core Options for more information.\n */\nexport type BrowserOptions = CoreOptions<BrowserTransportOptions> & BrowserSpecificOptions;\n\n/**\n * Configuration options for the Sentry Browser SDK Client class\n * @see BrowserClient for more information.\n */\nexport type BrowserClientOptions = ClientOptions<BrowserTransportOptions> & BrowserSpecificOptions;\n\n/**\n * The Sentry Browser SDK Client.\n *\n * @see BrowserOptions for documentation on configuration options.\n * @see SentryClient for usage documentation.\n */\nexport class BrowserClient extends Client<BrowserClientOptions> {\n /**\n * Creates a new Browser SDK instance.\n *\n * @param options Configuration options for this SDK.\n */\n public constructor(options: BrowserClientOptions) {\n const opts = applyDefaultOptions(options);\n const sdkSource = WINDOW.SENTRY_SDK_SOURCE || getSDKSource();\n applySdkMetadata(opts, 'browser', ['browser'], sdkSource);\n\n super(opts);\n\n if (opts.routeProvider) {\n setRouteProvider(opts.routeProvider, this);\n }\n\n // Unhandled errors don't actually crash the browser, so we report `unhandled` rather than `crashed`.\n this._unhandledSessionStatus = 'unhandled';\n\n const { userInfo } = this.getDataCollectionOptions();\n\n if (opts._metadata?.sdk) {\n opts._metadata.sdk.settings = {\n // Only allow IP inferral by Relay if the user opted in via dataCollection\n infer_ip: userInfo ? 'auto' : 'never',\n // purposefully allowing already passed settings to override the default\n ...opts._metadata.sdk.settings,\n };\n }\n\n const { sendClientReports } = this._options;\n\n // Devices usually hide the page before they sleep and show it again after they wake up. Checking for drift\n // at both points makes the time origin correction happen at the sleep, rather than at the next regular timestamp call.\n const checkDrift = (): void => {\n timestampInSeconds();\n };\n\n // Most bundle-size-efficient way to add and remove listeners: Create a table to avoid repeated\n // addeventlistener and removeeventlistener calls. The alternative, using an AbortController, can\n // lead to app breakage on old Angular<>Zone.js < 0.14.3 versions.\n const listeners: [EventTarget | undefined, string, () => void][] = [\n // Flush buffered data when the page becomes hidden (e.g. tab switch, navigation, or the page\n // being discarded). `flush()` emits the `flush` hook, which drains the span (streaming), log and\n // metric buffers and hands the resulting envelopes to the transport (which uses `keepalive`).\n // Client report outcomes don't listen to the `flush` hook, so we flush them separately.\n [\n WINDOW.document,\n 'visibilitychange',\n () => {\n // Devices usually hide the page before they sleep and show it again after they wake up. Checking for drift\n // at both points makes the time origin correction happen at the sleep, rather than at the next regular timestamp call.\n checkDrift();\n\n if (WINDOW.document.visibilityState === 'hidden') {\n if (sendClientReports) {\n this._flushOutcomes();\n }\n // Defer the flush to a microtask so that visibilitychange listeners registered after this\n // one have already run. In particular, browser tracing's background-tab detection ends the\n // active pageload/navigation (segment) span when the page is hidden. Deferring ensures that\n // segment span has been added to the streaming buffer before we flush, so it is sent\n // together with its child spans instead of being orphaned.\n queueMicrotask(() => {\n void this.flush();\n });\n }\n },\n ],\n // `freeze` and `resume` are only fired by Chromium browsers. Other browsers never fire them, so these listeners\n // are no-ops there.\n [WINDOW.document, 'freeze', checkDrift],\n [WINDOW.document, 'resume', checkDrift],\n // Pages restored from the back/forward cache were paused while they were cached.\n [WINDOW, 'pagehide', checkDrift],\n [WINDOW, 'pageshow', checkDrift],\n ];\n\n listeners.forEach(([target, name, listener]) => target?.addEventListener?.(name, listener));\n this.on('close', () =>\n listeners.forEach(([target, name, listener]) => target?.removeEventListener?.(name, listener)),\n );\n\n if (userInfo) {\n this.on('beforeSendSession', addAutoIpAddressToSession);\n }\n }\n\n /**\n * @inheritDoc\n */\n public eventFromException(exception: unknown, hint?: EventHint): PromiseLike<Event> {\n return eventFromException(this._options.stackParser, exception, hint, this._options.attachStacktrace);\n }\n\n /**\n * @inheritDoc\n */\n public eventFromMessage(\n message: ParameterizedString,\n level: SeverityLevel = 'info',\n hint?: EventHint,\n ): PromiseLike<Event> {\n return eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace);\n }\n\n /**\n * @inheritDoc\n */\n protected _prepareEvent(\n event: Event,\n hint: EventHint,\n currentScope: Scope,\n isolationScope: Scope,\n ): PromiseLike<Event | null> {\n event.platform = event.platform || 'javascript';\n\n return super._prepareEvent(event, hint, currentScope, isolationScope);\n }\n}\n\n/** Exported only for tests. */\nexport function applyDefaultOptions<T extends Partial<BrowserClientOptions>>(optionsArg: T): T {\n return {\n release:\n typeof __SENTRY_RELEASE__ === 'string' // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value\n ? __SENTRY_RELEASE__\n : WINDOW.SENTRY_RELEASE?.id, // This supports the variable that sentry-webpack-plugin injects\n sendClientReports: true,\n // We default this to true, as it is the safer scenario\n parentSpanIsAlwaysRootSpan: true,\n ...optionsArg,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { SENTRY_OP, HTTP_REQUEST_METHOD, URL_DOMAIN, URL_FULL } from '@sentry/conventions/attributes';
1
+ import { SENTRY_ORIGIN, SENTRY_OP, HTTP_REQUEST_METHOD, URL_DOMAIN, URL_FULL } from '@sentry/conventions/attributes';
2
2
  import { HTTP_CLIENT_STREAM } from '@sentry/conventions/op';
3
- import { defineIntegration, addFetchEndInstrumentationHandler, addFetchInstrumentationHandler, parseStringToURLObject, stripDataUrlContent, getSanitizedUrlStringFromUrlObject, getUrlDomain, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, filterCollectedUrl, hasSpanStreamingEnabled } from '@sentry/core';
3
+ import { defineIntegration, addFetchEndInstrumentationHandler, addFetchInstrumentationHandler, parseStringToURLObject, stripDataUrlContent, getSanitizedUrlStringFromUrlObject, getUrlDomain, filterCollectedUrl, hasSpanStreamingEnabled } from '@sentry/core';
4
4
  import { startInactiveSpan } from '@sentry/core/browser';
5
5
  import { WINDOW } from '../helpers.js';
6
6
 
@@ -45,7 +45,7 @@ const fetchStreamPerformanceIntegration = defineIntegration(() => {
45
45
  [HTTP_REQUEST_METHOD]: method,
46
46
  type: "fetch",
47
47
  [SENTRY_OP]: HTTP_CLIENT_STREAM,
48
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser.stream"
48
+ [SENTRY_ORIGIN]: "auto.http.browser.stream"
49
49
  }
50
50
  });
51
51
  responseToStreamSpan.set(handlerData.response, streamSpan);
@@ -1 +1 @@
1
- {"version":3,"file":"fetchStreamPerformance.js","sources":["../../../../../src/integrations/fetchStreamPerformance.ts"],"sourcesContent":["import { HTTP_REQUEST_METHOD, SENTRY_OP, URL_DOMAIN, URL_FULL } from '@sentry/conventions/attributes';\nimport { HTTP_CLIENT_STREAM } from '@sentry/conventions/op';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n addFetchEndInstrumentationHandler,\n addFetchInstrumentationHandler,\n defineIntegration,\n getSanitizedUrlStringFromUrlObject,\n getUrlDomain,\n hasSpanStreamingEnabled,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n stripDataUrlContent,\n filterCollectedUrl,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport { WINDOW } from '../helpers';\n\nconst responseToStreamSpan = new WeakMap<object, Span>();\nconst responseToFallbackTimeout = new WeakMap<object, ReturnType<typeof setTimeout>>();\n\n// Matches the max timeout in `resolveResponse` in packages/core/src/instrument/fetch.ts\nconst STREAM_RESOLVE_FALLBACK_MS = 90_000;\n\nconst STREAMING_CONTENT_TYPES = ['text/event-stream', 'application/x-ndjson', 'application/stream+json'];\n\n/**\n * Tracks streamed fetch response bodies by creating an `http.client.stream` sibling span.\n *\n * The regular `http.client` span ends when response headers arrive. This integration adds\n * a span that starts at header arrival and ends when the body fully resolves:\n *\n * ```\n * --------- pageload --------------------------------\n * -- http.client --\n * -- http.client.stream -------\n * ```\n */\nexport const fetchStreamPerformanceIntegration = defineIntegration(() => {\n return {\n name: 'FetchStreamPerformance' as const,\n\n setup(client) {\n // End the stream span when the response body finishes resolving\n addFetchEndInstrumentationHandler(handlerData => {\n if (handlerData.response) {\n const streamSpan = responseToStreamSpan.get(handlerData.response);\n if (streamSpan && handlerData.endTimestamp) {\n streamSpan.end(handlerData.endTimestamp);\n\n const fallbackTimeout = responseToFallbackTimeout.get(handlerData.response);\n if (fallbackTimeout) {\n clearTimeout(fallbackTimeout);\n }\n }\n }\n });\n\n addFetchInstrumentationHandler(handlerData => {\n // Only create the stream span once headers have arrived\n if (handlerData.endTimestamp && handlerData.response) {\n // Only create stream spans for responses that are likely streamed:\n // 1. No content-length header (streamed responses don't know the size upfront)\n // 2. Content-type is a known streaming type (avoids false positives on HTTP/2\n // where content-length is often omitted even for regular responses)\n const contentType = handlerData.response.headers?.get('content-type') || '';\n if (\n handlerData.response.headers?.get('content-length') ||\n !STREAMING_CONTENT_TYPES.some(t => contentType.startsWith(t))\n ) {\n return;\n }\n\n const url = handlerData.fetchData?.url || '';\n const method = handlerData.fetchData?.method || 'GET';\n\n const parsedUrl = parseStringToURLObject(url);\n const sanitizedUrl = url.startsWith('data:')\n ? stripDataUrlContent(url)\n : parsedUrl\n ? getSanitizedUrlStringFromUrlObject(parsedUrl)\n : url;\n\n // `http.client.stream` follows the same name rules as `http.client`.\n const domain = getUrlDomain(url, WINDOW.location?.origin);\n const streamedName = domain ? `${method} ${domain}` : method;\n const streamSpan = startInactiveSpan({\n name: hasSpanStreamingEnabled(client) ? streamedName : `${method} ${sanitizedUrl}`,\n startTime: handlerData.endTimestamp,\n attributes: {\n [URL_FULL]: filterCollectedUrl(stripDataUrlContent(url)),\n [URL_DOMAIN]: domain,\n [HTTP_REQUEST_METHOD]: method,\n type: 'fetch',\n [SENTRY_OP]: HTTP_CLIENT_STREAM,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.stream',\n },\n });\n\n responseToStreamSpan.set(handlerData.response, streamSpan);\n\n // prevent the span from leaking indefinitely if the body never resolves\n const fallbackTimeout = setTimeout(() => {\n if (streamSpan.isRecording()) {\n streamSpan.end();\n }\n }, STREAM_RESOLVE_FALLBACK_MS);\n\n responseToFallbackTimeout.set(handlerData.response, fallbackTimeout);\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetchStreamPerformance.js","sources":["../../../../../src/integrations/fetchStreamPerformance.ts"],"sourcesContent":["import { HTTP_REQUEST_METHOD, SENTRY_OP, URL_DOMAIN, URL_FULL, SENTRY_ORIGIN } from '@sentry/conventions/attributes';\nimport { HTTP_CLIENT_STREAM } from '@sentry/conventions/op';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n addFetchEndInstrumentationHandler,\n addFetchInstrumentationHandler,\n defineIntegration,\n getSanitizedUrlStringFromUrlObject,\n getUrlDomain,\n hasSpanStreamingEnabled,\n parseStringToURLObject,\n stripDataUrlContent,\n filterCollectedUrl,\n} from '@sentry/core';\nimport { startInactiveSpan } from '@sentry/core/browser';\nimport { WINDOW } from '../helpers';\n\nconst responseToStreamSpan = new WeakMap<object, Span>();\nconst responseToFallbackTimeout = new WeakMap<object, ReturnType<typeof setTimeout>>();\n\n// Matches the max timeout in `resolveResponse` in packages/core/src/instrument/fetch.ts\nconst STREAM_RESOLVE_FALLBACK_MS = 90_000;\n\nconst STREAMING_CONTENT_TYPES = ['text/event-stream', 'application/x-ndjson', 'application/stream+json'];\n\n/**\n * Tracks streamed fetch response bodies by creating an `http.client.stream` sibling span.\n *\n * The regular `http.client` span ends when response headers arrive. This integration adds\n * a span that starts at header arrival and ends when the body fully resolves:\n *\n * ```\n * --------- pageload --------------------------------\n * -- http.client --\n * -- http.client.stream -------\n * ```\n */\nexport const fetchStreamPerformanceIntegration = defineIntegration(() => {\n return {\n name: 'FetchStreamPerformance' as const,\n\n setup(client) {\n // End the stream span when the response body finishes resolving\n addFetchEndInstrumentationHandler(handlerData => {\n if (handlerData.response) {\n const streamSpan = responseToStreamSpan.get(handlerData.response);\n if (streamSpan && handlerData.endTimestamp) {\n streamSpan.end(handlerData.endTimestamp);\n\n const fallbackTimeout = responseToFallbackTimeout.get(handlerData.response);\n if (fallbackTimeout) {\n clearTimeout(fallbackTimeout);\n }\n }\n }\n });\n\n addFetchInstrumentationHandler(handlerData => {\n // Only create the stream span once headers have arrived\n if (handlerData.endTimestamp && handlerData.response) {\n // Only create stream spans for responses that are likely streamed:\n // 1. No content-length header (streamed responses don't know the size upfront)\n // 2. Content-type is a known streaming type (avoids false positives on HTTP/2\n // where content-length is often omitted even for regular responses)\n const contentType = handlerData.response.headers?.get('content-type') || '';\n if (\n handlerData.response.headers?.get('content-length') ||\n !STREAMING_CONTENT_TYPES.some(t => contentType.startsWith(t))\n ) {\n return;\n }\n\n const url = handlerData.fetchData?.url || '';\n const method = handlerData.fetchData?.method || 'GET';\n\n const parsedUrl = parseStringToURLObject(url);\n const sanitizedUrl = url.startsWith('data:')\n ? stripDataUrlContent(url)\n : parsedUrl\n ? getSanitizedUrlStringFromUrlObject(parsedUrl)\n : url;\n\n // `http.client.stream` follows the same name rules as `http.client`.\n const domain = getUrlDomain(url, WINDOW.location?.origin);\n const streamedName = domain ? `${method} ${domain}` : method;\n const streamSpan = startInactiveSpan({\n name: hasSpanStreamingEnabled(client) ? streamedName : `${method} ${sanitizedUrl}`,\n startTime: handlerData.endTimestamp,\n attributes: {\n [URL_FULL]: filterCollectedUrl(stripDataUrlContent(url)),\n [URL_DOMAIN]: domain,\n [HTTP_REQUEST_METHOD]: method,\n type: 'fetch',\n [SENTRY_OP]: HTTP_CLIENT_STREAM,\n [SENTRY_ORIGIN]: 'auto.http.browser.stream',\n },\n });\n\n responseToStreamSpan.set(handlerData.response, streamSpan);\n\n // prevent the span from leaking indefinitely if the body never resolves\n const fallbackTimeout = setTimeout(() => {\n if (streamSpan.isRecording()) {\n streamSpan.end();\n }\n }, STREAM_RESOLVE_FALLBACK_MS);\n\n responseToFallbackTimeout.set(handlerData.response, fallbackTimeout);\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n"],"names":[],"mappings":";;;;;;AAiBA,MAAM,oBAAA,uBAA2B,OAAA,EAAsB;AACvD,MAAM,yBAAA,uBAAgC,OAAA,EAA+C;AAGrF,MAAM,0BAAA,GAA6B,GAAA;AAEnC,MAAM,uBAAA,GAA0B,CAAC,mBAAA,EAAqB,sBAAA,EAAwB,yBAAyB,CAAA;AAchG,MAAM,iCAAA,GAAoC,kBAAkB,MAAM;AACvE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,wBAAA;AAAA,IAEN,MAAM,MAAA,EAAQ;AAEZ,MAAA,iCAAA,CAAkC,CAAA,WAAA,KAAe;AAC/C,QAAA,IAAI,YAAY,QAAA,EAAU;AACxB,UAAA,MAAM,UAAA,GAAa,oBAAA,CAAqB,GAAA,CAAI,WAAA,CAAY,QAAQ,CAAA;AAChE,UAAA,IAAI,UAAA,IAAc,YAAY,YAAA,EAAc;AAC1C,YAAA,UAAA,CAAW,GAAA,CAAI,YAAY,YAAY,CAAA;AAEvC,YAAA,MAAM,eAAA,GAAkB,yBAAA,CAA0B,GAAA,CAAI,WAAA,CAAY,QAAQ,CAAA;AAC1E,YAAA,IAAI,eAAA,EAAiB;AACnB,cAAA,YAAA,CAAa,eAAe,CAAA;AAAA,YAC9B;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC,CAAA;AAED,MAAA,8BAAA,CAA+B,CAAA,WAAA,KAAe;AAE5C,QAAA,IAAI,WAAA,CAAY,YAAA,IAAgB,WAAA,CAAY,QAAA,EAAU;AAKpD,UAAA,MAAM,cAAc,WAAA,CAAY,QAAA,CAAS,OAAA,EAAS,GAAA,CAAI,cAAc,CAAA,IAAK,EAAA;AACzE,UAAA,IACE,WAAA,CAAY,QAAA,CAAS,OAAA,EAAS,GAAA,CAAI,gBAAgB,CAAA,IAClD,CAAC,uBAAA,CAAwB,IAAA,CAAK,CAAA,CAAA,KAAK,WAAA,CAAY,UAAA,CAAW,CAAC,CAAC,CAAA,EAC5D;AACA,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,GAAA,GAAM,WAAA,CAAY,SAAA,EAAW,GAAA,IAAO,EAAA;AAC1C,UAAA,MAAM,MAAA,GAAS,WAAA,CAAY,SAAA,EAAW,MAAA,IAAU,KAAA;AAEhD,UAAA,MAAM,SAAA,GAAY,uBAAuB,GAAG,CAAA;AAC5C,UAAA,MAAM,YAAA,GAAe,GAAA,CAAI,UAAA,CAAW,OAAO,CAAA,GACvC,mBAAA,CAAoB,GAAG,CAAA,GACvB,SAAA,GACE,kCAAA,CAAmC,SAAS,CAAA,GAC5C,GAAA;AAGN,UAAA,MAAM,MAAA,GAAS,YAAA,CAAa,GAAA,EAAK,MAAA,CAAO,UAAU,MAAM,CAAA;AACxD,UAAA,MAAM,eAAe,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,GAAK,MAAA;AACtD,UAAA,MAAM,aAAa,iBAAA,CAAkB;AAAA,YACnC,IAAA,EAAM,wBAAwB,MAAM,CAAA,GAAI,eAAe,CAAA,EAAG,MAAM,IAAI,YAAY,CAAA,CAAA;AAAA,YAChF,WAAW,WAAA,CAAY,YAAA;AAAA,YACvB,UAAA,EAAY;AAAA,cACV,CAAC,QAAQ,GAAG,kBAAA,CAAmB,mBAAA,CAAoB,GAAG,CAAC,CAAA;AAAA,cACvD,CAAC,UAAU,GAAG,MAAA;AAAA,cACd,CAAC,mBAAmB,GAAG,MAAA;AAAA,cACvB,IAAA,EAAM,OAAA;AAAA,cACN,CAAC,SAAS,GAAG,kBAAA;AAAA,cACb,CAAC,aAAa,GAAG;AAAA;AACnB,WACD,CAAA;AAED,UAAA,oBAAA,CAAqB,GAAA,CAAI,WAAA,CAAY,QAAA,EAAU,UAAU,CAAA;AAGzD,UAAA,MAAM,eAAA,GAAkB,WAAW,MAAM;AACvC,YAAA,IAAI,UAAA,CAAW,aAAY,EAAG;AAC5B,cAAA,UAAA,CAAW,GAAA,EAAI;AAAA,YACjB;AAAA,UACF,GAAG,0BAA0B,CAAA;AAE7B,UAAA,yBAAA,CAA0B,GAAA,CAAI,WAAA,CAAY,QAAA,EAAU,eAAe,CAAA;AAAA,QACrE;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAC;;;;"}
@@ -1 +1 @@
1
- {"type":"module","version":"11.4.0","sideEffects":false}
1
+ {"type":"module","version":"11.6.0","sideEffects":false}
@@ -1,4 +1,4 @@
1
- import { GLOBAL_OBJ, debug, uuid4, browserPerformanceTimeOrigin, getClient, getDebugImagesForResources } from '@sentry/core';
1
+ import { GLOBAL_OBJ, debug, uuid4, _INTERNAL_performanceTimeToSeconds, getClient, getDebugImagesForResources } from '@sentry/core';
2
2
  import { DEBUG_BUILD } from '../debug-build.js';
3
3
  import { WINDOW } from '../helpers.js';
4
4
 
@@ -93,16 +93,13 @@ function convertToContinuousProfile(input) {
93
93
  }
94
94
  stacks[i] = list;
95
95
  }
96
- const perfOrigin = browserPerformanceTimeOrigin();
97
- const origin = typeof performance.timeOrigin === "number" ? performance.timeOrigin : perfOrigin || 0;
98
- const adjustForOriginChange = origin - (perfOrigin || origin);
99
96
  const samples = [];
100
97
  for (let i = 0; i < input.samples.length; i++) {
101
98
  const sample = input.samples[i];
102
99
  if (!sample) {
103
100
  continue;
104
101
  }
105
- const timestampSeconds = (origin + (sample.timestamp - adjustForOriginChange)) / 1e3;
102
+ const timestampSeconds = _INTERNAL_performanceTimeToSeconds(sample.timestamp);
106
103
  samples[i] = {
107
104
  stack_id: sample.stackId ?? 0,
108
105
  thread_id: PROFILER_THREAD_ID_STRING,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../../src/profiling/utils.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, ContinuousThreadCpuProfile, DebugImage, ProfileChunk, Span } from '@sentry/core';\nimport {\n browserPerformanceTimeOrigin,\n debug,\n getClient,\n getDebugImagesForResources,\n GLOBAL_OBJ,\n uuid4,\n} from '@sentry/core';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport type { JSSelfProfile, JSSelfProfiler, JSSelfProfilerConstructor } from './jsSelfProfiling';\n\n// Checking if we are in Main or Worker thread: `self` (not `window`) is the `globalThis` in Web Workers and `importScripts` are only available in Web Workers\nconst isMainThread = 'window' in GLOBAL_OBJ && GLOBAL_OBJ.window === GLOBAL_OBJ && typeof importScripts === 'undefined';\n\n// Setting ID to 0 as we cannot get an ID from Web Workers\nexport const PROFILER_THREAD_ID_STRING = String(0);\nexport const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker';\n\n/**\n * Create a profile chunk envelope item\n */\nexport function createProfileChunkPayload(\n jsSelfProfile: JSSelfProfile,\n client: Client,\n profilerId?: string,\n): ProfileChunk {\n // only == to catch null and undefined\n if (jsSelfProfile == null) {\n throw new TypeError(\n `Cannot construct profiling event envelope without a valid profile. Got ${jsSelfProfile} instead.`,\n );\n }\n\n const continuousProfile = convertToContinuousProfile(jsSelfProfile);\n\n const options = client.getOptions();\n const sdk = client.getSdkMetadata?.()?.sdk;\n\n return {\n chunk_id: uuid4(),\n client_sdk: {\n name: sdk?.name ?? 'sentry.javascript.browser',\n version: sdk?.version ?? '0.0.0',\n },\n profiler_id: profilerId || uuid4(),\n platform: 'javascript',\n version: '2',\n release: options.release ?? '',\n environment: options.environment ?? 'production',\n debug_meta: {\n // function name obfuscation\n images: applyDebugMetadata(jsSelfProfile.resources),\n },\n profile: continuousProfile,\n };\n}\n\n/**\n * Validate a profile chunk against the Sample Format V2 requirements.\n * https://develop.sentry.dev/sdk/telemetry/profiles/sample-format-v2/\n * - Presence of samples, stacks, frames\n * - Required metadata fields\n */\nexport function validateProfileChunk(chunk: ProfileChunk): { valid: true } | { reason: string } {\n try {\n // Required metadata\n if (!chunk || typeof chunk !== 'object') {\n return { reason: 'chunk is not an object' };\n }\n\n // profiler_id and chunk_id must be 32 lowercase hex chars\n const isHex32 = (val: unknown): boolean => typeof val === 'string' && /^[a-f0-9]{32}$/.test(val);\n if (!isHex32(chunk.profiler_id)) {\n return { reason: 'missing or invalid profiler_id' };\n }\n if (!isHex32(chunk.chunk_id)) {\n return { reason: 'missing or invalid chunk_id' };\n }\n\n if (!chunk.client_sdk) {\n return { reason: 'missing client_sdk metadata' };\n }\n\n // Profile data must have frames, stacks, samples\n const profile = chunk.profile as { frames?: unknown[]; stacks?: unknown[]; samples?: unknown[] } | undefined;\n if (!profile) {\n return { reason: 'missing profile data' };\n }\n\n if (!Array.isArray(profile.frames) || !profile.frames.length) {\n return { reason: 'profile has no frames' };\n }\n if (!Array.isArray(profile.stacks) || !profile.stacks.length) {\n return { reason: 'profile has no stacks' };\n }\n if (!Array.isArray(profile.samples) || !profile.samples.length) {\n return { reason: 'profile has no samples' };\n }\n\n return { valid: true };\n } catch (e) {\n return { reason: `unknown validation error: ${e}` };\n }\n}\n\n/**\n * Convert from JSSelfProfile format to ContinuousThreadCpuProfile format.\n */\nfunction convertToContinuousProfile(input: {\n frames: { name: string; resourceId?: number; line?: number; column?: number }[];\n stacks: { frameId: number; parentId?: number }[];\n samples: { timestamp: number; stackId?: number }[];\n resources: string[];\n}): ContinuousThreadCpuProfile {\n // Frames map 1:1 by index; fill only when present to avoid sparse writes\n const frames: ContinuousThreadCpuProfile['frames'] = [];\n for (let i = 0; i < input.frames.length; i++) {\n const frame = input.frames[i];\n if (!frame) {\n continue;\n }\n frames[i] = {\n function: frame.name,\n abs_path: typeof frame.resourceId === 'number' ? input.resources[frame.resourceId] : undefined,\n lineno: frame.line,\n colno: frame.column,\n };\n }\n\n // Build stacks by following parent links, top->down order (root last)\n const stacks: ContinuousThreadCpuProfile['stacks'] = [];\n for (let i = 0; i < input.stacks.length; i++) {\n const stackHead = input.stacks[i];\n if (!stackHead) {\n continue;\n }\n const list: number[] = [];\n let current: { frameId: number; parentId?: number } | undefined = stackHead;\n while (current) {\n list.push(current.frameId);\n current = current.parentId === undefined ? undefined : input.stacks[current.parentId];\n }\n stacks[i] = list;\n }\n\n // Align timestamps to SDK time origin to match span/event timelines\n const perfOrigin = browserPerformanceTimeOrigin();\n const origin = typeof performance.timeOrigin === 'number' ? performance.timeOrigin : perfOrigin || 0;\n const adjustForOriginChange = origin - (perfOrigin || origin);\n\n const samples: ContinuousThreadCpuProfile['samples'] = [];\n for (let i = 0; i < input.samples.length; i++) {\n const sample = input.samples[i];\n if (!sample) {\n continue;\n }\n // Convert ms to seconds epoch-based timestamp\n const timestampSeconds = (origin + (sample.timestamp - adjustForOriginChange)) / 1000;\n samples[i] = {\n stack_id: sample.stackId ?? 0,\n thread_id: PROFILER_THREAD_ID_STRING,\n timestamp: timestampSeconds,\n };\n }\n\n return {\n frames,\n stacks,\n samples,\n thread_metadata: { [PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME } },\n };\n}\n\n/**\n * Applies debug meta data to an event from a list of paths to resources (sourcemaps)\n */\nexport function applyDebugMetadata(resource_paths: ReadonlyArray<string>): DebugImage[] {\n const client = getClient();\n const options = client?.getOptions();\n const stackParser = options?.stackParser;\n\n if (!stackParser) {\n return [];\n }\n\n return getDebugImagesForResources(stackParser, resource_paths);\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 */\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 debug.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 && debug.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// Keep a flag value to avoid re-initializing the profiler constructor. If it fails\n// once, it will always fail and this allows us to early return.\nlet PROFILING_CONSTRUCTOR_FAILED: boolean = false;\nexport const MAX_PROFILE_DURATION_MS = 30_000;\n\n/**\n * Check if profiler constructor is available.\n * @param maybeProfiler\n */\nfunction isJSProfilerSupported(maybeProfiler: unknown): maybeProfiler is typeof JSSelfProfilerConstructor {\n return typeof maybeProfiler === 'function';\n}\n\n/**\n * Starts the profiler and returns the profiler instance.\n */\nexport function startJSSelfProfile(): JSSelfProfiler | undefined {\n // Feature support check first\n const JSProfilerConstructor = WINDOW.Profiler;\n\n if (!isJSProfilerSupported(JSProfilerConstructor)) {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.');\n }\n return;\n }\n\n // From initial testing, it seems that the minimum value for sampleInterval is 10ms.\n const samplingIntervalMS = 10;\n // Start the profiler\n const maxSamples = Math.floor(MAX_PROFILE_DURATION_MS / samplingIntervalMS);\n\n // Attempt to initialize the profiler constructor, if it fails, we disable profiling for the current user session.\n // This is likely due to a missing 'Document-Policy': 'js-profiling' header. We do not want to throw an error if this happens\n // as we risk breaking the user's application, so just disable profiling and log an error.\n try {\n return new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples });\n } catch {\n if (DEBUG_BUILD) {\n debug.log(\n \"[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.\",\n );\n debug.log('[Profiling] Disabling profiling for current user session.');\n }\n PROFILING_CONSTRUCTOR_FAILED = true;\n }\n\n return;\n}\n\n/**\n * Determine if a profile should be created for the current session.\n */\nexport function shouldProfileSession(options: BrowserOptions): boolean {\n // If constructor failed once, it will always fail, so we can early return.\n if (PROFILING_CONSTRUCTOR_FAILED) {\n if (DEBUG_BUILD) {\n debug.log(\n '[Profiling] Profiling has been disabled for the duration of the current user session as the JS Profiler could not be started.',\n );\n }\n return false;\n }\n\n if (options.profileLifecycle !== 'trace' && options.profileLifecycle !== 'manual') {\n DEBUG_BUILD && debug.warn('[Profiling] Session not sampled. Invalid `profileLifecycle` option.');\n return false;\n }\n\n // Session sampling: profileSessionSampleRate gates whether profiling is enabled for this session\n const profileSessionSampleRate = options.profileSessionSampleRate;\n\n if (!isValidSampleRate(profileSessionSampleRate)) {\n DEBUG_BUILD && debug.warn('[Profiling] Discarding profile because of invalid profileSessionSampleRate.');\n return false;\n }\n\n if (!profileSessionSampleRate) {\n DEBUG_BUILD &&\n debug.log('[Profiling] Discarding profile because profileSessionSampleRate is not defined or set to 0');\n return false;\n }\n\n return Math.random() <= profileSessionSampleRate;\n}\n\nexport function setThreadAttributes(span: Span): void {\n span.setAttribute('thread.id', PROFILER_THREAD_ID_STRING);\n span.setAttribute('thread.name', PROFILER_THREAD_NAME);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../../src/profiling/utils.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, ContinuousThreadCpuProfile, DebugImage, ProfileChunk, Span } from '@sentry/core';\nimport {\n debug,\n getClient,\n getDebugImagesForResources,\n GLOBAL_OBJ,\n _INTERNAL_performanceTimeToSeconds,\n uuid4,\n} from '@sentry/core';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport type { JSSelfProfile, JSSelfProfiler, JSSelfProfilerConstructor } from './jsSelfProfiling';\n\n// Checking if we are in Main or Worker thread: `self` (not `window`) is the `globalThis` in Web Workers and `importScripts` are only available in Web Workers\nconst isMainThread = 'window' in GLOBAL_OBJ && GLOBAL_OBJ.window === GLOBAL_OBJ && typeof importScripts === 'undefined';\n\n// Setting ID to 0 as we cannot get an ID from Web Workers\nexport const PROFILER_THREAD_ID_STRING = String(0);\nexport const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker';\n\n/**\n * Create a profile chunk envelope item\n */\nexport function createProfileChunkPayload(\n jsSelfProfile: JSSelfProfile,\n client: Client,\n profilerId?: string,\n): ProfileChunk {\n // only == to catch null and undefined\n if (jsSelfProfile == null) {\n throw new TypeError(\n `Cannot construct profiling event envelope without a valid profile. Got ${jsSelfProfile} instead.`,\n );\n }\n\n const continuousProfile = convertToContinuousProfile(jsSelfProfile);\n\n const options = client.getOptions();\n const sdk = client.getSdkMetadata?.()?.sdk;\n\n return {\n chunk_id: uuid4(),\n client_sdk: {\n name: sdk?.name ?? 'sentry.javascript.browser',\n version: sdk?.version ?? '0.0.0',\n },\n profiler_id: profilerId || uuid4(),\n platform: 'javascript',\n version: '2',\n release: options.release ?? '',\n environment: options.environment ?? 'production',\n debug_meta: {\n // function name obfuscation\n images: applyDebugMetadata(jsSelfProfile.resources),\n },\n profile: continuousProfile,\n };\n}\n\n/**\n * Validate a profile chunk against the Sample Format V2 requirements.\n * https://develop.sentry.dev/sdk/telemetry/profiles/sample-format-v2/\n * - Presence of samples, stacks, frames\n * - Required metadata fields\n */\nexport function validateProfileChunk(chunk: ProfileChunk): { valid: true } | { reason: string } {\n try {\n // Required metadata\n if (!chunk || typeof chunk !== 'object') {\n return { reason: 'chunk is not an object' };\n }\n\n // profiler_id and chunk_id must be 32 lowercase hex chars\n const isHex32 = (val: unknown): boolean => typeof val === 'string' && /^[a-f0-9]{32}$/.test(val);\n if (!isHex32(chunk.profiler_id)) {\n return { reason: 'missing or invalid profiler_id' };\n }\n if (!isHex32(chunk.chunk_id)) {\n return { reason: 'missing or invalid chunk_id' };\n }\n\n if (!chunk.client_sdk) {\n return { reason: 'missing client_sdk metadata' };\n }\n\n // Profile data must have frames, stacks, samples\n const profile = chunk.profile as { frames?: unknown[]; stacks?: unknown[]; samples?: unknown[] } | undefined;\n if (!profile) {\n return { reason: 'missing profile data' };\n }\n\n if (!Array.isArray(profile.frames) || !profile.frames.length) {\n return { reason: 'profile has no frames' };\n }\n if (!Array.isArray(profile.stacks) || !profile.stacks.length) {\n return { reason: 'profile has no stacks' };\n }\n if (!Array.isArray(profile.samples) || !profile.samples.length) {\n return { reason: 'profile has no samples' };\n }\n\n return { valid: true };\n } catch (e) {\n return { reason: `unknown validation error: ${e}` };\n }\n}\n\n/**\n * Convert from JSSelfProfile format to ContinuousThreadCpuProfile format.\n */\nfunction convertToContinuousProfile(input: {\n frames: { name: string; resourceId?: number; line?: number; column?: number }[];\n stacks: { frameId: number; parentId?: number }[];\n samples: { timestamp: number; stackId?: number }[];\n resources: string[];\n}): ContinuousThreadCpuProfile {\n // Frames map 1:1 by index; fill only when present to avoid sparse writes\n const frames: ContinuousThreadCpuProfile['frames'] = [];\n for (let i = 0; i < input.frames.length; i++) {\n const frame = input.frames[i];\n if (!frame) {\n continue;\n }\n frames[i] = {\n function: frame.name,\n abs_path: typeof frame.resourceId === 'number' ? input.resources[frame.resourceId] : undefined,\n lineno: frame.line,\n colno: frame.column,\n };\n }\n\n // Build stacks by following parent links, top->down order (root last)\n const stacks: ContinuousThreadCpuProfile['stacks'] = [];\n for (let i = 0; i < input.stacks.length; i++) {\n const stackHead = input.stacks[i];\n if (!stackHead) {\n continue;\n }\n const list: number[] = [];\n let current: { frameId: number; parentId?: number } | undefined = stackHead;\n while (current) {\n list.push(current.frameId);\n current = current.parentId === undefined ? undefined : input.stacks[current.parentId];\n }\n stacks[i] = list;\n }\n\n const samples: ContinuousThreadCpuProfile['samples'] = [];\n for (let i = 0; i < input.samples.length; i++) {\n const sample = input.samples[i];\n if (!sample) {\n continue;\n }\n // Sample timestamps are relative to `performance.timeOrigin`, so we convert them like performance entries.\n // The cast is safe: the JS Self-Profiling API only exists if the Performance API does.\n const timestampSeconds = _INTERNAL_performanceTimeToSeconds(sample.timestamp) as number;\n samples[i] = {\n stack_id: sample.stackId ?? 0,\n thread_id: PROFILER_THREAD_ID_STRING,\n timestamp: timestampSeconds,\n };\n }\n\n return {\n frames,\n stacks,\n samples,\n thread_metadata: { [PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME } },\n };\n}\n\n/**\n * Applies debug meta data to an event from a list of paths to resources (sourcemaps)\n */\nexport function applyDebugMetadata(resource_paths: ReadonlyArray<string>): DebugImage[] {\n const client = getClient();\n const options = client?.getOptions();\n const stackParser = options?.stackParser;\n\n if (!stackParser) {\n return [];\n }\n\n return getDebugImagesForResources(stackParser, resource_paths);\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 */\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 debug.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 && debug.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// Keep a flag value to avoid re-initializing the profiler constructor. If it fails\n// once, it will always fail and this allows us to early return.\nlet PROFILING_CONSTRUCTOR_FAILED: boolean = false;\nexport const MAX_PROFILE_DURATION_MS = 30_000;\n\n/**\n * Check if profiler constructor is available.\n * @param maybeProfiler\n */\nfunction isJSProfilerSupported(maybeProfiler: unknown): maybeProfiler is typeof JSSelfProfilerConstructor {\n return typeof maybeProfiler === 'function';\n}\n\n/**\n * Starts the profiler and returns the profiler instance.\n */\nexport function startJSSelfProfile(): JSSelfProfiler | undefined {\n // Feature support check first\n const JSProfilerConstructor = WINDOW.Profiler;\n\n if (!isJSProfilerSupported(JSProfilerConstructor)) {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.');\n }\n return;\n }\n\n // From initial testing, it seems that the minimum value for sampleInterval is 10ms.\n const samplingIntervalMS = 10;\n // Start the profiler\n const maxSamples = Math.floor(MAX_PROFILE_DURATION_MS / samplingIntervalMS);\n\n // Attempt to initialize the profiler constructor, if it fails, we disable profiling for the current user session.\n // This is likely due to a missing 'Document-Policy': 'js-profiling' header. We do not want to throw an error if this happens\n // as we risk breaking the user's application, so just disable profiling and log an error.\n try {\n return new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples });\n } catch {\n if (DEBUG_BUILD) {\n debug.log(\n \"[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.\",\n );\n debug.log('[Profiling] Disabling profiling for current user session.');\n }\n PROFILING_CONSTRUCTOR_FAILED = true;\n }\n\n return;\n}\n\n/**\n * Determine if a profile should be created for the current session.\n */\nexport function shouldProfileSession(options: BrowserOptions): boolean {\n // If constructor failed once, it will always fail, so we can early return.\n if (PROFILING_CONSTRUCTOR_FAILED) {\n if (DEBUG_BUILD) {\n debug.log(\n '[Profiling] Profiling has been disabled for the duration of the current user session as the JS Profiler could not be started.',\n );\n }\n return false;\n }\n\n if (options.profileLifecycle !== 'trace' && options.profileLifecycle !== 'manual') {\n DEBUG_BUILD && debug.warn('[Profiling] Session not sampled. Invalid `profileLifecycle` option.');\n return false;\n }\n\n // Session sampling: profileSessionSampleRate gates whether profiling is enabled for this session\n const profileSessionSampleRate = options.profileSessionSampleRate;\n\n if (!isValidSampleRate(profileSessionSampleRate)) {\n DEBUG_BUILD && debug.warn('[Profiling] Discarding profile because of invalid profileSessionSampleRate.');\n return false;\n }\n\n if (!profileSessionSampleRate) {\n DEBUG_BUILD &&\n debug.log('[Profiling] Discarding profile because profileSessionSampleRate is not defined or set to 0');\n return false;\n }\n\n return Math.random() <= profileSessionSampleRate;\n}\n\nexport function setThreadAttributes(span: Span): void {\n span.setAttribute('thread.id', PROFILER_THREAD_ID_STRING);\n span.setAttribute('thread.name', PROFILER_THREAD_NAME);\n}\n"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { addFetchInstrumentationHandler, instrumentFetchRequest, parseUrl, stripDataUrlContent, filterCollectedUrl, spanToJSON, hasSpanStreamingEnabled, timestampInSeconds, hasSpansEnabled, setHttpStatus, stripUrlQueryAndFragment, getClient, getActiveSpan, getUrlDomain, getUrlFragment, filterCollectedUrlQuery, getUrlQuery, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, spanIsIgnored, matchesTracePropagationTargets, getTraceData } from '@sentry/core';
1
+ import { addFetchInstrumentationHandler, instrumentFetchRequest, parseUrl, stripDataUrlContent, filterCollectedUrl, spanToJSON, hasSpanStreamingEnabled, timestampInSeconds, hasSpansEnabled, setHttpStatus, stripUrlQueryAndFragment, getClient, getActiveSpan, getUrlDomain, getUrlFragment, filterCollectedUrlQuery, getUrlQuery, SentryNonRecordingSpan, spanIsIgnored, matchesTracePropagationTargets, getTraceData } from '@sentry/core';
2
2
  import { startInactiveSpan } from '@sentry/core/browser';
3
3
  import { addXhrInstrumentationHandler, addPerformanceInstrumentationHandler, resourceTimingToSpanAttributes, SENTRY_XHR_DATA_KEY, parseXhrResponseHeaders, getLocationHref } from '@sentry/browser-utils';
4
4
  import { WINDOW } from '../helpers.js';
5
5
  import { getFullURL, createHeadersSafely, isPerformanceResourceTiming, baggageHeaderHasSentryValues } from './utils.js';
6
- import { SERVER_ADDRESS, URL_FULL, URL_FRAGMENT, URL_QUERY, SENTRY_OP, URL_DOMAIN, HTTP_REQUEST_METHOD } from '@sentry/conventions/attributes';
6
+ import { SERVER_ADDRESS, URL_FULL, URL_FRAGMENT, URL_QUERY, SENTRY_OP, SENTRY_ORIGIN, URL_DOMAIN, HTTP_REQUEST_METHOD } from '@sentry/conventions/attributes';
7
7
  import { HTTP_CLIENT } from '@sentry/conventions/op';
8
8
 
9
9
  const defaultRequestInstrumentationOptions = {
@@ -176,7 +176,7 @@ function xhrCallback(handlerData, shouldCreateSpan, shouldAttachHeaders2, spans,
176
176
  [URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
177
177
  [SERVER_ADDRESS]: host,
178
178
  [URL_DOMAIN]: domain,
179
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.browser",
179
+ [SENTRY_ORIGIN]: "auto.http.browser",
180
180
  [SENTRY_OP]: HTTP_CLIENT,
181
181
  [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl?.search)),
182
182
  [URL_FRAGMENT]: getUrlFragment(parsedUrl?.hash)