Skip to content

Commit e8ea26f

Browse files
committed
await params
1 parent 8393b79 commit e8ea26f

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

packages/nextjs/src/common/utils/wrapperUtils.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getRootSpan,
77
getTraceData,
88
httpRequestToRequestData,
9+
isThenable,
910
} from '@sentry/core';
1011
import type { IncomingMessage, ServerResponse } from 'http';
1112
import { TRANSACTION_ATTR_SENTRY_ROUTE_BACKFILL } from '../span-attributes-with-logic-attached';
@@ -102,3 +103,39 @@ export async function callDataFetcherTraced<F extends (...args: any[]) => Promis
102103
throw e;
103104
}
104105
}
106+
107+
/**
108+
* Extracts the params and searchParams from the props object.
109+
*
110+
* Depending on the next version, params and searchParams may be a promise.
111+
*/
112+
export async function safeExtractParamsAndSearchParamsFromProps(props: unknown): Promise<{
113+
params: Record<string, string> | undefined;
114+
searchParams: Record<string, string> | undefined;
115+
}> {
116+
let params =
117+
props && typeof props === 'object' && 'params' in props
118+
? (props.params as Record<string, string> | Promise<Record<string, string>> | undefined)
119+
: undefined;
120+
if (isThenable(params)) {
121+
try {
122+
params = await params;
123+
} catch (e) {
124+
params = undefined;
125+
}
126+
}
127+
128+
let searchParams =
129+
props && typeof props === 'object' && 'searchParams' in props
130+
? (props.searchParams as Record<string, string> | Promise<Record<string, string>> | undefined)
131+
: undefined;
132+
if (isThenable(searchParams)) {
133+
try {
134+
searchParams = await searchParams;
135+
} catch (e) {
136+
searchParams = undefined;
137+
}
138+
}
139+
140+
return { params, searchParams };
141+
}

packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavi
2424
import { TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL } from './span-attributes-with-logic-attached';
2525
import { commonObjectToIsolationScope, commonObjectToPropagationContext } from './utils/tracingUtils';
2626
import { getSanitizedRequestUrl } from './utils/urls';
27+
import { safeExtractParamsAndSearchParamsFromProps } from './utils/wrapperUtils';
2728
/**
2829
* Wraps a generation function (e.g. generateMetadata) with Sentry error and performance instrumentation.
2930
*/
@@ -34,7 +35,7 @@ export function wrapGenerationFunctionWithSentry<F extends (...args: any[]) => a
3435
): F {
3536
const { requestAsyncStorage, componentRoute, componentType, generationFunctionIdentifier } = context;
3637
return new Proxy(generationFunction, {
37-
apply: (originalFunction, thisArg, args) => {
38+
apply: async (originalFunction, thisArg, args) => {
3839
const requestTraceId = getActiveSpan()?.spanContext().traceId;
3940
let headers: WebFetchHeaders | undefined = undefined;
4041
// We try-catch here just in case anything goes wrong with the async storage here goes wrong since it is Next.js internal API
@@ -65,9 +66,7 @@ export function wrapGenerationFunctionWithSentry<F extends (...args: any[]) => a
6566
let data: Record<string, unknown> | undefined = undefined;
6667
if (getClient()?.getOptions().sendDefaultPii) {
6768
const props: unknown = args[0];
68-
const params = props && typeof props === 'object' && 'params' in props ? props.params : undefined;
69-
const searchParams =
70-
props && typeof props === 'object' && 'searchParams' in props ? props.searchParams : undefined;
69+
const { params, searchParams } = await safeExtractParamsAndSearchParamsFromProps(props);
7170
data = { params, searchParams };
7271
}
7372

packages/nextjs/src/common/wrapServerComponentWithSentry.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL } from './span-attributes-with-l
2626
import { flushSafelyWithTimeout } from './utils/responseEnd';
2727
import { commonObjectToIsolationScope, commonObjectToPropagationContext } from './utils/tracingUtils';
2828
import { getSanitizedRequestUrl } from './utils/urls';
29+
import { safeExtractParamsAndSearchParamsFromProps } from './utils/wrapperUtils';
2930

3031
/**
3132
* Wraps an `app` directory server component with Sentry error instrumentation.
@@ -40,7 +41,7 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
4041
// Next.js will turn them into synchronous functions and it will transform any `await`s into instances of the `use`
4142
// hook. 🤯
4243
return new Proxy(appDirComponent, {
43-
apply: (originalFunction, thisArg, args) => {
44+
apply: async (originalFunction, thisArg, args) => {
4445
const requestTraceId = getActiveSpan()?.spanContext().traceId;
4546
const isolationScope = commonObjectToIsolationScope(context.headers);
4647

@@ -64,10 +65,8 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
6465

6566
if (getClient()?.getOptions().sendDefaultPii) {
6667
const props: unknown = args[0];
67-
params =
68-
props && typeof props === 'object' && 'params' in props
69-
? (props.params as Record<string, string>)
70-
: undefined;
68+
const { params: paramsFromProps } = await safeExtractParamsAndSearchParamsFromProps(props);
69+
params = paramsFromProps;
7170
}
7271

7372
isolationScope.setSDKProcessingMetadata({

0 commit comments

Comments
 (0)