Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Bump to Sentry Javascript V9 #4568

Open
wants to merge 29 commits into
base: v7
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
04b6c06
bump SDKs
lucas-zimerman Feb 14, 2025
0dc4bca
bump SDKs
lucas-zimerman Feb 14, 2025
382fef6
fix build
lucas-zimerman Feb 14, 2025
33af36c
fix tests
lucas-zimerman Feb 19, 2025
ad6a76c
fix tests
lucas-zimerman Feb 19, 2025
15342a2
fix lint errors
lucas-zimerman Feb 19, 2025
c267f9b
test ts 5.0
lucas-zimerman Feb 19, 2025
efea84f
rollback
lucas-zimerman Feb 19, 2025
65a10d5
Merge branch 'v7' into lz/bump/jsv9
lucas-zimerman Feb 24, 2025
028dbf9
fix merge conflict with yarn
lucas-zimerman Feb 25, 2025
a57459a
fix new lint issue
lucas-zimerman Feb 25, 2025
5de9867
sync yarn.lock with V7 branch and install new packages
lucas-zimerman Feb 26, 2025
ae65521
ensure we are using the JS version from the default node resolution
lucas-zimerman Feb 26, 2025
bd64169
update changelog with javascript version bump
lucas-zimerman Feb 26, 2025
39a81c7
fix check type (#4587)
lucas-zimerman Feb 25, 2025
3a4fd4c
add major changes to the SDK
lucas-zimerman Feb 26, 2025
d8088ad
fix lint
lucas-zimerman Feb 26, 2025
6f71cda
review check: fix changelog PR number / Fix wrapper incorrect null c…
lucas-zimerman Feb 26, 2025
55c1961
fix incorrect cli version
lucas-zimerman Feb 26, 2025
97853c6
fix lint
lucas-zimerman Feb 26, 2025
dc2e123
Merge branch 'v7' into lz/bump/jsv9
lucas-zimerman Feb 25, 2025
9a0b21e
remove shutdowntimeout from android / use newer wizard version
lucas-zimerman Mar 3, 2025
45ee6fa
rollback feedback test change, rollback jest version, fix safe test
lucas-zimerman Mar 14, 2025
816b506
return shutdowntimeout
lucas-zimerman Mar 14, 2025
25bf147
explain tracing sample rate
lucas-zimerman Mar 14, 2025
8584214
fix tracing extension test
lucas-zimerman Mar 14, 2025
a26497e
Merge branch 'v7' into lz/bump/jsv9
lucas-zimerman Mar 14, 2025
499e5a3
lint fix
lucas-zimerman Mar 14, 2025
578ad2c
update changelog
lucas-zimerman Mar 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

## Unreleased

### Upgrading from 6.x to 7.0

Version 7 of the Sentry React Native SDK primarily introduces API cleanup and version support changes. This update contains behavioral changes that will not be caught by type checkers, linters, or tests, so we recommend carefully reading through the entire migration guide instead of relying on automatic tooling.

Version 7 of the SDK is compatible with Sentry self-hosted versions 24.4.2 or higher (unchanged from v6). Lower versions may continue to work, but may not support all features.

### Features

- Adds Sentry Android Gradle Plugin as an experimental Expo plugin feature ([#4440](https://github.com/getsentry/sentry-react-native/pull/4440))
Expand Down Expand Up @@ -38,6 +44,9 @@ Change `Cold/Warm App Start` span description to `Cold/Warm Start` ([#4636](http

### Dependencies

- Bump JavaScript SDK from v8.54.0 to v9.1.0 ([#4568](https://github.com/getsentry/sentry-react-native/pull/4568))
- [changelog](https://github.com/getsentry/sentry-javascript/blob/9.1.0/CHANGELOG.md)
- [diff](https://github.com/getsentry/sentry-javascript/compare/8.54.0...9.1.0)
- Bump Android SDK from v7.20.1 to v8.3.0 ([#4490](https://github.com/getsentry/sentry-react-native/pull/4490))
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#830)
- [diff](https://github.com/getsentry/sentry-java/compare/7.20.1...8.3.0)
Expand All @@ -48,6 +57,39 @@ Change `Cold/Warm App Start` span description to `Cold/Warm Start` ([#4636](http
- [changelog](https://github.com/getsentry/sentry-cli/blob/master/CHANGELOG.md#2421)
- [diff](https://github.com/getsentry/sentry-cli/compare/2.41.1...2.42.1)


### Major Changes

- `ip addresses` is only collected when `sendDefaultPii`: `true`
- Exceptions from `captureConsoleIntegration` are now marked as handled: true by default
- `shutdownTimeout` moved from `core` to `@sentry/react-native`
- `hasTracingEnabled` was renamed to `hasSpansEnabled`
- You can no longer drop spans or return null on `beforeSendSpan` hook

### Removed types

- TransactionNamingScheme
- Request
- Scope (prefer using the Scope class)

### Other removed items.

- `autoSessionTracking` from options.
To enable session tracking, ensure that `enableAutoSessionTracking` is enabled.

- `enableTracing`. Instead, set `tracesSampleRate` to a value greater than `zero` to `enable tracing`, `0` to keep tracing integrations active without sampling, or `undefined` to disable the performance integration.

- `getCurrentHub()`, `Hub`, and `getCurrentHubShim()`
- `spanId` from propagation `context`
- metrics API
- `transactionContext` from `samplingContext`
- `@sentry/utils` package, the exports were moved to `@sentry/core`
- Standalone `Client` interface & deprecate `BaseClient`

## Other Changes

- Fork `scope` if custom scope is passed to `startSpanManual` or `startSpan`

## 6.7.0

### Features
Expand Down
3 changes: 3 additions & 0 deletions dev-packages/type-check/ts3.8-test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ declare global {
interface IDBObjectStore {}
interface Window {
fetch: any;
setTimeout: any;
document: any;
}
interface ShadowRoot {}
interface BufferSource {}
Expand All @@ -19,6 +21,7 @@ declare global {
redirectCount: number;
}
interface PerformanceEntry {}
interface Performance {}
}
import 'react-native';

Expand Down
17 changes: 8 additions & 9 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,20 @@
},
"dependencies": {
"@sentry/babel-plugin-component-annotate": "3.1.2",
"@sentry/browser": "8.54.0",
"@sentry/browser": "9.1.0",
"@sentry/cli": "2.42.1",
"@sentry/core": "8.54.0",
"@sentry/react": "8.54.0",
"@sentry/types": "8.54.0",
"@sentry/utils": "8.54.0"
"@sentry/core": "9.1.0",
"@sentry/react": "9.1.0",
"@sentry/types": "9.1.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@expo/metro-config": "0.19.5",
"@mswjs/interceptors": "^0.25.15",
"@react-native/babel-preset": "0.77.1",
"@sentry-internal/eslint-config-sdk": "8.54.0",
"@sentry-internal/eslint-plugin-sdk": "8.54.0",
"@sentry-internal/typescript": "8.54.0",
"@sentry-internal/eslint-config-sdk": "9.1.0",
"@sentry-internal/eslint-plugin-sdk": "9.1.0",
"@sentry-internal/typescript": "9.1.0",
"@sentry/wizard": "3.42.0",
"@testing-library/react-native": "^12.7.2",
"@types/jest": "^29.5.13",
Expand Down Expand Up @@ -110,7 +109,7 @@
"react-native": "0.77.1",
"react-test-renderer": "^18.3.1",
"rimraf": "^4.1.1",
"ts-jest": "^29.1.1",
"ts-jest": "^29.2.5",
"typescript": "4.9.5",
"uglify-js": "^3.17.4",
"uuid": "^9.0.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/plugin/src/withSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface PluginProps {
const withSentryPlugin: ConfigPlugin<PluginProps | void> = (config, props) => {
const sentryProperties = getSentryProperties(props);

if (props && props.authToken) {
if (props?.authToken) {
// If not removed, the plugin config with the authToken will be written to the application package
delete props.authToken;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function withSentryAndroidGradlePlugin(
const withSentryProjectBuildGradle = (config: any): any => {
return withProjectBuildGradle(config, (projectBuildGradle: any) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (!projectBuildGradle.modResults || !projectBuildGradle.modResults.contents) {
if (!projectBuildGradle.modResults?.contents) {
warnOnce('android/build.gradle content is missing or undefined.');
return config;
}
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/js/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export type {
Breadcrumb,
Request,
SdkInfo,
Event,
Exception,
Expand Down Expand Up @@ -43,7 +42,6 @@ export {
getClient,
setCurrentClient,
addEventProcessor,
metricsDefault as metrics,
lastEventId,
} from '@sentry/core';

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/integrations/debugsymbolicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ function replaceExceptionFramesInException(exception: Exception, frames: SentryS
* @param frames StackFrame[]
*/
function replaceThreadFramesInEvent(event: Event, frames: SentryStackFrame[]): void {
if (event.threads && event.threads.values && event.threads.values[0] && event.threads.values[0].stacktrace) {
if (event.threads?.values?.[0]?.stacktrace) {
event.threads.values[0].stacktrace.frames = frames.reverse();
}
}
Expand Down
5 changes: 1 addition & 4 deletions packages/core/src/js/integrations/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,7 @@ export function getDefaultIntegrations(options: ReactNativeClientOptions): Integ
// hasTracingEnabled from `@sentry/core` only check if tracesSampler or tracesSampleRate keys are present
// that's different from prev imp here and might lead misconfiguration
// `tracesSampleRate: undefined` should not enable tracing
const hasTracingEnabled =
options.enableTracing ||
typeof options.tracesSampleRate === 'number' ||
typeof options.tracesSampler === 'function';
const hasTracingEnabled = typeof options.tracesSampleRate === 'number' || typeof options.tracesSampler === 'function';
if (hasTracingEnabled && options.enableAppStartTracking) {
integrations.push(appStartIntegration());
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/js/integrations/nativelinkederrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const nativeLinkedErrorsIntegration = (options: Partial<LinkedErrorsOptio
};

function preprocessEvent(event: Event, hint: EventHint | undefined, client: Client, limit: number, key: string): void {
if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {
if (!event.exception?.values || !hint || !isInstanceOf(hint.originalException, Error)) {
return;
}

Expand Down Expand Up @@ -176,10 +176,10 @@ function exceptionFromAppleStackReturnAddresses(objCException: {
type: objCException.name,
value: objCException.message,
stacktrace: {
frames: (nativeStackFrames && nativeStackFrames.frames.reverse()) || [],
frames: nativeStackFrames?.frames.reverse() || [],
},
},
appleDebugImages: (nativeStackFrames && (nativeStackFrames.debugMetaImages as DebugImage[])) || [],
appleDebugImages: (nativeStackFrames?.debugMetaImages as DebugImage[]) || [],
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { EventHint, Integration, SeverityLevel } from '@sentry/core';
import { addExceptionMechanism, captureException, getClient, getCurrentScope, logger } from '@sentry/core';

import type { ReactNativeClientOptions } from '../options';
import { createSyntheticError, isErrorLike } from '../utils/error';
import { RN_GLOBAL_OBJ } from '../utils/worldwide';
import { checkPromiseAndWarn, polyfillPromise, requireRejectionTracking } from './reactnativeerrorhandlersutils';
Expand Down Expand Up @@ -99,7 +100,7 @@ function setupErrorUtilsGlobalHandler(): void {
return;
}

const defaultHandler = errorUtils.getGlobalHandler && errorUtils.getGlobalHandler();
const defaultHandler = errorUtils.getGlobalHandler?.();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
errorUtils.setGlobalHandler(async (error: any, isFatal?: boolean) => {
Expand Down Expand Up @@ -155,7 +156,7 @@ function setupErrorUtilsGlobalHandler(): void {
return;
}

void client.flush(client.getOptions().shutdownTimeout || 2000).then(
void client.flush((client.getOptions() as ReactNativeClientOptions).shutdownTimeout || 2000).then(
() => {
defaultHandler(error, isFatal);
},
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/js/integrations/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ export const screenshotIntegration = (): Integration => {
};

async function processEvent(event: Event, hint: EventHint, client: ReactNativeClient): Promise<Event> {
const hasException = event.exception && event.exception.values && event.exception.values.length > 0;
const hasException = event.exception?.values?.length > 0;
if (!hasException || client.getOptions().beforeScreenshot?.(event, hint) === false) {
return event;
}

const screenshots: ScreenshotAttachment[] | null = await NATIVE.captureScreenshot();
if (screenshots && screenshots.length > 0) {
if (screenshots?.length > 0) {
hint.attachments = [...screenshots, ...(hint?.attachments || [])];
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/integrations/spotlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function getHostnameFromString(urlString: string): string | null {
const regex = /^(?:\w+:)?\/\/([^/:]+)(:\d+)?(.*)$/;
const matches = urlString.match(regex);

if (matches && matches[1]) {
if (matches?.[1]) {
return matches[1];
} else {
// Invalid URL format
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/integrations/viewhierarchy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const viewHierarchyIntegration = (): Integration => {
};

async function processEvent(event: Event, hint: EventHint): Promise<Event> {
const hasException = event.exception && event.exception.values && event.exception.values.length > 0;
const hasException = event.exception?.values?.length > 0;
if (!hasException) {
return event;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/js/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ export interface BaseReactNativeOptions {
*/
replaysOnErrorSampleRate?: number;

/**
* Controls how many milliseconds to wait before shutting down. The default is 2 seconds. Setting this too low can cause
* problems for sending events from command line applications. Setting it too
* high can cause the application to block for users with network connectivity
* problems.
*/
shutdownTimeout?: number;

/**
* Options which are in beta, or otherwise not guaranteed to be stable.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/profiling/convertHermesProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function mapStacks(
while (currentHermesFrameId !== undefined) {
const sentryFrameId = hermesStackFrameIdToSentryFrameIdMap.get(currentHermesFrameId);
sentryFrameId !== undefined && stack.push(sentryFrameId);
currentHermesFrameId = hermesStackFrames[currentHermesFrameId] && hermesStackFrames[currentHermesFrameId].parent;
currentHermesFrameId = hermesStackFrames[currentHermesFrameId]?.parent;
}
stacks.push(stack);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/profiling/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const hermesProfilingIntegration = (initOptions: HermesProfilingOptions =
}

const client = getClient<ReactNativeClient>();
const options = client && client.getOptions();
const options = client?.getOptions?.();

const profilesSampleRate =
options && typeof options.profilesSampleRate === 'number' ? options.profilesSampleRate : undefined;
Expand Down
44 changes: 20 additions & 24 deletions packages/core/src/js/profiling/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ export function enrichCombinedProfileWithEventContext(
return null;
}

const trace_id = (event.contexts && event.contexts.trace && event.contexts.trace.trace_id) || '';
const trace_id = event.contexts?.trace?.trace_id || '';

// Log a warning if the profile has an invalid traceId (should be uuidv4).
// All profiles and transactions are rejected if this is the case and we want to
// warn users that this is happening if they enable debug flag
if (trace_id && trace_id.length !== 32) {
if (trace_id?.length !== 32) {
if (__DEV__) {
logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);
}
Expand All @@ -97,25 +97,25 @@ export function enrichCombinedProfileWithEventContext(
release: event.release || '',
environment: event.environment || getDefaultEnvironment(),
os: {
name: (event.contexts && event.contexts.os && event.contexts.os.name) || '',
version: (event.contexts && event.contexts.os && event.contexts.os.version) || '',
build_number: (event.contexts && event.contexts.os && event.contexts.os.build) || '',
name: event.contexts?.os?.name || '',
version: event.contexts?.os?.version || '',
build_number: event.contexts?.os?.build || '',
},
device: {
locale: (event.contexts && event.contexts.device && (event.contexts.device.locale as string)) || '',
model: (event.contexts && event.contexts.device && event.contexts.device.model) || '',
manufacturer: (event.contexts && event.contexts.device && event.contexts.device.manufacturer) || '',
architecture: (event.contexts && event.contexts.device && event.contexts.device.arch) || '',
is_emulator: (event.contexts && event.contexts.device && event.contexts.device.simulator) || false,
locale: (event.contexts?.device && (event.contexts.device.locale as string)) || '',
model: event.contexts?.device?.model || '',
manufacturer: event.contexts?.device?.manufacturer || '',
architecture: event.contexts?.device?.arch || '',
is_emulator: event.contexts?.device?.simulator || false,
},
transaction: {
name: event.transaction || '',
id: event.event_id || '',
trace_id,
active_thread_id: (profile.transaction && profile.transaction.active_thread_id) || '',
active_thread_id: profile.transaction?.active_thread_id || '',
},
debug_meta: {
images: [...getDebugMetadata(), ...((profile.debug_meta && profile.debug_meta.images) || [])],
images: [...getDebugMetadata(), ...(profile.debug_meta?.images || [])],
},
};
}
Expand All @@ -136,19 +136,15 @@ export function enrichAndroidProfileWithEventContext(
build_id: profile.build_id || '',

device_cpu_frequencies: [],
device_is_emulator: (event.contexts && event.contexts.device && event.contexts.device.simulator) || false,
device_locale: (event.contexts && event.contexts.device && (event.contexts.device.locale as string)) || '',
device_manufacturer: (event.contexts && event.contexts.device && event.contexts.device.manufacturer) || '',
device_model: (event.contexts && event.contexts.device && event.contexts.device.model) || '',
device_os_name: (event.contexts && event.contexts.os && event.contexts.os.name) || '',
device_os_version: (event.contexts && event.contexts.os && event.contexts.os.version) || '',
device_is_emulator: event.contexts?.device?.simulator || false,
device_locale: (event.contexts?.device && (event.contexts.device.locale as string)) || '',
device_manufacturer: event.contexts?.device?.manufacturer || '',
device_model: event.contexts?.device?.model || '',
device_os_name: event.contexts?.os?.name || '',
device_os_version: event.contexts?.os?.version || '',

device_physical_memory_bytes:
(event.contexts &&
event.contexts.device &&
event.contexts.device.memory_size &&
Number(event.contexts.device.memory_size).toString(10)) ||
'',
(event.contexts?.device?.memory_size && Number(event.contexts.device.memory_size).toString(10)) || '',

environment: event.environment || getDefaultEnvironment(),

Expand All @@ -161,7 +157,7 @@ export function enrichAndroidProfileWithEventContext(

transaction_id: event.event_id || '',
transaction_name: event.transaction || '',
trace_id: (event.contexts && event.contexts.trace && event.contexts.trace.trace_id) || '',
trace_id: event.contexts?.trace?.trace_id || '',

version_name: event.release || '',
version_code: event.dist || '',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/replay/CustomMask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const UnmaskFallback = (viewProps: ViewProps): React.ReactElement => {
return <View {...viewProps} />;
};

const hasViewManagerConfig = (nativeComponentName: string): boolean => UIManager.hasViewManagerConfig && UIManager.hasViewManagerConfig(nativeComponentName);
const hasViewManagerConfig = (nativeComponentName: string): boolean => UIManager.hasViewManagerConfig?.(nativeComponentName);

const Mask = ((): HostComponent<ViewProps> | React.ComponentType<ViewProps> => {
if (!hasViewManagerConfig(MaskNativeComponentName)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/replay/mobilereplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const mobileReplayIntegration = (initOptions: MobileReplayOptions = defau
const options = { ...defaultOptions, ...initOptions };

async function processEvent(event: Event): Promise<Event> {
const hasException = event.exception && event.exception.values && event.exception.values.length > 0;
const hasException = event.exception?.values?.length > 0;
if (!hasException) {
// Event is not an error, will not capture replay
return event;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/js/sdk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export function wrap<P extends Record<string, unknown>>(
const profilerProps = {
...(options?.profilerProps ?? {}),
name: RootComponent.displayName ?? 'Root',
updateProps: {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required? I don't know the prop.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was always required, but for for some reason it only started to complain once I started working on V9
https://github.com/getsentry/sentry-javascript/blob/6914a2453472b3683fe76e67e248414d7ec4ec06/packages/react/src/profiler.tsx#L24

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I see, thank you for the details.

Could you open a follow-up PR with options?.profilerProps type update to exclude the update props and children. https://github.com/getsentry/sentry-javascript/blob/1048a437b09955d31118960624b6d58242389c45/packages/react/src/profiler.tsx#L158

};

const RootApp: React.FC<P> = (appProps) => {
Expand Down
Loading
Loading