Skip to content

Commit aa37922

Browse files
authored
Merge branch 'develop' into sig/nuxt-cloudflare
2 parents db78cd8 + 7226ba9 commit aa37922

File tree

143 files changed

+5427
-202
lines changed

Some content is hidden

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

143 files changed

+5427
-202
lines changed

CHANGELOG.md

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

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

7+
## 9.33.0
8+
9+
### Important Changes
10+
11+
- **feat: Add opt-in `vercelAiIntegration` to cloudflare & vercel-edge ([#16732](https://github.com/getsentry/sentry-javascript/pull/16732))**
12+
13+
The `vercelAiIntegration` is now available as opt-in for the Cloudflare and the Next.js SDK for Vercel Edge.
14+
To use it, add the integration in `Sentry.init`
15+
16+
```js
17+
Sentry.init({
18+
tracesSampleRate: 1.0,
19+
integrations: [Sentry.vercelAIIntegration()],
20+
});
21+
```
22+
23+
And enable telemetry for Vercel AI calls
24+
25+
```js
26+
const result = await generateText({
27+
model: openai('gpt-4o'),
28+
experimental_telemetry: {
29+
isEnabled: true,
30+
},
31+
});
32+
```
33+
34+
- **feat(node): Add postgresjs instrumentation ([#16665](https://github.com/getsentry/sentry-javascript/pull/16665))**
35+
36+
The Node.js SDK now includes instrumentation for [Postgres.js](https://www.npmjs.com/package/postgres).
37+
38+
- **feat(node): Use diagnostics channel for Fastify v5 error handling ([#16715](https://github.com/getsentry/sentry-javascript/pull/16715))**
39+
40+
If you're on Fastify v5, you no longer need to call `setupFastifyErrorHandler`. It is done automatically by the node SDK. Older versions still rely on calling `setupFastifyErrorHandler`.
41+
42+
### Other Changes
43+
44+
- feat(cloudflare): Allow interop with OpenTelemetry emitted spans ([#16714](https://github.com/getsentry/sentry-javascript/pull/16714))
45+
- feat(cloudflare): Flush after `waitUntil` ([#16681](https://github.com/getsentry/sentry-javascript/pull/16681))
46+
- fix(nextjs): Remove `ai` from default server external packages ([#16736](https://github.com/getsentry/sentry-javascript/pull/16736))
47+
48+
Work in this release was contributed by @0xbad0c0d3. Thank you for your contribution!
49+
750
## 9.32.0
851

952
### Important Changes

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": "9.32.0",
3+
"version": "9.33.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.34.0",
45-
"@sentry/browser": "9.32.0",
45+
"@sentry/browser": "9.33.0",
4646
"@supabase/supabase-js": "2.49.3",
4747
"axios": "1.8.2",
4848
"babel-loader": "^8.2.2",

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": "9.32.0",
3+
"version": "9.33.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/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": "9.32.0",
4+
"version": "9.33.0",
55
"license": "MIT",
66
"engines": {
77
"node": ">=18"

dev-packages/e2e-tests/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/e2e-tests",
3-
"version": "9.32.0",
3+
"version": "9.33.0",
44
"license": "MIT",
55
"private": true,
66
"scripts": {

dev-packages/e2e-tests/test-applications/angular-20/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
"typescript": "~5.8.3"
4747
},
4848
"volta": {
49-
"extends": "../../package.json",
50-
"node": "20.19.2"
49+
"extends": "../../package.json"
5150
}
5251
}

dev-packages/e2e-tests/test-applications/node-fastify-5/src/app.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ const app = fastify();
3434
const port = 3030;
3535
const port2 = 3040;
3636

37-
Sentry.setupFastifyErrorHandler(app);
38-
3937
app.get('/test-success', function (_req, res) {
4038
res.send({ version: 'v1' });
4139
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
25+
/test-results/
26+
/playwright-report/
27+
/playwright/.cache/
28+
29+
!*.d.ts
30+
31+
# react router
32+
.react-router
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
html,
2+
body {
3+
@media (prefers-color-scheme: dark) {
4+
color-scheme: dark;
5+
}
6+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as Sentry from '@sentry/react-router';
2+
import { StrictMode, startTransition } from 'react';
3+
import { hydrateRoot } from 'react-dom/client';
4+
import { HydratedRouter } from 'react-router/dom';
5+
6+
Sentry.init({
7+
environment: 'qa', // dynamic sampling bias to keep transactions
8+
// todo: get this from env
9+
dsn: 'https://username@domain/123',
10+
tunnel: `http://localhost:3031/`, // proxy server
11+
integrations: [Sentry.reactRouterTracingIntegration()],
12+
tracesSampleRate: 1.0,
13+
tracePropagationTargets: [/^\//],
14+
});
15+
16+
startTransition(() => {
17+
hydrateRoot(
18+
document,
19+
<StrictMode>
20+
<HydratedRouter />
21+
</StrictMode>,
22+
);
23+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { createReadableStreamFromReadable } from '@react-router/node';
2+
import * as Sentry from '@sentry/react-router';
3+
import { renderToPipeableStream } from 'react-dom/server';
4+
import { ServerRouter } from 'react-router';
5+
import { type HandleErrorFunction } from 'react-router';
6+
7+
const ABORT_DELAY = 5_000;
8+
9+
const handleRequest = Sentry.createSentryHandleRequest({
10+
streamTimeout: ABORT_DELAY,
11+
ServerRouter,
12+
renderToPipeableStream,
13+
createReadableStreamFromReadable,
14+
});
15+
16+
export default handleRequest;
17+
18+
export const handleError: HandleErrorFunction = (error, { request }) => {
19+
// React Router may abort some interrupted requests, don't log those
20+
if (!request.signal.aborted) {
21+
Sentry.captureException(error);
22+
23+
// make sure to still log the error so you can see it
24+
console.error(error);
25+
}
26+
};
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as Sentry from '@sentry/react-router';
2+
import { Links, Meta, Outlet, Scripts, ScrollRestoration, isRouteErrorResponse } from 'react-router';
3+
import type { Route } from './+types/root';
4+
import stylesheet from './app.css?url';
5+
6+
export const links: Route.LinksFunction = () => [
7+
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
8+
{
9+
rel: 'preconnect',
10+
href: 'https://fonts.gstatic.com',
11+
crossOrigin: 'anonymous',
12+
},
13+
{
14+
rel: 'stylesheet',
15+
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
16+
},
17+
{ rel: 'stylesheet', href: stylesheet },
18+
];
19+
20+
export function Layout({ children }: { children: React.ReactNode }) {
21+
return (
22+
<html lang="en">
23+
<head>
24+
<meta charSet="utf-8" />
25+
<meta name="viewport" content="width=device-width, initial-scale=1" />
26+
<Meta />
27+
<Links />
28+
</head>
29+
<body>
30+
{children}
31+
<ScrollRestoration />
32+
<Scripts />
33+
</body>
34+
</html>
35+
);
36+
}
37+
38+
export default function App() {
39+
return <Outlet />;
40+
}
41+
42+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
43+
let message = 'Oops!';
44+
let details = 'An unexpected error occurred.';
45+
let stack: string | undefined;
46+
47+
if (isRouteErrorResponse(error)) {
48+
message = error.status === 404 ? '404' : 'Error';
49+
details = error.status === 404 ? 'The requested page could not be found.' : error.statusText || details;
50+
} else if (error && error instanceof Error) {
51+
Sentry.captureException(error);
52+
if (import.meta.env.DEV) {
53+
details = error.message;
54+
stack = error.stack;
55+
}
56+
}
57+
58+
return (
59+
<main className="pt-16 p-4 container mx-auto">
60+
<h1>{message}</h1>
61+
<p>{details}</p>
62+
{stack && (
63+
<pre className="w-full p-4 overflow-x-auto">
64+
<code>{stack}</code>
65+
</pre>
66+
)}
67+
</main>
68+
);
69+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { type RouteConfig, index, prefix, route } from '@react-router/dev/routes';
2+
3+
export default [
4+
index('routes/home.tsx'),
5+
...prefix('errors', [
6+
route('client', 'routes/errors/client.tsx'),
7+
route('client/:client-param', 'routes/errors/client-param.tsx'),
8+
route('client-loader', 'routes/errors/client-loader.tsx'),
9+
route('server-loader', 'routes/errors/server-loader.tsx'),
10+
route('client-action', 'routes/errors/client-action.tsx'),
11+
route('server-action', 'routes/errors/server-action.tsx'),
12+
]),
13+
...prefix('performance', [
14+
index('routes/performance/index.tsx'),
15+
route('ssr', 'routes/performance/ssr.tsx'),
16+
route('with/:param', 'routes/performance/dynamic-param.tsx'),
17+
route('static', 'routes/performance/static.tsx'),
18+
route('server-loader', 'routes/performance/server-loader.tsx'),
19+
route('server-action', 'routes/performance/server-action.tsx'),
20+
]),
21+
] satisfies RouteConfig;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Form } from 'react-router';
2+
3+
export function clientAction() {
4+
throw new Error('Madonna mia! Che casino nella Client Action!');
5+
}
6+
7+
export default function ClientActionErrorPage() {
8+
return (
9+
<div>
10+
<h1>Client Error Action Page</h1>
11+
<Form method="post">
12+
<button id="submit" type="submit">
13+
Submit
14+
</button>
15+
</Form>
16+
</div>
17+
);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { Route } from './+types/server-loader';
2+
3+
export function clientLoader() {
4+
throw new Error('¡Madre mía del client loader!');
5+
return { data: 'sad' };
6+
}
7+
8+
export default function ClientLoaderErrorPage({ loaderData }: Route.ComponentProps) {
9+
const { data } = loaderData;
10+
return (
11+
<div>
12+
<h1>Client Loader Error Page</h1>
13+
<div>{data}</div>
14+
</div>
15+
);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { Route } from './+types/client-param';
2+
3+
export default function ClientErrorParamPage({ params }: Route.ComponentProps) {
4+
return (
5+
<div>
6+
<h1>Client Error Param Page</h1>
7+
<button
8+
id="throw-on-click"
9+
onClick={() => {
10+
throw new Error(`¡Madre mía de ${params['client-param']}!`);
11+
}}
12+
>
13+
Throw Error
14+
</button>
15+
</div>
16+
);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function ClientErrorPage() {
2+
return (
3+
<div>
4+
<h1>Client Error Page</h1>
5+
<button
6+
id="throw-on-click"
7+
onClick={() => {
8+
throw new Error('¡Madre mía!');
9+
}}
10+
>
11+
Throw Error
12+
</button>
13+
</div>
14+
);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Form } from 'react-router';
2+
3+
export function action() {
4+
throw new Error('Madonna mia! Che casino nella Server Action!');
5+
}
6+
7+
export default function ServerActionErrorPage() {
8+
return (
9+
<div>
10+
<h1>Server Error Action Page</h1>
11+
<Form method="post">
12+
<button id="submit" type="submit">
13+
Submit
14+
</button>
15+
</Form>
16+
</div>
17+
);
18+
}

0 commit comments

Comments
 (0)