Skip to content

Commit dd83160

Browse files
authored
Merge pull request #17356 from getsentry/prepare-release/10.3.0
meta(changelog): Update changelog for 10.3.0
2 parents f8b3557 + f0661fc commit dd83160

File tree

71 files changed

+2121
-513
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2121
-513
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
## 10.3.0
8+
9+
- feat(core): MCP Server - Capture prompt results from prompt function calls (#17284)
10+
- feat(bun): Export `skipOpenTelemetrySetup` option ([#17349](https://github.com/getsentry/sentry-javascript/pull/17349))
11+
- feat(sveltekit): Streamline build logs ([#17306](https://github.com/getsentry/sentry-javascript/pull/17306))
12+
- fix(browser): Handle data urls in errors caught by `globalHandlersIntegration` ([#17216](https://github.com/getsentry/sentry-javascript/pull/17216))
13+
- fix(browser): Improve navigation vs. redirect detection ([#17275](https://github.com/getsentry/sentry-javascript/pull/17275))
14+
- fix(react-router): Ensure source map upload fails silently if Sentry CLI fails ([#17081](https://github.com/getsentry/sentry-javascript/pull/17081))
15+
- fix(react): Add support for React Router sub-routes from `handle` ([#17277](https://github.com/getsentry/sentry-javascript/pull/17277))
16+
717
## 10.2.0
818

919
### Important Changes
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const workerCode = `
2+
self.addEventListener('message', (event) => {
3+
if (event.data.type === 'error') {
4+
throw new Error('Error thrown in worker');
5+
}
6+
});
7+
`;
8+
9+
const worker = new Worker(`data:text/javascript;base64,${btoa(workerCode)}`);
10+
11+
worker.postMessage({ type: 'error' });
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { expect } from '@playwright/test';
2+
import { sentryTest } from '../../../../utils/fixtures';
3+
import { envelopeRequestParser, waitForErrorRequest } from '../../../../utils/helpers';
4+
5+
/**
6+
* Tests a special case where the `globalHandlersIntegration` itself creates a stack frame instead of using
7+
* stack parsers. This is necessary because we don't always get an `error` object passed to `window.onerror`.
8+
* @see `globalhandlers.ts#_enhanceEventWithInitialFrame`
9+
*/
10+
sentryTest('detects and handles data urls on first stack frame', async ({ getLocalTestUrl, page }) => {
11+
const url = await getLocalTestUrl({ testDir: __dirname });
12+
13+
const errorEventPromise = waitForErrorRequest(page, e => {
14+
return !!e.exception?.values;
15+
});
16+
17+
await page.goto(url);
18+
19+
const errorEvent = envelopeRequestParser(await errorEventPromise);
20+
21+
expect(errorEvent?.exception?.values?.[0]).toEqual({
22+
mechanism: {
23+
handled: false,
24+
synthetic: true,
25+
type: 'auto.browser.global_handlers.onerror',
26+
},
27+
stacktrace: {
28+
frames: [
29+
{
30+
colno: expect.any(Number), // webkit reports different colno than chromium
31+
filename: '<data:text/javascript,base64>',
32+
function: '?',
33+
in_app: true,
34+
lineno: 4,
35+
},
36+
],
37+
},
38+
type: 'Error',
39+
value: expect.stringMatching(/(Uncaught )?Error: Error thrown in worker/), // webikt throws without "Uncaught "
40+
});
41+
});

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/navigation-aborting-pageload/init.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ window.Sentry = Sentry;
44

55
Sentry.init({
66
dsn: 'https://[email protected]/1337',
7-
integrations: [Sentry.browserTracingIntegration({ idleTimeout: 2000 })],
7+
integrations: [Sentry.browserTracingIntegration({ idleTimeout: 2000, detectRedirects: false })],
88
tracesSampleRate: 1,
99
});
1010

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/navigation-redirect/keypress-early/init.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/navigation-redirect/keypress-early/test.ts

Lines changed: 0 additions & 42 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [Sentry.browserTracingIntegration()],
8+
tracesSampleRate: 1,
9+
});
10+
11+
window.history.pushState({}, '', '/sub-page-redirect-1');
12+
13+
setTimeout(() => {
14+
window.history.pushState({}, '', '/sub-page-redirect-2');
15+
}, 400);
16+
17+
setTimeout(() => {
18+
window.history.pushState({}, '', '/sub-page-redirect-3');
19+
}, 800);
20+
21+
document.getElementById('btn1').addEventListener('click', () => {
22+
window.history.pushState({}, '', '/next-page');
23+
});
24+
25+
setTimeout(() => {
26+
document.getElementById('btn1').click();
27+
// 1s is still within the 1.5s time window, but the click should trigger a new navigation root span
28+
}, 1000);
29+
30+
setTimeout(() => {
31+
window.history.pushState({}, '', '/next-page-redirect-1');
32+
}, 1100);
33+
34+
setTimeout(() => {
35+
window.history.pushState({}, '', '/next-page-redirect-2');
36+
}, 2000);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { expect } from '@playwright/test';
2+
import {
3+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
4+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
5+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
6+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
7+
} from '@sentry/core';
8+
import { sentryTest } from '../../../../../utils/fixtures';
9+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../../utils/helpers';
10+
11+
sentryTest(
12+
'creates a pageload and navigation root spans each with multiple navigation.redirect childspans',
13+
async ({ getLocalTestUrl, page }) => {
14+
if (shouldSkipTracingTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
const url = await getLocalTestUrl({ testDir: __dirname });
19+
20+
const pageloadRequestPromise = waitForTransactionRequest(page, event => event.contexts?.trace?.op === 'pageload');
21+
const navigationRequestPromise = waitForTransactionRequest(
22+
page,
23+
event => event.contexts?.trace?.op === 'navigation' && event.transaction === '/next-page',
24+
);
25+
26+
await page.goto(url);
27+
28+
const pageloadRequest = envelopeRequestParser(await pageloadRequestPromise);
29+
const navigationRequest = envelopeRequestParser(await navigationRequestPromise);
30+
31+
expect(pageloadRequest.contexts?.trace?.op).toBe('pageload');
32+
33+
expect(pageloadRequest.contexts?.trace?.data).toMatchObject({
34+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',
35+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
36+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
37+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
38+
['sentry.idle_span_finish_reason']: 'cancelled',
39+
});
40+
41+
expect(pageloadRequest.request).toEqual({
42+
headers: {
43+
'User-Agent': expect.any(String),
44+
},
45+
url: 'http://sentry-test.io/index.html',
46+
});
47+
48+
const spans = pageloadRequest.spans || [];
49+
50+
const redirectSpans = spans.filter(span => span.op === 'navigation.redirect');
51+
expect(redirectSpans).toHaveLength(3);
52+
53+
redirectSpans.forEach(redirectSpan => {
54+
expect(redirectSpan?.timestamp).toEqual(redirectSpan?.start_timestamp);
55+
expect(redirectSpan).toEqual({
56+
data: {
57+
'sentry.op': 'navigation.redirect',
58+
'sentry.origin': 'auto.navigation.browser',
59+
'sentry.source': 'url',
60+
},
61+
description: expect.stringContaining('/sub-page-redirect-'),
62+
op: 'navigation.redirect',
63+
origin: 'auto.navigation.browser',
64+
parent_span_id: pageloadRequest.contexts!.trace!.span_id,
65+
span_id: expect.any(String),
66+
start_timestamp: expect.any(Number),
67+
timestamp: expect.any(Number),
68+
trace_id: expect.any(String),
69+
});
70+
});
71+
72+
expect(navigationRequest.contexts?.trace?.op).toBe('navigation');
73+
expect(navigationRequest.transaction).toEqual('/next-page');
74+
75+
// 2 subsequent redirects belonging to the navigation root span
76+
expect(navigationRequest.spans?.filter(span => span.op === 'navigation.redirect')).toHaveLength(2);
77+
},
78+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
integrations: [Sentry.browserTracingIntegration()],
8+
tracesSampleRate: 1,
9+
debug: true,
10+
});
11+
12+
document.getElementById('btn1').addEventListener('click', () => {
13+
window.history.pushState({}, '', '/sub-page');
14+
15+
// then trigger redirect inside of this navigation, which should not be detected as a redirect
16+
// because the last click was less than 1.5s ago
17+
setTimeout(() => {
18+
document.getElementById('btn2').click();
19+
}, 100);
20+
});
21+
22+
document.getElementById('btn2').addEventListener('click', () => {
23+
setTimeout(() => {
24+
// navigation happens ~1100ms after the last navigation
25+
window.history.pushState({}, '', '/sub-page-2');
26+
}, 1000);
27+
});

0 commit comments

Comments
 (0)