Skip to content

Commit cf4df75

Browse files
authored
Merge pull request #9417 from getsentry/prepare-release/7.77.0
meta: Update CHANGELOG for 7.77.0
2 parents 136ca9c + 3e619dc commit cf4df75

File tree

52 files changed

+4855
-174
lines changed

Some content is hidden

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

52 files changed

+4855
-174
lines changed

.size-limit.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module.exports = [
2121
__RRWEB_EXCLUDE_CANVAS__: true,
2222
__RRWEB_EXCLUDE_SHADOW_DOM__: true,
2323
__RRWEB_EXCLUDE_IFRAME__: true,
24+
__SENTRY_EXCLUDE_REPLAY_WORKER__: true,
2425
}),
2526
);
2627
return config;

CHANGELOG.md

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

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

7+
## 7.77.0
8+
9+
- feat: Move LinkedErrors integration to @sentry/core (#9404)
10+
- feat(remix): Update sentry-cli version to ^2.21.2 (#9401)
11+
- feat(replay): Allow to treeshake & configure compression worker URL (#9409)
12+
- fix(angular-ivy): Adjust package entry points to support Angular 17 with SSR config (#9412)
13+
- fix(feedback): Fixing feedback import (#9403)
14+
- fix(nextjs): Match only numbers as orgid in tunnelRoute (#9416)
15+
- fix(nextjs): Strictly validate tunnel target parameters (#9415)
16+
- fix(utils): Avoid keeping a reference of last used event (#9387)
17+
718
## 7.76.0
819

920
### Important Changes

packages/angular-ivy/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"build:watch": "yarn build:syncSymlinks && yarn build:transpile:watch",
4747
"build:dev:watch": "yarn build:watch",
4848
"build:transpile:watch": "ng build --watch",
49-
"build:tarball": "npm pack ./build",
49+
"build:tarball": "ts-node ./scripts/prepack.ts && npm pack ./build",
5050
"build:syncSymlinks": "ts-node ./scripts/syncSourceFiles.ts",
5151
"circularDepCheck": "madge --circular src/index.ts",
5252
"clean": "rimraf build coverage sentry-angular-ivy-*.tgz",
@@ -56,7 +56,7 @@
5656
"lint": "run-s lint:prettier lint:eslint",
5757
"lint:eslint": "eslint . --format stylish",
5858
"lint:prettier": "prettier --check \"{src,test,scripts}/**/**.ts\"",
59-
"yalc:publish": "yalc publish build --push --sig"
59+
"yalc:publish": "ts-node ./scripts/prepack.ts && yalc publish build --push --sig"
6060
},
6161
"volta": {
6262
"extends": "../../package.json"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
4+
type PackageJson = {
5+
main?: string;
6+
type?: string;
7+
nx?: string;
8+
volta?: any;
9+
};
10+
11+
const buildDir = path.join(process.cwd(), 'build');
12+
const pkjJsonPath = path.join(buildDir, 'package.json');
13+
const pkgJson: PackageJson = JSON.parse(fs.readFileSync(pkjJsonPath).toString());
14+
15+
// This is necessary for Angular 17+ compatibility when SSR is configured which switches dev mode to using Vite.
16+
// Deleting "main" and adding "type": "module" will direct Vite to
17+
// use the fesm2015 bundle instead of the UMD bundle.
18+
delete pkgJson.main;
19+
pkgJson.type = 'module';
20+
21+
// no need to keep around other properties that are only relevant for our reop:
22+
delete pkgJson.nx;
23+
delete pkgJson.volta;
24+
25+
fs.writeFileSync(pkjJsonPath, JSON.stringify(pkgJson, null, 2));
26+
27+
console.log('Adjusted package.json for Angular 17+ compatibility.');
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title></title>
6+
</head>
7+
<body>
8+
<button id="button1" type="button">Button 1</button>
9+
<button id="button2" type="button">Button 2</button>
10+
</body>
11+
</html>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/types';
3+
4+
import { sentryTest } from '../../../../../utils/fixtures';
5+
import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers';
6+
7+
sentryTest('captures Breadcrumb for clicks & debounces them for a second', async ({ getLocalTestUrl, page }) => {
8+
const url = await getLocalTestUrl({ testDir: __dirname });
9+
10+
await page.route('**/foo', route => {
11+
return route.fulfill({
12+
status: 200,
13+
body: JSON.stringify({
14+
userNames: ['John', 'Jane'],
15+
}),
16+
headers: {
17+
'Content-Type': 'application/json',
18+
},
19+
});
20+
});
21+
22+
const promise = getFirstSentryEnvelopeRequest<Event>(page);
23+
24+
await page.goto(url);
25+
26+
await page.click('#button1');
27+
// not debounced because other target
28+
await page.click('#button2');
29+
// This should be debounced
30+
await page.click('#button2');
31+
32+
// Wait a second for the debounce to finish
33+
await page.waitForTimeout(1000);
34+
await page.click('#button2');
35+
36+
await page.evaluate('Sentry.captureException("test exception")');
37+
38+
const eventData = await promise;
39+
40+
expect(eventData.exception?.values).toHaveLength(1);
41+
42+
expect(eventData.breadcrumbs).toEqual([
43+
{
44+
timestamp: expect.any(Number),
45+
category: 'ui.click',
46+
message: 'body > button#button1[type="button"]',
47+
},
48+
{
49+
timestamp: expect.any(Number),
50+
category: 'ui.click',
51+
message: 'body > button#button2[type="button"]',
52+
},
53+
{
54+
timestamp: expect.any(Number),
55+
category: 'ui.click',
56+
message: 'body > button#button2[type="button"]',
57+
},
58+
]);
59+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
defaultIntegrations: false,
8+
integrations: [new Sentry.Integrations.Breadcrumbs()],
9+
sampleRate: 1,
10+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title></title>
6+
</head>
7+
<body>
8+
<input id="input1" type="text" />
9+
<input id="input2" type="text" />
10+
</body>
11+
</html>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/types';
3+
4+
import { sentryTest } from '../../../../../utils/fixtures';
5+
import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers';
6+
7+
sentryTest('captures Breadcrumb for events on inputs & debounced them', async ({ getLocalTestUrl, page }) => {
8+
const url = await getLocalTestUrl({ testDir: __dirname });
9+
10+
await page.route('**/foo', route => {
11+
return route.fulfill({
12+
status: 200,
13+
body: JSON.stringify({
14+
userNames: ['John', 'Jane'],
15+
}),
16+
headers: {
17+
'Content-Type': 'application/json',
18+
},
19+
});
20+
});
21+
22+
const promise = getFirstSentryEnvelopeRequest<Event>(page);
23+
24+
await page.goto(url);
25+
26+
await page.click('#input1');
27+
// Not debounced because other event type
28+
await page.type('#input1', 'John', { delay: 1 });
29+
// This should be debounced
30+
await page.type('#input1', 'Abby', { delay: 1 });
31+
// not debounced because other target
32+
await page.type('#input2', 'Anne', { delay: 1 });
33+
34+
// Wait a second for the debounce to finish
35+
await page.waitForTimeout(1000);
36+
await page.type('#input2', 'John', { delay: 1 });
37+
38+
await page.evaluate('Sentry.captureException("test exception")');
39+
40+
const eventData = await promise;
41+
42+
expect(eventData.exception?.values).toHaveLength(1);
43+
44+
expect(eventData.breadcrumbs).toEqual([
45+
{
46+
timestamp: expect.any(Number),
47+
category: 'ui.click',
48+
message: 'body > input#input1[type="text"]',
49+
},
50+
{
51+
timestamp: expect.any(Number),
52+
category: 'ui.input',
53+
message: 'body > input#input1[type="text"]',
54+
},
55+
{
56+
timestamp: expect.any(Number),
57+
category: 'ui.input',
58+
message: 'body > input#input2[type="text"]',
59+
},
60+
{
61+
timestamp: expect.any(Number),
62+
category: 'ui.input',
63+
message: 'body > input#input2[type="text"]',
64+
},
65+
]);
66+
});

packages/browser-integration-tests/suites/replay/compression/subject.js

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

packages/browser-integration-tests/suites/replay/compression/test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { getExpectedReplayEvent } from '../../../utils/replayEventTemplates';
55
import {
66
getFullRecordingSnapshots,
77
getReplayEvent,
8+
replayEnvelopeIsCompressed,
89
shouldSkipReplayTest,
910
waitForReplayRequest,
1011
} from '../../../utils/replayHelpers';
1112

12-
sentryTest('replay recording should be compressed by default', async ({ getLocalTestPath, page }) => {
13+
sentryTest('replay recording should be compressed by default', async ({ getLocalTestPath, page, forceFlushReplay }) => {
1314
if (shouldSkipReplayTest()) {
1415
sentryTest.skip();
1516
}
@@ -27,10 +28,16 @@ sentryTest('replay recording should be compressed by default', async ({ getLocal
2728
const url = await getLocalTestPath({ testDir: __dirname });
2829

2930
await page.goto(url);
30-
const replayEvent0 = getReplayEvent(await reqPromise0);
31+
await forceFlushReplay();
32+
33+
const req0 = await reqPromise0;
34+
35+
const replayEvent0 = getReplayEvent(req0);
3136
expect(replayEvent0).toEqual(getExpectedReplayEvent());
3237

33-
const snapshots = getFullRecordingSnapshots(await reqPromise0);
38+
expect(replayEnvelopeIsCompressed(req0)).toEqual(true);
39+
40+
const snapshots = getFullRecordingSnapshots(req0);
3441
expect(snapshots.length).toEqual(1);
3542

3643
const stringifiedSnapshot = JSON.stringify(snapshots[0]);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window.Replay = new Sentry.Replay({
5+
flushMinDelay: 200,
6+
flushMaxDelay: 200,
7+
minReplayDuration: 0,
8+
useCompression: false,
9+
});
10+
11+
Sentry.init({
12+
dsn: 'https://[email protected]/1337',
13+
sampleRate: 0,
14+
replaysSessionSampleRate: 1.0,
15+
replaysOnErrorSampleRate: 0.0,
16+
17+
integrations: [window.Replay],
18+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="go-background">New Tab</button>
8+
</body>
9+
</html>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../utils/fixtures';
4+
import { getExpectedReplayEvent } from '../../../utils/replayEventTemplates';
5+
import {
6+
getFullRecordingSnapshots,
7+
getReplayEvent,
8+
replayEnvelopeIsCompressed,
9+
shouldSkipReplayTest,
10+
waitForReplayRequest,
11+
} from '../../../utils/replayHelpers';
12+
13+
sentryTest(
14+
'replay recording should allow to disable compression',
15+
async ({ getLocalTestPath, page, forceFlushReplay }) => {
16+
if (shouldSkipReplayTest()) {
17+
sentryTest.skip();
18+
}
19+
20+
const reqPromise0 = waitForReplayRequest(page, 0);
21+
22+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
23+
return route.fulfill({
24+
status: 200,
25+
contentType: 'application/json',
26+
body: JSON.stringify({ id: 'test-id' }),
27+
});
28+
});
29+
30+
const url = await getLocalTestPath({ testDir: __dirname });
31+
32+
await page.goto(url);
33+
await forceFlushReplay();
34+
35+
const req0 = await reqPromise0;
36+
37+
const replayEvent0 = getReplayEvent(req0);
38+
expect(replayEvent0).toEqual(getExpectedReplayEvent());
39+
40+
expect(replayEnvelopeIsCompressed(req0)).toEqual(false);
41+
42+
const snapshots = getFullRecordingSnapshots(req0);
43+
expect(snapshots.length).toEqual(1);
44+
45+
const stringifiedSnapshot = JSON.stringify(snapshots[0]);
46+
expect(stringifiedSnapshot).toContain('"tagName":"body"');
47+
expect(stringifiedSnapshot).toContain('"tagName":"html"');
48+
expect(stringifiedSnapshot).toContain('"tagName":"button"');
49+
expect(stringifiedSnapshot).toContain('"textContent":"*** ***"');
50+
expect(stringifiedSnapshot).toContain('"id":"go-background"');
51+
},
52+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window.Replay = new Sentry.Replay({
5+
flushMinDelay: 200,
6+
flushMaxDelay: 200,
7+
minReplayDuration: 0,
8+
useCompression: true,
9+
workerUrl: `${window.location.origin}/my-test-worker.js`,
10+
});
11+
12+
Sentry.init({
13+
dsn: 'https://[email protected]/1337',
14+
sampleRate: 0,
15+
replaysSessionSampleRate: 1.0,
16+
replaysOnErrorSampleRate: 0.0,
17+
18+
integrations: [window.Replay],
19+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="go-background">New Tab</button>
8+
</body>
9+
</html>

0 commit comments

Comments
 (0)