Skip to content

Commit 70811c9

Browse files
authored
Merge pull request #17807 from getsentry/prepare-release/10.16.0
meta(changelog): Update changelog for 10.16.0
2 parents 863c169 + 55d8514 commit 70811c9

File tree

38 files changed

+1716
-210
lines changed

38 files changed

+1716
-210
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Release Command
2+
3+
Execute the standard Sentry JavaScript SDK release process.
4+
5+
Find the "publishing_release" rule in `.cursor/rules/publishing_release` and follow those complete instructions step by step.

CHANGELOG.md

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

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

7+
## 10.16.0
8+
9+
- feat(logs): Add internal `replay_is_buffering` flag ([#17752](https://github.com/getsentry/sentry-javascript/pull/17752))
10+
- feat(react-router): Update loadContext type to be compatible with middleware ([#17758](https://github.com/getsentry/sentry-javascript/pull/17758))
11+
- feat(replay/logs): Only attach sampled replay Ids to logs ([#17750](https://github.com/getsentry/sentry-javascript/pull/17750))
12+
- fix(browser): Use current start timestamp for CLS span when CLS is 0 ([#17800](https://github.com/getsentry/sentry-javascript/pull/17800))
13+
- fix(core): Prevent `instrumentAnthropicAiClient` breaking MessageStream api ([#17754](https://github.com/getsentry/sentry-javascript/pull/17754))
14+
- fix(nextjs): Don't use chalk in turbopack config file ([#17806](https://github.com/getsentry/sentry-javascript/pull/17806))
15+
- fix(react): Do not send additional navigation span on pageload ([#17799](https://github.com/getsentry/sentry-javascript/pull/17799))
16+
17+
<details>
18+
<summary> <strong>Internal Changes</strong> </summary>
19+
20+
- build(aws): Ensure AWS build cache does not keep old files ([#17776](https://github.com/getsentry/sentry-javascript/pull/17776))
21+
- chore: Add `publish_release` command ([#17797](https://github.com/getsentry/sentry-javascript/pull/17797))
22+
- ref(aws-serverless): Add resolution for `import-in-the-middle` when building the Lambda layer ([#17780](https://github.com/getsentry/sentry-javascript/pull/17780))
23+
- ref(aws-serverless): Improve README with better examples ([#17787](https://github.com/getsentry/sentry-javascript/pull/17787))
24+
- ref(core): Improve promise buffer ([#17788](https://github.com/getsentry/sentry-javascript/pull/17788))
25+
- Revert "test(e2e): Pin `import-in-the-middle@1.14.2` due to `@vercel/nft` incompatibility ([#17777](https://github.com/getsentry/sentry-javascript/pull/17777))" (#17784)
26+
- test(e2e): Pin `import-in-the-middle@1.14.2` due to `@vercel/nft` incompatibility ([#17777](https://github.com/getsentry/sentry-javascript/pull/17777))
27+
- test(nextjs): Add route handler tests for turbopack ([#17515](https://github.com/getsentry/sentry-javascript/pull/17515))
28+
- test(react-router): Test v8 middleware ([#17783](https://github.com/getsentry/sentry-javascript/pull/17783))
29+
30+
</details>
31+
732
## 10.15.0
833

934
### Important Changes
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export async function GET(request: Request) {
2+
throw new Error('Dynamic route handler error');
3+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { NextResponse } from 'next/server';
2+
3+
export async function GET() {
4+
return NextResponse.json({ name: 'Beep' });
5+
}
6+
7+
export async function POST() {
8+
return NextResponse.json({ name: 'Boop' }, { status: 400 });
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { NextResponse } from 'next/server';
2+
3+
export async function GET(request: Request) {
4+
return NextResponse.json({ name: 'Static' });
5+
}

dev-packages/e2e-tests/test-applications/nextjs-turbo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"@types/node": "^18.19.1",
1818
"@types/react": "^19",
1919
"@types/react-dom": "^19",
20-
"next": "^15.3.5",
20+
"next": "^15.5.4",
2121
"react": "^19",
2222
"react-dom": "^19",
2323
"typescript": "~5.0.0"
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
3+
4+
test('Should create a transaction for dynamic route handlers', async ({ request }) => {
5+
const routehandlerTransactionPromise = waitForTransaction('nextjs-turbo', async transactionEvent => {
6+
return transactionEvent?.transaction === 'GET /route-handlers/[param]';
7+
});
8+
9+
const response = await request.get('/route-handlers/foo');
10+
expect(await response.json()).toStrictEqual({ name: 'Beep' });
11+
12+
const routehandlerTransaction = await routehandlerTransactionPromise;
13+
14+
expect(routehandlerTransaction.contexts?.trace?.status).toBe('ok');
15+
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
16+
});
17+
18+
test('Should create a transaction for static route handlers', async ({ request }) => {
19+
const routehandlerTransactionPromise = waitForTransaction('nextjs-turbo', async transactionEvent => {
20+
return transactionEvent?.transaction === 'GET /route-handlers/static';
21+
});
22+
23+
const response = await request.get('/route-handlers/static');
24+
expect(await response.json()).toStrictEqual({ name: 'Static' });
25+
26+
const routehandlerTransaction = await routehandlerTransactionPromise;
27+
28+
expect(routehandlerTransaction.contexts?.trace?.status).toBe('ok');
29+
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
30+
});
31+
32+
test('Should create a transaction for route handlers and correctly set span status depending on http status', async ({
33+
request,
34+
}) => {
35+
const routehandlerTransactionPromise = waitForTransaction('nextjs-turbo', async transactionEvent => {
36+
return transactionEvent?.transaction === 'POST /route-handlers/[param]';
37+
});
38+
39+
const response = await request.post('/route-handlers/bar');
40+
expect(await response.json()).toStrictEqual({ name: 'Boop' });
41+
42+
const routehandlerTransaction = await routehandlerTransactionPromise;
43+
44+
expect(routehandlerTransaction.contexts?.trace?.status).toBe('invalid_argument');
45+
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
46+
});
47+
48+
test('Should record exceptions and transactions for faulty route handlers', async ({ request }) => {
49+
const errorEventPromise = waitForError('nextjs-turbo', errorEvent => {
50+
return errorEvent?.exception?.values?.[0]?.value === 'Dynamic route handler error';
51+
});
52+
53+
const routehandlerTransactionPromise = waitForTransaction('nextjs-turbo', async transactionEvent => {
54+
return transactionEvent?.transaction === 'GET /route-handlers/[param]/error';
55+
});
56+
57+
await request.get('/route-handlers/boop/error').catch(() => {});
58+
59+
const routehandlerTransaction = await routehandlerTransactionPromise;
60+
const routehandlerError = await errorEventPromise;
61+
62+
expect(routehandlerTransaction.contexts?.trace?.status).toBe('internal_error');
63+
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
64+
expect(routehandlerTransaction.contexts?.trace?.origin).toContain('auto');
65+
66+
expect(routehandlerError.exception?.values?.[0].value).toBe('Dynamic route handler error');
67+
68+
expect(routehandlerError.request?.method).toBe('GET');
69+
// todo: make sure url is attached to request object
70+
// expect(routehandlerError.request?.url).toContain('/route-handlers/boop/error');
71+
72+
expect(routehandlerError.transaction).toBe('/route-handlers/[param]/error');
73+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createContext } from 'react-router';
2+
3+
export type User = {
4+
id: string;
5+
name: string;
6+
};
7+
8+
export const userContext = createContext<User | null>(null);

dev-packages/e2e-tests/test-applications/react-router-7-framework/app/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ export default [
1717
route('static', 'routes/performance/static.tsx'),
1818
route('server-loader', 'routes/performance/server-loader.tsx'),
1919
route('server-action', 'routes/performance/server-action.tsx'),
20+
route('with-middleware', 'routes/performance/with-middleware.tsx'),
2021
]),
2122
] satisfies RouteConfig;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { Route } from './+types/with-middleware';
2+
import type { User } from '../../context';
3+
import { userContext } from '../../context';
4+
import * as Sentry from '@sentry/react-router';
5+
6+
async function getUser() {
7+
await new Promise(resolve => setTimeout(resolve, 500));
8+
return {
9+
id: '1',
10+
name: 'Carlos Gomez',
11+
};
12+
}
13+
14+
const authMiddleware: Route.MiddlewareFunction = async ({ request, context }, next) => {
15+
Sentry.startSpan({ name: 'authMiddleware', op: 'middleware.auth' }, async () => {
16+
const user: User = await getUser();
17+
context.set(userContext, user);
18+
await next();
19+
});
20+
};
21+
22+
export const middleware: Route.MiddlewareFunction[] = [authMiddleware];
23+
24+
export const loader = async ({ context }: Route.LoaderArgs) => {
25+
const user = context.get(userContext);
26+
return { user };
27+
};
28+
29+
export default function WithMiddlewarePage({ loaderData }: Route.ComponentProps) {
30+
const { user } = loaderData;
31+
32+
return (
33+
<div>
34+
<h1>With Middleware Page</h1>
35+
<p>User: {user?.name}</p>
36+
</div>
37+
);
38+
}

0 commit comments

Comments
 (0)