Skip to content

Commit 91c5d97

Browse files
committed
Merge branch 'main' into antonis/rn-0.83.1
2 parents 6d7e56f + bb4ea33 commit 91c5d97

File tree

29 files changed

+988
-176
lines changed

29 files changed

+988
-176
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444

4545
# Initializes the CodeQL tools for scanning.
4646
- name: Initialize CodeQL
47-
uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # pin@v4.31.8
47+
uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # pin@v4.31.9
4848
with:
4949
languages: ${{ matrix.language }}
5050
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -55,7 +55,7 @@ jobs:
5555
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
5656
# If this step fails, then you should remove it and run the build manually (see below)
5757
- name: Autobuild
58-
uses: github/codeql-action/autobuild@1b168cd39490f61582a9beae412bb7057a6b2c4e # pin@v4.31.8
58+
uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # pin@v4.31.9
5959

6060
# ℹ️ Command-line programs to run using the OS shell.
6161
# 📚 https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
@@ -66,4 +66,4 @@ jobs:
6666
# make bootstrap
6767
# make release
6868
- name: Perform CodeQL Analysis
69-
uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # pin@v4.31.8
69+
uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # pin@v4.31.9

.github/workflows/sample-application.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ concurrency:
1515
env:
1616
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
1717
MAESTRO_VERSION: '2.0.10'
18+
MAESTRO_DRIVER_STARTUP_TIMEOUT: 90000 # Increase timeout from default 30s to 90s for CI stability
1819
RN_SENTRY_POD_NAME: RNSentry
1920
IOS_APP_ARCHIVE_PATH: sentry-react-native-sample.app.zip
2021
ANDROID_APP_ARCHIVE_PATH: sentry-react-native-sample.apk.zip

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
### Fixes
1212

1313
- Fix for missing `replay_id` from metrics ([#5483](https://github.com/getsentry/sentry-react-native/pull/5483))
14+
- Skip span ID check when standalone mode is enabled ([#5493](https://github.com/getsentry/sentry-react-native/pull/5493))
1415

1516
### Dependencies
1617

17-
- Bump JavaScript SDK from v10.30.0 to v10.32.0 ([#5480](https://github.com/getsentry/sentry-react-native/pull/5480), [#5487](https://github.com/getsentry/sentry-react-native/pull/5487))
18-
- [changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#10320)
19-
- [diff](https://github.com/getsentry/sentry-javascript/compare/10.30.0...10.32.0)
18+
- Bump JavaScript SDK from v10.30.0 to v10.32.1 ([#5480](https://github.com/getsentry/sentry-react-native/pull/5480), [#5487](https://github.com/getsentry/sentry-react-native/pull/5487), [#5496](https://github.com/getsentry/sentry-react-native/pull/5496))
19+
- [changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#10321)
20+
- [diff](https://github.com/getsentry/sentry-javascript/compare/10.30.0...10.32.1)
2021

2122
## 7.8.0
2223

dev-packages/e2e-tests/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"devDependencies": {
1414
"@babel/preset-env": "^7.25.3",
1515
"@babel/preset-typescript": "^7.18.6",
16-
"@sentry/core": "10.32.0",
16+
"@sentry/core": "10.32.1",
1717
"@sentry/react-native": "7.8.0",
1818
"@types/node": "^20.9.3",
1919
"@types/react": "^18.2.64",

packages/core/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,20 @@
6969
},
7070
"dependencies": {
7171
"@sentry/babel-plugin-component-annotate": "4.6.1",
72-
"@sentry/browser": "10.32.0",
72+
"@sentry/browser": "10.32.1",
7373
"@sentry/cli": "2.58.4",
74-
"@sentry/core": "10.32.0",
75-
"@sentry/react": "10.32.0",
76-
"@sentry/types": "10.32.0"
74+
"@sentry/core": "10.32.1",
75+
"@sentry/react": "10.32.1",
76+
"@sentry/types": "10.32.1"
7777
},
7878
"devDependencies": {
7979
"@babel/core": "^7.26.7",
8080
"@expo/metro-config": "~0.20.0",
8181
"@mswjs/interceptors": "^0.25.15",
8282
"@react-native/babel-preset": "0.80.0",
83-
"@sentry-internal/eslint-config-sdk": "10.32.0",
84-
"@sentry-internal/eslint-plugin-sdk": "10.32.0",
85-
"@sentry-internal/typescript": "10.32.0",
83+
"@sentry-internal/eslint-config-sdk": "10.32.1",
84+
"@sentry-internal/eslint-plugin-sdk": "10.32.1",
85+
"@sentry-internal/typescript": "10.32.1",
8686
"@sentry/wizard": "6.10.0",
8787
"@testing-library/react-native": "^13.2.2",
8888
"@types/jest": "^29.5.13",

packages/core/src/js/integrations/nativelinkederrors.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,10 @@ function walkErrorTree(
101101
} else if (isInstanceOf(linkedError, Error)) {
102102
exception = exceptionFromError(parser, error[key]);
103103
} else if (isPlainObject(linkedError)) {
104+
const plainError = linkedError as Record<string, unknown>;
104105
exception = {
105-
type: typeof linkedError.name === 'string' ? linkedError.name : undefined,
106-
value: typeof linkedError.message === 'string' ? linkedError.message : undefined,
106+
type: typeof plainError.name === 'string' ? plainError.name : undefined,
107+
value: typeof plainError.message === 'string' ? plainError.message : undefined,
107108
};
108109
} else {
109110
return {

packages/core/src/js/tracing/integrations/appStart.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -320,21 +320,26 @@ export const appStartIntegration = ({
320320
return;
321321
}
322322

323-
if (!firstStartedActiveRootSpanId) {
324-
debug.warn('[AppStart] No first started active root span id recorded. Can not attach app start.');
325-
return;
326-
}
327-
328323
if (!event.contexts?.trace) {
329324
debug.warn('[AppStart] Transaction event is missing trace context. Can not attach app start.');
330325
return;
331326
}
332327

333-
if (firstStartedActiveRootSpanId !== event.contexts.trace.span_id) {
334-
debug.warn(
335-
'[AppStart] First started active root span id does not match the transaction event span id. Can not attached app start.',
336-
);
337-
return;
328+
// When standalone is true, we create our own transaction and don't need to verify
329+
// it matches the first navigation transaction. When standalone is false, we need to
330+
// ensure we're attaching app start to the first transaction (not a later one).
331+
if (!standalone) {
332+
if (!firstStartedActiveRootSpanId) {
333+
debug.warn('[AppStart] No first started active root span id recorded. Can not attach app start.');
334+
return;
335+
}
336+
337+
if (firstStartedActiveRootSpanId !== event.contexts.trace.span_id) {
338+
debug.warn(
339+
'[AppStart] First started active root span id does not match the transaction event span id. Can not attached app start.',
340+
);
341+
return;
342+
}
338343
}
339344

340345
const appStart = await NATIVE.fetchNativeAppStart();

packages/core/test/tracing/integrations/appStart.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
SEMANTIC_ATTRIBUTE_SENTRY_OP,
77
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
88
setCurrentClient,
9+
startInactiveSpan,
910
timestampInSeconds,
1011
} from '@sentry/core';
1112
import {
@@ -385,6 +386,69 @@ describe('App Start Integration', () => {
385386
expect(actualEvent).toStrictEqual(undefined);
386387
expect(NATIVE.fetchNativeAppStart).toHaveBeenCalledTimes(1);
387388
});
389+
390+
it('Attaches app start to standalone transaction even when navigation transaction starts first', async () => {
391+
// This test simulates the Android scenario where React Navigation auto-instrumentation
392+
// starts a navigation transaction before the standalone app start transaction is created.
393+
// The fix ensures that when standalone: true, the span ID check is skipped so app start
394+
// can be attached to the standalone transaction even if a navigation transaction started first.
395+
getCurrentScope().clear();
396+
getIsolationScope().clear();
397+
getGlobalScope().clear();
398+
399+
mockAppStart({ cold: true });
400+
401+
const integration = appStartIntegration({
402+
standalone: true,
403+
});
404+
const client = new TestClient({
405+
...getDefaultTestClientOptions(),
406+
enableAppStartTracking: true,
407+
tracesSampleRate: 1.0,
408+
});
409+
setCurrentClient(client);
410+
integration.setup(client);
411+
412+
// Simulate a navigation transaction starting first (like React Navigation auto-instrumentation)
413+
// This will set firstStartedActiveRootSpanId to the navigation span's ID
414+
const navigationSpan = startInactiveSpan({
415+
name: 'calendar/home',
416+
op: 'navigation',
417+
forceTransaction: true,
418+
});
419+
const navigationSpanId = navigationSpan?.spanContext().spanId;
420+
if (navigationSpan) {
421+
navigationSpan.end();
422+
}
423+
424+
// Now capture standalone app start - it should still work even though navigation span started first
425+
// The standalone transaction will have a different span ID, but the fix skips the check
426+
await integration.captureStandaloneAppStart();
427+
428+
const actualEvent = client.event as TransactionEvent | undefined;
429+
expect(actualEvent).toBeDefined();
430+
expect(actualEvent?.spans).toBeDefined();
431+
expect(actualEvent?.spans?.length).toBeGreaterThan(0);
432+
433+
// Verify that app start was attached successfully
434+
const appStartSpan = actualEvent!.spans!.find(({ description }) => description === 'Cold Start');
435+
expect(appStartSpan).toBeDefined();
436+
expect(appStartSpan).toEqual(
437+
expect.objectContaining<Partial<SpanJSON>>({
438+
description: 'Cold Start',
439+
op: APP_START_COLD_OP,
440+
}),
441+
);
442+
443+
// Verify the standalone transaction has a different span ID than the navigation transaction
444+
// This confirms that the span ID check was skipped (otherwise app start wouldn't be attached)
445+
expect(actualEvent?.contexts?.trace?.span_id).toBeDefined();
446+
if (navigationSpanId) {
447+
expect(actualEvent?.contexts?.trace?.span_id).not.toBe(navigationSpanId);
448+
}
449+
450+
expect(actualEvent?.measurements?.[APP_START_COLD_MEASUREMENT]).toBeDefined();
451+
});
388452
});
389453

390454
describe('App Start Attached to the First Root Span', () => {

samples/expo/.eslintrc.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module.exports = {
2+
root: true,
3+
extends: ['expo', '@react-native'],
4+
parser: '@typescript-eslint/parser',
5+
plugins: ['@typescript-eslint'],
6+
settings: {
7+
'import/resolver': {
8+
typescript: {
9+
project: ['tsconfig.json'],
10+
},
11+
node: {
12+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
13+
},
14+
},
15+
},
16+
overrides: [
17+
{
18+
files: ['*.ts', '*.tsx'],
19+
rules: {
20+
'@typescript-eslint/no-shadow': ['error'],
21+
'no-shadow': 'off',
22+
'no-undef': 'off',
23+
quotes: [2, 'single', { avoidEscape: true }],
24+
// Disable deprecated rules removed in @typescript-eslint v8
25+
'@typescript-eslint/func-call-spacing': 'off',
26+
'@typescript-eslint/ban-types': 'off',
27+
// Disable import/no-unresolved for workspace packages that may not be built yet
28+
'import/no-unresolved': ['error', { ignore: ['^@sentry/'] }],
29+
},
30+
},
31+
],
32+
ignorePatterns: ['/node_modules', '/ios', '/android', '/.expo'],
33+
};

samples/expo/.prettierignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
ios/
3+
android/
4+
.expo/
5+
*.md
6+

0 commit comments

Comments
 (0)