@sentry/react-native 3.3.1 → 3.3.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.3.2
4
+
5
+ - fix: Do not report empty measurements #1983
6
+ - fix(iOS): Bump Sentry Cocoa to 7.10.1 and report slow and frozen measurements (#2132)
7
+ - fix(iOS): Missing userId on iOS when the user is not set in the Scope (#2133)
8
+
3
9
  ## 3.3.1
4
10
 
5
11
  - feat: Support setting maxCacheItems #2102
package/RNSentry.podspec CHANGED
@@ -17,7 +17,7 @@ Pod::Spec.new do |s|
17
17
  s.preserve_paths = '*.js'
18
18
 
19
19
  s.dependency 'React-Core'
20
- s.dependency 'Sentry', '7.10.0'
20
+ s.dependency 'Sentry', '7.10.1'
21
21
 
22
22
  s.source_files = 'ios/RNSentry.{h,m}'
23
23
  s.public_header_files = 'ios/RNSentry.h'
@@ -269,6 +269,11 @@ public class RNSentryModule extends ReactContextBaseJavaModule {
269
269
  }
270
270
  }
271
271
 
272
+ if (totalFrames == 0 && slowFrames == 0 && frozenFrames == 0) {
273
+ promise.resolve(null);
274
+ return;
275
+ }
276
+
272
277
  WritableMap map = Arguments.createMap();
273
278
  map.putInt("totalFrames", totalFrames);
274
279
  map.putInt("slowFrames", slowFrames);
@@ -1 +1 @@
1
- {"version":3,"file":"devicecontext.d.ts","sourceRoot":"","sources":["../../../src/js/integrations/devicecontext.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,WAAW,EAAE,MAAM,eAAe,CAAC;AAKnD,uCAAuC;AACvC,qBAAa,aAAc,YAAW,WAAW;IAC/C;;OAEG;IACH,OAAc,EAAE,EAAE,MAAM,CAAmB;IAE3C;;OAEG;IACI,IAAI,EAAE,MAAM,CAAoB;IAEvC;;OAEG;IACI,SAAS,IAAI,IAAI;CAiBzB"}
1
+ {"version":3,"file":"devicecontext.d.ts","sourceRoot":"","sources":["../../../src/js/integrations/devicecontext.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,WAAW,EAAE,MAAM,eAAe,CAAC;AAK7D,uCAAuC;AACvC,qBAAa,aAAc,YAAW,WAAW;IAC/C;;OAEG;IACH,OAAc,EAAE,EAAE,MAAM,CAAmB;IAE3C;;OAEG;IACI,IAAI,EAAE,MAAM,CAAoB;IAEvC;;OAEG;IACI,SAAS,IAAI,IAAI;CAyBzB"}
@@ -15,13 +15,19 @@ export class DeviceContext {
15
15
  */
16
16
  setupOnce() {
17
17
  addGlobalEventProcessor((event) => __awaiter(this, void 0, void 0, function* () {
18
+ var _a, _b;
18
19
  const self = getCurrentHub().getIntegration(DeviceContext);
19
20
  if (!self) {
20
21
  return event;
21
22
  }
22
23
  try {
23
- const deviceContexts = yield NATIVE.fetchNativeDeviceContexts();
24
- event.contexts = Object.assign(Object.assign({}, deviceContexts), event.contexts);
24
+ const contexts = yield NATIVE.fetchNativeDeviceContexts();
25
+ const context = (_a = contexts['context']) !== null && _a !== void 0 ? _a : {};
26
+ const user = (_b = contexts['user']) !== null && _b !== void 0 ? _b : {};
27
+ event.contexts = Object.assign(Object.assign({}, context), event.contexts);
28
+ if (!event.user) {
29
+ event.user = Object.assign({}, user);
30
+ }
25
31
  }
26
32
  catch (e) {
27
33
  logger.log(`Failed to get device context from native: ${e}`);
@@ -1 +1 @@
1
- {"version":3,"file":"devicecontext.js","sourceRoot":"","sources":["../../../src/js/integrations/devicecontext.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,uCAAuC;AACvC,MAAM,OAAO,aAAa;IAA1B;QAME;;WAEG;QACI,SAAI,GAAW,aAAa,CAAC,EAAE,CAAC;IAsBzC,CAAC;IApBC;;OAEG;IACI,SAAS;QACd,uBAAuB,CAAC,CAAO,KAAY,EAAE,EAAE;YAC7C,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC3D,IAAI,CAAC,IAAI,EAAE;gBACT,OAAO,KAAK,CAAC;aACd;YAED,IAAI;gBACF,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,yBAAyB,EAAE,CAAC;gBAChE,KAAK,CAAC,QAAQ,mCAAQ,cAAc,GAAK,KAAK,CAAC,QAAQ,CAAE,CAAC;aAC3D;YAAC,OAAO,CAAC,EAAE;gBACV,MAAM,CAAC,GAAG,CAAC,6CAA6C,CAAC,EAAE,CAAC,CAAC;aAC9D;YAED,OAAO,KAAK,CAAC;QACf,CAAC,CAAA,CAAC,CAAC;IACL,CAAC;;AA7BD;;GAEG;AACW,gBAAE,GAAW,eAAe,CAAC","sourcesContent":["import { addGlobalEventProcessor, getCurrentHub } from \"@sentry/core\";\nimport { Event, Integration } from \"@sentry/types\";\nimport { logger } from \"@sentry/utils\";\n\nimport { NATIVE } from \"../wrapper\";\n\n/** Load device context from native. */\nexport class DeviceContext implements Integration {\n /**\n * @inheritDoc\n */\n public static id: string = \"DeviceContext\";\n\n /**\n * @inheritDoc\n */\n public name: string = DeviceContext.id;\n\n /**\n * @inheritDoc\n */\n public setupOnce(): void {\n addGlobalEventProcessor(async (event: Event) => {\n const self = getCurrentHub().getIntegration(DeviceContext);\n if (!self) {\n return event;\n }\n\n try {\n const deviceContexts = await NATIVE.fetchNativeDeviceContexts();\n event.contexts = { ...deviceContexts, ...event.contexts };\n } catch (e) {\n logger.log(`Failed to get device context from native: ${e}`);\n }\n\n return event;\n });\n }\n}\n"]}
1
+ {"version":3,"file":"devicecontext.js","sourceRoot":"","sources":["../../../src/js/integrations/devicecontext.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,uCAAuC;AACvC,MAAM,OAAO,aAAa;IAA1B;QAME;;WAEG;QACI,SAAI,GAAW,aAAa,CAAC,EAAE,CAAC;IA8BzC,CAAC;IA5BC;;OAEG;IACI,SAAS;QACd,uBAAuB,CAAC,CAAO,KAAY,EAAE,EAAE;;YAC7C,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC3D,IAAI,CAAC,IAAI,EAAE;gBACT,OAAO,KAAK,CAAC;aACd;YAED,IAAI;gBACF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,yBAAyB,EAAE,CAAC;gBAE1D,MAAM,OAAO,SAAG,QAAQ,CAAC,SAAS,CAAa,mCAAI,EAAE,CAAC;gBACtD,MAAM,IAAI,SAAG,QAAQ,CAAC,MAAM,CAAC,mCAAI,EAAE,CAAC;gBAEpC,KAAK,CAAC,QAAQ,mCAAQ,OAAO,GAAK,KAAK,CAAC,QAAQ,CAAE,CAAC;gBAEnD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBACf,KAAK,CAAC,IAAI,qBAAQ,IAAI,CAAE,CAAC;iBAC1B;aACF;YAAC,OAAO,CAAC,EAAE;gBACV,MAAM,CAAC,GAAG,CAAC,6CAA6C,CAAC,EAAE,CAAC,CAAC;aAC9D;YAED,OAAO,KAAK,CAAC;QACf,CAAC,CAAA,CAAC,CAAC;IACL,CAAC;;AArCD;;GAEG;AACW,gBAAE,GAAW,eAAe,CAAC","sourcesContent":["import { addGlobalEventProcessor, getCurrentHub } from \"@sentry/core\";\nimport { Contexts, Event, Integration } from \"@sentry/types\";\nimport { logger } from \"@sentry/utils\";\n\nimport { NATIVE } from \"../wrapper\";\n\n/** Load device context from native. */\nexport class DeviceContext implements Integration {\n /**\n * @inheritDoc\n */\n public static id: string = \"DeviceContext\";\n\n /**\n * @inheritDoc\n */\n public name: string = DeviceContext.id;\n\n /**\n * @inheritDoc\n */\n public setupOnce(): void {\n addGlobalEventProcessor(async (event: Event) => {\n const self = getCurrentHub().getIntegration(DeviceContext);\n if (!self) {\n return event;\n }\n\n try {\n const contexts = await NATIVE.fetchNativeDeviceContexts();\n\n const context = contexts['context'] as Contexts ?? {};\n const user = contexts['user'] ?? {};\n\n event.contexts = { ...context, ...event.contexts };\n\n if (!event.user) {\n event.user = { ...user };\n }\n } catch (e) {\n logger.log(`Failed to get device context from native: ${e}`);\n }\n\n return event;\n });\n }\n}\n"]}
@@ -12,7 +12,7 @@ interface ReactNavigationOptions {
12
12
  routeChangeTimeoutMs: number;
13
13
  }
14
14
  /**
15
- * Instrumentation for React-Navigation V5. See docs or sample app for usage.
15
+ * Instrumentation for React-Navigation V5 and above. See docs or sample app for usage.
16
16
  *
17
17
  * How this works:
18
18
  * - `_onDispatch` is called every time a dispatch happens and sets an IdleTransaction on the scope without any route context.
@@ -5,7 +5,7 @@ const defaultOptions = {
5
5
  routeChangeTimeoutMs: 1000,
6
6
  };
7
7
  /**
8
- * Instrumentation for React-Navigation V5. See docs or sample app for usage.
8
+ * Instrumentation for React-Navigation V5 and above. See docs or sample app for usage.
9
9
  *
10
10
  * How this works:
11
11
  * - `_onDispatch` is called every time a dispatch happens and sets an IdleTransaction on the scope without any route context.
@@ -75,17 +75,17 @@ export class ReactNavigationInstrumentation extends InternalRoutingInstrumentati
75
75
  this._initialStateHandled = true;
76
76
  }
77
77
  else {
78
- logger.log("[ReactNavigationV5Instrumentation] Navigation container registered, but integration has not been setup yet.");
78
+ logger.log("[ReactNavigationInstrumentation] Navigation container registered, but integration has not been setup yet.");
79
79
  }
80
80
  }
81
81
  _global.__sentry_rn_v5_registered = true;
82
82
  }
83
83
  else {
84
- logger.warn("[ReactNavigationV5Instrumentation] Received invalid navigation container ref!");
84
+ logger.warn("[ReactNavigationInstrumentation] Received invalid navigation container ref!");
85
85
  }
86
86
  }
87
87
  else {
88
- logger.log("[ReactNavigationV5Instrumentation] Instrumentation already exists, but register has been called again, doing nothing.");
88
+ logger.log("[ReactNavigationInstrumentation] Instrumentation already exists, but register has been called again, doing nothing.");
89
89
  }
90
90
  }
91
91
  /**
@@ -110,7 +110,7 @@ export class ReactNavigationInstrumentation extends InternalRoutingInstrumentati
110
110
  // Use the getCurrentRoute method to be accurate.
111
111
  const previousRoute = this._latestRoute;
112
112
  if (!this._navigationContainer) {
113
- logger.warn("[ReactNavigationV5Instrumentation] Missing navigation container ref. Route transactions will not be sent.");
113
+ logger.warn("[ReactNavigationInstrumentation] Missing navigation container ref. Route transactions will not be sent.");
114
114
  return;
115
115
  }
116
116
  const route = this._navigationContainer.getCurrentRoute();
@@ -135,12 +135,12 @@ export class ReactNavigationInstrumentation extends InternalRoutingInstrumentati
135
135
  let finalContext = (_c = this._beforeNavigate) === null || _c === void 0 ? void 0 : _c.call(this, updatedContext);
136
136
  // This block is to catch users not returning a transaction context
137
137
  if (!finalContext) {
138
- logger.error(`[ReactNavigationV5Instrumentation] beforeNavigate returned ${finalContext}, return context.sampled = false to not send transaction.`);
138
+ logger.error(`[ReactNavigationInstrumentation] beforeNavigate returned ${finalContext}, return context.sampled = false to not send transaction.`);
139
139
  finalContext = Object.assign(Object.assign({}, updatedContext), { sampled: false });
140
140
  }
141
141
  // Note: finalContext.sampled will be false at this point only if the user sets it to be so in beforeNavigate.
142
142
  if (finalContext.sampled === false) {
143
- logger.log(`[ReactNavigationV5Instrumentation] Will not send transaction "${finalContext.name}" due to beforeNavigate.`);
143
+ logger.log(`[ReactNavigationInstrumentation] Will not send transaction "${finalContext.name}" due to beforeNavigate.`);
144
144
  }
145
145
  else {
146
146
  // Clear the timeout so the transaction does not get cancelled.
@@ -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 { Transaction as TransactionType } from \"@sentry/types\";\nimport { getGlobalObject, logger } from \"@sentry/utils\";\n\nimport { BeforeNavigate } from \"./reactnativetracing\";\nimport {\n InternalRoutingInstrumentation,\n OnConfirmRoute,\n TransactionCreator,\n} from \"./routingInstrumentation\";\nimport {\n ReactNavigationTransactionContext,\n RouteChangeContextData,\n} from \"./types\";\nimport { getBlankTransactionContext } from \"./utils\";\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}\n\ninterface NavigationContainer {\n addListener: (type: string, listener: () => void) => void;\n getCurrentRoute: () => NavigationRoute;\n}\n\ninterface ReactNavigationOptions {\n /**\n * The time the transaction will wait for route to mount before it is discarded.\n */\n routeChangeTimeoutMs: number;\n}\n\nconst defaultOptions: ReactNavigationOptions = {\n routeChangeTimeoutMs: 1000,\n};\n\n/**\n * Instrumentation for React-Navigation V5. 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 class ReactNavigationInstrumentation extends InternalRoutingInstrumentation {\n public static instrumentationName: string = \"react-navigation-v5\";\n\n private _navigationContainer: NavigationContainer | null = null;\n\n private readonly _maxRecentRouteLen: number = 200;\n\n private _latestRoute?: NavigationRoute;\n private _latestTransaction?: TransactionType;\n private _initialStateHandled: boolean = false;\n private _stateChangeTimeout?: number | undefined;\n private _recentRouteKeys: string[] = [];\n\n private _options: ReactNavigationOptions;\n\n public constructor(options: Partial<ReactNavigationOptions> = {}) {\n super();\n\n this._options = {\n ...defaultOptions,\n ...options,\n };\n }\n\n /**\n * Extends by calling _handleInitialState at the end.\n */\n public registerRoutingInstrumentation(\n listener: TransactionCreator,\n beforeNavigate: BeforeNavigate,\n onConfirmRoute: OnConfirmRoute\n ): void {\n super.registerRoutingInstrumentation(\n listener,\n beforeNavigate,\n onConfirmRoute\n );\n\n // We create an initial state here to ensure a transaction gets created before the first route mounts.\n if (!this._initialStateHandled) {\n this._onDispatch();\n if (this._navigationContainer) {\n // Navigation container already registered, just populate with route state\n this._onStateChange();\n\n this._initialStateHandled = true;\n }\n }\n }\n\n /**\n * Pass the ref to the navigation container to register it to the instrumentation\n * @param navigationContainerRef Ref to a `NavigationContainer`\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types\n public registerNavigationContainer(navigationContainerRef: any): void {\n const _global = getGlobalObject<{ __sentry_rn_v5_registered?: boolean }>();\n\n /* We prevent duplicate routing instrumentation to be initialized on fast refreshes\n\n Explanation: If the user triggers a fast refresh on the file that the instrumentation is\n initialized in, it will initialize a new instance and will cause undefined behavior.\n */\n if (!_global.__sentry_rn_v5_registered) {\n if (\"current\" in navigationContainerRef) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n this._navigationContainer = navigationContainerRef.current;\n } else {\n this._navigationContainer = navigationContainerRef;\n }\n\n if (this._navigationContainer) {\n this._navigationContainer.addListener(\n \"__unsafe_action__\", // This action is emitted on every dispatch\n this._onDispatch.bind(this)\n );\n this._navigationContainer.addListener(\n \"state\", // This action is emitted on every state change\n this._onStateChange.bind(this)\n );\n\n if (!this._initialStateHandled) {\n if (this._latestTransaction) {\n // If registerRoutingInstrumentation was called first _onDispatch has already been called\n this._onStateChange();\n\n this._initialStateHandled = true;\n } else {\n logger.log(\n \"[ReactNavigationV5Instrumentation] Navigation container registered, but integration has not been setup yet.\"\n );\n }\n }\n\n _global.__sentry_rn_v5_registered = true;\n } else {\n logger.warn(\n \"[ReactNavigationV5Instrumentation] Received invalid navigation container ref!\"\n );\n }\n } else {\n logger.log(\n \"[ReactNavigationV5Instrumentation] Instrumentation already exists, but register has been called again, doing nothing.\"\n );\n }\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 _onStateChange\n */\n private _onDispatch(): void {\n if (this._latestTransaction) {\n logger.log(\n `[ReactNavigationInstrumentation] A transaction was detected that turned out to be a noop, discarding.`\n );\n this._discardLatestTransaction();\n this._clearStateChangeTimeout();\n }\n\n this._latestTransaction = this.onRouteWillChange(\n getBlankTransactionContext(\n ReactNavigationInstrumentation.instrumentationName\n )\n );\n\n this._stateChangeTimeout = setTimeout(\n this._discardLatestTransaction.bind(this),\n this._options.routeChangeTimeoutMs\n );\n }\n\n /**\n * To be called AFTER the state has been changed to populate the transaction with the current route.\n */\n private _onStateChange(): void {\n // Use the getCurrentRoute method to be accurate.\n const previousRoute = this._latestRoute;\n\n if (!this._navigationContainer) {\n logger.warn(\n \"[ReactNavigationV5Instrumentation] Missing navigation container ref. Route transactions will not be sent.\"\n );\n\n return;\n }\n\n const route = this._navigationContainer.getCurrentRoute();\n\n if (route) {\n if (this._latestTransaction) {\n if (!previousRoute || previousRoute.key !== route.key) {\n const originalContext = this._latestTransaction.toContext() as typeof BLANK_TRANSACTION_CONTEXT;\n const routeHasBeenSeen = this._recentRouteKeys.includes(route.key);\n\n const data: RouteChangeContextData = {\n ...originalContext.data,\n route: {\n name: route.name,\n key: route.key,\n params: route.params ?? {},\n hasBeenSeen: routeHasBeenSeen,\n },\n previousRoute: previousRoute\n ? {\n name: previousRoute.name,\n key: previousRoute.key,\n params: previousRoute.params ?? {},\n }\n : null,\n };\n\n const updatedContext: ReactNavigationTransactionContext = {\n ...originalContext,\n name: route.name,\n tags: {\n ...originalContext.tags,\n \"routing.route.name\": route.name,\n },\n data,\n };\n\n let finalContext = this._beforeNavigate?.(updatedContext);\n\n // This block is to catch users not returning a transaction context\n if (!finalContext) {\n logger.error(\n `[ReactNavigationV5Instrumentation] beforeNavigate returned ${finalContext}, return context.sampled = false to not send transaction.`\n );\n\n finalContext = {\n ...updatedContext,\n sampled: false,\n };\n }\n\n // Note: finalContext.sampled will be false at this point only if the user sets it to be so in beforeNavigate.\n if (finalContext.sampled === false) {\n logger.log(\n `[ReactNavigationV5Instrumentation] Will not send transaction \"${finalContext.name}\" due to beforeNavigate.`\n );\n } else {\n // Clear the timeout so the transaction does not get cancelled.\n this._clearStateChangeTimeout();\n }\n\n this._latestTransaction.updateWithContext(finalContext);\n this._onConfirmRoute?.(finalContext);\n }\n\n this._pushRecentRouteKey(route.key);\n this._latestRoute = route;\n }\n }\n\n // Clear the latest transaction as it has been handled.\n this._latestTransaction = undefined;\n }\n\n /** Pushes a recent route key, and removes earlier routes when there is greater than the max length */\n private _pushRecentRouteKey = (key: string): void => {\n this._recentRouteKeys.push(key);\n\n if (this._recentRouteKeys.length > this._maxRecentRouteLen) {\n this._recentRouteKeys = this._recentRouteKeys.slice(\n this._recentRouteKeys.length - this._maxRecentRouteLen\n );\n }\n };\n\n /** Cancels the latest transaction so it does not get sent to Sentry. */\n private _discardLatestTransaction(): void {\n if (this._latestTransaction) {\n this._latestTransaction.sampled = false;\n this._latestTransaction.finish();\n this._latestTransaction = undefined;\n }\n }\n\n /**\n *\n */\n private _clearStateChangeTimeout(): void {\n if (typeof this._stateChangeTimeout !== \"undefined\") {\n clearTimeout(this._stateChangeTimeout);\n this._stateChangeTimeout = undefined;\n }\n }\n}\n\n/**\n * Backwards compatibility alias for ReactNavigationInstrumentation\n * @deprecated Use ReactNavigationInstrumentation\n */\nexport const ReactNavigationV5Instrumentation = ReactNavigationInstrumentation;\n\nexport const BLANK_TRANSACTION_CONTEXT = {\n name: \"Route Change\",\n op: \"navigation\",\n tags: {\n \"routing.instrumentation\":\n ReactNavigationInstrumentation.instrumentationName,\n },\n data: {},\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 { Transaction as TransactionType } from \"@sentry/types\";\nimport { getGlobalObject, logger } from \"@sentry/utils\";\n\nimport { BeforeNavigate } from \"./reactnativetracing\";\nimport {\n InternalRoutingInstrumentation,\n OnConfirmRoute,\n TransactionCreator,\n} from \"./routingInstrumentation\";\nimport {\n ReactNavigationTransactionContext,\n RouteChangeContextData,\n} from \"./types\";\nimport { getBlankTransactionContext } from \"./utils\";\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}\n\ninterface NavigationContainer {\n addListener: (type: string, listener: () => void) => void;\n getCurrentRoute: () => NavigationRoute;\n}\n\ninterface ReactNavigationOptions {\n /**\n * The time the transaction will wait for route to mount before it is discarded.\n */\n routeChangeTimeoutMs: number;\n}\n\nconst defaultOptions: ReactNavigationOptions = {\n routeChangeTimeoutMs: 1000,\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 class ReactNavigationInstrumentation extends InternalRoutingInstrumentation {\n public static instrumentationName: string = \"react-navigation-v5\";\n\n private _navigationContainer: NavigationContainer | null = null;\n\n private readonly _maxRecentRouteLen: number = 200;\n\n private _latestRoute?: NavigationRoute;\n private _latestTransaction?: TransactionType;\n private _initialStateHandled: boolean = false;\n private _stateChangeTimeout?: number | undefined;\n private _recentRouteKeys: string[] = [];\n\n private _options: ReactNavigationOptions;\n\n public constructor(options: Partial<ReactNavigationOptions> = {}) {\n super();\n\n this._options = {\n ...defaultOptions,\n ...options,\n };\n }\n\n /**\n * Extends by calling _handleInitialState at the end.\n */\n public registerRoutingInstrumentation(\n listener: TransactionCreator,\n beforeNavigate: BeforeNavigate,\n onConfirmRoute: OnConfirmRoute\n ): void {\n super.registerRoutingInstrumentation(\n listener,\n beforeNavigate,\n onConfirmRoute\n );\n\n // We create an initial state here to ensure a transaction gets created before the first route mounts.\n if (!this._initialStateHandled) {\n this._onDispatch();\n if (this._navigationContainer) {\n // Navigation container already registered, just populate with route state\n this._onStateChange();\n\n this._initialStateHandled = true;\n }\n }\n }\n\n /**\n * Pass the ref to the navigation container to register it to the instrumentation\n * @param navigationContainerRef Ref to a `NavigationContainer`\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types\n public registerNavigationContainer(navigationContainerRef: any): void {\n const _global = getGlobalObject<{ __sentry_rn_v5_registered?: boolean }>();\n\n /* We prevent duplicate routing instrumentation to be initialized on fast refreshes\n\n Explanation: If the user triggers a fast refresh on the file that the instrumentation is\n initialized in, it will initialize a new instance and will cause undefined behavior.\n */\n if (!_global.__sentry_rn_v5_registered) {\n if (\"current\" in navigationContainerRef) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n this._navigationContainer = navigationContainerRef.current;\n } else {\n this._navigationContainer = navigationContainerRef;\n }\n\n if (this._navigationContainer) {\n this._navigationContainer.addListener(\n \"__unsafe_action__\", // This action is emitted on every dispatch\n this._onDispatch.bind(this)\n );\n this._navigationContainer.addListener(\n \"state\", // This action is emitted on every state change\n this._onStateChange.bind(this)\n );\n\n if (!this._initialStateHandled) {\n if (this._latestTransaction) {\n // If registerRoutingInstrumentation was called first _onDispatch has already been called\n this._onStateChange();\n\n this._initialStateHandled = true;\n } else {\n logger.log(\n \"[ReactNavigationInstrumentation] Navigation container registered, but integration has not been setup yet.\"\n );\n }\n }\n\n _global.__sentry_rn_v5_registered = true;\n } else {\n logger.warn(\n \"[ReactNavigationInstrumentation] Received invalid navigation container ref!\"\n );\n }\n } else {\n logger.log(\n \"[ReactNavigationInstrumentation] Instrumentation already exists, but register has been called again, doing nothing.\"\n );\n }\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 _onStateChange\n */\n private _onDispatch(): void {\n if (this._latestTransaction) {\n logger.log(\n `[ReactNavigationInstrumentation] A transaction was detected that turned out to be a noop, discarding.`\n );\n this._discardLatestTransaction();\n this._clearStateChangeTimeout();\n }\n\n this._latestTransaction = this.onRouteWillChange(\n getBlankTransactionContext(\n ReactNavigationInstrumentation.instrumentationName\n )\n );\n\n this._stateChangeTimeout = setTimeout(\n this._discardLatestTransaction.bind(this),\n this._options.routeChangeTimeoutMs\n );\n }\n\n /**\n * To be called AFTER the state has been changed to populate the transaction with the current route.\n */\n private _onStateChange(): void {\n // Use the getCurrentRoute method to be accurate.\n const previousRoute = this._latestRoute;\n\n if (!this._navigationContainer) {\n logger.warn(\n \"[ReactNavigationInstrumentation] Missing navigation container ref. Route transactions will not be sent.\"\n );\n\n return;\n }\n\n const route = this._navigationContainer.getCurrentRoute();\n\n if (route) {\n if (this._latestTransaction) {\n if (!previousRoute || previousRoute.key !== route.key) {\n const originalContext = this._latestTransaction.toContext() as typeof BLANK_TRANSACTION_CONTEXT;\n const routeHasBeenSeen = this._recentRouteKeys.includes(route.key);\n\n const data: RouteChangeContextData = {\n ...originalContext.data,\n route: {\n name: route.name,\n key: route.key,\n params: route.params ?? {},\n hasBeenSeen: routeHasBeenSeen,\n },\n previousRoute: previousRoute\n ? {\n name: previousRoute.name,\n key: previousRoute.key,\n params: previousRoute.params ?? {},\n }\n : null,\n };\n\n const updatedContext: ReactNavigationTransactionContext = {\n ...originalContext,\n name: route.name,\n tags: {\n ...originalContext.tags,\n \"routing.route.name\": route.name,\n },\n data,\n };\n\n let finalContext = this._beforeNavigate?.(updatedContext);\n\n // This block is to catch users not returning a transaction context\n if (!finalContext) {\n logger.error(\n `[ReactNavigationInstrumentation] beforeNavigate returned ${finalContext}, return context.sampled = false to not send transaction.`\n );\n\n finalContext = {\n ...updatedContext,\n sampled: false,\n };\n }\n\n // Note: finalContext.sampled will be false at this point only if the user sets it to be so in beforeNavigate.\n if (finalContext.sampled === false) {\n logger.log(\n `[ReactNavigationInstrumentation] Will not send transaction \"${finalContext.name}\" due to beforeNavigate.`\n );\n } else {\n // Clear the timeout so the transaction does not get cancelled.\n this._clearStateChangeTimeout();\n }\n\n this._latestTransaction.updateWithContext(finalContext);\n this._onConfirmRoute?.(finalContext);\n }\n\n this._pushRecentRouteKey(route.key);\n this._latestRoute = route;\n }\n }\n\n // Clear the latest transaction as it has been handled.\n this._latestTransaction = undefined;\n }\n\n /** Pushes a recent route key, and removes earlier routes when there is greater than the max length */\n private _pushRecentRouteKey = (key: string): void => {\n this._recentRouteKeys.push(key);\n\n if (this._recentRouteKeys.length > this._maxRecentRouteLen) {\n this._recentRouteKeys = this._recentRouteKeys.slice(\n this._recentRouteKeys.length - this._maxRecentRouteLen\n );\n }\n };\n\n /** Cancels the latest transaction so it does not get sent to Sentry. */\n private _discardLatestTransaction(): void {\n if (this._latestTransaction) {\n this._latestTransaction.sampled = false;\n this._latestTransaction.finish();\n this._latestTransaction = undefined;\n }\n }\n\n /**\n *\n */\n private _clearStateChangeTimeout(): void {\n if (typeof this._stateChangeTimeout !== \"undefined\") {\n clearTimeout(this._stateChangeTimeout);\n this._stateChangeTimeout = undefined;\n }\n }\n}\n\n/**\n * Backwards compatibility alias for ReactNavigationInstrumentation\n * @deprecated Use ReactNavigationInstrumentation\n */\nexport const ReactNavigationV5Instrumentation = ReactNavigationInstrumentation;\n\nexport const BLANK_TRANSACTION_CONTEXT = {\n name: \"Route Change\",\n op: \"navigation\",\n tags: {\n \"routing.instrumentation\":\n ReactNavigationInstrumentation.instrumentationName,\n },\n data: {},\n};\n"]}
@@ -1,3 +1,3 @@
1
1
  export declare const SDK_NAME = "sentry.javascript.react-native";
2
- export declare const SDK_VERSION = "3.3.1";
2
+ export declare const SDK_VERSION = "3.3.2";
3
3
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  export const SDK_NAME = "sentry.javascript.react-native";
2
- export const SDK_VERSION = "3.3.1";
2
+ export const SDK_VERSION = "3.3.2";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/js/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AACzD,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC","sourcesContent":["export const SDK_NAME = \"sentry.javascript.react-native\";\nexport const SDK_VERSION = \"3.3.1\";\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/js/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AACzD,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC","sourcesContent":["export const SDK_NAME = \"sentry.javascript.react-native\";\nexport const SDK_VERSION = \"3.3.2\";\n"]}
package/ios/RNSentry.m CHANGED
@@ -44,8 +44,6 @@ RCT_EXPORT_METHOD(initNativeSdk:(NSDictionary *_Nonnull)options
44
44
  resolve:(RCTPromiseResolveBlock)resolve
45
45
  rejecter:(RCTPromiseRejectBlock)reject)
46
46
  {
47
- PrivateSentrySDKOnly.appStartMeasurementHybridSDKMode = true;
48
-
49
47
  NSError *error = nil;
50
48
 
51
49
  SentryBeforeSendEventCallback beforeSend = ^SentryEvent*(SentryEvent *event) {
@@ -76,17 +74,25 @@ RCT_EXPORT_METHOD(initNativeSdk:(NSDictionary *_Nonnull)options
76
74
  reject(@"SentryReactNative", error.localizedDescription, error);
77
75
  return;
78
76
  }
79
-
77
+
80
78
  if ([mutableOptions valueForKey:@"enableNativeCrashHandling"] != nil) {
81
79
  BOOL enableNativeCrashHandling = (BOOL)[mutableOptions valueForKey:@"enableNativeCrashHandling"];
82
-
80
+
83
81
  if (!enableNativeCrashHandling) {
84
82
  NSMutableArray *integrations = sentryOptions.integrations.mutableCopy;
85
83
  [integrations removeObject:@"SentryCrashIntegration"];
86
84
  sentryOptions.integrations = integrations;
87
85
  }
88
86
  }
89
-
87
+
88
+ // Enable the App start and Frames tracking measurements
89
+ if ([mutableOptions valueForKey:@"enableAutoPerformanceTracking"] != nil) {
90
+ BOOL enableAutoPerformanceTracking = (BOOL)[mutableOptions valueForKey:@"enableAutoPerformanceTracking"];
91
+
92
+ PrivateSentrySDKOnly.appStartMeasurementHybridSDKMode = enableAutoPerformanceTracking;
93
+ PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode = enableAutoPerformanceTracking;
94
+ }
95
+
90
96
  [SentrySDK startWithOptionsObject:sentryOptions];
91
97
 
92
98
  // If the app is active/in foreground, and we have not sent the SentryHybridSdkDidBecomeActive notification, send it.
@@ -158,8 +164,19 @@ RCT_EXPORT_METHOD(fetchNativeDeviceContexts:(RCTPromiseResolveBlock)resolve
158
164
  NSDictionary<NSString *, id> *serializedScope = [scope serialize];
159
165
  // Scope serializes as 'context' instead of 'contexts' as it does for the event.
160
166
  NSDictionary<NSString *, id> *tempContexts = [serializedScope valueForKey:@"context"];
167
+
168
+ NSMutableDictionary<NSString *, id> *user = [NSMutableDictionary new];
169
+
170
+ NSDictionary<NSString *, id> *tempUser = [serializedScope valueForKey:@"user"];
171
+ if (tempUser != nil) {
172
+ [user addEntriesFromDictionary:[tempUser valueForKey:@"user"]];
173
+ } else {
174
+ [user setValue:PrivateSentrySDKOnly.installationID forKey:@"id"];
175
+ }
176
+ [contexts setValue:user forKey:@"user"];
177
+
161
178
  if (tempContexts != nil) {
162
- [contexts addEntriesFromDictionary:tempContexts];
179
+ [contexts setValue:tempContexts forKey:@"context"];
163
180
  }
164
181
  if (sentryOptions != nil && sentryOptions.debug) {
165
182
  NSData *data = [NSJSONSerialization dataWithJSONObject:contexts options:0 error:nil];
@@ -203,12 +220,23 @@ RCT_EXPORT_METHOD(fetchNativeFrames:(RCTPromiseResolveBlock)resolve
203
220
 
204
221
  if (frames == nil) {
205
222
  resolve(nil);
223
+ return;
224
+ }
225
+
226
+ NSNumber *total = [NSNumber numberWithLong:frames.total];
227
+ NSNumber *frozen = [NSNumber numberWithLong:frames.frozen];
228
+ NSNumber *slow = [NSNumber numberWithLong:frames.slow];
229
+ NSNumber *zero = [NSNumber numberWithLong:0L];
230
+
231
+ if ([total isEqualToNumber:zero] && [frozen isEqualToNumber:zero] && [slow isEqualToNumber:zero]) {
232
+ resolve(nil);
233
+ return;
206
234
  }
207
235
 
208
236
  resolve(@{
209
- @"totalFrames": [NSNumber numberWithLong:frames.total],
210
- @"frozenFrames": [NSNumber numberWithLong:frames.frozen],
211
- @"slowFrames": [NSNumber numberWithLong:frames.slow],
237
+ @"totalFrames": total,
238
+ @"frozenFrames": frozen,
239
+ @"slowFrames": slow,
212
240
  });
213
241
  } else {
214
242
  resolve(nil);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@sentry/react-native",
3
3
  "homepage": "https://github.com/getsentry/sentry-react-native",
4
4
  "repository": "https://github.com/getsentry/sentry-react-native",
5
- "version": "3.3.1",
5
+ "version": "3.3.2",
6
6
  "description": "Official Sentry SDK for react-native",
7
7
  "typings": "dist/js/index.d.ts",
8
8
  "types": "dist/js/index.d.ts",