Skip to content

Commit 03ea1fd

Browse files
authored
Merge branch 'develop' into colin/log-api
2 parents b598526 + 9789f32 commit 03ea1fd

File tree

245 files changed

+6779
-1036
lines changed

Some content is hidden

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

245 files changed

+6779
-1036
lines changed

.size-limit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ module.exports = [
5454
path: 'packages/browser/build/npm/esm/index.js',
5555
import: createImport('init', 'browserTracingIntegration', 'replayIntegration'),
5656
gzip: true,
57-
limit: '68 KB',
57+
limit: '70 KB',
5858
modifyWebpackConfig: function (config) {
5959
const webpack = require('webpack');
6060
const TerserPlugin = require('terser-webpack-plugin');

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@
1010

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

13+
Work in this release was contributed by @6farer. Thank you for your contribution!
14+
15+
## 9.1.0
16+
17+
- feat(browser): Add `graphqlClientIntegration` ([#13783](https://github.com/getsentry/sentry-javascript/pull/13783))
18+
- feat(core): Allow for nested trpc context ([#15379](https://github.com/getsentry/sentry-javascript/pull/15379))
19+
- feat(core): Create types and utilities for span links ([#15375](https://github.com/getsentry/sentry-javascript/pull/15375))
20+
- feat(deps): bump @opentelemetry/instrumentation-pg from 0.50.0 to 0.51.0 ([#15273](https://github.com/getsentry/sentry-javascript/pull/15273))
21+
- feat(node): Extract Sentry-specific node-fetch instrumentation ([#15231](https://github.com/getsentry/sentry-javascript/pull/15231))
22+
- feat(vue): Support Pinia v3 ([#15383](https://github.com/getsentry/sentry-javascript/pull/15383))
23+
- fix(sveltekit): Avoid request body double read errors ([#15368](https://github.com/getsentry/sentry-javascript/pull/15368))
24+
- fix(sveltekit): Avoid top-level `vite` import ([#15371](https://github.com/getsentry/sentry-javascript/pull/15371))
25+
26+
Work in this release was contributed by @Zen-cronic and @filips-alpe. Thank you for your contribution!
27+
1328
## 9.0.1
1429

1530
- ref(flags): rename unleash integration param ([#15343](https://github.com/getsentry/sentry-javascript/pull/15343))

dev-packages/browser-integration-tests/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry-internal/browser-integration-tests",
3-
"version": "9.0.1",
3+
"version": "9.1.0",
44
"main": "index.js",
55
"license": "MIT",
66
"engines": {
@@ -42,7 +42,7 @@
4242
"@babel/preset-typescript": "^7.16.7",
4343
"@playwright/test": "~1.50.0",
4444
"@sentry-internal/rrweb": "2.31.0",
45-
"@sentry/browser": "9.0.1",
45+
"@sentry/browser": "9.1.0",
4646
"axios": "1.7.7",
4747
"babel-loader": "^8.2.2",
4848
"fflate": "0.8.2",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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({ instrumentPageLoad: false, instrumentNavigation: false })],
8+
tracePropagationTargets: ['http://sentry-test-site.example'],
9+
tracesSampleRate: 1,
10+
autoSessionTracking: false,
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function withRootSpan(cb) {
2+
return Sentry.startSpan({ name: 'rootSpan' }, cb);
3+
}
4+
5+
document.getElementById('btnQuery').addEventListener('click', async () => {
6+
await withRootSpan(() => fetch('http://sentry-test-site.example/0?id=123;page=5'));
7+
});
8+
9+
document.getElementById('btnFragment').addEventListener('click', async () => {
10+
await withRootSpan(() => fetch('http://sentry-test-site.example/1#fragment'));
11+
});
12+
13+
document.getElementById('btnQueryFragment').addEventListener('click', async () => {
14+
await withRootSpan(() => fetch('http://sentry-test-site.example/2?id=1#fragment'));
15+
});
16+
17+
document.getElementById('btnQueryFragmentSameOrigin').addEventListener('click', async () => {
18+
await withRootSpan(() => fetch('/api/users?id=1#fragment'));
19+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="btnQuery">Request with query</button>
8+
<button id="btnFragment">Request with fragment</button>
9+
<button id="btnQueryFragment">Request with query and fragment</button>
10+
<button id="btnQueryFragmentSameOrigin">Request with query and fragment</button>
11+
</body>
12+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { expect } from '@playwright/test';
2+
import { sentryTest } from '../../../../utils/fixtures';
3+
import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers';
4+
5+
sentryTest('strips query params in fetch request spans', async ({ getLocalTestUrl, page }) => {
6+
if (shouldSkipTracingTest()) {
7+
sentryTest.skip();
8+
}
9+
10+
await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' }));
11+
12+
const url = await getLocalTestUrl({ testDir: __dirname });
13+
14+
await page.goto(url);
15+
16+
const txnPromise = waitForTransactionRequest(page);
17+
await page.locator('#btnQuery').click();
18+
const transactionEvent = envelopeRequestParser(await txnPromise);
19+
20+
expect(transactionEvent.transaction).toEqual('rootSpan');
21+
22+
const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client');
23+
24+
expect(requestSpan).toMatchObject({
25+
description: 'GET http://sentry-test-site.example/0',
26+
parent_span_id: transactionEvent.contexts?.trace?.span_id,
27+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
28+
start_timestamp: expect.any(Number),
29+
timestamp: expect.any(Number),
30+
trace_id: transactionEvent.contexts?.trace?.trace_id,
31+
data: expect.objectContaining({
32+
'http.method': 'GET',
33+
'http.url': 'http://sentry-test-site.example/0?id=123;page=5',
34+
'http.query': '?id=123;page=5',
35+
'http.response.status_code': 200,
36+
'http.response_content_length': 2,
37+
'sentry.op': 'http.client',
38+
'sentry.origin': 'auto.http.browser',
39+
type: 'fetch',
40+
'server.address': 'sentry-test-site.example',
41+
url: 'http://sentry-test-site.example/0?id=123;page=5',
42+
}),
43+
});
44+
45+
expect(requestSpan?.data).not.toHaveProperty('http.fragment');
46+
});
47+
48+
sentryTest('strips hash fragment in fetch request spans', async ({ getLocalTestUrl, page }) => {
49+
if (shouldSkipTracingTest()) {
50+
sentryTest.skip();
51+
}
52+
53+
await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' }));
54+
55+
const url = await getLocalTestUrl({ testDir: __dirname });
56+
57+
await page.goto(url);
58+
59+
const txnPromise = waitForTransactionRequest(page);
60+
await page.locator('#btnFragment').click();
61+
const transactionEvent = envelopeRequestParser(await txnPromise);
62+
63+
expect(transactionEvent.transaction).toEqual('rootSpan');
64+
65+
const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client');
66+
67+
expect(requestSpan).toMatchObject({
68+
description: 'GET http://sentry-test-site.example/1',
69+
parent_span_id: transactionEvent.contexts?.trace?.span_id,
70+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
71+
start_timestamp: expect.any(Number),
72+
timestamp: expect.any(Number),
73+
trace_id: transactionEvent.contexts?.trace?.trace_id,
74+
data: expect.objectContaining({
75+
'http.method': 'GET',
76+
'http.url': 'http://sentry-test-site.example/1#fragment',
77+
'http.fragment': '#fragment',
78+
'http.response.status_code': 200,
79+
'http.response_content_length': 2,
80+
'sentry.op': 'http.client',
81+
'sentry.origin': 'auto.http.browser',
82+
type: 'fetch',
83+
'server.address': 'sentry-test-site.example',
84+
url: 'http://sentry-test-site.example/1#fragment',
85+
}),
86+
});
87+
88+
expect(requestSpan?.data).not.toHaveProperty('http.query');
89+
});
90+
91+
sentryTest('strips hash fragment and query params in fetch request spans', async ({ getLocalTestUrl, page }) => {
92+
if (shouldSkipTracingTest()) {
93+
sentryTest.skip();
94+
}
95+
96+
await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' }));
97+
98+
const url = await getLocalTestUrl({ testDir: __dirname });
99+
100+
await page.goto(url);
101+
102+
const txnPromise = waitForTransactionRequest(page);
103+
await page.locator('#btnQueryFragment').click();
104+
const transactionEvent = envelopeRequestParser(await txnPromise);
105+
106+
expect(transactionEvent.transaction).toEqual('rootSpan');
107+
108+
const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client');
109+
110+
expect(requestSpan).toMatchObject({
111+
description: 'GET http://sentry-test-site.example/2',
112+
parent_span_id: transactionEvent.contexts?.trace?.span_id,
113+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
114+
start_timestamp: expect.any(Number),
115+
timestamp: expect.any(Number),
116+
trace_id: transactionEvent.contexts?.trace?.trace_id,
117+
data: expect.objectContaining({
118+
'http.method': 'GET',
119+
'http.url': 'http://sentry-test-site.example/2?id=1#fragment',
120+
'http.query': '?id=1',
121+
'http.fragment': '#fragment',
122+
'http.response.status_code': 200,
123+
'http.response_content_length': 2,
124+
'sentry.op': 'http.client',
125+
'sentry.origin': 'auto.http.browser',
126+
type: 'fetch',
127+
'server.address': 'sentry-test-site.example',
128+
url: 'http://sentry-test-site.example/2?id=1#fragment',
129+
}),
130+
});
131+
});
132+
133+
sentryTest(
134+
'strips hash fragment and query params in same-origin fetch request spans',
135+
async ({ getLocalTestUrl, page }) => {
136+
if (shouldSkipTracingTest()) {
137+
sentryTest.skip();
138+
}
139+
140+
await page.route('**/*', route => route.fulfill({ body: 'ok' }));
141+
142+
const url = await getLocalTestUrl({ testDir: __dirname });
143+
144+
await page.goto(url);
145+
146+
const txnPromise = waitForTransactionRequest(page);
147+
await page.locator('#btnQueryFragmentSameOrigin').click();
148+
const transactionEvent = envelopeRequestParser(await txnPromise);
149+
150+
expect(transactionEvent.transaction).toEqual('rootSpan');
151+
152+
const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client');
153+
154+
expect(requestSpan).toMatchObject({
155+
description: 'GET /api/users',
156+
parent_span_id: transactionEvent.contexts?.trace?.span_id,
157+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
158+
start_timestamp: expect.any(Number),
159+
timestamp: expect.any(Number),
160+
trace_id: transactionEvent.contexts?.trace?.trace_id,
161+
data: expect.objectContaining({
162+
'http.method': 'GET',
163+
'http.url': 'http://sentry-test.io/api/users?id=1#fragment',
164+
'http.query': '?id=1',
165+
'http.fragment': '#fragment',
166+
'http.response.status_code': 200,
167+
'http.response_content_length': 2,
168+
'sentry.op': 'http.client',
169+
'sentry.origin': 'auto.http.browser',
170+
type: 'fetch',
171+
'server.address': 'sentry-test.io',
172+
url: '/api/users?id=1#fragment',
173+
}),
174+
});
175+
},
176+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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({ instrumentPageLoad: false, instrumentNavigation: false })],
8+
tracePropagationTargets: ['http://sentry-test-site.example'],
9+
tracesSampleRate: 1,
10+
autoSessionTracking: false,
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function withRootSpan(cb) {
2+
return Sentry.startSpan({ name: 'rootSpan' }, cb);
3+
}
4+
5+
function makeXHRRequest(url) {
6+
return new Promise((resolve, reject) => {
7+
const xhr = new XMLHttpRequest();
8+
xhr.open('GET', url);
9+
xhr.onload = () => resolve(xhr.responseText);
10+
xhr.onerror = () => reject(xhr.statusText);
11+
xhr.send();
12+
});
13+
}
14+
15+
document.getElementById('btnQuery').addEventListener('click', async () => {
16+
await withRootSpan(() => makeXHRRequest('http://sentry-test-site.example/0?id=123;page=5'));
17+
});
18+
19+
document.getElementById('btnFragment').addEventListener('click', async () => {
20+
await withRootSpan(() => makeXHRRequest('http://sentry-test-site.example/1#fragment'));
21+
});
22+
23+
document.getElementById('btnQueryFragment').addEventListener('click', async () => {
24+
await withRootSpan(() => makeXHRRequest('http://sentry-test-site.example/2?id=1#fragment'));
25+
});
26+
27+
document.getElementById('btnQueryFragmentSameOrigin').addEventListener('click', async () => {
28+
await withRootSpan(() => makeXHRRequest('/api/users?id=1#fragment'));
29+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="btnQuery">Request with query</button>
8+
<button id="btnFragment">Request with fragment</button>
9+
<button id="btnQueryFragment">Request with query and fragment</button>
10+
<button id="btnQueryFragmentSameOrigin">Same origin request with query and fragment</button>
11+
</body>
12+
</html>

0 commit comments

Comments
 (0)