Skip to content

Commit 0b706be

Browse files
authored
Merge pull request #15350 from getsentry/prepare-release/9.0.0
meta: Sync develop to master for 9.0.0
2 parents b48192c + 8d3851c commit 0b706be

File tree

129 files changed

+1629
-314
lines changed

Some content is hidden

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

129 files changed

+1629
-314
lines changed

.craft.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,19 @@ targets:
129129
includeNames: /^sentry-internal-eslint-config-sdk-\d.*\.tgz$/
130130

131131
# AWS Lambda Layer target
132-
# TODO(v9): Once stable, re-add this target to publish the AWS Lambda layer
133-
# - name: aws-lambda-layer
134-
# includeNames: /^sentry-node-serverless-\d+.\d+.\d+(-(beta|alpha|rc)\.\d+)?\.zip$/
135-
# layerName: SentryNodeServerlessSDKv9
136-
# compatibleRuntimes:
137-
# - name: node
138-
# versions:
139-
# - nodejs10.x
140-
# - nodejs12.x
141-
# - nodejs14.x
142-
# - nodejs16.x
143-
# - nodejs18.x
144-
# - nodejs20.x
145-
# license: MIT
132+
- name: aws-lambda-layer
133+
includeNames: /^sentry-node-serverless-\d+.\d+.\d+(-(beta|alpha|rc)\.\d+)?\.zip$/
134+
layerName: SentryNodeServerlessSDKv9
135+
compatibleRuntimes:
136+
- name: node
137+
versions:
138+
- nodejs10.x
139+
- nodejs12.x
140+
- nodejs14.x
141+
- nodejs16.x
142+
- nodejs18.x
143+
- nodejs20.x
144+
license: MIT
146145

147146
# CDN Bundle Target
148147
- name: gcs

CHANGELOG.md

Lines changed: 352 additions & 2 deletions
Large diffs are not rendered by default.

MIGRATION.md

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ These docs walk through how to migrate our JavaScript SDKs through different maj
99

1010
# Upgrading from 8.x to 9.x
1111

12-
Version 9 of the Sentry JavaScript SDK concerns API cleanup and version support changes.
13-
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 purely relying on automatic tooling.
12+
Version 9 of the Sentry JavaScript SDK primarily introduces API cleanup and version support changes.
13+
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.
1414

15-
`v9` of the SDK is compatible with Sentry self-hosted versions 24.4.2 or higher (unchanged from v8).
15+
Version 9 of the SDK is compatible with Sentry self-hosted versions 24.4.2 or higher (unchanged from v8).
1616
Lower versions may continue to work, but may not support all features.
1717

1818
## 1. Version Support Changes:
@@ -27,16 +27,16 @@ This includes features like Nullish Coalescing (`??`), Optional Chaining (`?.`),
2727
If you observe failures due to syntax or features listed above, it may indicate that your current runtime does not support ES2020.
2828
If your runtime does not support ES2020, we recommend transpiling the SDK using Babel or similar tooling.
2929

30-
**Node.js:** The minimum supported Node.js version is **18.0.0**, except for ESM-only SDKs (`@sentry/astro`, `@sentry/nuxt`, `@sentry/sveltekit`) which require Node.js version **18.19.1** or higher.
30+
**Node.js:** The minimum supported Node.js version is **18.0.0** (Released Apr 19, 2022), except for ESM-only SDKs (`@sentry/astro`, `@sentry/nuxt`, `@sentry/sveltekit`) which require Node.js version **18.19.1** (Released Feb 14, 2024) or higher.
3131

3232
**Browsers:** Due to SDK code now including ES2020 features, the minimum supported browser list now looks as follows:
3333

34-
- Chrome 80
35-
- Edge 80
36-
- Safari 14, iOS Safari 14.4
37-
- Firefox 74
38-
- Opera 67
39-
- Samsung Internet 13.0
34+
- Chrome 80 (Released Feb 5, 2020)
35+
- Edge 80 (Released Feb 7, 2020)
36+
- Safari 14, iOS Safari 14.4 (Released Sep 16, 2020)
37+
- Firefox 74 (Released Mar 10, 2020)
38+
- Opera 67 (Released Mar 12, 2020)
39+
- Samsung Internet 13.0 (Released Nov 20, 2020)
4040

4141
If you need to support older browsers, we recommend transpiling your code using SWC, Babel or similar tooling.
4242

@@ -54,11 +54,21 @@ Support for the following frameworks and library versions are dropped:
5454

5555
### TypeScript Version Policy
5656

57-
In preparation for v2 of the OpenTelemetry SDK, which will raise the minimum required TypeScript version, the minimum required TypeScript version is increased to version `5.0.4`.
57+
In preparation for v2 of the OpenTelemetry SDK, the minimum required TypeScript version is increased to version `5.0.4`.
5858

5959
Additionally, like the OpenTelemetry SDK, the Sentry JavaScript SDK will follow [DefinitelyType's version support policy](https://github.com/DefinitelyTyped/DefinitelyTyped#support-window) which has a support time frame of 2 years for any released version of TypeScript.
6060

61-
Older Typescript versions _may_ continue to be compatible, but no guarantees apply.
61+
Older TypeScript versions _may_ continue to be compatible, but no guarantees apply.
62+
63+
### AWS Lambda Layer Changes
64+
65+
A new AWS Lambda Layer for version 9 will be published as `SentryNodeServerlessSDKv9`.
66+
The ARN will be published in the [Sentry docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/install/cjs-layer/) once available.
67+
68+
The previous `SentryNodeServerlessSDK` layer will not receive new updates anymore.
69+
70+
Updates and fixes for version 8 will be published as `SentryNodeServerlessSDKv8`.
71+
The ARN will be published in the [Sentry docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/install/cjs-layer/) once available.
6272

6373
## 2. Behavior Changes
6474

@@ -80,7 +90,7 @@ Older Typescript versions _may_ continue to be compatible, but no guarantees app
8090
While in v8, the passed scope was set active directly on the passed scope, in v9, the scope is cloned. This behavior change does not apply to `@sentry/node` where the scope was already cloned.
8191
This change was made to ensure that the span only remains active within the callback and to align behavior between `@sentry/node` and all other SDKs.
8292
As a result of the change, span hierarchy should be more accurate.
83-
However, modifying the scope (e.g. set tags) within the `startSpan` callback behaves a bit differently now.
93+
However, modifying the scope (for example, setting tags) within the `startSpan` callback behaves a bit differently now.
8494

8595
```js
8696
startSpan({ name: 'example', scope: customScope }, () => {
@@ -91,12 +101,12 @@ Older Typescript versions _may_ continue to be compatible, but no guarantees app
91101
```
92102

93103
- Passing `undefined` as a `tracesSampleRate` option value will now be treated the same as if the attribute was not defined at all.
94-
In previous versions, it was checked whether the `tracesSampleRate` property existed in the SDK options to determine whether to propagate trace data for distributed tracing.
104+
In previous versions, it was checked whether the `tracesSampleRate` property existed in the SDK options to decide if trace data should be propagated for tracing.
95105
Consequentially, this sometimes caused the SDK to propagate negative sampling decisions when `tracesSampleRate: undefined` was passed.
96106
This is no longer the case and sampling decisions will be deferred to downstream SDKs for distributed tracing.
97107
This is more of a bugfix rather than a breaking change, however, depending on the setup of your SDKs, an increase in sampled traces may be observed.
98108

99-
- If you use the optional `captureConsoleIntegration` and set `attachStackTrace: true` in your `Sentry.init` call, console messages will no longer be marked as unhandled (i.e. `handled: false`) but as handled (i.e. `handled: true`).
109+
- If you use the optional `captureConsoleIntegration` and set `attachStackTrace: true` in your `Sentry.init` call, console messages will no longer be marked as unhandled (`handled: false`) but as handled (`handled: true`).
100110
If you want to keep sending them as unhandled, configure the `handled` option when adding the integration:
101111

102112
```js
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils.

dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/basic/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures';
44

55
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
66

7-
const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils.
7+
import { FLAG_BUFFER_SIZE } from '../../constants';
88

99
sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => {
1010
if (shouldSkipFeatureFlagsTest()) {

dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/basic/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures';
44

55
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
66

7-
const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils.
7+
import { FLAG_BUFFER_SIZE } from '../../constants';
88

99
sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => {
1010
if (shouldSkipFeatureFlagsTest()) {

dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/basic/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures';
44

55
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
66

7-
const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils.
7+
import { FLAG_BUFFER_SIZE } from '../../constants';
88

99
sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => {
1010
if (shouldSkipFeatureFlagsTest()) {

dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/errorHook/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures';
44

55
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
66

7-
const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils.
7+
import { FLAG_BUFFER_SIZE } from '../../constants';
88

99
sentryTest('Flag evaluation error hook', async ({ getLocalTestUrl, page }) => {
1010
if (shouldSkipFeatureFlagsTest()) {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../../../utils/fixtures';
4+
5+
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
6+
7+
import { FLAG_BUFFER_SIZE } from '../../constants';
8+
9+
sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => {
10+
if (shouldSkipFeatureFlagsTest()) {
11+
sentryTest.skip();
12+
}
13+
14+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
15+
return route.fulfill({
16+
status: 200,
17+
contentType: 'application/json',
18+
body: JSON.stringify({ id: 'test-id' }),
19+
});
20+
});
21+
22+
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
23+
await page.goto(url);
24+
25+
await page.evaluate(bufferSize => {
26+
const client = (window as any).statsigClient;
27+
for (let i = 1; i <= bufferSize; i++) {
28+
client.checkGate(`feat${i}`); // values default to false
29+
}
30+
31+
client.setMockGateValue(`feat${bufferSize + 1}`, true);
32+
client.checkGate(`feat${bufferSize + 1}`); // eviction
33+
34+
client.setMockGateValue('feat3', true);
35+
client.checkGate('feat3'); // update
36+
}, FLAG_BUFFER_SIZE);
37+
38+
const reqPromise = waitForErrorRequest(page);
39+
await page.locator('#error').click();
40+
const req = await reqPromise;
41+
const event = envelopeRequestParser(req);
42+
43+
const expectedFlags = [{ flag: 'feat2', result: false }];
44+
for (let i = 4; i <= FLAG_BUFFER_SIZE; i++) {
45+
expectedFlags.push({ flag: `feat${i}`, result: false });
46+
}
47+
expectedFlags.push({ flag: `feat${FLAG_BUFFER_SIZE + 1}`, result: true });
48+
expectedFlags.push({ flag: 'feat3', result: true });
49+
50+
expect(event.contexts?.flags?.values).toEqual(expectedFlags);
51+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
class MockStatsigClient {
4+
constructor() {
5+
this._gateEvaluationListeners = [];
6+
this._mockGateValues = {};
7+
}
8+
9+
on(event, listener) {
10+
this._gateEvaluationListeners.push(listener);
11+
}
12+
13+
checkGate(name) {
14+
const value = this._mockGateValues[name] || false; // unknown features default to false.
15+
this._gateEvaluationListeners.forEach(listener => {
16+
listener({ gate: { name, value } });
17+
});
18+
return value;
19+
}
20+
21+
setMockGateValue(name, value) {
22+
this._mockGateValues[name] = value;
23+
}
24+
}
25+
26+
window.statsigClient = new MockStatsigClient();
27+
28+
window.Sentry = Sentry;
29+
window.sentryStatsigIntegration = Sentry.statsigIntegration({ featureFlagClient: window.statsigClient });
30+
31+
Sentry.init({
32+
dsn: 'https://[email protected]/1337',
33+
sampleRate: 1.0,
34+
integrations: [window.sentryStatsigIntegration],
35+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
document.getElementById('error').addEventListener('click', () => {
2+
throw new Error('Button triggered error');
3+
});
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="error">Throw Error</button>
8+
</body>
9+
</html>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../../../utils/fixtures';
4+
5+
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
6+
7+
import type { Scope } from '@sentry/browser';
8+
9+
sentryTest('Flag evaluations in forked scopes are stored separately.', async ({ getLocalTestUrl, page }) => {
10+
if (shouldSkipFeatureFlagsTest()) {
11+
sentryTest.skip();
12+
}
13+
14+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
15+
return route.fulfill({
16+
status: 200,
17+
contentType: 'application/json',
18+
body: JSON.stringify({ id: 'test-id' }),
19+
});
20+
});
21+
22+
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
23+
await page.goto(url);
24+
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
27+
28+
await page.evaluate(() => {
29+
const Sentry = (window as any).Sentry;
30+
const errorButton = document.querySelector('#error') as HTMLButtonElement;
31+
const client = (window as any).statsigClient;
32+
33+
client.setMockGateValue('shared', true);
34+
client.setMockGateValue('main', true);
35+
36+
client.checkGate('shared');
37+
38+
Sentry.withScope((scope: Scope) => {
39+
client.setMockGateValue('forked', true);
40+
client.setMockGateValue('shared', false); // override the value in the parent scope.
41+
42+
client.checkGate('forked');
43+
client.checkGate('shared');
44+
scope.setTag('isForked', true);
45+
errorButton.click();
46+
});
47+
48+
client.checkGate('main');
49+
Sentry.getCurrentScope().setTag('isForked', false);
50+
errorButton.click();
51+
return true;
52+
});
53+
54+
const forkedReq = await forkedReqPromise;
55+
const forkedEvent = envelopeRequestParser(forkedReq);
56+
57+
const mainReq = await mainReqPromise;
58+
const mainEvent = envelopeRequestParser(mainReq);
59+
60+
expect(forkedEvent.contexts?.flags?.values).toEqual([
61+
{ flag: 'forked', result: true },
62+
{ flag: 'shared', result: false },
63+
]);
64+
65+
expect(mainEvent.contexts?.flags?.values).toEqual([
66+
{ flag: 'shared', result: true },
67+
{ flag: 'main', result: true },
68+
]);
69+
});

dev-packages/browser-integration-tests/suites/integrations/featureFlags/unleash/basic/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures';
44

55
import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers';
66

7-
const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils.
7+
import { FLAG_BUFFER_SIZE } from '../../constants';
88

99
sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => {
1010
if (shouldSkipFeatureFlagsTest()) {

dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/subject.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
window.calls = {};
22
const xhr = new XMLHttpRequest();
3-
xhr.open('GET', 'http://example.com');
3+
xhr.open('GET', 'http://sentry-test-site.example');
44
xhr.onreadystatechange = function wat() {
55
window.calls[xhr.readyState] = window.calls[xhr.readyState] ? window.calls[xhr.readyState] + 1 : 1;
66
};

dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sentryTest(
77
async ({ getLocalTestUrl, page }) => {
88
const url = await getLocalTestUrl({ testDir: __dirname });
99

10-
await page.route('http://example.com/', route => {
10+
await page.route('http://sentry-test-site.example/', route => {
1111
return route.fulfill({
1212
status: 200,
1313
contentType: 'application/json',

dev-packages/browser-integration-tests/suites/replay/requests/subject.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ document.getElementById('go-background').addEventListener('click', () => {
66
});
77

88
document.getElementById('fetch').addEventListener('click', () => {
9-
fetch('https://example.com', { method: 'POST', body: 'foo' });
9+
fetch('https://sentry-test-site.example', { method: 'POST', body: 'foo' });
1010
});
1111

1212
document.getElementById('xhr').addEventListener('click', () => {
1313
const xhr = new XMLHttpRequest();
14-
xhr.open('GET', 'https://example.com');
14+
xhr.open('GET', 'https://sentry-test-site.example');
1515
xhr.send();
1616
});

0 commit comments

Comments
 (0)