Skip to content

Commit c122987

Browse files
committed
Merge branch 'develop' into nh/automatic-function-middleware-instrumentation
2 parents a910011 + 5886804 commit c122987

File tree

74 files changed

+1350
-205
lines changed

Some content is hidden

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

74 files changed

+1350
-205
lines changed

CHANGELOG.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

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

7-
Work in this release was contributed by @sebws, @harshit078, and @fedetorre. Thank you for your contributions!
7+
Work in this release was contributed by @harshit078. Thank you for your contribution!
8+
9+
## 10.37.0
10+
11+
### Important Changes
812

913
- **feat(core): Introduces a new `Sentry.setConversationId()` API to track multi turn AI conversations across API calls. ([#18909](https://github.com/getsentry/sentry-javascript/pull/18909))**
1014

@@ -23,9 +27,7 @@ Work in this release was contributed by @sebws, @harshit078, and @fedetorre. Tha
2327
This is particularly useful for tracking multiple AI API calls that are part of the same conversation, allowing you to analyze entire conversation flows in Sentry.
2428
The conversation ID is stored on the isolation scope and automatically applied to spans via the new `conversationIdIntegration`.
2529

26-
### Important Changes
27-
28-
- **feat(tanstackstart-react): Auto-instrument global middleware in `sentryTanstackStart` Vite plugin ([#18884](https://github.com/getsentry/sentry-javascript/pull/18844))**
30+
- **feat(tanstackstart-react): Auto-instrument global middleware in `sentryTanstackStart` Vite plugin ([#18844](https://github.com/getsentry/sentry-javascript/pull/18844))**
2931

3032
The `sentryTanstackStart` Vite plugin now automatically instruments `requestMiddleware` and `functionMiddleware` arrays in `createStart()`. This captures performance data without requiring manual wrapping.
3133

@@ -43,7 +45,39 @@ Work in this release was contributed by @sebws, @harshit078, and @fedetorre. Tha
4345

4446
### Other Changes
4547

48+
- feat(core): simplify truncation logic to only keep the newest message ([#18906](https://github.com/getsentry/sentry-javascript/pull/18906))
49+
- feat(core): Support new client discard reason `invalid` ([#18901](https://github.com/getsentry/sentry-javascript/pull/18901))
4650
- feat(deps): Bump OpenTelemetry instrumentations ([#18934](https://github.com/getsentry/sentry-javascript/pull/18934))
51+
- feat(nextjs): Update default ignore list for sourcemaps ([#18938](https://github.com/getsentry/sentry-javascript/pull/18938))
52+
- feat(node): pass prisma instrumentation options through ([#18900](https://github.com/getsentry/sentry-javascript/pull/18900))
53+
- feat(nuxt): Don't run source maps related code on Nuxt "prepare" ([#18936](https://github.com/getsentry/sentry-javascript/pull/18936))
54+
- feat(replay): Update client report discard reason for invalid sessions ([#18796](https://github.com/getsentry/sentry-javascript/pull/18796))
55+
- feat(winston): Add customLevelMap for winston transport ([#18922](https://github.com/getsentry/sentry-javascript/pull/18922))
56+
- feat(react-router): Add support for React Router instrumentation API ([#18580](https://github.com/getsentry/sentry-javascript/pull/18580))
57+
- fix(astro): Do not show warnings for valid options ([#18947](https://github.com/getsentry/sentry-javascript/pull/18947))
58+
- fix(core): Report well known values in gen_ai.operation.name attribute ([#18925](https://github.com/getsentry/sentry-javascript/pull/18925))
59+
- fix(node-core): ignore vercel `AbortError` by default on unhandled rejection ([#18973](https://github.com/getsentry/sentry-javascript/pull/18973))
60+
- fix(nuxt): include sentry.config.server.ts in nuxt app types ([#18971](https://github.com/getsentry/sentry-javascript/pull/18971))
61+
- fix(profiling): Add `platform` to envelope item header ([#18954](https://github.com/getsentry/sentry-javascript/pull/18954))
62+
- fix(react): Defer React Router span finalization until lazy routes load ([#18881](https://github.com/getsentry/sentry-javascript/pull/18881))
63+
- ref(core): rename `gen_ai.input.messages.original_length` to `sentry.sdk_meta.gen_ai.input.messages.original_length` ([#18970](https://github.com/getsentry/sentry-javascript/pull/18970))
64+
- ref(core): rename `gen_ai.request.messages` to `gen_ai.input.messages` ([#18944](https://github.com/getsentry/sentry-javascript/pull/18944))
65+
- ref(core): Set system message as separate attribute ([#18978](https://github.com/getsentry/sentry-javascript/pull/18978))
66+
- deps: Bump version of sentry-bundler-plugins ([#18972](https://github.com/getsentry/sentry-javascript/pull/18972))
67+
68+
<details>
69+
<summary><strong>Internal Changes</strong></summary>
70+
71+
- chore(e2e): Add e2e claude skill ([#18957](https://github.com/getsentry/sentry-javascript/pull/18957))
72+
- chore(e2e): Add Makefile to make running specific e2e test apps easier ([#18953](https://github.com/getsentry/sentry-javascript/pull/18953))
73+
- chore(e2e): Modify e2e skill to also account for untracked files ([#18959](https://github.com/getsentry/sentry-javascript/pull/18959))
74+
- ref(tests): use constants in ai integration tests and add missing ones ([#18945](https://github.com/getsentry/sentry-javascript/pull/18945))
75+
- test(nextjs): Added nextjs CF workers test app ([#18928](https://github.com/getsentry/sentry-javascript/pull/18928))
76+
- test(prisma): Move to yarn prisma ([#18975](https://github.com/getsentry/sentry-javascript/pull/18975))
77+
78+
</details>
79+
80+
Work in this release was contributed by @sebws, @harshit078, and @fedetorre. Thank you for your contributions!
4781

4882
## 10.36.0
4983

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry-internal/browser-integration-tests",
3-
"version": "10.36.0",
3+
"version": "10.37.0",
44
"main": "index.js",
55
"license": "MIT",
66
"engines": {
@@ -49,7 +49,7 @@
4949
"@babel/preset-typescript": "^7.16.7",
5050
"@playwright/test": "~1.56.0",
5151
"@sentry-internal/rrweb": "2.34.0",
52-
"@sentry/browser": "10.36.0",
52+
"@sentry/browser": "10.37.0",
5353
"@supabase/supabase-js": "2.49.3",
5454
"axios": "^1.12.2",
5555
"babel-loader": "^8.2.2",
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// This worker manually replicates what Sentry.registerWebWorkerWasm() does.
2+
// the reason for manual replication is that it allows us to test the message-passing protocol
3+
// between worker and main thread independent of SDK implementation details
4+
// in production code you would do: registerWebWorkerWasm({ self });
5+
6+
const origInstantiateStreaming = WebAssembly.instantiateStreaming;
7+
WebAssembly.instantiateStreaming = function instantiateStreaming(response, importObject) {
8+
return Promise.resolve(response).then(res => {
9+
return origInstantiateStreaming(res, importObject).then(rv => {
10+
if (res.url) {
11+
registerModuleAndForward(rv.module, res.url);
12+
}
13+
return rv;
14+
});
15+
});
16+
};
17+
18+
function registerModuleAndForward(module, url) {
19+
const buildId = getBuildId(module);
20+
21+
if (buildId) {
22+
const image = {
23+
type: 'wasm',
24+
code_id: buildId,
25+
code_file: url,
26+
debug_file: null,
27+
debug_id: `${`${buildId}00000000000000000000000000000000`.slice(0, 32)}0`,
28+
};
29+
30+
self.postMessage({
31+
_sentryMessage: true,
32+
_sentryWasmImages: [image],
33+
});
34+
}
35+
}
36+
37+
// Extract build ID from WASM module
38+
function getBuildId(module) {
39+
const sections = WebAssembly.Module.customSections(module, 'build_id');
40+
if (sections.length > 0) {
41+
const buildId = Array.from(new Uint8Array(sections[0]))
42+
.map(b => b.toString(16).padStart(2, '0'))
43+
.join('');
44+
return buildId;
45+
}
46+
return null;
47+
}
48+
49+
// Handle messages from the main thread
50+
self.addEventListener('message', async event => {
51+
function crash() {
52+
throw new Error('WASM error from worker');
53+
}
54+
55+
if (event.data.type === 'load-wasm-and-crash') {
56+
const wasmUrl = event.data.wasmUrl;
57+
58+
try {
59+
const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), {
60+
env: {
61+
external_func: crash,
62+
},
63+
});
64+
65+
instance.exports.internal_func();
66+
} catch (err) {
67+
self.postMessage({
68+
_sentryMessage: true,
69+
_sentryWorkerError: {
70+
reason: err,
71+
filename: self.location.href,
72+
},
73+
});
74+
}
75+
}
76+
});
77+
78+
self.addEventListener('unhandledrejection', event => {
79+
self.postMessage({
80+
_sentryMessage: true,
81+
_sentryWorkerError: {
82+
reason: event.reason,
83+
filename: self.location.href,
84+
},
85+
});
86+
});
87+
88+
// Let the main thread know that worker is ready
89+
self.postMessage({ _sentryMessage: false, type: 'WORKER_READY' });
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as Sentry from '@sentry/browser';
2+
import { wasmIntegration } from '@sentry/wasm';
3+
4+
window.Sentry = Sentry;
5+
6+
Sentry.init({
7+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
8+
integrations: [wasmIntegration({ applicationKey: 'wasm-worker-app' })],
9+
});
10+
11+
const worker = new Worker('/worker.js');
12+
13+
Sentry.addIntegration(Sentry.webWorkerIntegration({ worker }));
14+
15+
window.wasmWorker = worker;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
window.events = [];
2+
3+
window.triggerWasmError = () => {
4+
window.wasmWorker.postMessage({
5+
type: 'load-wasm-and-crash',
6+
wasmUrl: 'https://localhost:5887/simple.wasm',
7+
});
8+
};
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="triggerWasmError">Trigger WASM Error in Worker</button>
8+
</body>
9+
</html>
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { expect } from '@playwright/test';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import { sentryTest } from '../../../utils/fixtures';
5+
import { envelopeRequestParser, waitForErrorRequest } from '../../../utils/helpers';
6+
import { shouldSkipWASMTests } from '../../../utils/wasmHelpers';
7+
8+
declare global {
9+
interface Window {
10+
wasmWorker: Worker;
11+
triggerWasmError: () => void;
12+
}
13+
}
14+
15+
const bundle = process.env.PW_BUNDLE || '';
16+
if (bundle.startsWith('bundle')) {
17+
sentryTest.skip();
18+
}
19+
20+
sentryTest(
21+
'WASM debug images from worker should be forwarded to main thread and attached to events',
22+
async ({ getLocalTestUrl, page, browserName }) => {
23+
if (shouldSkipWASMTests(browserName)) {
24+
sentryTest.skip();
25+
}
26+
27+
const url = await getLocalTestUrl({ testDir: __dirname });
28+
29+
await page.route('**/simple.wasm', route => {
30+
const wasmModule = fs.readFileSync(path.resolve(__dirname, '../simple.wasm'));
31+
return route.fulfill({
32+
status: 200,
33+
body: wasmModule,
34+
headers: {
35+
'Content-Type': 'application/wasm',
36+
},
37+
});
38+
});
39+
40+
await page.route('**/worker.js', route => {
41+
return route.fulfill({
42+
path: `${__dirname}/assets/worker.js`,
43+
});
44+
});
45+
46+
const errorEventPromise = waitForErrorRequest(page, e => {
47+
return e.exception?.values?.[0]?.value === 'WASM error from worker';
48+
});
49+
50+
await page.goto(url);
51+
52+
await page.waitForFunction(() => window.wasmWorker !== undefined);
53+
54+
await page.evaluate(() => {
55+
window.triggerWasmError();
56+
});
57+
58+
const errorEvent = envelopeRequestParser(await errorEventPromise);
59+
60+
expect(errorEvent.exception?.values?.[0]?.value).toBe('WASM error from worker');
61+
62+
expect(errorEvent.debug_meta?.images).toBeDefined();
63+
expect(errorEvent.debug_meta?.images).toEqual(
64+
expect.arrayContaining([
65+
expect.objectContaining({
66+
type: 'wasm',
67+
code_file: expect.stringMatching(/simple\.wasm$/),
68+
code_id: '0ba020cdd2444f7eafdd25999a8e9010',
69+
debug_id: '0ba020cdd2444f7eafdd25999a8e90100',
70+
}),
71+
]),
72+
);
73+
74+
expect(errorEvent.exception?.values?.[0]?.stacktrace?.frames).toEqual(
75+
expect.arrayContaining([
76+
expect.objectContaining({
77+
filename: expect.stringMatching(/simple\.wasm$/),
78+
platform: 'native',
79+
instruction_addr: expect.stringMatching(/^0x[a-fA-F\d]+$/),
80+
addr_mode: expect.stringMatching(/^rel:\d+$/),
81+
}),
82+
]),
83+
);
84+
},
85+
);
86+
87+
sentryTest(
88+
'WASM frames from worker should be recognized as first-party when applicationKey is configured',
89+
async ({ getLocalTestUrl, page, browserName }) => {
90+
if (shouldSkipWASMTests(browserName)) {
91+
sentryTest.skip();
92+
}
93+
94+
const url = await getLocalTestUrl({ testDir: __dirname });
95+
96+
await page.route('**/simple.wasm', route => {
97+
const wasmModule = fs.readFileSync(path.resolve(__dirname, '../simple.wasm'));
98+
return route.fulfill({
99+
status: 200,
100+
body: wasmModule,
101+
headers: {
102+
'Content-Type': 'application/wasm',
103+
},
104+
});
105+
});
106+
107+
await page.route('**/worker.js', route => {
108+
return route.fulfill({
109+
path: `${__dirname}/assets/worker.js`,
110+
});
111+
});
112+
113+
const errorEventPromise = waitForErrorRequest(page, e => {
114+
return e.exception?.values?.[0]?.value === 'WASM error from worker';
115+
});
116+
117+
await page.goto(url);
118+
119+
await page.waitForFunction(() => window.wasmWorker !== undefined);
120+
121+
await page.evaluate(() => {
122+
window.triggerWasmError();
123+
});
124+
125+
const errorEvent = envelopeRequestParser(await errorEventPromise);
126+
127+
expect(errorEvent.exception?.values?.[0]?.stacktrace?.frames).toEqual(
128+
expect.arrayContaining([
129+
expect.objectContaining({
130+
filename: expect.stringMatching(/simple\.wasm$/),
131+
platform: 'native',
132+
module_metadata: expect.objectContaining({
133+
'_sentryBundlerPluginAppKey:wasm-worker-app': true,
134+
}),
135+
}),
136+
]),
137+
);
138+
},
139+
);

dev-packages/bundle-analyzer-scenarios/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry-internal/bundle-analyzer-scenarios",
3-
"version": "10.36.0",
3+
"version": "10.37.0",
44
"description": "Scenarios to test bundle analysis with",
55
"repository": "git://github.com/getsentry/sentry-javascript.git",
66
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/dev-packages/bundle-analyzer-scenarios",

dev-packages/bundler-tests/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry-internal/bundler-tests",
3-
"version": "10.36.0",
3+
"version": "10.37.0",
44
"description": "Bundler tests for Sentry Browser SDK",
55
"repository": "git://github.com/getsentry/sentry-javascript.git",
66
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/bundler-tests",
@@ -13,7 +13,7 @@
1313
},
1414
"dependencies": {
1515
"@rollup/plugin-node-resolve": "^15.2.3",
16-
"@sentry/browser": "10.36.0",
16+
"@sentry/browser": "10.37.0",
1717
"rollup": "^4.0.0",
1818
"vite": "^5.0.0",
1919
"vitest": "^3.2.4",

dev-packages/clear-cache-gh-action/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@sentry-internal/clear-cache-gh-action",
33
"description": "An internal Github Action to clear GitHub caches.",
4-
"version": "10.36.0",
4+
"version": "10.37.0",
55
"license": "MIT",
66
"engines": {
77
"node": ">=18"

0 commit comments

Comments
 (0)