@sentry/react-native 8.4.0 → 8.5.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 (98) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/libs/replay-stubs.jar +0 -0
  3. package/android/replay-stubs/build.gradle +1 -1
  4. package/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +56 -4
  5. package/android/src/main/java/io/sentry/react/RNSentryStart.java +3 -0
  6. package/android/src/main/java/io/sentry/react/RNSentryVersion.java +1 -1
  7. package/android/src/newarch/java/io/sentry/react/RNSentryModule.java +10 -0
  8. package/android/src/oldarch/java/io/sentry/react/RNSentryModule.java +10 -0
  9. package/dist/js/NativeRNSentry.d.ts +2 -0
  10. package/dist/js/NativeRNSentry.d.ts.map +1 -1
  11. package/dist/js/NativeRNSentry.js.map +1 -1
  12. package/dist/js/feedback/FeedbackWidgetManager.d.ts +3 -1
  13. package/dist/js/feedback/FeedbackWidgetManager.d.ts.map +1 -1
  14. package/dist/js/feedback/FeedbackWidgetManager.js +15 -1
  15. package/dist/js/feedback/FeedbackWidgetManager.js.map +1 -1
  16. package/dist/js/feedback/FeedbackWidgetProvider.d.ts +3 -2
  17. package/dist/js/feedback/FeedbackWidgetProvider.d.ts.map +1 -1
  18. package/dist/js/feedback/FeedbackWidgetProvider.js +12 -4
  19. package/dist/js/feedback/FeedbackWidgetProvider.js.map +1 -1
  20. package/dist/js/feedback/ShakeToReportBug.d.ts +27 -0
  21. package/dist/js/feedback/ShakeToReportBug.d.ts.map +1 -0
  22. package/dist/js/feedback/ShakeToReportBug.js +83 -0
  23. package/dist/js/feedback/ShakeToReportBug.js.map +1 -0
  24. package/dist/js/feedback/integration.d.ts +11 -0
  25. package/dist/js/feedback/integration.d.ts.map +1 -1
  26. package/dist/js/feedback/integration.js +7 -1
  27. package/dist/js/feedback/integration.js.map +1 -1
  28. package/dist/js/index.d.ts +1 -1
  29. package/dist/js/index.d.ts.map +1 -1
  30. package/dist/js/index.js +1 -1
  31. package/dist/js/index.js.map +1 -1
  32. package/dist/js/integrations/debugsymbolicator.js +3 -1
  33. package/dist/js/integrations/debugsymbolicator.js.map +1 -1
  34. package/dist/js/integrations/default.d.ts.map +1 -1
  35. package/dist/js/integrations/default.js +2 -1
  36. package/dist/js/integrations/default.js.map +1 -1
  37. package/dist/js/integrations/exports.d.ts +1 -0
  38. package/dist/js/integrations/exports.d.ts.map +1 -1
  39. package/dist/js/integrations/exports.js +1 -0
  40. package/dist/js/integrations/exports.js.map +1 -1
  41. package/dist/js/integrations/expoupdateslistener.d.ts +38 -0
  42. package/dist/js/integrations/expoupdateslistener.d.ts.map +1 -0
  43. package/dist/js/integrations/expoupdateslistener.js +130 -0
  44. package/dist/js/integrations/expoupdateslistener.js.map +1 -0
  45. package/dist/js/misc.js +2 -2
  46. package/dist/js/misc.js.map +1 -1
  47. package/dist/js/options.d.ts +12 -0
  48. package/dist/js/options.d.ts.map +1 -1
  49. package/dist/js/options.js.map +1 -1
  50. package/dist/js/tools/utils.d.ts.map +1 -1
  51. package/dist/js/tools/utils.js +2 -3
  52. package/dist/js/tools/utils.js.map +1 -1
  53. package/dist/js/tracing/integrations/appStart.d.ts +8 -0
  54. package/dist/js/tracing/integrations/appStart.d.ts.map +1 -1
  55. package/dist/js/tracing/integrations/appStart.js +56 -7
  56. package/dist/js/tracing/integrations/appStart.js.map +1 -1
  57. package/dist/js/tracing/integrations/nativeFrames.d.ts.map +1 -1
  58. package/dist/js/tracing/integrations/nativeFrames.js +32 -22
  59. package/dist/js/tracing/integrations/nativeFrames.js.map +1 -1
  60. package/dist/js/tracing/integrations/timeToDisplayIntegration.d.ts.map +1 -1
  61. package/dist/js/tracing/integrations/timeToDisplayIntegration.js +1 -0
  62. package/dist/js/tracing/integrations/timeToDisplayIntegration.js.map +1 -1
  63. package/dist/js/tracing/reactnativenavigation.js +1 -1
  64. package/dist/js/tracing/reactnativenavigation.js.map +1 -1
  65. package/dist/js/tracing/reactnavigation.d.ts.map +1 -1
  66. package/dist/js/tracing/reactnavigation.js +3 -1
  67. package/dist/js/tracing/reactnavigation.js.map +1 -1
  68. package/dist/js/utils/ignorerequirecyclelogs.js +1 -1
  69. package/dist/js/utils/ignorerequirecyclelogs.js.map +1 -1
  70. package/dist/js/utils/safe.d.ts +1 -1
  71. package/dist/js/utils/safe.d.ts.map +1 -1
  72. package/dist/js/utils/safe.js.map +1 -1
  73. package/dist/js/version.d.ts +1 -1
  74. package/dist/js/version.js +1 -1
  75. package/dist/js/version.js.map +1 -1
  76. package/ios/RNSentry.mm +47 -1
  77. package/ios/RNSentryEvents.h +1 -0
  78. package/ios/RNSentryEvents.m +1 -0
  79. package/ios/RNSentryVersion.m +1 -1
  80. package/package.json +13 -13
  81. package/plugin/build/withSentry.js +1 -1
  82. package/plugin/build/withSentryAndroidGradlePlugin.d.ts +1 -1
  83. package/plugin/build/withSentryAndroidGradlePlugin.js +1 -1
  84. package/scripts/sentry-xcode.sh +14 -0
  85. package/sentry.gradle +13 -0
  86. package/src/js/NativeRNSentry.ts +2 -0
  87. package/ts3.8/dist/js/NativeRNSentry.d.ts +2 -0
  88. package/ts3.8/dist/js/feedback/FeedbackWidgetManager.d.ts +3 -1
  89. package/ts3.8/dist/js/feedback/FeedbackWidgetProvider.d.ts +3 -2
  90. package/ts3.8/dist/js/feedback/ShakeToReportBug.d.ts +27 -0
  91. package/ts3.8/dist/js/feedback/integration.d.ts +11 -0
  92. package/ts3.8/dist/js/index.d.ts +1 -1
  93. package/ts3.8/dist/js/integrations/exports.d.ts +1 -0
  94. package/ts3.8/dist/js/integrations/expoupdateslistener.d.ts +38 -0
  95. package/ts3.8/dist/js/options.d.ts +12 -0
  96. package/ts3.8/dist/js/tracing/integrations/appStart.d.ts +8 -0
  97. package/ts3.8/dist/js/utils/safe.d.ts +1 -1
  98. package/ts3.8/dist/js/version.d.ts +1 -1
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { debug, timestampInSeconds } from '@sentry/core';
10
+ import { debug, getRootSpan, spanToJSON, timestampInSeconds } from '@sentry/core';
11
11
  import { AsyncExpiringMap } from '../../utils/AsyncExpiringMap';
12
12
  import { isRootSpan } from '../../utils/span';
13
13
  import { NATIVE } from '../../wrapper';
@@ -46,8 +46,10 @@ export const createNativeFramesIntegrations = (enable) => {
46
46
  * and frame data (frames.total, frames.slow, frames.frozen) onto all spans.
47
47
  */
48
48
  export const nativeFramesIntegration = () => {
49
- /** The native frames at the finish time of the most recent span. */
50
- let _lastChildSpanEndFrames = null;
49
+ /** The native frames at the finish time of the most recent child span, keyed by root span ID.
50
+ * Stores promises so the data is available for processEvent to await even before
51
+ * the async native bridge call completes. */
52
+ const _lastChildSpanEndFramesByRootSpan = new AsyncExpiringMap({ ttl: START_FRAMES_TIMEOUT_MS });
51
53
  const _spanToNativeFramesAtStartMap = new AsyncExpiringMap({
52
54
  ttl: START_FRAMES_TIMEOUT_MS,
53
55
  });
@@ -86,15 +88,30 @@ export const nativeFramesIntegration = () => {
86
88
  * produce incorrect deltas. The native bridge calls are async and non-blocking.
87
89
  */
88
90
  const fetchEndFramesForSpan = (span) => __awaiter(void 0, void 0, void 0, function* () {
89
- const timestamp = timestampInSeconds();
90
91
  const spanId = span.spanContext().spanId;
91
92
  const hasStartFrames = _spanToNativeFramesAtStartMap.has(spanId);
92
93
  if (!hasStartFrames) {
93
94
  // We don't have start frames, won't be able to calculate the difference.
94
95
  return;
95
96
  }
97
+ // For child spans: immediately store a promise for fallback end frames before any awaits,
98
+ // so processEvent can find and await it even if this async function hasn't completed yet.
99
+ // Uses the actual span timestamp (not wall-clock time) so it matches the trimmed event.timestamp
100
+ // for idle transactions. Scoped per root span to avoid concurrent transaction interference.
101
+ let childEndFramesPromise;
102
+ if (!isRootSpan(span)) {
103
+ const rootSpanId = getRootSpan(span).spanContext().spanId;
104
+ const spanTimestamp = spanToJSON(span).timestamp;
105
+ if (spanTimestamp) {
106
+ childEndFramesPromise = fetchNativeFrames();
107
+ _lastChildSpanEndFramesByRootSpan.set(rootSpanId, childEndFramesPromise
108
+ .then(frames => ({ timestamp: spanTimestamp, nativeFrames: frames }))
109
+ .then(undefined, () => null));
110
+ }
111
+ }
96
112
  if (isRootSpan(span)) {
97
113
  // Root spans: Store end frames for transaction measurements (backward compatibility)
114
+ const timestamp = timestampInSeconds();
98
115
  debug.log(`[${INTEGRATION_NAME}] Fetch frames for root span end (${spanId}).`);
99
116
  _spanToNativeFramesAtEndMap.set(spanId, new Promise(resolve => {
100
117
  fetchNativeFrames()
@@ -117,10 +134,10 @@ export const nativeFramesIntegration = () => {
117
134
  debug.log(`[${INTEGRATION_NAME}] No start frames found for span ${spanId}, skipping frame data.`);
118
135
  return;
119
136
  }
120
- // NOTE: For root spans, this is the second call to fetchNativeFrames() for the same span.
137
+ // For child spans, reuse the already-kicked-off promise to avoid a redundant native bridge call.
138
+ // For root spans, this is the second call to fetchNativeFrames() for the same span.
121
139
  // The calls are very close together (microseconds apart), so inconsistency is minimal.
122
- // Future optimization: reuse the first call's promise to avoid redundant native bridge call.
123
- const endFrames = yield fetchNativeFrames();
140
+ const endFrames = childEndFramesPromise ? yield childEndFramesPromise : yield fetchNativeFrames();
124
141
  // Calculate deltas
125
142
  const totalFrames = endFrames.totalFrames - startFrames.totalFrames;
126
143
  const slowFrames = endFrames.slowFrames - startFrames.slowFrames;
@@ -132,24 +149,16 @@ export const nativeFramesIntegration = () => {
132
149
  span.setAttribute('frames.frozen', frozenFrames);
133
150
  debug.log(`[${INTEGRATION_NAME}] Attached frame data to span ${spanId}: total=${totalFrames}, slow=${slowFrames}, frozen=${frozenFrames}`);
134
151
  }
135
- // Update last child span end frames for root span fallback logic
136
- if (!isRootSpan(span)) {
137
- _lastChildSpanEndFrames = {
138
- timestamp,
139
- nativeFrames: endFrames,
140
- };
141
- }
142
152
  }
143
153
  catch (error) {
144
154
  debug.log(`[${INTEGRATION_NAME}] Error while capturing end frames for span ${spanId}.`, error);
145
155
  }
146
156
  });
147
157
  const processEvent = (event) => __awaiter(void 0, void 0, void 0, function* () {
148
- var _a;
158
+ var _a, _b;
149
159
  if (event.type !== 'transaction' ||
150
160
  !event.transaction ||
151
- !event.contexts ||
152
- !event.contexts.trace ||
161
+ !((_a = event.contexts) === null || _a === void 0 ? void 0 : _a.trace) ||
153
162
  !event.timestamp ||
154
163
  !event.contexts.trace.span_id) {
155
164
  return event;
@@ -162,17 +171,18 @@ export const nativeFramesIntegration = () => {
162
171
  return event;
163
172
  }
164
173
  const endFrames = yield _spanToNativeFramesAtEndMap.pop(spanId);
174
+ const lastChildFrames = yield _lastChildSpanEndFramesByRootSpan.pop(spanId);
165
175
  let finalEndFrames;
166
176
  if (endFrames && isClose(endFrames.timestamp, event.timestamp)) {
167
177
  // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)
168
178
  debug.log(`[${INTEGRATION_NAME}] Using frames from root span end (spanId, ${spanId}).`);
169
179
  finalEndFrames = endFrames.nativeFrames;
170
180
  }
171
- else if (_lastChildSpanEndFrames && isClose(_lastChildSpanEndFrames.timestamp, event.timestamp)) {
172
- // Fallback to the last span finish if it is within the margin of error of the actual finish timestamp.
173
- // This should be the case for trimEnd.
181
+ else if (lastChildFrames && isClose(lastChildFrames.timestamp, event.timestamp)) {
182
+ // Fallback to the last child span finish if it is within the margin of error of the actual finish timestamp.
183
+ // This handles idle transactions where event.timestamp is trimmed to the last child span's end time.
174
184
  debug.log(`[${INTEGRATION_NAME}] Using native frames from last child span end (spanId, ${spanId}).`);
175
- finalEndFrames = _lastChildSpanEndFrames.nativeFrames;
185
+ finalEndFrames = lastChildFrames.nativeFrames;
176
186
  }
177
187
  else {
178
188
  debug.warn(`[${INTEGRATION_NAME}] Frames were collected within larger than margin of error delay for spanId (${spanId}). Dropping the inaccurate values.`);
@@ -199,7 +209,7 @@ export const nativeFramesIntegration = () => {
199
209
  return event;
200
210
  }
201
211
  debug.log(`[${INTEGRATION_NAME}] Adding measurements to ${traceOp} transaction ${event.transaction}: ${JSON.stringify(measurements, undefined, 2)}`);
202
- event.measurements = Object.assign(Object.assign({}, ((_a = event.measurements) !== null && _a !== void 0 ? _a : {})), measurements);
212
+ event.measurements = Object.assign(Object.assign({}, ((_b = event.measurements) !== null && _b !== void 0 ? _b : {})), measurements);
203
213
  return event;
204
214
  });
205
215
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"nativeFrames.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/nativeFrames.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Client, Event, Integration, Measurements, MeasurementUnit, Span } from '@sentry/core';\nimport { debug, timestampInSeconds } from '@sentry/core';\nimport type { NativeFramesResponse } from '../../NativeRNSentry';\nimport { AsyncExpiringMap } from '../../utils/AsyncExpiringMap';\nimport { isRootSpan } from '../../utils/span';\nimport { NATIVE } from '../../wrapper';\n\n/**\n * Timeout from the start of a span to fetching the associated native frames.\n */\nconst FETCH_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time end frames data from the native layer will be\n * kept in memory and waiting for the event processing. This ensures that spans\n * which are never processed are not leaking memory.\n */\nconst END_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time start frames data from the native layer will be\n * kept in memory and waiting for span end. This ensures that spans\n * which never end or are not processed are not leaking memory.\n */\nconst START_FRAMES_TIMEOUT_MS = 60_000;\n\n/**\n * A margin of error of 50ms is allowed for the async native bridge call.\n * Anything larger would reduce the accuracy of our frames measurements.\n */\nconst MARGIN_OF_ERROR_SECONDS = 0.05;\n\nconst INTEGRATION_NAME = 'NativeFrames';\n\nexport interface FramesMeasurements extends Measurements {\n frames_total: { value: number; unit: MeasurementUnit };\n frames_slow: { value: number; unit: MeasurementUnit };\n frames_frozen: { value: number; unit: MeasurementUnit };\n}\n\ninterface NativeFramesResponseWithTimestamp {\n timestamp: number;\n nativeFrames: NativeFramesResponse;\n}\n\nexport const createNativeFramesIntegrations = (enable: boolean | undefined): Integration | undefined => {\n if (!enable && NATIVE.enableNative) {\n // On Android this will free up resource when JS reloaded (native modules stay) and thus JS side of the SDK reinitialized.\n NATIVE.disableNativeFramesTracking();\n return undefined;\n }\n\n return nativeFramesIntegration();\n};\n\n/**\n * Instrumentation to add native slow/frozen frames measurements onto transactions\n * and frame data (frames.total, frames.slow, frames.frozen) onto all spans.\n */\nexport const nativeFramesIntegration = (): Integration => {\n /** The native frames at the finish time of the most recent span. */\n let _lastChildSpanEndFrames: NativeFramesResponseWithTimestamp | null = null;\n const _spanToNativeFramesAtStartMap: AsyncExpiringMap<string, NativeFramesResponse | null> = new AsyncExpiringMap({\n ttl: START_FRAMES_TIMEOUT_MS,\n });\n const _spanToNativeFramesAtEndMap: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: END_FRAMES_TIMEOUT_MS });\n\n /**\n * Hooks into the client start and end span events.\n */\n const setup = (client: Client): void => {\n if (!NATIVE.enableNative) {\n debug.warn(\n `[${INTEGRATION_NAME}] This is not available on the Web, Expo Go and other platforms without native modules.`,\n );\n return undefined;\n }\n\n NATIVE.enableNativeFramesTracking();\n client.on('spanStart', fetchStartFramesForSpan);\n client.on('spanEnd', fetchEndFramesForSpan);\n };\n\n const fetchStartFramesForSpan = (span: Span): void => {\n const spanId = span.spanContext().spanId;\n const spanType = isRootSpan(span) ? 'root' : 'child';\n debug.log(`[${INTEGRATION_NAME}] Fetching frames for ${spanType} span start (${spanId}).`);\n\n _spanToNativeFramesAtStartMap.set(\n spanId,\n new Promise<NativeFramesResponse | null>(resolve => {\n fetchNativeFrames()\n .then(frames => resolve(frames))\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n };\n\n /**\n * Fetches end frames for a span and attaches frame data as span attributes.\n *\n * Note: This makes one native bridge call per span end. While this creates O(n) calls\n * for n spans, it's necessary for accuracy. Frame counts are cumulative and continuously\n * incrementing, so each span needs the exact frame count at its end time. Caching would\n * produce incorrect deltas. The native bridge calls are async and non-blocking.\n */\n const fetchEndFramesForSpan = async (span: Span): Promise<void> => {\n const timestamp = timestampInSeconds();\n const spanId = span.spanContext().spanId;\n const hasStartFrames = _spanToNativeFramesAtStartMap.has(spanId);\n\n if (!hasStartFrames) {\n // We don't have start frames, won't be able to calculate the difference.\n return;\n }\n\n if (isRootSpan(span)) {\n // Root spans: Store end frames for transaction measurements (backward compatibility)\n debug.log(`[${INTEGRATION_NAME}] Fetch frames for root span end (${spanId}).`);\n _spanToNativeFramesAtEndMap.set(\n spanId,\n new Promise<NativeFramesResponseWithTimestamp | null>(resolve => {\n fetchNativeFrames()\n .then(frames => {\n resolve({\n timestamp,\n nativeFrames: frames,\n });\n })\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n }\n\n // All spans (root and child): Attach frame data as span attributes\n try {\n const startFrames = await _spanToNativeFramesAtStartMap.get(spanId);\n if (!startFrames) {\n debug.log(`[${INTEGRATION_NAME}] No start frames found for span ${spanId}, skipping frame data.`);\n return;\n }\n\n // NOTE: For root spans, this is the second call to fetchNativeFrames() for the same span.\n // The calls are very close together (microseconds apart), so inconsistency is minimal.\n // Future optimization: reuse the first call's promise to avoid redundant native bridge call.\n const endFrames = await fetchNativeFrames();\n\n // Calculate deltas\n const totalFrames = endFrames.totalFrames - startFrames.totalFrames;\n const slowFrames = endFrames.slowFrames - startFrames.slowFrames;\n const frozenFrames = endFrames.frozenFrames - startFrames.frozenFrames;\n\n // Only attach if we have meaningful data\n if (totalFrames > 0 || slowFrames > 0 || frozenFrames > 0) {\n span.setAttribute('frames.total', totalFrames);\n span.setAttribute('frames.slow', slowFrames);\n span.setAttribute('frames.frozen', frozenFrames);\n debug.log(\n `[${INTEGRATION_NAME}] Attached frame data to span ${spanId}: total=${totalFrames}, slow=${slowFrames}, frozen=${frozenFrames}`,\n );\n }\n\n // Update last child span end frames for root span fallback logic\n if (!isRootSpan(span)) {\n _lastChildSpanEndFrames = {\n timestamp,\n nativeFrames: endFrames,\n };\n }\n } catch (error) {\n debug.log(`[${INTEGRATION_NAME}] Error while capturing end frames for span ${spanId}.`, error);\n }\n };\n\n const processEvent = async (event: Event): Promise<Event> => {\n if (\n event.type !== 'transaction' ||\n !event.transaction ||\n !event.contexts ||\n !event.contexts.trace ||\n !event.timestamp ||\n !event.contexts.trace.span_id\n ) {\n return event;\n }\n\n const traceOp = event.contexts.trace.op;\n const spanId = event.contexts.trace.span_id;\n const startFrames = await _spanToNativeFramesAtStartMap.pop(spanId);\n if (!startFrames) {\n debug.warn(\n `[${INTEGRATION_NAME}] Start frames of transaction ${event.transaction} (eventId, ${event.event_id}) are missing, but the transaction already ended.`,\n );\n return event;\n }\n\n const endFrames = await _spanToNativeFramesAtEndMap.pop(spanId);\n let finalEndFrames: NativeFramesResponse | undefined;\n\n if (endFrames && isClose(endFrames.timestamp, event.timestamp)) {\n // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)\n debug.log(`[${INTEGRATION_NAME}] Using frames from root span end (spanId, ${spanId}).`);\n finalEndFrames = endFrames.nativeFrames;\n } else if (_lastChildSpanEndFrames && isClose(_lastChildSpanEndFrames.timestamp, event.timestamp)) {\n // Fallback to the last span finish if it is within the margin of error of the actual finish timestamp.\n // This should be the case for trimEnd.\n debug.log(`[${INTEGRATION_NAME}] Using native frames from last child span end (spanId, ${spanId}).`);\n finalEndFrames = _lastChildSpanEndFrames.nativeFrames;\n } else {\n debug.warn(\n `[${INTEGRATION_NAME}] Frames were collected within larger than margin of error delay for spanId (${spanId}). Dropping the inaccurate values.`,\n );\n return event;\n }\n\n const measurements = {\n frames_total: {\n value: finalEndFrames.totalFrames - startFrames.totalFrames,\n unit: 'none',\n },\n frames_frozen: {\n value: finalEndFrames.frozenFrames - startFrames.frozenFrames,\n unit: 'none',\n },\n frames_slow: {\n value: finalEndFrames.slowFrames - startFrames.slowFrames,\n unit: 'none',\n },\n };\n\n if (\n measurements.frames_frozen.value <= 0 &&\n measurements.frames_slow.value <= 0 &&\n measurements.frames_total.value <= 0\n ) {\n debug.warn(\n `[${INTEGRATION_NAME}] Detected zero slow or frozen frames. Not adding measurements to spanId (${spanId}).`,\n );\n return event;\n }\n\n debug.log(\n `[${INTEGRATION_NAME}] Adding measurements to ${traceOp} transaction ${event.transaction}: ${JSON.stringify(\n measurements,\n undefined,\n 2,\n )}`,\n );\n event.measurements = {\n ...(event.measurements ?? {}),\n ...measurements,\n };\n return event;\n };\n\n return {\n name: INTEGRATION_NAME,\n setup,\n processEvent,\n };\n};\n\nfunction fetchNativeFrames(): Promise<NativeFramesResponse> {\n return new Promise<NativeFramesResponse>((resolve, reject) => {\n let settled = false;\n\n const timeoutId = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject('Fetching native frames took too long. Dropping frames.');\n }\n }, FETCH_FRAMES_TIMEOUT_MS);\n\n NATIVE.fetchNativeFrames()\n .then(value => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n\n if (!value) {\n reject('Native frames response is null.');\n return;\n }\n resolve(value);\n })\n .then(undefined, error => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n reject(error);\n });\n });\n}\n\nfunction isClose(t1: number, t2: number): boolean {\n return Math.abs(t1 - t2) < MARGIN_OF_ERROR_SECONDS;\n}\n"]}
1
+ {"version":3,"file":"nativeFrames.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/nativeFrames.ts"],"names":[],"mappings":";;;;;;;;;AACA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC;;GAEG;AACH,MAAM,uBAAuB,GAAG,IAAK,CAAC;AAEtC;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,IAAK,CAAC;AAEpC;;;;GAIG;AACH,MAAM,uBAAuB,GAAG,KAAM,CAAC;AAEvC;;;GAGG;AACH,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAErC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAaxC,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,MAA2B,EAA2B,EAAE;IACrG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,YAAY,EAAE;QAClC,0HAA0H;QAC1H,MAAM,CAAC,2BAA2B,EAAE,CAAC;QACrC,OAAO,SAAS,CAAC;KAClB;IAED,OAAO,uBAAuB,EAAE,CAAC;AACnC,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAgB,EAAE;IACvD;;kDAE8C;IAC9C,MAAM,iCAAiC,GACrC,IAAI,gBAAgB,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAC;IACzD,MAAM,6BAA6B,GAA0D,IAAI,gBAAgB,CAAC;QAChH,GAAG,EAAE,uBAAuB;KAC7B,CAAC,CAAC;IACH,MAAM,2BAA2B,GAC/B,IAAI,gBAAgB,CAAC,EAAE,GAAG,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAEvD;;OAEG;IACH,MAAM,KAAK,GAAG,CAAC,MAAc,EAAQ,EAAE;QACrC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YACxB,KAAK,CAAC,IAAI,CACR,IAAI,gBAAgB,yFAAyF,CAC9G,CAAC;YACF,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,CAAC,0BAA0B,EAAE,CAAC;QACpC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;QAChD,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;IAC9C,CAAC,CAAC;IAEF,MAAM,uBAAuB,GAAG,CAAC,IAAU,EAAQ,EAAE;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC;QACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QACrD,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,yBAAyB,QAAQ,gBAAgB,MAAM,IAAI,CAAC,CAAC;QAE3F,6BAA6B,CAAC,GAAG,CAC/B,MAAM,EACN,IAAI,OAAO,CAA8B,OAAO,CAAC,EAAE;YACjD,iBAAiB,EAAE;iBAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;iBAC/B,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;gBACvB,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,uCAAuC,EAAE,KAAK,CAAC,CAAC;gBAC9E,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC;IAEF;;;;;;;OAOG;IACH,MAAM,qBAAqB,GAAG,CAAO,IAAU,EAAiB,EAAE;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC;QACzC,MAAM,cAAc,GAAG,6BAA6B,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEjE,IAAI,CAAC,cAAc,EAAE;YACnB,yEAAyE;YACzE,OAAO;SACR;QAED,0FAA0F;QAC1F,0FAA0F;QAC1F,iGAAiG;QACjG,4FAA4F;QAC5F,IAAI,qBAAgE,CAAC;QACrE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;YACrB,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC;YAC1D,MAAM,aAAa,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;YACjD,IAAI,aAAa,EAAE;gBACjB,qBAAqB,GAAG,iBAAiB,EAAE,CAAC;gBAC5C,iCAAiC,CAAC,GAAG,CACnC,UAAU,EACV,qBAAqB;qBAClB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;qBACpE,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAC/B,CAAC;aACH;SACF;QAED,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE;YACpB,qFAAqF;YACrF,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;YACvC,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,qCAAqC,MAAM,IAAI,CAAC,CAAC;YAC/E,2BAA2B,CAAC,GAAG,CAC7B,MAAM,EACN,IAAI,OAAO,CAA2C,OAAO,CAAC,EAAE;gBAC9D,iBAAiB,EAAE;qBAChB,IAAI,CAAC,MAAM,CAAC,EAAE;oBACb,OAAO,CAAC;wBACN,SAAS;wBACT,YAAY,EAAE,MAAM;qBACrB,CAAC,CAAC;gBACL,CAAC,CAAC;qBACD,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;oBACvB,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,uCAAuC,EAAE,KAAK,CAAC,CAAC;oBAC9E,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CACH,CAAC;SACH;QAED,mEAAmE;QACnE,IAAI;YACF,MAAM,WAAW,GAAG,MAAM,6BAA6B,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACpE,IAAI,CAAC,WAAW,EAAE;gBAChB,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,oCAAoC,MAAM,wBAAwB,CAAC,CAAC;gBAClG,OAAO;aACR;YAED,iGAAiG;YACjG,oFAAoF;YACpF,uFAAuF;YACvF,MAAM,SAAS,GAAG,qBAAqB,CAAC,CAAC,CAAC,MAAM,qBAAqB,CAAC,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC;YAElG,mBAAmB;YACnB,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;YACpE,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;YACjE,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC;YAEvE,yCAAyC;YACzC,IAAI,WAAW,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE;gBACzD,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;gBAC/C,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;gBAC7C,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;gBACjD,KAAK,CAAC,GAAG,CACP,IAAI,gBAAgB,iCAAiC,MAAM,WAAW,WAAW,UAAU,UAAU,YAAY,YAAY,EAAE,CAChI,CAAC;aACH;SACF;QAAC,OAAO,KAAK,EAAE;YACd,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,+CAA+C,MAAM,GAAG,EAAE,KAAK,CAAC,CAAC;SAChG;IACH,CAAC,CAAA,CAAC;IAEF,MAAM,YAAY,GAAG,CAAO,KAAY,EAAkB,EAAE;;QAC1D,IACE,KAAK,CAAC,IAAI,KAAK,aAAa;YAC5B,CAAC,KAAK,CAAC,WAAW;YAClB,CAAC,CAAA,MAAA,KAAK,CAAC,QAAQ,0CAAE,KAAK,CAAA;YACtB,CAAC,KAAK,CAAC,SAAS;YAChB,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAC7B;YACA,OAAO,KAAK,CAAC;SACd;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;QAC5C,MAAM,WAAW,GAAG,MAAM,6BAA6B,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpE,IAAI,CAAC,WAAW,EAAE;YAChB,KAAK,CAAC,IAAI,CACR,IAAI,gBAAgB,iCAAiC,KAAK,CAAC,WAAW,cAAc,KAAK,CAAC,QAAQ,mDAAmD,CACtJ,CAAC;YACF,OAAO,KAAK,CAAC;SACd;QAED,MAAM,SAAS,GAAG,MAAM,2BAA2B,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChE,MAAM,eAAe,GAAG,MAAM,iCAAiC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5E,IAAI,cAAgD,CAAC;QAErD,IAAI,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE;YAC9D,2FAA2F;YAC3F,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,8CAA8C,MAAM,IAAI,CAAC,CAAC;YACxF,cAAc,GAAG,SAAS,CAAC,YAAY,CAAC;SACzC;aAAM,IAAI,eAAe,IAAI,OAAO,CAAC,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE;YACjF,6GAA6G;YAC7G,qGAAqG;YACrG,KAAK,CAAC,GAAG,CAAC,IAAI,gBAAgB,2DAA2D,MAAM,IAAI,CAAC,CAAC;YACrG,cAAc,GAAG,eAAe,CAAC,YAAY,CAAC;SAC/C;aAAM;YACL,KAAK,CAAC,IAAI,CACR,IAAI,gBAAgB,gFAAgF,MAAM,oCAAoC,CAC/I,CAAC;YACF,OAAO,KAAK,CAAC;SACd;QAED,MAAM,YAAY,GAAG;YACnB,YAAY,EAAE;gBACZ,KAAK,EAAE,cAAc,CAAC,WAAW,GAAG,WAAW,CAAC,WAAW;gBAC3D,IAAI,EAAE,MAAM;aACb;YACD,aAAa,EAAE;gBACb,KAAK,EAAE,cAAc,CAAC,YAAY,GAAG,WAAW,CAAC,YAAY;gBAC7D,IAAI,EAAE,MAAM;aACb;YACD,WAAW,EAAE;gBACX,KAAK,EAAE,cAAc,CAAC,UAAU,GAAG,WAAW,CAAC,UAAU;gBACzD,IAAI,EAAE,MAAM;aACb;SACF,CAAC;QAEF,IACE,YAAY,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;YACrC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;YACnC,YAAY,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC,EACpC;YACA,KAAK,CAAC,IAAI,CACR,IAAI,gBAAgB,6EAA6E,MAAM,IAAI,CAC5G,CAAC;YACF,OAAO,KAAK,CAAC;SACd;QAED,KAAK,CAAC,GAAG,CACP,IAAI,gBAAgB,4BAA4B,OAAO,gBAAgB,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,SAAS,CACzG,YAAY,EACZ,SAAS,EACT,CAAC,CACF,EAAE,CACJ,CAAC;QACF,KAAK,CAAC,YAAY,mCACb,CAAC,MAAA,KAAK,CAAC,YAAY,mCAAI,EAAE,CAAC,GAC1B,YAAY,CAChB,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC,CAAA,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,KAAK;QACL,YAAY;KACb,CAAC;AACJ,CAAC,CAAC;AAEF,SAAS,iBAAiB;IACxB,OAAO,IAAI,OAAO,CAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3D,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,OAAO,EAAE;gBACZ,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,wDAAwD,CAAC,CAAC;aAClE;QACH,CAAC,EAAE,uBAAuB,CAAC,CAAC;QAE5B,MAAM,CAAC,iBAAiB,EAAE;aACvB,IAAI,CAAC,KAAK,CAAC,EAAE;YACZ,IAAI,OAAO,EAAE;gBACX,OAAO;aACR;YACD,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,GAAG,IAAI,CAAC;YAEf,IAAI,CAAC,KAAK,EAAE;gBACV,MAAM,CAAC,iCAAiC,CAAC,CAAC;gBAC1C,OAAO;aACR;YACD,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC;aACD,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;YACvB,IAAI,OAAO,EAAE;gBACX,OAAO;aACR;YACD,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,EAAU,EAAE,EAAU;IACrC,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,uBAAuB,CAAC;AACrD,CAAC","sourcesContent":["import type { Client, Event, Integration, Measurements, MeasurementUnit, Span } from '@sentry/core';\nimport { debug, getRootSpan, spanToJSON, timestampInSeconds } from '@sentry/core';\nimport type { NativeFramesResponse } from '../../NativeRNSentry';\nimport { AsyncExpiringMap } from '../../utils/AsyncExpiringMap';\nimport { isRootSpan } from '../../utils/span';\nimport { NATIVE } from '../../wrapper';\n\n/**\n * Timeout from the start of a span to fetching the associated native frames.\n */\nconst FETCH_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time end frames data from the native layer will be\n * kept in memory and waiting for the event processing. This ensures that spans\n * which are never processed are not leaking memory.\n */\nconst END_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time start frames data from the native layer will be\n * kept in memory and waiting for span end. This ensures that spans\n * which never end or are not processed are not leaking memory.\n */\nconst START_FRAMES_TIMEOUT_MS = 60_000;\n\n/**\n * A margin of error of 50ms is allowed for the async native bridge call.\n * Anything larger would reduce the accuracy of our frames measurements.\n */\nconst MARGIN_OF_ERROR_SECONDS = 0.05;\n\nconst INTEGRATION_NAME = 'NativeFrames';\n\nexport interface FramesMeasurements extends Measurements {\n frames_total: { value: number; unit: MeasurementUnit };\n frames_slow: { value: number; unit: MeasurementUnit };\n frames_frozen: { value: number; unit: MeasurementUnit };\n}\n\ninterface NativeFramesResponseWithTimestamp {\n timestamp: number;\n nativeFrames: NativeFramesResponse;\n}\n\nexport const createNativeFramesIntegrations = (enable: boolean | undefined): Integration | undefined => {\n if (!enable && NATIVE.enableNative) {\n // On Android this will free up resource when JS reloaded (native modules stay) and thus JS side of the SDK reinitialized.\n NATIVE.disableNativeFramesTracking();\n return undefined;\n }\n\n return nativeFramesIntegration();\n};\n\n/**\n * Instrumentation to add native slow/frozen frames measurements onto transactions\n * and frame data (frames.total, frames.slow, frames.frozen) onto all spans.\n */\nexport const nativeFramesIntegration = (): Integration => {\n /** The native frames at the finish time of the most recent child span, keyed by root span ID.\n * Stores promises so the data is available for processEvent to await even before\n * the async native bridge call completes. */\n const _lastChildSpanEndFramesByRootSpan: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: START_FRAMES_TIMEOUT_MS });\n const _spanToNativeFramesAtStartMap: AsyncExpiringMap<string, NativeFramesResponse | null> = new AsyncExpiringMap({\n ttl: START_FRAMES_TIMEOUT_MS,\n });\n const _spanToNativeFramesAtEndMap: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: END_FRAMES_TIMEOUT_MS });\n\n /**\n * Hooks into the client start and end span events.\n */\n const setup = (client: Client): void => {\n if (!NATIVE.enableNative) {\n debug.warn(\n `[${INTEGRATION_NAME}] This is not available on the Web, Expo Go and other platforms without native modules.`,\n );\n return undefined;\n }\n\n NATIVE.enableNativeFramesTracking();\n client.on('spanStart', fetchStartFramesForSpan);\n client.on('spanEnd', fetchEndFramesForSpan);\n };\n\n const fetchStartFramesForSpan = (span: Span): void => {\n const spanId = span.spanContext().spanId;\n const spanType = isRootSpan(span) ? 'root' : 'child';\n debug.log(`[${INTEGRATION_NAME}] Fetching frames for ${spanType} span start (${spanId}).`);\n\n _spanToNativeFramesAtStartMap.set(\n spanId,\n new Promise<NativeFramesResponse | null>(resolve => {\n fetchNativeFrames()\n .then(frames => resolve(frames))\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n };\n\n /**\n * Fetches end frames for a span and attaches frame data as span attributes.\n *\n * Note: This makes one native bridge call per span end. While this creates O(n) calls\n * for n spans, it's necessary for accuracy. Frame counts are cumulative and continuously\n * incrementing, so each span needs the exact frame count at its end time. Caching would\n * produce incorrect deltas. The native bridge calls are async and non-blocking.\n */\n const fetchEndFramesForSpan = async (span: Span): Promise<void> => {\n const spanId = span.spanContext().spanId;\n const hasStartFrames = _spanToNativeFramesAtStartMap.has(spanId);\n\n if (!hasStartFrames) {\n // We don't have start frames, won't be able to calculate the difference.\n return;\n }\n\n // For child spans: immediately store a promise for fallback end frames before any awaits,\n // so processEvent can find and await it even if this async function hasn't completed yet.\n // Uses the actual span timestamp (not wall-clock time) so it matches the trimmed event.timestamp\n // for idle transactions. Scoped per root span to avoid concurrent transaction interference.\n let childEndFramesPromise: Promise<NativeFramesResponse> | undefined;\n if (!isRootSpan(span)) {\n const rootSpanId = getRootSpan(span).spanContext().spanId;\n const spanTimestamp = spanToJSON(span).timestamp;\n if (spanTimestamp) {\n childEndFramesPromise = fetchNativeFrames();\n _lastChildSpanEndFramesByRootSpan.set(\n rootSpanId,\n childEndFramesPromise\n .then(frames => ({ timestamp: spanTimestamp, nativeFrames: frames }))\n .then(undefined, () => null),\n );\n }\n }\n\n if (isRootSpan(span)) {\n // Root spans: Store end frames for transaction measurements (backward compatibility)\n const timestamp = timestampInSeconds();\n debug.log(`[${INTEGRATION_NAME}] Fetch frames for root span end (${spanId}).`);\n _spanToNativeFramesAtEndMap.set(\n spanId,\n new Promise<NativeFramesResponseWithTimestamp | null>(resolve => {\n fetchNativeFrames()\n .then(frames => {\n resolve({\n timestamp,\n nativeFrames: frames,\n });\n })\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n }\n\n // All spans (root and child): Attach frame data as span attributes\n try {\n const startFrames = await _spanToNativeFramesAtStartMap.get(spanId);\n if (!startFrames) {\n debug.log(`[${INTEGRATION_NAME}] No start frames found for span ${spanId}, skipping frame data.`);\n return;\n }\n\n // For child spans, reuse the already-kicked-off promise to avoid a redundant native bridge call.\n // For root spans, this is the second call to fetchNativeFrames() for the same span.\n // The calls are very close together (microseconds apart), so inconsistency is minimal.\n const endFrames = childEndFramesPromise ? await childEndFramesPromise : await fetchNativeFrames();\n\n // Calculate deltas\n const totalFrames = endFrames.totalFrames - startFrames.totalFrames;\n const slowFrames = endFrames.slowFrames - startFrames.slowFrames;\n const frozenFrames = endFrames.frozenFrames - startFrames.frozenFrames;\n\n // Only attach if we have meaningful data\n if (totalFrames > 0 || slowFrames > 0 || frozenFrames > 0) {\n span.setAttribute('frames.total', totalFrames);\n span.setAttribute('frames.slow', slowFrames);\n span.setAttribute('frames.frozen', frozenFrames);\n debug.log(\n `[${INTEGRATION_NAME}] Attached frame data to span ${spanId}: total=${totalFrames}, slow=${slowFrames}, frozen=${frozenFrames}`,\n );\n }\n } catch (error) {\n debug.log(`[${INTEGRATION_NAME}] Error while capturing end frames for span ${spanId}.`, error);\n }\n };\n\n const processEvent = async (event: Event): Promise<Event> => {\n if (\n event.type !== 'transaction' ||\n !event.transaction ||\n !event.contexts?.trace ||\n !event.timestamp ||\n !event.contexts.trace.span_id\n ) {\n return event;\n }\n\n const traceOp = event.contexts.trace.op;\n const spanId = event.contexts.trace.span_id;\n const startFrames = await _spanToNativeFramesAtStartMap.pop(spanId);\n if (!startFrames) {\n debug.warn(\n `[${INTEGRATION_NAME}] Start frames of transaction ${event.transaction} (eventId, ${event.event_id}) are missing, but the transaction already ended.`,\n );\n return event;\n }\n\n const endFrames = await _spanToNativeFramesAtEndMap.pop(spanId);\n const lastChildFrames = await _lastChildSpanEndFramesByRootSpan.pop(spanId);\n let finalEndFrames: NativeFramesResponse | undefined;\n\n if (endFrames && isClose(endFrames.timestamp, event.timestamp)) {\n // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)\n debug.log(`[${INTEGRATION_NAME}] Using frames from root span end (spanId, ${spanId}).`);\n finalEndFrames = endFrames.nativeFrames;\n } else if (lastChildFrames && isClose(lastChildFrames.timestamp, event.timestamp)) {\n // Fallback to the last child span finish if it is within the margin of error of the actual finish timestamp.\n // This handles idle transactions where event.timestamp is trimmed to the last child span's end time.\n debug.log(`[${INTEGRATION_NAME}] Using native frames from last child span end (spanId, ${spanId}).`);\n finalEndFrames = lastChildFrames.nativeFrames;\n } else {\n debug.warn(\n `[${INTEGRATION_NAME}] Frames were collected within larger than margin of error delay for spanId (${spanId}). Dropping the inaccurate values.`,\n );\n return event;\n }\n\n const measurements = {\n frames_total: {\n value: finalEndFrames.totalFrames - startFrames.totalFrames,\n unit: 'none',\n },\n frames_frozen: {\n value: finalEndFrames.frozenFrames - startFrames.frozenFrames,\n unit: 'none',\n },\n frames_slow: {\n value: finalEndFrames.slowFrames - startFrames.slowFrames,\n unit: 'none',\n },\n };\n\n if (\n measurements.frames_frozen.value <= 0 &&\n measurements.frames_slow.value <= 0 &&\n measurements.frames_total.value <= 0\n ) {\n debug.warn(\n `[${INTEGRATION_NAME}] Detected zero slow or frozen frames. Not adding measurements to spanId (${spanId}).`,\n );\n return event;\n }\n\n debug.log(\n `[${INTEGRATION_NAME}] Adding measurements to ${traceOp} transaction ${event.transaction}: ${JSON.stringify(\n measurements,\n undefined,\n 2,\n )}`,\n );\n event.measurements = {\n ...(event.measurements ?? {}),\n ...measurements,\n };\n return event;\n };\n\n return {\n name: INTEGRATION_NAME,\n setup,\n processEvent,\n };\n};\n\nfunction fetchNativeFrames(): Promise<NativeFramesResponse> {\n return new Promise<NativeFramesResponse>((resolve, reject) => {\n let settled = false;\n\n const timeoutId = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject('Fetching native frames took too long. Dropping frames.');\n }\n }, FETCH_FRAMES_TIMEOUT_MS);\n\n NATIVE.fetchNativeFrames()\n .then(value => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n\n if (!value) {\n reject('Native frames response is null.');\n return;\n }\n resolve(value);\n })\n .then(undefined, error => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n reject(error);\n });\n });\n}\n\nfunction isClose(t1: number, t2: number): boolean {\n return Math.abs(t1 - t2) < MARGIN_OF_ERROR_SECONDS;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"timeToDisplayIntegration.d.ts","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/timeToDisplayIntegration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,WAAW,EAAY,MAAM,cAAc,CAAC;AAWjE,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAKhD,eAAO,MAAM,wBAAwB,QAAO,WAwE3C,CAAC"}
1
+ {"version":3,"file":"timeToDisplayIntegration.d.ts","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/timeToDisplayIntegration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,WAAW,EAAY,MAAM,cAAc,CAAC;AAWjE,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAKhD,eAAO,MAAM,wBAAwB,QAAO,WAyE3C,CAAC"}
@@ -28,6 +28,7 @@ export const timeToDisplayIntegration = () => {
28
28
  enableTimeToInitialDisplayForPreloadedRoutes =
29
29
  (_b = (_a = getReactNavigationIntegration(client)) === null || _a === void 0 ? void 0 : _a.options.enableTimeToInitialDisplayForPreloadedRoutes) !== null && _b !== void 0 ? _b : false;
30
30
  },
31
+ // eslint-disable-next-line complexity
31
32
  processEvent: (event) => __awaiter(void 0, void 0, void 0, function* () {
32
33
  var _a, _b, _c, _d, _e;
33
34
  if (event.type !== 'transaction') {
@@ -1 +1 @@
1
- {"version":3,"file":"timeToDisplayIntegration.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/timeToDisplayIntegration.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Event, Integration, SpanJSON } from '@sentry/core';\nimport { debug } from '@sentry/core';\nimport { NATIVE } from '../../wrapper';\nimport { UI_LOAD_FULL_DISPLAY, UI_LOAD_INITIAL_DISPLAY } from '../ops';\nimport { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from '../origin';\nimport { getReactNavigationIntegration } from '../reactnavigation';\nimport { SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN } from '../semanticAttributes';\nimport { SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../span';\nimport { getTimeToInitialDisplayFallback } from '../timeToDisplayFallback';\nimport { createSpanJSON } from '../utils';\n\nexport const INTEGRATION_NAME = 'TimeToDisplay';\n\nconst TIME_TO_DISPLAY_TIMEOUT_MS = 30_000;\nconst isDeadlineExceeded = (durationMs: number): boolean => durationMs > TIME_TO_DISPLAY_TIMEOUT_MS;\n\nexport const timeToDisplayIntegration = (): Integration => {\n let enableTimeToInitialDisplayForPreloadedRoutes = false;\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup(client) {\n enableTimeToInitialDisplayForPreloadedRoutes =\n getReactNavigationIntegration(client)?.options.enableTimeToInitialDisplayForPreloadedRoutes ?? false;\n },\n processEvent: async event => {\n if (event.type !== 'transaction') {\n // TimeToDisplay data is only relevant for transactions\n return event;\n }\n\n const rootSpanId = event.contexts?.trace?.span_id;\n if (!rootSpanId) {\n debug.warn(`[${INTEGRATION_NAME}] No root span id found in transaction.`);\n return event;\n }\n\n const transactionStartTimestampSeconds = event.start_timestamp;\n if (!transactionStartTimestampSeconds) {\n // This should never happen\n debug.warn(`[${INTEGRATION_NAME}] No transaction start timestamp found in transaction.`);\n return event;\n }\n\n event.spans = event.spans || [];\n event.measurements = event.measurements || {};\n\n const ttidSpan = await addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n const ttfdSpan = await addTimeToFullDisplay({ event, rootSpanId, transactionStartTimestampSeconds, ttidSpan });\n\n if (ttidSpan?.start_timestamp && ttidSpan?.timestamp) {\n event.measurements['time_to_initial_display'] = {\n value: (ttidSpan.timestamp - ttidSpan.start_timestamp) * 1000,\n unit: 'millisecond',\n };\n }\n\n if (ttfdSpan?.start_timestamp && ttfdSpan?.timestamp) {\n const durationMs = (ttfdSpan.timestamp - ttfdSpan.start_timestamp) * 1000;\n if (isDeadlineExceeded(durationMs)) {\n if (event.measurements['time_to_initial_display']) {\n event.measurements['time_to_full_display'] = event.measurements['time_to_initial_display'];\n }\n } else {\n event.measurements['time_to_full_display'] = {\n value: durationMs,\n unit: 'millisecond',\n };\n }\n }\n\n const newTransactionEndTimestampSeconds = Math.max(\n ttidSpan?.timestamp ?? -1,\n ttfdSpan?.timestamp ?? -1,\n event.timestamp ?? -1,\n );\n if (newTransactionEndTimestampSeconds !== -1) {\n event.timestamp = newTransactionEndTimestampSeconds;\n }\n\n return event;\n },\n };\n};\n\nasync function addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-${rootSpanId}`);\n\n event.spans = event.spans || [];\n\n let ttidSpan: SpanJSON | undefined = event.spans?.find(span => span.op === UI_LOAD_INITIAL_DISPLAY);\n\n if (ttidSpan && (ttidSpan.status === undefined || ttidSpan.status === 'ok') && !ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] Ttid span already exists and is ok.`, ttidSpan);\n return ttidSpan;\n }\n\n if (!ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No manual ttid end timestamp found for span ${rootSpanId}.`);\n return addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n }\n\n if (ttidSpan?.status && ttidSpan.status !== 'ok') {\n ttidSpan.status = 'ok';\n ttidSpan.timestamp = ttidEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttid span.`, ttidSpan);\n return ttidSpan;\n }\n\n ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttid span to transaction.`, ttidSpan);\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidNativeTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-navigation-${rootSpanId}`);\n const ttidFallbackTimestampSeconds = await getTimeToInitialDisplayFallback(rootSpanId);\n\n const hasBeenSeen = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN];\n if (hasBeenSeen && !enableTimeToInitialDisplayForPreloadedRoutes) {\n debug.log(\n `[${INTEGRATION_NAME}] Route has been seen and time to initial display is disabled for preloaded routes.`,\n );\n return undefined;\n }\n\n const ttidTimestampSeconds = ttidNativeTimestampSeconds ?? ttidFallbackTimestampSeconds;\n if (!ttidTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No automatic ttid end timestamp found for span ${rootSpanId}.`);\n return undefined;\n }\n\n const viewNames = event.contexts?.app?.view_names;\n const screenName = Array.isArray(viewNames) ? viewNames[0] : viewNames;\n\n const ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: screenName ? `${screenName} initial display` : 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidTimestampSeconds,\n origin: SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n event.spans = event.spans ?? [];\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addTimeToFullDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n ttidSpan,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n ttidSpan: SpanJSON | undefined;\n}): Promise<SpanJSON | undefined> {\n const ttfdEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttfd-${rootSpanId}`);\n\n if (!ttidSpan || !ttfdEndTimestampSeconds) {\n return undefined;\n }\n\n event.spans = event.spans || [];\n\n let ttfdSpan = event.spans?.find(span => span.op === UI_LOAD_FULL_DISPLAY);\n\n let ttfdAdjustedEndTimestampSeconds = ttfdEndTimestampSeconds;\n const ttfdIsBeforeTtid = ttidSpan.timestamp && ttfdEndTimestampSeconds < ttidSpan.timestamp;\n if (ttfdIsBeforeTtid && ttidSpan.timestamp) {\n ttfdAdjustedEndTimestampSeconds = ttidSpan.timestamp;\n }\n\n const durationMs = (ttfdAdjustedEndTimestampSeconds - transactionStartTimestampSeconds) * 1000;\n\n if (ttfdSpan?.status && ttfdSpan.status !== 'ok') {\n ttfdSpan.status = 'ok';\n ttfdSpan.timestamp = ttfdAdjustedEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttfd span.`, ttfdSpan);\n return ttfdSpan;\n }\n\n ttfdSpan = createSpanJSON({\n status: isDeadlineExceeded(durationMs) ? 'deadline_exceeded' : 'ok',\n op: UI_LOAD_FULL_DISPLAY,\n description: 'Time To Full Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttfdAdjustedEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttfd span to transaction.`, ttfdSpan);\n event.spans.push(ttfdSpan);\n return ttfdSpan;\n}\n"]}
1
+ {"version":3,"file":"timeToDisplayIntegration.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/timeToDisplayIntegration.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Event, Integration, SpanJSON } from '@sentry/core';\nimport { debug } from '@sentry/core';\nimport { NATIVE } from '../../wrapper';\nimport { UI_LOAD_FULL_DISPLAY, UI_LOAD_INITIAL_DISPLAY } from '../ops';\nimport { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from '../origin';\nimport { getReactNavigationIntegration } from '../reactnavigation';\nimport { SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN } from '../semanticAttributes';\nimport { SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../span';\nimport { getTimeToInitialDisplayFallback } from '../timeToDisplayFallback';\nimport { createSpanJSON } from '../utils';\n\nexport const INTEGRATION_NAME = 'TimeToDisplay';\n\nconst TIME_TO_DISPLAY_TIMEOUT_MS = 30_000;\nconst isDeadlineExceeded = (durationMs: number): boolean => durationMs > TIME_TO_DISPLAY_TIMEOUT_MS;\n\nexport const timeToDisplayIntegration = (): Integration => {\n let enableTimeToInitialDisplayForPreloadedRoutes = false;\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup(client) {\n enableTimeToInitialDisplayForPreloadedRoutes =\n getReactNavigationIntegration(client)?.options.enableTimeToInitialDisplayForPreloadedRoutes ?? false;\n },\n // eslint-disable-next-line complexity\n processEvent: async event => {\n if (event.type !== 'transaction') {\n // TimeToDisplay data is only relevant for transactions\n return event;\n }\n\n const rootSpanId = event.contexts?.trace?.span_id;\n if (!rootSpanId) {\n debug.warn(`[${INTEGRATION_NAME}] No root span id found in transaction.`);\n return event;\n }\n\n const transactionStartTimestampSeconds = event.start_timestamp;\n if (!transactionStartTimestampSeconds) {\n // This should never happen\n debug.warn(`[${INTEGRATION_NAME}] No transaction start timestamp found in transaction.`);\n return event;\n }\n\n event.spans = event.spans || [];\n event.measurements = event.measurements || {};\n\n const ttidSpan = await addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n const ttfdSpan = await addTimeToFullDisplay({ event, rootSpanId, transactionStartTimestampSeconds, ttidSpan });\n\n if (ttidSpan?.start_timestamp && ttidSpan?.timestamp) {\n event.measurements['time_to_initial_display'] = {\n value: (ttidSpan.timestamp - ttidSpan.start_timestamp) * 1000,\n unit: 'millisecond',\n };\n }\n\n if (ttfdSpan?.start_timestamp && ttfdSpan?.timestamp) {\n const durationMs = (ttfdSpan.timestamp - ttfdSpan.start_timestamp) * 1000;\n if (isDeadlineExceeded(durationMs)) {\n if (event.measurements['time_to_initial_display']) {\n event.measurements['time_to_full_display'] = event.measurements['time_to_initial_display'];\n }\n } else {\n event.measurements['time_to_full_display'] = {\n value: durationMs,\n unit: 'millisecond',\n };\n }\n }\n\n const newTransactionEndTimestampSeconds = Math.max(\n ttidSpan?.timestamp ?? -1,\n ttfdSpan?.timestamp ?? -1,\n event.timestamp ?? -1,\n );\n if (newTransactionEndTimestampSeconds !== -1) {\n event.timestamp = newTransactionEndTimestampSeconds;\n }\n\n return event;\n },\n };\n};\n\nasync function addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-${rootSpanId}`);\n\n event.spans = event.spans || [];\n\n let ttidSpan: SpanJSON | undefined = event.spans?.find(span => span.op === UI_LOAD_INITIAL_DISPLAY);\n\n if (ttidSpan && (ttidSpan.status === undefined || ttidSpan.status === 'ok') && !ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] Ttid span already exists and is ok.`, ttidSpan);\n return ttidSpan;\n }\n\n if (!ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No manual ttid end timestamp found for span ${rootSpanId}.`);\n return addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n }\n\n if (ttidSpan?.status && ttidSpan.status !== 'ok') {\n ttidSpan.status = 'ok';\n ttidSpan.timestamp = ttidEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttid span.`, ttidSpan);\n return ttidSpan;\n }\n\n ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttid span to transaction.`, ttidSpan);\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidNativeTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-navigation-${rootSpanId}`);\n const ttidFallbackTimestampSeconds = await getTimeToInitialDisplayFallback(rootSpanId);\n\n const hasBeenSeen = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN];\n if (hasBeenSeen && !enableTimeToInitialDisplayForPreloadedRoutes) {\n debug.log(\n `[${INTEGRATION_NAME}] Route has been seen and time to initial display is disabled for preloaded routes.`,\n );\n return undefined;\n }\n\n const ttidTimestampSeconds = ttidNativeTimestampSeconds ?? ttidFallbackTimestampSeconds;\n if (!ttidTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No automatic ttid end timestamp found for span ${rootSpanId}.`);\n return undefined;\n }\n\n const viewNames = event.contexts?.app?.view_names;\n const screenName = Array.isArray(viewNames) ? viewNames[0] : viewNames;\n\n const ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: screenName ? `${screenName} initial display` : 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidTimestampSeconds,\n origin: SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n event.spans = event.spans ?? [];\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addTimeToFullDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n ttidSpan,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n ttidSpan: SpanJSON | undefined;\n}): Promise<SpanJSON | undefined> {\n const ttfdEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttfd-${rootSpanId}`);\n\n if (!ttidSpan || !ttfdEndTimestampSeconds) {\n return undefined;\n }\n\n event.spans = event.spans || [];\n\n let ttfdSpan = event.spans?.find(span => span.op === UI_LOAD_FULL_DISPLAY);\n\n let ttfdAdjustedEndTimestampSeconds = ttfdEndTimestampSeconds;\n const ttfdIsBeforeTtid = ttidSpan.timestamp && ttfdEndTimestampSeconds < ttidSpan.timestamp;\n if (ttfdIsBeforeTtid && ttidSpan.timestamp) {\n ttfdAdjustedEndTimestampSeconds = ttidSpan.timestamp;\n }\n\n const durationMs = (ttfdAdjustedEndTimestampSeconds - transactionStartTimestampSeconds) * 1000;\n\n if (ttfdSpan?.status && ttfdSpan.status !== 'ok') {\n ttfdSpan.status = 'ok';\n ttfdSpan.timestamp = ttfdAdjustedEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttfd span.`, ttfdSpan);\n return ttfdSpan;\n }\n\n ttfdSpan = createSpanJSON({\n status: isDeadlineExceeded(durationMs) ? 'deadline_exceeded' : 'ok',\n op: UI_LOAD_FULL_DISPLAY,\n description: 'Time To Full Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttfdAdjustedEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttfd span to transaction.`, ttfdSpan);\n event.spans.push(ttfdSpan);\n return ttfdSpan;\n}\n"]}
@@ -52,7 +52,7 @@ export const reactNativeNavigationIntegration = ({ navigation: optionsNavigation
52
52
  return;
53
53
  }
54
54
  // We ignore actions that pertain to the same screen.
55
- const isSameComponent = prevComponentEvent && event.componentId === prevComponentEvent.componentId;
55
+ const isSameComponent = event.componentId === (prevComponentEvent === null || prevComponentEvent === void 0 ? void 0 : prevComponentEvent.componentId);
56
56
  if (isSameComponent) {
57
57
  discardLatestNavigationSpan();
58
58
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"reactnativenavigation.js","sourceRoot":"","sources":["../../../src/js/tracing/reactnativenavigation.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,SAAS,EACT,4BAA4B,EAC5B,gCAAgC,EAChC,gCAAgC,EAChC,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,mDAAmD,EAAE,MAAM,UAAU,CAAC;AAE/E,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,EAClB,mCAAmC,EACnC,uBAAuB,IAAI,8BAA8B,GAC1D,MAAM,QAAQ,CAAC;AAEhB,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAkExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,EAC/C,UAAU,EAAE,iBAAiB,EAC7B,oBAAoB,GAAG,IAAK,EAC5B,yBAAyB,GAAG,KAAK,EACjC,qCAAqC,GAAG,IAAI,GACf,EAAe,EAAE;IAC9C,MAAM,UAAU,GAAG,iBAAuC,CAAC;IAC3D,IAAI,kBAAkB,GAAa,EAAE,CAAC;IAEtC,IAAI,OAAkD,CAAC;IACvD,IAAI,eAAe,GAAyD,kBAAkB,CAAC;IAE/F,IAAI,kBAA6D,CAAC;IAClE,IAAI,kBAAkB,GAAoC,IAAI,CAAC;IAC/D,IAAI,oBAAsC,CAAC;IAE3C,MAAM,aAAa,GAAG,CAAC,MAAc,EAAQ,EAAE;QAC7C,OAAO,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,OAAO,EAAE;YACX,eAAe,GAAG;gBAChB,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc;gBAC5C,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa;aAC3C,CAAC;SACH;IACH,CAAC,CAAC;IAEF,MAAM,uBAAuB,GAAG,GAAS,EAAE;QACzC,IAAI,oBAAoB,EAAE;YACxB,2BAA2B,EAAE,CAAC;SAC/B;QAED,oBAAoB,GAAG,8BAA8B,CACnD,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,CAAC,eAAe;YAC9B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,mCAAmC,EAAE,CAAC;YACxE,CAAC,CAAC,mCAAmC,EAAE,EACzC,eAAe,CAChB,CAAC;QACF,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAE,YAAY,CAChC,gCAAgC,EAChC,mDAAmD,CACpD,CAAC;QACF,IAAI,qCAAqC,EAAE;YACzC,yBAAyB,CAAC,SAAS,EAAE,EAAE,oBAAoB,CAAC,CAAC;SAC9D;QACD,mEAAmE;QACnE,MAAM,WAAW,GAAG,oBAAoB,CAAC;QACzC,kCAAkC,CAChC,SAAS,EAAE,EACX,WAAW,EACX,4BAA4B,EAC5B,GAAG,EAAE,CAAC,oBAAoB,KAAK,WAAW,CAC3C,CAAC;QAEF,kBAAkB,GAAG,UAAU,CAAC,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAChG,CAAC,CAAC;IAEF,MAAM,8CAA8C,GAAG,CAAC,KAA+B,EAAQ,EAAE;QAC/F,IAAI,CAAC,oBAAoB,EAAE;YACzB,OAAO;SACR;QAED,qDAAqD;QACrD,MAAM,eAAe,GAAG,kBAAkB,IAAI,KAAK,CAAC,WAAW,KAAK,kBAAkB,CAAC,WAAW,CAAC;QACnG,IAAI,eAAe,EAAE;YACnB,2BAA2B,EAAE,CAAC;YAC9B,OAAO;SACR;QAED,uBAAuB,EAAE,CAAC;QAE1B,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAExE,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC,WAAW,KAAK,4BAA4B,EAAE;YACjF,oBAAoB,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;SACtD;QACD,oBAAoB,CAAC,aAAa,CAAC;YACjC,kHAAkH;YAClH,YAAY,EAAE,KAAK,CAAC,aAAa;YACjC,oBAAoB,EAAE,KAAK,CAAC,WAAW;YACvC,sBAAsB,EAAE,KAAK,CAAC,aAAa;YAC3C,qBAAqB,EAAE,gBAAgB;YACvC,qBAAqB,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,aAAa;YACxD,6BAA6B,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,WAAW;YAC9D,+BAA+B,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,aAAa;YAClE,CAAC,gCAAgC,CAAC,EAAE,WAAW;YAC/C,CAAC,4BAA4B,CAAC,EAAE,YAAY;SAC7C,CAAC,CAAC;QAEH,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAE9C,aAAa,CAAC;YACZ,QAAQ,EAAE,YAAY;YACtB,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,iBAAiB,KAAK,CAAC,aAAa,EAAE;YAC/C,IAAI,EAAE;gBACJ,IAAI,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,aAAa;gBACvC,EAAE,EAAE,KAAK,CAAC,aAAa;aACxB;SACF,CAAC,CAAC;QAEH,qBAAqB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACzC,kBAAkB,GAAG,KAAK,CAAC;QAC3B,oBAAoB,GAAG,SAAS,CAAC;IACnC,CAAC,CAAC;IAEF,UAAU,CAAC,MAAM,EAAE,CAAC,uBAAuB,CAAC,uBAAuB,CAAC,CAAC;IACrE,IAAI,yBAAyB,EAAE;QAC7B,UAAU,CAAC,MAAM,EAAE,CAAC,gCAAgC,CAAC,uBAAuB,CAAC,CAAC;KAC/E;IACD,UAAU,CAAC,MAAM,EAAE,CAAC,mCAAmC,CAAC,8CAA8C,CAAC,CAAC;IAExG,MAAM,qBAAqB,GAAG,CAAC,EAAU,EAAQ,EAAE;QACjD,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE5B,IAAI,kBAAkB,CAAC,MAAM,GAAG,2BAA2B,EAAE;YAC3D,kBAAkB,GAAG,kBAAkB,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,GAAG,2BAA2B,CAAC,CAAC;SACxG;IACH,CAAC,CAAC;IAEF,MAAM,2BAA2B,GAAG,GAAS,EAAE;QAC7C,IAAI,oBAAoB,EAAE;YACxB,IAAI,YAAY,CAAC,oBAAoB,CAAC,EAAE;gBACtC,oBAAoB,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;aAC1C;YACD,qCAAqC;YACrC,oBAAoB,CAAC,GAAG,EAAE,CAAC;YAC3B,oBAAoB,GAAG,SAAS,CAAC;SAClC;QAED,uBAAuB,EAAE,CAAC;IAC5B,CAAC,CAAC;IAEF,MAAM,uBAAuB,GAAG,GAAS,EAAE;QACzC,IAAI,OAAO,kBAAkB,KAAK,WAAW,EAAE;YAC7C,YAAY,CAAC,kBAAkB,CAAC,CAAC;YACjC,kBAAkB,GAAG,SAAS,CAAC;SAChC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,aAAa;KACd,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { Client, Integration, Span } from '@sentry/core';\nimport {\n addBreadcrumb,\n getClient,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n} from '@sentry/core';\nimport type { EmitterSubscription } from '../utils/rnlibrariesinterface';\nimport { isSentrySpan } from '../utils/span';\nimport { ignoreEmptyBackNavigation, ignoreEmptyRouteChangeTransactions } from './onSpanEndUtils';\nimport { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NATIVE_NAVIGATION } from './origin';\nimport type { ReactNativeTracingIntegration } from './reactnativetracing';\nimport { getReactNativeTracingIntegration } from './reactnativetracing';\nimport {\n DEFAULT_NAVIGATION_SPAN_NAME,\n defaultIdleOptions,\n getDefaultIdleNavigationSpanOptions,\n startIdleNavigationSpan as startGenericIdleNavigationSpan,\n} from './span';\n\nexport const INTEGRATION_NAME = 'ReactNativeNavigation';\n\nconst NAVIGATION_HISTORY_MAX_SIZE = 200;\n\ninterface ReactNativeNavigationOptions {\n /**\n * How long the instrumentation will wait for the route to mount after a change has been initiated,\n * before the transaction is discarded.\n *\n * @default 1_000 (ms)\n */\n routeChangeTimeoutMs?: number;\n\n /**\n * Instrumentation will create a transaction on tab change.\n * By default only navigation commands create transactions.\n *\n * @default false\n */\n enableTabsInstrumentation?: boolean;\n\n /**\n * Does not sample transactions that are from routes that have been seen any more and don't have any spans.\n * This removes a lot of the clutter as most back navigation transactions are now ignored.\n *\n * @default true\n */\n ignoreEmptyBackNavigationTransactions?: boolean;\n\n /** The React Native Navigation `NavigationDelegate`.\n *\n * ```js\n * import { Navigation } from 'react-native-navigation';\n * ```\n */\n navigation: unknown;\n}\n\ninterface ComponentEvent {\n componentId: string;\n}\n\ntype ComponentType = 'Component' | 'TopBarTitle' | 'TopBarBackground' | 'TopBarButton';\n\nexport interface ComponentWillAppearEvent extends ComponentEvent {\n componentName: string;\n passProps?: Record<string | number | symbol, unknown>;\n componentType: ComponentType;\n}\n\nexport interface EventSubscription {\n remove(): void;\n}\n\nexport interface BottomTabPressedEvent {\n tabIndex: number;\n}\n\nexport interface EventsRegistry {\n registerComponentWillAppearListener(callback: (event: ComponentWillAppearEvent) => void): EmitterSubscription;\n registerCommandListener(callback: (name: string, params: unknown) => void): EventSubscription;\n registerBottomTabPressedListener(callback: (event: BottomTabPressedEvent) => void): EmitterSubscription;\n}\n\nexport interface NavigationDelegate {\n events: () => EventsRegistry;\n}\n\n/**\n * Instrumentation for React Native Navigation. See docs or sample app for usage.\n *\n * How this works:\n * - `_onCommand` is called every time a commands happens and sets an IdleTransaction on the scope without any route context.\n * - `_onComponentWillAppear` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.\n * - If `_onComponentWillAppear` isn't called within `options.routeChangeTimeoutMs` of the dispatch, then the transaction is not sampled and finished.\n */\nexport const reactNativeNavigationIntegration = ({\n navigation: optionsNavigation,\n routeChangeTimeoutMs = 1_000,\n enableTabsInstrumentation = false,\n ignoreEmptyBackNavigationTransactions = true,\n}: ReactNativeNavigationOptions): Integration => {\n const navigation = optionsNavigation as NavigationDelegate;\n let recentComponentIds: string[] = [];\n\n let tracing: ReactNativeTracingIntegration | undefined;\n let idleSpanOptions: Parameters<typeof startGenericIdleNavigationSpan>[1] = defaultIdleOptions;\n\n let stateChangeTimeout: ReturnType<typeof setTimeout> | undefined;\n let prevComponentEvent: ComponentWillAppearEvent | null = null;\n let latestNavigationSpan: Span | undefined;\n\n const afterAllSetup = (client: Client): void => {\n tracing = getReactNativeTracingIntegration(client);\n if (tracing) {\n idleSpanOptions = {\n finalTimeout: tracing.options.finalTimeoutMs,\n idleTimeout: tracing.options.idleTimeoutMs,\n };\n }\n };\n\n const startIdleNavigationSpan = (): void => {\n if (latestNavigationSpan) {\n discardLatestNavigationSpan();\n }\n\n latestNavigationSpan = startGenericIdleNavigationSpan(\n tracing?.options.beforeStartSpan\n ? tracing.options.beforeStartSpan(getDefaultIdleNavigationSpanOptions())\n : getDefaultIdleNavigationSpanOptions(),\n idleSpanOptions,\n );\n latestNavigationSpan?.setAttribute(\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NATIVE_NAVIGATION,\n );\n if (ignoreEmptyBackNavigationTransactions) {\n ignoreEmptyBackNavigation(getClient(), latestNavigationSpan);\n }\n // Always discard transactions that never receive route information\n const spanToCheck = latestNavigationSpan;\n ignoreEmptyRouteChangeTransactions(\n getClient(),\n spanToCheck,\n DEFAULT_NAVIGATION_SPAN_NAME,\n () => latestNavigationSpan === spanToCheck,\n );\n\n stateChangeTimeout = setTimeout(discardLatestNavigationSpan.bind(this), routeChangeTimeoutMs);\n };\n\n const updateLatestNavigationSpanWithCurrentComponent = (event: ComponentWillAppearEvent): void => {\n if (!latestNavigationSpan) {\n return;\n }\n\n // We ignore actions that pertain to the same screen.\n const isSameComponent = prevComponentEvent && event.componentId === prevComponentEvent.componentId;\n if (isSameComponent) {\n discardLatestNavigationSpan();\n return;\n }\n\n clearStateChangeTimeout();\n\n const routeHasBeenSeen = recentComponentIds.includes(event.componentId);\n\n if (spanToJSON(latestNavigationSpan).description === DEFAULT_NAVIGATION_SPAN_NAME) {\n latestNavigationSpan.updateName(event.componentName);\n }\n latestNavigationSpan.setAttributes({\n // TODO: Should we include pass props? I don't know exactly what it contains, cant find it in the RNavigation docs\n 'route.name': event.componentName,\n 'route.component_id': event.componentId,\n 'route.component_type': event.componentType,\n 'route.has_been_seen': routeHasBeenSeen,\n 'previous_route.name': prevComponentEvent?.componentName,\n 'previous_route.component_id': prevComponentEvent?.componentId,\n 'previous_route.component_type': prevComponentEvent?.componentType,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n });\n\n tracing?.setCurrentRoute(event.componentName);\n\n addBreadcrumb({\n category: 'navigation',\n type: 'navigation',\n message: `Navigation to ${event.componentName}`,\n data: {\n from: prevComponentEvent?.componentName,\n to: event.componentName,\n },\n });\n\n pushRecentComponentId(event.componentId);\n prevComponentEvent = event;\n latestNavigationSpan = undefined;\n };\n\n navigation.events().registerCommandListener(startIdleNavigationSpan);\n if (enableTabsInstrumentation) {\n navigation.events().registerBottomTabPressedListener(startIdleNavigationSpan);\n }\n navigation.events().registerComponentWillAppearListener(updateLatestNavigationSpanWithCurrentComponent);\n\n const pushRecentComponentId = (id: string): void => {\n recentComponentIds.push(id);\n\n if (recentComponentIds.length > NAVIGATION_HISTORY_MAX_SIZE) {\n recentComponentIds = recentComponentIds.slice(recentComponentIds.length - NAVIGATION_HISTORY_MAX_SIZE);\n }\n };\n\n const discardLatestNavigationSpan = (): void => {\n if (latestNavigationSpan) {\n if (isSentrySpan(latestNavigationSpan)) {\n latestNavigationSpan['_sampled'] = false;\n }\n // TODO: What if it's not SentrySpan?\n latestNavigationSpan.end();\n latestNavigationSpan = undefined;\n }\n\n clearStateChangeTimeout();\n };\n\n const clearStateChangeTimeout = (): void => {\n if (typeof stateChangeTimeout !== 'undefined') {\n clearTimeout(stateChangeTimeout);\n stateChangeTimeout = undefined;\n }\n };\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup,\n };\n};\n"]}
1
+ {"version":3,"file":"reactnativenavigation.js","sourceRoot":"","sources":["../../../src/js/tracing/reactnativenavigation.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,SAAS,EACT,4BAA4B,EAC5B,gCAAgC,EAChC,gCAAgC,EAChC,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,mDAAmD,EAAE,MAAM,UAAU,CAAC;AAE/E,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,EAClB,mCAAmC,EACnC,uBAAuB,IAAI,8BAA8B,GAC1D,MAAM,QAAQ,CAAC;AAEhB,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAkExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,EAC/C,UAAU,EAAE,iBAAiB,EAC7B,oBAAoB,GAAG,IAAK,EAC5B,yBAAyB,GAAG,KAAK,EACjC,qCAAqC,GAAG,IAAI,GACf,EAAe,EAAE;IAC9C,MAAM,UAAU,GAAG,iBAAuC,CAAC;IAC3D,IAAI,kBAAkB,GAAa,EAAE,CAAC;IAEtC,IAAI,OAAkD,CAAC;IACvD,IAAI,eAAe,GAAyD,kBAAkB,CAAC;IAE/F,IAAI,kBAA6D,CAAC;IAClE,IAAI,kBAAkB,GAAoC,IAAI,CAAC;IAC/D,IAAI,oBAAsC,CAAC;IAE3C,MAAM,aAAa,GAAG,CAAC,MAAc,EAAQ,EAAE;QAC7C,OAAO,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,OAAO,EAAE;YACX,eAAe,GAAG;gBAChB,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc;gBAC5C,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa;aAC3C,CAAC;SACH;IACH,CAAC,CAAC;IAEF,MAAM,uBAAuB,GAAG,GAAS,EAAE;QACzC,IAAI,oBAAoB,EAAE;YACxB,2BAA2B,EAAE,CAAC;SAC/B;QAED,oBAAoB,GAAG,8BAA8B,CACnD,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,CAAC,eAAe;YAC9B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,mCAAmC,EAAE,CAAC;YACxE,CAAC,CAAC,mCAAmC,EAAE,EACzC,eAAe,CAChB,CAAC;QACF,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAE,YAAY,CAChC,gCAAgC,EAChC,mDAAmD,CACpD,CAAC;QACF,IAAI,qCAAqC,EAAE;YACzC,yBAAyB,CAAC,SAAS,EAAE,EAAE,oBAAoB,CAAC,CAAC;SAC9D;QACD,mEAAmE;QACnE,MAAM,WAAW,GAAG,oBAAoB,CAAC;QACzC,kCAAkC,CAChC,SAAS,EAAE,EACX,WAAW,EACX,4BAA4B,EAC5B,GAAG,EAAE,CAAC,oBAAoB,KAAK,WAAW,CAC3C,CAAC;QAEF,kBAAkB,GAAG,UAAU,CAAC,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAChG,CAAC,CAAC;IAEF,MAAM,8CAA8C,GAAG,CAAC,KAA+B,EAAQ,EAAE;QAC/F,IAAI,CAAC,oBAAoB,EAAE;YACzB,OAAO;SACR;QAED,qDAAqD;QACrD,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,MAAK,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,WAAW,CAAA,CAAC;QAC9E,IAAI,eAAe,EAAE;YACnB,2BAA2B,EAAE,CAAC;YAC9B,OAAO;SACR;QAED,uBAAuB,EAAE,CAAC;QAE1B,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAExE,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC,WAAW,KAAK,4BAA4B,EAAE;YACjF,oBAAoB,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;SACtD;QACD,oBAAoB,CAAC,aAAa,CAAC;YACjC,kHAAkH;YAClH,YAAY,EAAE,KAAK,CAAC,aAAa;YACjC,oBAAoB,EAAE,KAAK,CAAC,WAAW;YACvC,sBAAsB,EAAE,KAAK,CAAC,aAAa;YAC3C,qBAAqB,EAAE,gBAAgB;YACvC,qBAAqB,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,aAAa;YACxD,6BAA6B,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,WAAW;YAC9D,+BAA+B,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,aAAa;YAClE,CAAC,gCAAgC,CAAC,EAAE,WAAW;YAC/C,CAAC,4BAA4B,CAAC,EAAE,YAAY;SAC7C,CAAC,CAAC;QAEH,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAE9C,aAAa,CAAC;YACZ,QAAQ,EAAE,YAAY;YACtB,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,iBAAiB,KAAK,CAAC,aAAa,EAAE;YAC/C,IAAI,EAAE;gBACJ,IAAI,EAAE,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,aAAa;gBACvC,EAAE,EAAE,KAAK,CAAC,aAAa;aACxB;SACF,CAAC,CAAC;QAEH,qBAAqB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACzC,kBAAkB,GAAG,KAAK,CAAC;QAC3B,oBAAoB,GAAG,SAAS,CAAC;IACnC,CAAC,CAAC;IAEF,UAAU,CAAC,MAAM,EAAE,CAAC,uBAAuB,CAAC,uBAAuB,CAAC,CAAC;IACrE,IAAI,yBAAyB,EAAE;QAC7B,UAAU,CAAC,MAAM,EAAE,CAAC,gCAAgC,CAAC,uBAAuB,CAAC,CAAC;KAC/E;IACD,UAAU,CAAC,MAAM,EAAE,CAAC,mCAAmC,CAAC,8CAA8C,CAAC,CAAC;IAExG,MAAM,qBAAqB,GAAG,CAAC,EAAU,EAAQ,EAAE;QACjD,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE5B,IAAI,kBAAkB,CAAC,MAAM,GAAG,2BAA2B,EAAE;YAC3D,kBAAkB,GAAG,kBAAkB,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,GAAG,2BAA2B,CAAC,CAAC;SACxG;IACH,CAAC,CAAC;IAEF,MAAM,2BAA2B,GAAG,GAAS,EAAE;QAC7C,IAAI,oBAAoB,EAAE;YACxB,IAAI,YAAY,CAAC,oBAAoB,CAAC,EAAE;gBACtC,oBAAoB,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;aAC1C;YACD,qCAAqC;YACrC,oBAAoB,CAAC,GAAG,EAAE,CAAC;YAC3B,oBAAoB,GAAG,SAAS,CAAC;SAClC;QAED,uBAAuB,EAAE,CAAC;IAC5B,CAAC,CAAC;IAEF,MAAM,uBAAuB,GAAG,GAAS,EAAE;QACzC,IAAI,OAAO,kBAAkB,KAAK,WAAW,EAAE;YAC7C,YAAY,CAAC,kBAAkB,CAAC,CAAC;YACjC,kBAAkB,GAAG,SAAS,CAAC;SAChC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,aAAa;KACd,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { Client, Integration, Span } from '@sentry/core';\nimport {\n addBreadcrumb,\n getClient,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n} from '@sentry/core';\nimport type { EmitterSubscription } from '../utils/rnlibrariesinterface';\nimport { isSentrySpan } from '../utils/span';\nimport { ignoreEmptyBackNavigation, ignoreEmptyRouteChangeTransactions } from './onSpanEndUtils';\nimport { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NATIVE_NAVIGATION } from './origin';\nimport type { ReactNativeTracingIntegration } from './reactnativetracing';\nimport { getReactNativeTracingIntegration } from './reactnativetracing';\nimport {\n DEFAULT_NAVIGATION_SPAN_NAME,\n defaultIdleOptions,\n getDefaultIdleNavigationSpanOptions,\n startIdleNavigationSpan as startGenericIdleNavigationSpan,\n} from './span';\n\nexport const INTEGRATION_NAME = 'ReactNativeNavigation';\n\nconst NAVIGATION_HISTORY_MAX_SIZE = 200;\n\ninterface ReactNativeNavigationOptions {\n /**\n * How long the instrumentation will wait for the route to mount after a change has been initiated,\n * before the transaction is discarded.\n *\n * @default 1_000 (ms)\n */\n routeChangeTimeoutMs?: number;\n\n /**\n * Instrumentation will create a transaction on tab change.\n * By default only navigation commands create transactions.\n *\n * @default false\n */\n enableTabsInstrumentation?: boolean;\n\n /**\n * Does not sample transactions that are from routes that have been seen any more and don't have any spans.\n * This removes a lot of the clutter as most back navigation transactions are now ignored.\n *\n * @default true\n */\n ignoreEmptyBackNavigationTransactions?: boolean;\n\n /** The React Native Navigation `NavigationDelegate`.\n *\n * ```js\n * import { Navigation } from 'react-native-navigation';\n * ```\n */\n navigation: unknown;\n}\n\ninterface ComponentEvent {\n componentId: string;\n}\n\ntype ComponentType = 'Component' | 'TopBarTitle' | 'TopBarBackground' | 'TopBarButton';\n\nexport interface ComponentWillAppearEvent extends ComponentEvent {\n componentName: string;\n passProps?: Record<string | number | symbol, unknown>;\n componentType: ComponentType;\n}\n\nexport interface EventSubscription {\n remove(): void;\n}\n\nexport interface BottomTabPressedEvent {\n tabIndex: number;\n}\n\nexport interface EventsRegistry {\n registerComponentWillAppearListener(callback: (event: ComponentWillAppearEvent) => void): EmitterSubscription;\n registerCommandListener(callback: (name: string, params: unknown) => void): EventSubscription;\n registerBottomTabPressedListener(callback: (event: BottomTabPressedEvent) => void): EmitterSubscription;\n}\n\nexport interface NavigationDelegate {\n events: () => EventsRegistry;\n}\n\n/**\n * Instrumentation for React Native Navigation. See docs or sample app for usage.\n *\n * How this works:\n * - `_onCommand` is called every time a commands happens and sets an IdleTransaction on the scope without any route context.\n * - `_onComponentWillAppear` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.\n * - If `_onComponentWillAppear` isn't called within `options.routeChangeTimeoutMs` of the dispatch, then the transaction is not sampled and finished.\n */\nexport const reactNativeNavigationIntegration = ({\n navigation: optionsNavigation,\n routeChangeTimeoutMs = 1_000,\n enableTabsInstrumentation = false,\n ignoreEmptyBackNavigationTransactions = true,\n}: ReactNativeNavigationOptions): Integration => {\n const navigation = optionsNavigation as NavigationDelegate;\n let recentComponentIds: string[] = [];\n\n let tracing: ReactNativeTracingIntegration | undefined;\n let idleSpanOptions: Parameters<typeof startGenericIdleNavigationSpan>[1] = defaultIdleOptions;\n\n let stateChangeTimeout: ReturnType<typeof setTimeout> | undefined;\n let prevComponentEvent: ComponentWillAppearEvent | null = null;\n let latestNavigationSpan: Span | undefined;\n\n const afterAllSetup = (client: Client): void => {\n tracing = getReactNativeTracingIntegration(client);\n if (tracing) {\n idleSpanOptions = {\n finalTimeout: tracing.options.finalTimeoutMs,\n idleTimeout: tracing.options.idleTimeoutMs,\n };\n }\n };\n\n const startIdleNavigationSpan = (): void => {\n if (latestNavigationSpan) {\n discardLatestNavigationSpan();\n }\n\n latestNavigationSpan = startGenericIdleNavigationSpan(\n tracing?.options.beforeStartSpan\n ? tracing.options.beforeStartSpan(getDefaultIdleNavigationSpanOptions())\n : getDefaultIdleNavigationSpanOptions(),\n idleSpanOptions,\n );\n latestNavigationSpan?.setAttribute(\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NATIVE_NAVIGATION,\n );\n if (ignoreEmptyBackNavigationTransactions) {\n ignoreEmptyBackNavigation(getClient(), latestNavigationSpan);\n }\n // Always discard transactions that never receive route information\n const spanToCheck = latestNavigationSpan;\n ignoreEmptyRouteChangeTransactions(\n getClient(),\n spanToCheck,\n DEFAULT_NAVIGATION_SPAN_NAME,\n () => latestNavigationSpan === spanToCheck,\n );\n\n stateChangeTimeout = setTimeout(discardLatestNavigationSpan.bind(this), routeChangeTimeoutMs);\n };\n\n const updateLatestNavigationSpanWithCurrentComponent = (event: ComponentWillAppearEvent): void => {\n if (!latestNavigationSpan) {\n return;\n }\n\n // We ignore actions that pertain to the same screen.\n const isSameComponent = event.componentId === prevComponentEvent?.componentId;\n if (isSameComponent) {\n discardLatestNavigationSpan();\n return;\n }\n\n clearStateChangeTimeout();\n\n const routeHasBeenSeen = recentComponentIds.includes(event.componentId);\n\n if (spanToJSON(latestNavigationSpan).description === DEFAULT_NAVIGATION_SPAN_NAME) {\n latestNavigationSpan.updateName(event.componentName);\n }\n latestNavigationSpan.setAttributes({\n // TODO: Should we include pass props? I don't know exactly what it contains, cant find it in the RNavigation docs\n 'route.name': event.componentName,\n 'route.component_id': event.componentId,\n 'route.component_type': event.componentType,\n 'route.has_been_seen': routeHasBeenSeen,\n 'previous_route.name': prevComponentEvent?.componentName,\n 'previous_route.component_id': prevComponentEvent?.componentId,\n 'previous_route.component_type': prevComponentEvent?.componentType,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n });\n\n tracing?.setCurrentRoute(event.componentName);\n\n addBreadcrumb({\n category: 'navigation',\n type: 'navigation',\n message: `Navigation to ${event.componentName}`,\n data: {\n from: prevComponentEvent?.componentName,\n to: event.componentName,\n },\n });\n\n pushRecentComponentId(event.componentId);\n prevComponentEvent = event;\n latestNavigationSpan = undefined;\n };\n\n navigation.events().registerCommandListener(startIdleNavigationSpan);\n if (enableTabsInstrumentation) {\n navigation.events().registerBottomTabPressedListener(startIdleNavigationSpan);\n }\n navigation.events().registerComponentWillAppearListener(updateLatestNavigationSpanWithCurrentComponent);\n\n const pushRecentComponentId = (id: string): void => {\n recentComponentIds.push(id);\n\n if (recentComponentIds.length > NAVIGATION_HISTORY_MAX_SIZE) {\n recentComponentIds = recentComponentIds.slice(recentComponentIds.length - NAVIGATION_HISTORY_MAX_SIZE);\n }\n };\n\n const discardLatestNavigationSpan = (): void => {\n if (latestNavigationSpan) {\n if (isSentrySpan(latestNavigationSpan)) {\n latestNavigationSpan['_sampled'] = false;\n }\n // TODO: What if it's not SentrySpan?\n latestNavigationSpan.end();\n latestNavigationSpan = undefined;\n }\n\n clearStateChangeTimeout();\n };\n\n const clearStateChangeTimeout = (): void => {\n if (typeof stateChangeTimeout !== 'undefined') {\n clearTimeout(stateChangeTimeout);\n stateChangeTimeout = undefined;\n }\n };\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup,\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"reactnavigation.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/reactnavigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAQ,MAAM,cAAc,CAAC;AA+B9D,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAIlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CA2BpC;AA0BD,UAAU,iCAAiC;IACzC;;;;;OAKG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,0BAA0B,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,qCAAqC,EAAE,OAAO,CAAC;IAE/C;;;;;OAKG;IACH,4CAA4C,EAAE,OAAO,CAAC;IAEtD;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;IAEjC;;;;OAIG;IACH,+BAA+B,EAAE,OAAO,CAAC;IAEzC;;;;;;OAMG;IACH,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,kOAQpC,QAAQ,iCAAiC,CAAC;IAC3C;;;OAGG;0DACmD,OAAO,KAAK,IAAI;aAC7D,iCAAiC;CA4W3C,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IAEZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAQD;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,MAAM,GACb,UAAU,CAAC,OAAO,0BAA0B,CAAC,GAAG,SAAS,CAE3D"}
1
+ {"version":3,"file":"reactnavigation.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/reactnavigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAQ,MAAM,cAAc,CAAC;AA+B9D,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAIlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CA2BpC;AA0BD,UAAU,iCAAiC;IACzC;;;;;OAKG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,0BAA0B,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,qCAAqC,EAAE,OAAO,CAAC;IAE/C;;;;;OAKG;IACH,4CAA4C,EAAE,OAAO,CAAC;IAEtD;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;IAEjC;;;;OAIG;IACH,+BAA+B,EAAE,OAAO,CAAC;IAEzC;;;;;;OAMG;IACH,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,kOAQpC,QAAQ,iCAAiC,CAAC;IAC3C;;;OAGG;0DACmD,OAAO,KAAK,IAAI;aAC7D,iCAAiC;CA8W3C,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IAEZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAQD;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,MAAM,GACb,UAAU,CAAC,OAAO,0BAA0B,CAAC,GAAG,SAAS,CAE3D"}
@@ -183,6 +183,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
183
183
  * @param unknownEvent - The event object that contains navigation action data
184
184
  * @param isAppRestart - Whether this span is being started due to an app restart rather than a normal navigation action
185
185
  */
186
+ // eslint-disable-next-line complexity
186
187
  const startIdleNavigationSpan = (unknownEvent, isAppRestart = false) => {
187
188
  const event = unknownEvent;
188
189
  if (useDispatchedActionData && (event === null || event === void 0 ? void 0 : event.data.noop)) {
@@ -262,6 +263,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
262
263
  /**
263
264
  * To be called AFTER the state has been changed to populate the transaction with the current route.
264
265
  */
266
+ // eslint-disable-next-line complexity
265
267
  const updateLatestNavigationSpanWithCurrentRoute = () => {
266
268
  var _a, _b, _c;
267
269
  const stateChangedTimestamp = timestampInSeconds();
@@ -280,7 +282,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
280
282
  return undefined;
281
283
  }
282
284
  addTimeToInitialDisplayFallback(latestNavigationSpan.spanContext().spanId, NATIVE.getNewScreenTimeToDisplay());
283
- if (previousRoute && previousRoute.key === route.key) {
285
+ if ((previousRoute === null || previousRoute === void 0 ? void 0 : previousRoute.key) === route.key) {
284
286
  debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but route is the same as previous.`);
285
287
  pushRecentRouteKey(route.key);
286
288
  latestRoute = route;
@@ -1 +1 @@
1
- {"version":3,"file":"reactnavigation.js","sourceRoot":"","sources":["../../../src/js/tracing/reactnavigation.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Integration, Span } from '@sentry/core';\nimport {\n addBreadcrumb,\n debug,\n getClient,\n isPlainObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_OK,\n spanToJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { getAppRegistryIntegration } from '../integrations/appRegistry';\nimport { isSentrySpan } from '../utils/span';\nimport { RN_GLOBAL_OBJ } from '../utils/worldwide';\nimport type { UnsafeAction } from '../vendor/react-navigation/types';\nimport { NATIVE } from '../wrapper';\nimport { ignoreEmptyBackNavigation, ignoreEmptyRouteChangeTransactions } from './onSpanEndUtils';\nimport { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION } from './origin';\nimport type { ReactNativeTracingIntegration } from './reactnativetracing';\nimport { getReactNativeTracingIntegration } from './reactnativetracing';\nimport { SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from './semanticAttributes';\nimport {\n DEFAULT_NAVIGATION_SPAN_NAME,\n defaultIdleOptions,\n getDefaultIdleNavigationSpanOptions,\n startIdleNavigationSpan as startGenericIdleNavigationSpan,\n} from './span';\nimport { addTimeToInitialDisplayFallback } from './timeToDisplayFallback';\n\nexport const INTEGRATION_NAME = 'ReactNavigation';\n\nconst NAVIGATION_HISTORY_MAX_SIZE = 200;\n\n/**\n * Extracts dynamic route parameters from a route name and its params.\n * Matches Expo Router style dynamic segments like `[id]` and `[...slug]`.\n *\n * Only params whose keys appear as dynamic segments in the route name are returned,\n * filtering out non-structural params (query params, etc.) that may contain PII.\n *\n * Note: dynamic segment values (e.g. the `123` in `profile/[id]`) may be user-identifiable.\n * This function only extracts params — callers are responsible for checking `sendDefaultPii`\n * before including the result in span attributes.\n *\n * Previous route params are intentionally not captured — only the current route's\n * structural params are needed for trace attribution.\n */\nexport function extractDynamicRouteParams(\n routeName: string,\n params?: Record<string, unknown>,\n): Record<string, string> | undefined {\n if (!params) {\n return undefined;\n }\n\n const dynamicKeys = new Set<string>();\n const pattern = /\\[(?:\\.\\.\\.)?(\\w+)\\]/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(routeName)) !== null) {\n if (match[1]) {\n dynamicKeys.add(match[1]);\n }\n }\n\n if (dynamicKeys.size === 0) {\n return undefined;\n }\n\n const result: Record<string, string> = {};\n for (const key of dynamicKeys) {\n if (key in params) {\n const value = params[key];\n result[`route.params.${key}`] = Array.isArray(value) ? value.join('/') : String(value ?? '');\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Builds a full path from the navigation state by traversing nested navigators.\n * For example, with nested navigators: \"Home/Settings/Profile\"\n */\nfunction getPathFromState(state?: NavigationState): string | undefined {\n if (!state) {\n return undefined;\n }\n\n const routeNames: string[] = [];\n let currentState: NavigationState | undefined = state;\n\n while (currentState) {\n const index: number = currentState.index ?? 0;\n const route: NavigationRoute | undefined = currentState.routes[index];\n if (route?.name) {\n routeNames.push(route.name);\n }\n currentState = route?.state;\n }\n\n return routeNames.length > 0 ? routeNames.join('/') : undefined;\n}\n\ninterface ReactNavigationIntegrationOptions {\n /**\n * How long the instrumentation will wait for the route to mount after a change has been initiated,\n * before the transaction is discarded.\n *\n * @default 1_000 (ms)\n */\n routeChangeTimeoutMs: number;\n\n /**\n * Time to initial display measures the time it takes from\n * navigation dispatch to the render of the first frame of the new screen.\n *\n * @default false\n */\n enableTimeToInitialDisplay: boolean;\n\n /**\n * Does not sample transactions that are from routes that have been seen any more and don't have any spans.\n * This removes a lot of the clutter as most back navigation transactions are now ignored.\n *\n * @default true\n */\n ignoreEmptyBackNavigationTransactions: boolean;\n\n /**\n * Enabled measuring Time to Initial Display for routes that are already loaded in memory.\n * (a.k.a., Routes that the navigation integration has already seen.)\n *\n * @default false\n */\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n\n /**\n * Whether to use the dispatched action data to populate the transaction metadata.\n *\n * @default false\n */\n useDispatchedActionData: boolean;\n\n /**\n * Whether to use the full paths for navigation routes.\n *\n * @default false\n */\n useFullPathsForNavigationRoutes: boolean;\n\n /**\n * Track performance of route prefetching operations.\n * Creates separate spans for PRELOAD actions to measure prefetch performance.\n * This is useful for Expo Router apps that use the prefetch functionality.\n *\n * @default false\n */\n enablePrefetchTracking: boolean;\n}\n\n/**\n * Instrumentation for React-Navigation V5 and above. See docs or sample app for usage.\n *\n * How this works:\n * - `_onDispatch` is called every time a dispatch happens and sets an IdleTransaction on the scope without any route context.\n * - `_onStateChange` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.\n * - If `_onStateChange` isn't called within `STATE_CHANGE_TIMEOUT_DURATION` of the dispatch, then the transaction is not sampled and finished.\n */\nexport const reactNavigationIntegration = ({\n routeChangeTimeoutMs = 1_000,\n enableTimeToInitialDisplay = false,\n ignoreEmptyBackNavigationTransactions = true,\n enableTimeToInitialDisplayForPreloadedRoutes = false,\n useDispatchedActionData = false,\n useFullPathsForNavigationRoutes = false,\n enablePrefetchTracking = false,\n}: Partial<ReactNavigationIntegrationOptions> = {}): Integration & {\n /**\n * Pass the ref to the navigation container to register it to the instrumentation\n * @param navigationContainerRef Ref to a `NavigationContainer`\n */\n registerNavigationContainer: (navigationContainerRef: unknown) => void;\n options: ReactNavigationIntegrationOptions;\n} => {\n let navigationContainer: NavigationContainer | undefined;\n\n let tracing: ReactNativeTracingIntegration | undefined;\n let idleSpanOptions: Parameters<typeof startGenericIdleNavigationSpan>[1] = defaultIdleOptions;\n let latestRoute: NavigationRoute | undefined;\n\n let latestNavigationSpan: Span | undefined;\n let navigationProcessingSpan: Span | undefined;\n\n let initialStateHandled: boolean = false;\n let isSetupComplete: boolean = false;\n let stateChangeTimeout: ReturnType<typeof setTimeout> | undefined;\n let recentRouteKeys: string[] = [];\n\n if (enableTimeToInitialDisplay) {\n NATIVE.initNativeReactNavigationNewFrameTracking().catch((reason: unknown) => {\n debug.error(`${INTEGRATION_NAME} Failed to initialize native new frame tracking: ${reason}`);\n });\n }\n\n /**\n * Set the initial state and start initial navigation span for the current screen.\n */\n const afterAllSetup = (client: Client): void => {\n tracing = getReactNativeTracingIntegration(client);\n if (tracing) {\n idleSpanOptions = {\n finalTimeout: tracing.options.finalTimeoutMs,\n idleTimeout: tracing.options.idleTimeoutMs,\n };\n }\n\n if (initialStateHandled) {\n // We create an initial state here to ensure a transaction gets created before the first route mounts.\n // This assumes that the Sentry.init() call is made before the first route mounts.\n // If this is not the case, the first transaction will be nameless 'Route Changed'\n return undefined;\n }\n\n getAppRegistryIntegration(client)?.onRunApplication(() => {\n if (initialStateHandled) {\n // To avoid conflict with the initial transaction we check if it was already handled.\n // This ensures runApplication calls after the initial start are correctly traced.\n // This is used for example when Activity is (re)started on Android.\n debug.log('[ReactNavigationIntegration] Starting new idle navigation span based on runApplication call.');\n startIdleNavigationSpan(undefined, true);\n }\n });\n\n isSetupComplete = true;\n\n if (!navigationContainer) {\n // This is expected as navigation container is registered after the root component is mounted.\n return undefined;\n }\n\n // Navigation container already registered, create and populate initial span\n startIdleNavigationSpan();\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n const registerNavigationContainer = (maybeNewNavigationContainer: unknown): void => {\n if (RN_GLOBAL_OBJ.__sentry_rn_v5_registered) {\n debug.log(`${INTEGRATION_NAME} Instrumentation already exists, but registering again...`);\n // In the past we have not allowed re-registering the navigation container to avoid unexpected behavior.\n // But this doesn't work for Android and re-recreating application main activity.\n // Where new navigation container is created and the old one is discarded. We need to re-register to\n // trace the new navigation container navigation.\n }\n\n let newNavigationContainer: NavigationContainer | undefined;\n if (isPlainObject(maybeNewNavigationContainer) && 'current' in maybeNewNavigationContainer) {\n newNavigationContainer = maybeNewNavigationContainer.current as NavigationContainer;\n } else {\n newNavigationContainer = maybeNewNavigationContainer as NavigationContainer;\n }\n\n if (navigationContainer === newNavigationContainer) {\n debug.log(`${INTEGRATION_NAME} Navigation container ref is the same as the one already registered.`);\n return;\n }\n navigationContainer = newNavigationContainer;\n\n if (!navigationContainer) {\n debug.warn(`${INTEGRATION_NAME} Received invalid navigation container ref!`);\n return undefined;\n }\n\n // This action is emitted on every dispatch\n navigationContainer.addListener('__unsafe_action__', startIdleNavigationSpan);\n navigationContainer.addListener('state', updateLatestNavigationSpanWithCurrentRoute);\n RN_GLOBAL_OBJ.__sentry_rn_v5_registered = true;\n\n if (initialStateHandled) {\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n if (!isSetupComplete) {\n debug.log(\n `${INTEGRATION_NAME} Navigation container registered before integration setup. Initial span will be created when setup completes.`,\n );\n return undefined;\n }\n startIdleNavigationSpan();\n }\n\n // Navigation Container is registered after the first navigation\n // Initial navigation span was started, after integration setup,\n // so now we populate it with the current route.\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n /**\n * To be called on every React-Navigation action dispatch.\n * It does not name the transaction or populate it with route information. Instead, it waits for the state to fully change\n * and gets the route information from there, @see updateLatestNavigationSpanWithCurrentRoute\n *\n * @param unknownEvent - The event object that contains navigation action data\n * @param isAppRestart - Whether this span is being started due to an app restart rather than a normal navigation action\n */\n const startIdleNavigationSpan = (unknownEvent?: unknown, isAppRestart = false): void => {\n const event = unknownEvent as UnsafeAction | undefined;\n if (useDispatchedActionData && event?.data.noop) {\n debug.log(`${INTEGRATION_NAME} Navigation action is a noop, not starting navigation span.`);\n return;\n }\n\n const navigationActionType = useDispatchedActionData ? event?.data.action.type : undefined;\n\n // Handle PRELOAD actions separately if prefetch tracking is enabled\n if (enablePrefetchTracking && navigationActionType === 'PRELOAD') {\n const preloadData = event?.data.action;\n const payload = preloadData?.payload;\n const targetRoute =\n payload && typeof payload === 'object' && 'name' in payload && typeof payload.name === 'string'\n ? payload.name\n : 'Unknown Route';\n\n debug.log(`${INTEGRATION_NAME} Starting prefetch span for route: ${targetRoute}`);\n\n const prefetchSpan = startInactiveSpan({\n op: 'navigation.prefetch',\n name: `Prefetch ${targetRoute}`,\n attributes: {\n 'route.name': targetRoute,\n },\n });\n\n // Store prefetch span to end it when state changes or timeout\n navigationProcessingSpan = prefetchSpan;\n\n // Set timeout to ensure we don't leave hanging spans\n stateChangeTimeout = setTimeout(() => {\n if (navigationProcessingSpan === prefetchSpan) {\n debug.log(`${INTEGRATION_NAME} Prefetch span timed out for route: ${targetRoute}`);\n prefetchSpan?.setStatus({ code: SPAN_STATUS_OK });\n prefetchSpan?.end();\n navigationProcessingSpan = undefined;\n }\n }, routeChangeTimeoutMs);\n\n return;\n }\n\n if (\n useDispatchedActionData &&\n navigationActionType &&\n [\n // Process common actions\n 'PRELOAD', // Still filter PRELOAD when enablePrefetchTracking is false\n 'SET_PARAMS',\n // Drawer actions\n 'OPEN_DRAWER',\n 'CLOSE_DRAWER',\n 'TOGGLE_DRAWER',\n ].includes(navigationActionType)\n ) {\n debug.log(`${INTEGRATION_NAME} Navigation action is ${navigationActionType}, not starting navigation span.`);\n return;\n }\n\n if (latestNavigationSpan) {\n debug.log(`${INTEGRATION_NAME} A transaction was detected that turned out to be a noop, discarding.`);\n _discardLatestTransaction();\n clearStateChangeTimeout();\n }\n\n latestNavigationSpan = startGenericIdleNavigationSpan(\n tracing?.options.beforeStartSpan\n ? tracing.options.beforeStartSpan(getDefaultIdleNavigationSpanOptions())\n : getDefaultIdleNavigationSpanOptions(),\n { ...idleSpanOptions, isAppRestart },\n );\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION);\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, navigationActionType);\n if (ignoreEmptyBackNavigationTransactions) {\n ignoreEmptyBackNavigation(getClient(), latestNavigationSpan);\n }\n // Always discard transactions that never receive route information\n const spanToCheck = latestNavigationSpan;\n ignoreEmptyRouteChangeTransactions(\n getClient(),\n spanToCheck,\n DEFAULT_NAVIGATION_SPAN_NAME,\n () => latestNavigationSpan === spanToCheck,\n );\n\n if (enableTimeToInitialDisplay && latestNavigationSpan) {\n NATIVE.setActiveSpanId(latestNavigationSpan.spanContext().spanId);\n navigationProcessingSpan = startInactiveSpan({\n op: 'navigation.processing',\n name: 'Navigation dispatch to navigation cancelled or screen mounted',\n startTime: spanToJSON(latestNavigationSpan).start_timestamp,\n });\n navigationProcessingSpan.setAttribute(\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION,\n );\n }\n\n stateChangeTimeout = setTimeout(_discardLatestTransaction, routeChangeTimeoutMs);\n };\n\n /**\n * To be called AFTER the state has been changed to populate the transaction with the current route.\n */\n const updateLatestNavigationSpanWithCurrentRoute = (): void => {\n const stateChangedTimestamp = timestampInSeconds();\n const previousRoute = latestRoute;\n\n if (!navigationContainer) {\n debug.warn(`${INTEGRATION_NAME} Missing navigation container ref. Route transactions will not be sent.`);\n return undefined;\n }\n\n const route = navigationContainer.getCurrentRoute();\n if (!route) {\n debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but no route is rendered.`);\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n debug.log(\n `[${INTEGRATION_NAME}] Navigation state changed, but navigation transaction was not started on dispatch.`,\n );\n return undefined;\n }\n\n addTimeToInitialDisplayFallback(latestNavigationSpan.spanContext().spanId, NATIVE.getNewScreenTimeToDisplay());\n\n if (previousRoute && previousRoute.key === route.key) {\n debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but route is the same as previous.`);\n pushRecentRouteKey(route.key);\n latestRoute = route;\n\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n return undefined;\n }\n\n const routeHasBeenSeen = recentRouteKeys.includes(route.key);\n\n // Get the full navigation path for nested navigators\n let routeName = route.name;\n if (useFullPathsForNavigationRoutes) {\n const navigationState = navigationContainer.getState();\n routeName = getPathFromState(navigationState) || route.name;\n }\n\n navigationProcessingSpan?.updateName(`Navigation dispatch to screen ${routeName} mounted`);\n navigationProcessingSpan?.setStatus({ code: SPAN_STATUS_OK });\n navigationProcessingSpan?.end(stateChangedTimestamp);\n navigationProcessingSpan = undefined;\n\n if (spanToJSON(latestNavigationSpan).description === DEFAULT_NAVIGATION_SPAN_NAME) {\n latestNavigationSpan.updateName(routeName);\n }\n const sendDefaultPii = getClient()?.getOptions()?.sendDefaultPii ?? false;\n latestNavigationSpan.setAttributes({\n 'route.name': routeName,\n 'route.key': route.key,\n ...(sendDefaultPii ? extractDynamicRouteParams(routeName, route.params) : undefined),\n 'route.has_been_seen': routeHasBeenSeen,\n 'previous_route.name': previousRoute?.name,\n 'previous_route.key': previousRoute?.key,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n });\n\n // Clear the timeout so the transaction does not get cancelled.\n clearStateChangeTimeout();\n\n addBreadcrumb({\n category: 'navigation',\n type: 'navigation',\n message: `Navigation to ${routeName}`,\n data: {\n from: previousRoute?.name,\n to: routeName,\n },\n });\n\n tracing?.setCurrentRoute(routeName);\n\n pushRecentRouteKey(route.key);\n if (useFullPathsForNavigationRoutes) {\n latestRoute = { ...route, name: routeName };\n } else {\n latestRoute = route;\n }\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n };\n\n /** Pushes a recent route key, and removes earlier routes when there is greater than the max length */\n const pushRecentRouteKey = (key: string): void => {\n recentRouteKeys.push(key);\n\n if (recentRouteKeys.length > NAVIGATION_HISTORY_MAX_SIZE) {\n recentRouteKeys = recentRouteKeys.slice(recentRouteKeys.length - NAVIGATION_HISTORY_MAX_SIZE);\n }\n };\n\n /** Cancels the latest transaction so it does not get sent to Sentry. */\n const _discardLatestTransaction = (): void => {\n if (latestNavigationSpan) {\n if (isSentrySpan(latestNavigationSpan)) {\n latestNavigationSpan['_sampled'] = false;\n }\n // TODO: What if it's not SentrySpan?\n latestNavigationSpan.end();\n latestNavigationSpan = undefined;\n }\n if (navigationProcessingSpan) {\n navigationProcessingSpan = undefined;\n }\n };\n\n const clearStateChangeTimeout = (): void => {\n if (typeof stateChangeTimeout !== 'undefined') {\n clearTimeout(stateChangeTimeout);\n stateChangeTimeout = undefined;\n }\n };\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup,\n registerNavigationContainer,\n options: {\n routeChangeTimeoutMs,\n enableTimeToInitialDisplay,\n ignoreEmptyBackNavigationTransactions,\n enableTimeToInitialDisplayForPreloadedRoutes,\n useDispatchedActionData,\n useFullPathsForNavigationRoutes,\n enablePrefetchTracking,\n },\n };\n};\n\nexport interface NavigationRoute {\n name: string;\n key: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n params?: Record<string, any>;\n state?: NavigationState;\n}\n\ninterface NavigationState {\n index?: number;\n routes: NavigationRoute[];\n}\n\ninterface NavigationContainer {\n addListener: (type: string, listener: (event?: unknown) => void) => void;\n getCurrentRoute: () => NavigationRoute;\n getState: () => NavigationState | undefined;\n}\n\n/**\n * Returns React Navigation integration of the given client.\n */\nexport function getReactNavigationIntegration(\n client: Client,\n): ReturnType<typeof reactNavigationIntegration> | undefined {\n return client.getIntegrationByName<ReturnType<typeof reactNavigationIntegration>>(INTEGRATION_NAME);\n}\n"]}
1
+ {"version":3,"file":"reactnavigation.js","sourceRoot":"","sources":["../../../src/js/tracing/reactnavigation.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Integration, Span } from '@sentry/core';\nimport {\n addBreadcrumb,\n debug,\n getClient,\n isPlainObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_OK,\n spanToJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { getAppRegistryIntegration } from '../integrations/appRegistry';\nimport { isSentrySpan } from '../utils/span';\nimport { RN_GLOBAL_OBJ } from '../utils/worldwide';\nimport type { UnsafeAction } from '../vendor/react-navigation/types';\nimport { NATIVE } from '../wrapper';\nimport { ignoreEmptyBackNavigation, ignoreEmptyRouteChangeTransactions } from './onSpanEndUtils';\nimport { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION } from './origin';\nimport type { ReactNativeTracingIntegration } from './reactnativetracing';\nimport { getReactNativeTracingIntegration } from './reactnativetracing';\nimport { SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from './semanticAttributes';\nimport {\n DEFAULT_NAVIGATION_SPAN_NAME,\n defaultIdleOptions,\n getDefaultIdleNavigationSpanOptions,\n startIdleNavigationSpan as startGenericIdleNavigationSpan,\n} from './span';\nimport { addTimeToInitialDisplayFallback } from './timeToDisplayFallback';\n\nexport const INTEGRATION_NAME = 'ReactNavigation';\n\nconst NAVIGATION_HISTORY_MAX_SIZE = 200;\n\n/**\n * Extracts dynamic route parameters from a route name and its params.\n * Matches Expo Router style dynamic segments like `[id]` and `[...slug]`.\n *\n * Only params whose keys appear as dynamic segments in the route name are returned,\n * filtering out non-structural params (query params, etc.) that may contain PII.\n *\n * Note: dynamic segment values (e.g. the `123` in `profile/[id]`) may be user-identifiable.\n * This function only extracts params — callers are responsible for checking `sendDefaultPii`\n * before including the result in span attributes.\n *\n * Previous route params are intentionally not captured — only the current route's\n * structural params are needed for trace attribution.\n */\nexport function extractDynamicRouteParams(\n routeName: string,\n params?: Record<string, unknown>,\n): Record<string, string> | undefined {\n if (!params) {\n return undefined;\n }\n\n const dynamicKeys = new Set<string>();\n const pattern = /\\[(?:\\.\\.\\.)?(\\w+)\\]/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(routeName)) !== null) {\n if (match[1]) {\n dynamicKeys.add(match[1]);\n }\n }\n\n if (dynamicKeys.size === 0) {\n return undefined;\n }\n\n const result: Record<string, string> = {};\n for (const key of dynamicKeys) {\n if (key in params) {\n const value = params[key];\n result[`route.params.${key}`] = Array.isArray(value) ? value.join('/') : String(value ?? '');\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Builds a full path from the navigation state by traversing nested navigators.\n * For example, with nested navigators: \"Home/Settings/Profile\"\n */\nfunction getPathFromState(state?: NavigationState): string | undefined {\n if (!state) {\n return undefined;\n }\n\n const routeNames: string[] = [];\n let currentState: NavigationState | undefined = state;\n\n while (currentState) {\n const index: number = currentState.index ?? 0;\n const route: NavigationRoute | undefined = currentState.routes[index];\n if (route?.name) {\n routeNames.push(route.name);\n }\n currentState = route?.state;\n }\n\n return routeNames.length > 0 ? routeNames.join('/') : undefined;\n}\n\ninterface ReactNavigationIntegrationOptions {\n /**\n * How long the instrumentation will wait for the route to mount after a change has been initiated,\n * before the transaction is discarded.\n *\n * @default 1_000 (ms)\n */\n routeChangeTimeoutMs: number;\n\n /**\n * Time to initial display measures the time it takes from\n * navigation dispatch to the render of the first frame of the new screen.\n *\n * @default false\n */\n enableTimeToInitialDisplay: boolean;\n\n /**\n * Does not sample transactions that are from routes that have been seen any more and don't have any spans.\n * This removes a lot of the clutter as most back navigation transactions are now ignored.\n *\n * @default true\n */\n ignoreEmptyBackNavigationTransactions: boolean;\n\n /**\n * Enabled measuring Time to Initial Display for routes that are already loaded in memory.\n * (a.k.a., Routes that the navigation integration has already seen.)\n *\n * @default false\n */\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n\n /**\n * Whether to use the dispatched action data to populate the transaction metadata.\n *\n * @default false\n */\n useDispatchedActionData: boolean;\n\n /**\n * Whether to use the full paths for navigation routes.\n *\n * @default false\n */\n useFullPathsForNavigationRoutes: boolean;\n\n /**\n * Track performance of route prefetching operations.\n * Creates separate spans for PRELOAD actions to measure prefetch performance.\n * This is useful for Expo Router apps that use the prefetch functionality.\n *\n * @default false\n */\n enablePrefetchTracking: boolean;\n}\n\n/**\n * Instrumentation for React-Navigation V5 and above. See docs or sample app for usage.\n *\n * How this works:\n * - `_onDispatch` is called every time a dispatch happens and sets an IdleTransaction on the scope without any route context.\n * - `_onStateChange` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.\n * - If `_onStateChange` isn't called within `STATE_CHANGE_TIMEOUT_DURATION` of the dispatch, then the transaction is not sampled and finished.\n */\nexport const reactNavigationIntegration = ({\n routeChangeTimeoutMs = 1_000,\n enableTimeToInitialDisplay = false,\n ignoreEmptyBackNavigationTransactions = true,\n enableTimeToInitialDisplayForPreloadedRoutes = false,\n useDispatchedActionData = false,\n useFullPathsForNavigationRoutes = false,\n enablePrefetchTracking = false,\n}: Partial<ReactNavigationIntegrationOptions> = {}): Integration & {\n /**\n * Pass the ref to the navigation container to register it to the instrumentation\n * @param navigationContainerRef Ref to a `NavigationContainer`\n */\n registerNavigationContainer: (navigationContainerRef: unknown) => void;\n options: ReactNavigationIntegrationOptions;\n} => {\n let navigationContainer: NavigationContainer | undefined;\n\n let tracing: ReactNativeTracingIntegration | undefined;\n let idleSpanOptions: Parameters<typeof startGenericIdleNavigationSpan>[1] = defaultIdleOptions;\n let latestRoute: NavigationRoute | undefined;\n\n let latestNavigationSpan: Span | undefined;\n let navigationProcessingSpan: Span | undefined;\n\n let initialStateHandled: boolean = false;\n let isSetupComplete: boolean = false;\n let stateChangeTimeout: ReturnType<typeof setTimeout> | undefined;\n let recentRouteKeys: string[] = [];\n\n if (enableTimeToInitialDisplay) {\n NATIVE.initNativeReactNavigationNewFrameTracking().catch((reason: unknown) => {\n debug.error(`${INTEGRATION_NAME} Failed to initialize native new frame tracking: ${reason}`);\n });\n }\n\n /**\n * Set the initial state and start initial navigation span for the current screen.\n */\n const afterAllSetup = (client: Client): void => {\n tracing = getReactNativeTracingIntegration(client);\n if (tracing) {\n idleSpanOptions = {\n finalTimeout: tracing.options.finalTimeoutMs,\n idleTimeout: tracing.options.idleTimeoutMs,\n };\n }\n\n if (initialStateHandled) {\n // We create an initial state here to ensure a transaction gets created before the first route mounts.\n // This assumes that the Sentry.init() call is made before the first route mounts.\n // If this is not the case, the first transaction will be nameless 'Route Changed'\n return undefined;\n }\n\n getAppRegistryIntegration(client)?.onRunApplication(() => {\n if (initialStateHandled) {\n // To avoid conflict with the initial transaction we check if it was already handled.\n // This ensures runApplication calls after the initial start are correctly traced.\n // This is used for example when Activity is (re)started on Android.\n debug.log('[ReactNavigationIntegration] Starting new idle navigation span based on runApplication call.');\n startIdleNavigationSpan(undefined, true);\n }\n });\n\n isSetupComplete = true;\n\n if (!navigationContainer) {\n // This is expected as navigation container is registered after the root component is mounted.\n return undefined;\n }\n\n // Navigation container already registered, create and populate initial span\n startIdleNavigationSpan();\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n const registerNavigationContainer = (maybeNewNavigationContainer: unknown): void => {\n if (RN_GLOBAL_OBJ.__sentry_rn_v5_registered) {\n debug.log(`${INTEGRATION_NAME} Instrumentation already exists, but registering again...`);\n // In the past we have not allowed re-registering the navigation container to avoid unexpected behavior.\n // But this doesn't work for Android and re-recreating application main activity.\n // Where new navigation container is created and the old one is discarded. We need to re-register to\n // trace the new navigation container navigation.\n }\n\n let newNavigationContainer: NavigationContainer | undefined;\n if (isPlainObject(maybeNewNavigationContainer) && 'current' in maybeNewNavigationContainer) {\n newNavigationContainer = maybeNewNavigationContainer.current as NavigationContainer;\n } else {\n newNavigationContainer = maybeNewNavigationContainer as NavigationContainer;\n }\n\n if (navigationContainer === newNavigationContainer) {\n debug.log(`${INTEGRATION_NAME} Navigation container ref is the same as the one already registered.`);\n return;\n }\n navigationContainer = newNavigationContainer;\n\n if (!navigationContainer) {\n debug.warn(`${INTEGRATION_NAME} Received invalid navigation container ref!`);\n return undefined;\n }\n\n // This action is emitted on every dispatch\n navigationContainer.addListener('__unsafe_action__', startIdleNavigationSpan);\n navigationContainer.addListener('state', updateLatestNavigationSpanWithCurrentRoute);\n RN_GLOBAL_OBJ.__sentry_rn_v5_registered = true;\n\n if (initialStateHandled) {\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n if (!isSetupComplete) {\n debug.log(\n `${INTEGRATION_NAME} Navigation container registered before integration setup. Initial span will be created when setup completes.`,\n );\n return undefined;\n }\n startIdleNavigationSpan();\n }\n\n // Navigation Container is registered after the first navigation\n // Initial navigation span was started, after integration setup,\n // so now we populate it with the current route.\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n /**\n * To be called on every React-Navigation action dispatch.\n * It does not name the transaction or populate it with route information. Instead, it waits for the state to fully change\n * and gets the route information from there, @see updateLatestNavigationSpanWithCurrentRoute\n *\n * @param unknownEvent - The event object that contains navigation action data\n * @param isAppRestart - Whether this span is being started due to an app restart rather than a normal navigation action\n */\n // eslint-disable-next-line complexity\n const startIdleNavigationSpan = (unknownEvent?: unknown, isAppRestart = false): void => {\n const event = unknownEvent as UnsafeAction | undefined;\n if (useDispatchedActionData && event?.data.noop) {\n debug.log(`${INTEGRATION_NAME} Navigation action is a noop, not starting navigation span.`);\n return;\n }\n\n const navigationActionType = useDispatchedActionData ? event?.data.action.type : undefined;\n\n // Handle PRELOAD actions separately if prefetch tracking is enabled\n if (enablePrefetchTracking && navigationActionType === 'PRELOAD') {\n const preloadData = event?.data.action;\n const payload = preloadData?.payload;\n const targetRoute =\n payload && typeof payload === 'object' && 'name' in payload && typeof payload.name === 'string'\n ? payload.name\n : 'Unknown Route';\n\n debug.log(`${INTEGRATION_NAME} Starting prefetch span for route: ${targetRoute}`);\n\n const prefetchSpan = startInactiveSpan({\n op: 'navigation.prefetch',\n name: `Prefetch ${targetRoute}`,\n attributes: {\n 'route.name': targetRoute,\n },\n });\n\n // Store prefetch span to end it when state changes or timeout\n navigationProcessingSpan = prefetchSpan;\n\n // Set timeout to ensure we don't leave hanging spans\n stateChangeTimeout = setTimeout(() => {\n if (navigationProcessingSpan === prefetchSpan) {\n debug.log(`${INTEGRATION_NAME} Prefetch span timed out for route: ${targetRoute}`);\n prefetchSpan?.setStatus({ code: SPAN_STATUS_OK });\n prefetchSpan?.end();\n navigationProcessingSpan = undefined;\n }\n }, routeChangeTimeoutMs);\n\n return;\n }\n\n if (\n useDispatchedActionData &&\n navigationActionType &&\n [\n // Process common actions\n 'PRELOAD', // Still filter PRELOAD when enablePrefetchTracking is false\n 'SET_PARAMS',\n // Drawer actions\n 'OPEN_DRAWER',\n 'CLOSE_DRAWER',\n 'TOGGLE_DRAWER',\n ].includes(navigationActionType)\n ) {\n debug.log(`${INTEGRATION_NAME} Navigation action is ${navigationActionType}, not starting navigation span.`);\n return;\n }\n\n if (latestNavigationSpan) {\n debug.log(`${INTEGRATION_NAME} A transaction was detected that turned out to be a noop, discarding.`);\n _discardLatestTransaction();\n clearStateChangeTimeout();\n }\n\n latestNavigationSpan = startGenericIdleNavigationSpan(\n tracing?.options.beforeStartSpan\n ? tracing.options.beforeStartSpan(getDefaultIdleNavigationSpanOptions())\n : getDefaultIdleNavigationSpanOptions(),\n { ...idleSpanOptions, isAppRestart },\n );\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION);\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, navigationActionType);\n if (ignoreEmptyBackNavigationTransactions) {\n ignoreEmptyBackNavigation(getClient(), latestNavigationSpan);\n }\n // Always discard transactions that never receive route information\n const spanToCheck = latestNavigationSpan;\n ignoreEmptyRouteChangeTransactions(\n getClient(),\n spanToCheck,\n DEFAULT_NAVIGATION_SPAN_NAME,\n () => latestNavigationSpan === spanToCheck,\n );\n\n if (enableTimeToInitialDisplay && latestNavigationSpan) {\n NATIVE.setActiveSpanId(latestNavigationSpan.spanContext().spanId);\n navigationProcessingSpan = startInactiveSpan({\n op: 'navigation.processing',\n name: 'Navigation dispatch to navigation cancelled or screen mounted',\n startTime: spanToJSON(latestNavigationSpan).start_timestamp,\n });\n navigationProcessingSpan.setAttribute(\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION,\n );\n }\n\n stateChangeTimeout = setTimeout(_discardLatestTransaction, routeChangeTimeoutMs);\n };\n\n /**\n * To be called AFTER the state has been changed to populate the transaction with the current route.\n */\n // eslint-disable-next-line complexity\n const updateLatestNavigationSpanWithCurrentRoute = (): void => {\n const stateChangedTimestamp = timestampInSeconds();\n const previousRoute = latestRoute;\n\n if (!navigationContainer) {\n debug.warn(`${INTEGRATION_NAME} Missing navigation container ref. Route transactions will not be sent.`);\n return undefined;\n }\n\n const route = navigationContainer.getCurrentRoute();\n if (!route) {\n debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but no route is rendered.`);\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n debug.log(\n `[${INTEGRATION_NAME}] Navigation state changed, but navigation transaction was not started on dispatch.`,\n );\n return undefined;\n }\n\n addTimeToInitialDisplayFallback(latestNavigationSpan.spanContext().spanId, NATIVE.getNewScreenTimeToDisplay());\n\n if (previousRoute?.key === route.key) {\n debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but route is the same as previous.`);\n pushRecentRouteKey(route.key);\n latestRoute = route;\n\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n return undefined;\n }\n\n const routeHasBeenSeen = recentRouteKeys.includes(route.key);\n\n // Get the full navigation path for nested navigators\n let routeName = route.name;\n if (useFullPathsForNavigationRoutes) {\n const navigationState = navigationContainer.getState();\n routeName = getPathFromState(navigationState) || route.name;\n }\n\n navigationProcessingSpan?.updateName(`Navigation dispatch to screen ${routeName} mounted`);\n navigationProcessingSpan?.setStatus({ code: SPAN_STATUS_OK });\n navigationProcessingSpan?.end(stateChangedTimestamp);\n navigationProcessingSpan = undefined;\n\n if (spanToJSON(latestNavigationSpan).description === DEFAULT_NAVIGATION_SPAN_NAME) {\n latestNavigationSpan.updateName(routeName);\n }\n const sendDefaultPii = getClient()?.getOptions()?.sendDefaultPii ?? false;\n latestNavigationSpan.setAttributes({\n 'route.name': routeName,\n 'route.key': route.key,\n ...(sendDefaultPii ? extractDynamicRouteParams(routeName, route.params) : undefined),\n 'route.has_been_seen': routeHasBeenSeen,\n 'previous_route.name': previousRoute?.name,\n 'previous_route.key': previousRoute?.key,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n });\n\n // Clear the timeout so the transaction does not get cancelled.\n clearStateChangeTimeout();\n\n addBreadcrumb({\n category: 'navigation',\n type: 'navigation',\n message: `Navigation to ${routeName}`,\n data: {\n from: previousRoute?.name,\n to: routeName,\n },\n });\n\n tracing?.setCurrentRoute(routeName);\n\n pushRecentRouteKey(route.key);\n if (useFullPathsForNavigationRoutes) {\n latestRoute = { ...route, name: routeName };\n } else {\n latestRoute = route;\n }\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n };\n\n /** Pushes a recent route key, and removes earlier routes when there is greater than the max length */\n const pushRecentRouteKey = (key: string): void => {\n recentRouteKeys.push(key);\n\n if (recentRouteKeys.length > NAVIGATION_HISTORY_MAX_SIZE) {\n recentRouteKeys = recentRouteKeys.slice(recentRouteKeys.length - NAVIGATION_HISTORY_MAX_SIZE);\n }\n };\n\n /** Cancels the latest transaction so it does not get sent to Sentry. */\n const _discardLatestTransaction = (): void => {\n if (latestNavigationSpan) {\n if (isSentrySpan(latestNavigationSpan)) {\n latestNavigationSpan['_sampled'] = false;\n }\n // TODO: What if it's not SentrySpan?\n latestNavigationSpan.end();\n latestNavigationSpan = undefined;\n }\n if (navigationProcessingSpan) {\n navigationProcessingSpan = undefined;\n }\n };\n\n const clearStateChangeTimeout = (): void => {\n if (typeof stateChangeTimeout !== 'undefined') {\n clearTimeout(stateChangeTimeout);\n stateChangeTimeout = undefined;\n }\n };\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup,\n registerNavigationContainer,\n options: {\n routeChangeTimeoutMs,\n enableTimeToInitialDisplay,\n ignoreEmptyBackNavigationTransactions,\n enableTimeToInitialDisplayForPreloadedRoutes,\n useDispatchedActionData,\n useFullPathsForNavigationRoutes,\n enablePrefetchTracking,\n },\n };\n};\n\nexport interface NavigationRoute {\n name: string;\n key: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n params?: Record<string, any>;\n state?: NavigationState;\n}\n\ninterface NavigationState {\n index?: number;\n routes: NavigationRoute[];\n}\n\ninterface NavigationContainer {\n addListener: (type: string, listener: (event?: unknown) => void) => void;\n getCurrentRoute: () => NavigationRoute;\n getState: () => NavigationState | undefined;\n}\n\n/**\n * Returns React Navigation integration of the given client.\n */\nexport function getReactNavigationIntegration(\n client: Client,\n): ReturnType<typeof reactNavigationIntegration> | undefined {\n return client.getIntegrationByName<ReturnType<typeof reactNavigationIntegration>>(INTEGRATION_NAME);\n}\n"]}
@@ -3,7 +3,7 @@ import { LogBox } from 'react-native';
3
3
  * This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.
4
4
  */
5
5
  export function ignoreRequireCycleLogs(version) {
6
- if (version && version.major === 0 && version.minor < 70) {
6
+ if ((version === null || version === void 0 ? void 0 : version.major) === 0 && version.minor < 70) {
7
7
  // Do not ignore require cycle logs on React Native versions >= 0.70
8
8
  // https://github.com/getsentry/sentry-react-native/issues/3484#issuecomment-1877034820
9
9
  LogBox.ignoreLogs(['Require cycle:']);
@@ -1 +1 @@
1
- {"version":3,"file":"ignorerequirecyclelogs.js","sourceRoot":"","sources":["../../../src/js/utils/ignorerequirecyclelogs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA4B;IACjE,IAAI,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG,EAAE,EAAE;QACxD,oEAAoE;QACpE,uFAAuF;QACvF,MAAM,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;KACvC;AACH,CAAC","sourcesContent":["import { LogBox } from 'react-native';\n\ninterface ReactNativeVersion {\n major: number;\n minor: number;\n}\n\n/**\n * This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.\n */\nexport function ignoreRequireCycleLogs(version?: ReactNativeVersion): void {\n if (version && version.major === 0 && version.minor < 70) {\n // Do not ignore require cycle logs on React Native versions >= 0.70\n // https://github.com/getsentry/sentry-react-native/issues/3484#issuecomment-1877034820\n LogBox.ignoreLogs(['Require cycle:']);\n }\n}\n"]}
1
+ {"version":3,"file":"ignorerequirecyclelogs.js","sourceRoot":"","sources":["../../../src/js/utils/ignorerequirecyclelogs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA4B;IACjE,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,MAAK,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG,EAAE,EAAE;QAC9C,oEAAoE;QACpE,uFAAuF;QACvF,MAAM,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;KACvC;AACH,CAAC","sourcesContent":["import { LogBox } from 'react-native';\n\ninterface ReactNativeVersion {\n major: number;\n minor: number;\n}\n\n/**\n * This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.\n */\nexport function ignoreRequireCycleLogs(version?: ReactNativeVersion): void {\n if (version?.major === 0 && version.minor < 70) {\n // Do not ignore require cycle logs on React Native versions >= 0.70\n // https://github.com/getsentry/sentry-react-native/issues/3484#issuecomment-1877034820\n LogBox.ignoreLogs(['Require cycle:']);\n }\n}\n"]}