Skip to content

Commit e615479

Browse files
committed
fix(nextjs): support next v15.0.0-canary.180 or higher
1 parent d7c33a2 commit e615479

File tree

4 files changed

+45
-9
lines changed

4 files changed

+45
-9
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"@types/node": "18.11.17",
1818
"@types/react": "18.0.26",
1919
"@types/react-dom": "18.0.9",
20-
"next": "15.0.0-canary.112",
20+
"next": "15.0.0-canary.182",
2121
"react": "beta",
2222
"react-dom": "beta",
2323
"typescript": "4.9.5"

packages/nextjs/src/config/templates/routeHandlerWrapperTemplate.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,29 @@ import * as Sentry from '@sentry/nextjs';
22
import type { WebFetchHeaders } from '@sentry/types';
33
// @ts-expect-error Because we cannot be sure if the RequestAsyncStorage module exists (it is not part of the Next.js public
44
// API) we use a shim if it doesn't exist. The logic for this is in the wrapping loader.
5-
import { requestAsyncStorage } from '__SENTRY_NEXTJS_REQUEST_ASYNC_STORAGE_SHIM__';
5+
import * as origModule from '__SENTRY_NEXTJS_REQUEST_ASYNC_STORAGE_SHIM__';
66
// @ts-expect-error See above
77
import * as routeModule from '__SENTRY_WRAPPING_TARGET_FILE__';
88

99
import type { RequestAsyncStorage } from './requestAsyncStorageShim';
1010

11+
type NextAsyncStorageModule =
12+
| {
13+
workUnitAsyncStorage: RequestAsyncStorage;
14+
}
15+
| {
16+
requestAsyncStorage: RequestAsyncStorage;
17+
};
18+
19+
const asyncStorageModule = { ...origModule } as NextAsyncStorageModule;
20+
21+
const requestAsyncStorage: RequestAsyncStorage | undefined =
22+
'workUnitAsyncStorage' in asyncStorageModule
23+
? asyncStorageModule.workUnitAsyncStorage
24+
: 'requestAsyncStorage' in asyncStorageModule
25+
? asyncStorageModule.requestAsyncStorage
26+
: undefined;
27+
1128
function wrapHandler<T>(handler: T, method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'): T {
1229
// Running the instrumentation code during the build phase will mark any function as "dynamic" because we're accessing
1330
// the Request object. We do not want to turn handlers dynamic so we skip instrumentation in the build phase.
@@ -28,7 +45,7 @@ function wrapHandler<T>(handler: T, method: 'GET' | 'POST' | 'PUT' | 'PATCH' | '
2845
// We try-catch here just in case the API around `requestAsyncStorage` changes unexpectedly since it is not public API
2946
try {
3047
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
31-
const requestAsyncStore = requestAsyncStorage.getStore() as ReturnType<RequestAsyncStorage['getStore']>;
48+
const requestAsyncStore = requestAsyncStorage?.getStore() as ReturnType<RequestAsyncStorage['getStore']>;
3249
sentryTraceHeader = requestAsyncStore?.headers.get('sentry-trace') ?? undefined;
3350
baggageHeader = requestAsyncStore?.headers.get('baggage') ?? undefined;
3451
headers = requestAsyncStore?.headers;
@@ -54,8 +71,6 @@ export * from '__SENTRY_WRAPPING_TARGET_FILE__';
5471
// @ts-expect-error This is the file we're wrapping
5572
export { default } from '__SENTRY_WRAPPING_TARGET_FILE__';
5673

57-
declare const requestAsyncStorage: RequestAsyncStorage;
58-
5974
type RouteHandler = (...args: unknown[]) => unknown;
6075

6176
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access

packages/nextjs/src/config/templates/serverComponentWrapperTemplate.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,29 @@ import * as Sentry from '@sentry/nextjs';
22
import type { WebFetchHeaders } from '@sentry/types';
33
// @ts-expect-error Because we cannot be sure if the RequestAsyncStorage module exists (it is not part of the Next.js public
44
// API) we use a shim if it doesn't exist. The logic for this is in the wrapping loader.
5-
// biome-ignore lint/nursery/noUnusedImports: Biome doesn't understand the shim with variable import path
6-
import { requestAsyncStorage } from '__SENTRY_NEXTJS_REQUEST_ASYNC_STORAGE_SHIM__';
5+
import * as origModule from '__SENTRY_NEXTJS_REQUEST_ASYNC_STORAGE_SHIM__';
76
// @ts-expect-error We use `__SENTRY_WRAPPING_TARGET_FILE__` as a placeholder for the path to the file being wrapped.
87
// biome-ignore lint/nursery/noUnusedImports: Biome doesn't understand the shim with variable import path
98
import * as serverComponentModule from '__SENTRY_WRAPPING_TARGET_FILE__';
109

1110
import type { RequestAsyncStorage } from './requestAsyncStorageShim';
1211

13-
declare const requestAsyncStorage: RequestAsyncStorage;
12+
type NextAsyncStorageModule =
13+
| {
14+
workUnitAsyncStorage: RequestAsyncStorage;
15+
}
16+
| {
17+
requestAsyncStorage: RequestAsyncStorage;
18+
};
19+
20+
const asyncStorageModule = { ...origModule } as NextAsyncStorageModule;
21+
22+
const requestAsyncStorage: RequestAsyncStorage | undefined =
23+
'workUnitAsyncStorage' in asyncStorageModule
24+
? asyncStorageModule.workUnitAsyncStorage
25+
: 'requestAsyncStorage' in asyncStorageModule
26+
? asyncStorageModule.requestAsyncStorage
27+
: undefined;
1428

1529
declare const serverComponentModule: {
1630
default: unknown;
@@ -34,7 +48,8 @@ if (typeof serverComponent === 'function') {
3448

3549
// We try-catch here just in `requestAsyncStorage` is undefined since it may not be defined
3650
try {
37-
const requestAsyncStore = requestAsyncStorage.getStore();
51+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
52+
const requestAsyncStore = requestAsyncStorage?.getStore() as ReturnType<RequestAsyncStorage['getStore']>;
3853
sentryTraceHeader = requestAsyncStore?.headers.get('sentry-trace') ?? undefined;
3954
baggageHeader = requestAsyncStore?.headers.get('baggage') ?? undefined;
4055
headers = requestAsyncStore?.headers;

packages/nextjs/src/config/webpack.ts

+6
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,12 @@ const POTENTIAL_REQUEST_ASYNC_STORAGE_LOCATIONS = [
644644
// Introduced in Next.js 13.4.20
645645
// https://github.com/vercel/next.js/blob/e1bc270830f2fc2df3542d4ef4c61b916c802df3/packages/next/src/client/components/request-async-storage.external.ts
646646
'next/dist/client/components/request-async-storage.external.js',
647+
// Introduced in Next.js 15.0.0-canary.180
648+
// https://github.com/vercel/next.js/blob/541167b9b0fed6af9f36472e632863ffec41f18c/packages/next/src/server/app-render/work-unit-async-storage.external.ts
649+
'next/dist/server/app-render/work-unit-async-storage.external.js',
650+
// Introduced in Next.js 15.0.0-canary.182
651+
// https://github.com/vercel/next.js/blob/f35159e5e80138ca7373f57b47edcaae3bcf1728/packages/next/src/client/components/work-unit-async-storage.external.ts
652+
'next/dist/client/components/work-unit-async-storage.external.js',
647653
];
648654

649655
function getRequestAsyncStorageModuleLocation(

0 commit comments

Comments
 (0)