Skip to content

fix(nextjs): Export isomorphic data fetching wrappers from client SDK #6790

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jan 16, 2023
Merged
22 changes: 22 additions & 0 deletions packages/nextjs/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,25 @@ function addClientIntegrations(options: BrowserOptions): void {

options.integrations = integrations;
}

export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideGetInitialProps,
wrapGetInitialPropsWithSentry,
} from './wrapGetInitialPropsWithSentry';

export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideAppGetInitialProps,
wrapAppGetInitialPropsWithSentry,
} from './wrapAppGetInitialPropsWithSentry';
export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideDocumentGetInitialProps,
wrapDocumentGetInitialPropsWithSentry,
} from './wrapDocumentGetInitialPropsWithSentry';
export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideErrorGetInitialProps,
wrapErrorGetInitialPropsWithSentry,
} from './wrapErrorGetInitialPropsWithSentry';
18 changes: 18 additions & 0 deletions packages/nextjs/src/client/wrapAppGetInitialPropsWithSentry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type App from 'next/app';

type AppGetInitialProps = typeof App['getInitialProps'];

/**
* A passthrough function in case this function is used on the clientside. We need to make the returned function async
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we theoretically create spans instead of transactions here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we definitely could in the future!

* so we are consistent with the serverside implementation.
*/
export function wrapAppGetInitialPropsWithSentry(origAppGetInitialProps: AppGetInitialProps): AppGetInitialProps {
return async function (this: unknown, ...args: Parameters<AppGetInitialProps>): ReturnType<AppGetInitialProps> {
return await origAppGetInitialProps.apply(this, args);
};
}

/**
* @deprecated Use `wrapAppGetInitialPropsWithSentry` instead.
*/
export const withSentryServerSideAppGetInitialProps = wrapAppGetInitialPropsWithSentry;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type Document from 'next/document';

type DocumentGetInitialProps = typeof Document.getInitialProps;

/**
* A passthrough function in case this function is used on the clientside. We need to make the returned function async
* so we are consistent with the serverside implementation.
*/
export function wrapDocumentGetInitialPropsWithSentry(
origDocumentGetInitialProps: DocumentGetInitialProps,
): DocumentGetInitialProps {
return async function (
this: unknown,
...args: Parameters<DocumentGetInitialProps>
): ReturnType<DocumentGetInitialProps> {
return await origDocumentGetInitialProps.apply(this, args);
};
}

/**
* @deprecated Use `wrapDocumentGetInitialPropsWithSentry` instead.
*/
export const withSentryServerSideDocumentGetInitialProps = wrapDocumentGetInitialPropsWithSentry;
21 changes: 21 additions & 0 deletions packages/nextjs/src/client/wrapErrorGetInitialPropsWithSentry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { NextPageContext } from 'next';
import type { ErrorProps } from 'next/error';

type ErrorGetInitialProps = (context: NextPageContext) => Promise<ErrorProps>;

/**
* A passthrough function in case this function is used on the clientside. We need to make the returned function async
* so we are consistent with the serverside implementation.
*/
export function wrapErrorGetInitialPropsWithSentry(
origErrorGetInitialProps: ErrorGetInitialProps,
): ErrorGetInitialProps {
return async function (this: unknown, ...args: Parameters<ErrorGetInitialProps>): ReturnType<ErrorGetInitialProps> {
return await origErrorGetInitialProps.apply(this, args);
};
}

/**
* @deprecated Use `wrapErrorGetInitialPropsWithSentry` instead.
*/
export const withSentryServerSideErrorGetInitialProps = wrapErrorGetInitialPropsWithSentry;
18 changes: 18 additions & 0 deletions packages/nextjs/src/client/wrapGetInitialPropsWithSentry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { NextPage } from 'next';

type GetInitialProps = Required<NextPage>['getInitialProps'];

/**
* A passthrough function in case this function is used on the clientside. We need to make the returned function async
* so we are consistent with the serverside implementation.
*/
export function wrapGetInitialPropsWithSentry(origGetInitialProps: GetInitialProps): GetInitialProps {
return async function (this: unknown, ...args: Parameters<GetInitialProps>): Promise<ReturnType<GetInitialProps>> {
return origGetInitialProps.apply(this, args);
};
}

/**
* @deprecated Use `wrapGetInitialPropsWithSentry` instead.
*/
export const withSentryServerSideGetInitialProps = wrapGetInitialPropsWithSentry;
2 changes: 1 addition & 1 deletion packages/nextjs/src/config/templates/apiWrapperTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const config = {
},
};

export default userProvidedHandler ? Sentry.withSentryAPI(userProvidedHandler, '__ROUTE__') : undefined;
export default userProvidedHandler ? Sentry.wrapApiHandlerWithSentry(userProvidedHandler, '__ROUTE__') : undefined;

// Re-export anything exported by the page module we're wrapping. When processing this code, Rollup is smart enough to
// not include anything whose name matchs something we've explicitly exported above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ if ('middleware' in userApiModule && typeof userApiModule.middleware === 'functi
userProvidedDefaultHandler = userApiModule;
}

export const middleware = userProvidedNamedHandler ? Sentry.withSentryMiddleware(userProvidedNamedHandler) : undefined;
export default userProvidedDefaultHandler ? Sentry.withSentryMiddleware(userProvidedDefaultHandler) : undefined;
export const middleware = userProvidedNamedHandler
? Sentry.wrapMiddlewareWithSentry(userProvidedNamedHandler)
: undefined;
export default userProvidedDefaultHandler ? Sentry.wrapMiddlewareWithSentry(userProvidedDefaultHandler) : undefined;

// Re-export anything exported by the page module we're wrapping. When processing this code, Rollup is smart enough to
// not include anything whose name matchs something we've explicitly exported above.
Expand Down
12 changes: 6 additions & 6 deletions packages/nextjs/src/config/templates/pageWrapperTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,24 @@ const origGetStaticProps = userPageModule.getStaticProps;
const origGetServerSideProps = userPageModule.getServerSideProps;

const getInitialPropsWrappers: Record<string, any> = {
'/_app': Sentry.withSentryServerSideAppGetInitialProps,
'/_document': Sentry.withSentryServerSideDocumentGetInitialProps,
'/_error': Sentry.withSentryServerSideErrorGetInitialProps,
'/_app': Sentry.wrapAppGetInitialPropsWithSentry,
'/_document': Sentry.wrapDocumentGetInitialPropsWithSentry,
'/_error': Sentry.wrapErrorGetInitialPropsWithSentry,
};

const getInitialPropsWrapper = getInitialPropsWrappers['__ROUTE__'] || Sentry.withSentryServerSideGetInitialProps;
const getInitialPropsWrapper = getInitialPropsWrappers['__ROUTE__'] || Sentry.wrapGetInitialPropsWithSentry;

if (typeof origGetInitialProps === 'function') {
pageComponent.getInitialProps = getInitialPropsWrapper(origGetInitialProps) as NextPageComponent['getInitialProps'];
}

export const getStaticProps =
typeof origGetStaticProps === 'function'
? Sentry.withSentryGetStaticProps(origGetStaticProps, '__ROUTE__')
? Sentry.wrapGetStaticPropsWithSentry(origGetStaticProps, '__ROUTE__')
: undefined;
export const getServerSideProps =
typeof origGetServerSideProps === 'function'
? Sentry.withSentryGetServerSideProps(origGetServerSideProps, '__ROUTE__')
? Sentry.wrapGetServerSidePropsWithSentry(origGetServerSideProps, '__ROUTE__')
: undefined;

export default pageComponent;
Expand Down
10 changes: 8 additions & 2 deletions packages/nextjs/src/edge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,11 @@ export function lastEventId(): string | undefined {
export { flush } from './utils/flush';

export * from '@sentry/core';
export { withSentryAPI } from './withSentryAPI';
export { withSentryMiddleware } from './withSentryMiddleware';

export {
// eslint-disable-next-line deprecation/deprecation
withSentryAPI,
wrapApiHandlerWithSentry,
} from './wrapApiHandlerWithSentry';

export { wrapMiddlewareWithSentry } from './wrapMiddlewareWithSentry';
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { withEdgeWrapping } from './utils/edgeWrapperUtils';
/**
* Wraps a Next.js edge route handler with Sentry error and performance instrumentation.
*/
export function withSentryAPI<H extends EdgeRouteHandler>(
export function wrapApiHandlerWithSentry<H extends EdgeRouteHandler>(
handler: H,
parameterizedRoute: string,
): (...params: Parameters<H>) => Promise<ReturnType<H>> {
Expand All @@ -21,9 +21,14 @@ export function withSentryAPI<H extends EdgeRouteHandler>(
? `handler (${parameterizedRoute})`
: `${req.method} ${parameterizedRoute}`,
spanOp: activeSpan ? 'function' : 'http.server',
mechanismFunctionName: 'withSentryAPI',
mechanismFunctionName: 'wrapApiHandlerWithSentry',
});

return await wrappedHandler.apply(this, args);
};
}

/**
* @deprecated Use `wrapApiHandlerWithSentry` instead.
*/
export const withSentryAPI = wrapApiHandlerWithSentry;
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { withEdgeWrapping } from './utils/edgeWrapperUtils';

/**
* Wraps Next.js middleware with Sentry error and performance instrumentation.
*
* @param middleware The middleware handler.
* @returns a wrapped middleware handler.
*/
export function withSentryMiddleware<H extends EdgeRouteHandler>(
export function wrapMiddlewareWithSentry<H extends EdgeRouteHandler>(
middleware: H,
): (...params: Parameters<H>) => Promise<ReturnType<H>> {
return withEdgeWrapping(middleware, {
Expand Down
85 changes: 85 additions & 0 deletions packages/nextjs/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,94 @@ export declare function flush(timeout?: number | undefined): PromiseLike<boolean
export declare function lastEventId(): string | undefined;
export declare function getSentryRelease(fallback?: string): string | undefined;

/**
* @deprecated Use `wrapApiHandlerWithSentry` instead
*/
export declare function withSentryAPI<APIHandler extends (...args: any[]) => any>(
handler: APIHandler,
parameterizedRoute: string,
): (
...args: Parameters<APIHandler>
) => ReturnType<APIHandler> extends Promise<unknown> ? ReturnType<APIHandler> : Promise<ReturnType<APIHandler>>;

/**
* Wraps a Next.js API handler with Sentry error and performance instrumentation.
*
* @param handler The handler exported from the API route file.
* @param parameterizedRoute The page's parameterized route.
* @returns The wrapped handler.
*/
export declare function wrapApiHandlerWithSentry<APIHandler extends (...args: any[]) => any>(
handler: APIHandler,
parameterizedRoute: string,
): (
...args: Parameters<APIHandler>
) => ReturnType<APIHandler> extends Promise<unknown> ? ReturnType<APIHandler> : Promise<ReturnType<APIHandler>>;

/**
* Wraps a `getInitialProps` function with Sentry error and performance instrumentation.
*
* @param getInitialProps The `getInitialProps` function
* @returns A wrapped version of the function
*/
export declare function wrapGetInitialPropsWithSentry<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* @deprecated Use `wrapGetInitialPropsWithSentry` instead.
*/
export declare function withSentryServerSideGetInitialProps<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* Wraps a `getInitialProps` function of a custom `_app` page with Sentry error and performance instrumentation.
*
* @param getInitialProps The `getInitialProps` function
* @returns A wrapped version of the function
*/
export declare function wrapAppGetInitialPropsWithSentry<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* @deprecated Use `wrapAppGetInitialPropsWithSentry` instead.
*/
export declare function withSentryServerSideAppGetInitialProps<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* Wraps a `getInitialProps` function of a custom `_document` page with Sentry error and performance instrumentation.
*
* @param getInitialProps The `getInitialProps` function
* @returns A wrapped version of the function
*/
export declare function wrapDocumentGetInitialPropsWithSentry<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* @deprecated Use `wrapDocumentGetInitialPropsWithSentry` instead.
*/
export declare function withSentryServerSideDocumentGetInitialProps<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* Wraps a `getInitialProps` function of a custom `_error` page with Sentry error and performance instrumentation.
*
* @param getInitialProps The `getInitialProps` function
* @returns A wrapped version of the function
*/
export declare function wrapErrorGetInitialPropsWithSentry<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;

/**
* @deprecated Use `wrapErrorGetInitialPropsWithSentry` instead.
*/
export declare function withSentryServerSideErrorGetInitialProps<F extends (...args: any[]) => any>(
getInitialProps: F,
): (...args: Parameters<F>) => ReturnType<F> extends Promise<unknown> ? ReturnType<F> : Promise<ReturnType<F>>;
48 changes: 41 additions & 7 deletions packages/nextjs/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,44 @@ const deprecatedIsBuild = (): boolean => isBuild();
// eslint-disable-next-line deprecation/deprecation
export { deprecatedIsBuild as isBuild };

export { withSentryGetStaticProps } from './withSentryGetStaticProps';
export { withSentryServerSideGetInitialProps } from './withSentryServerSideGetInitialProps';
export { withSentryServerSideAppGetInitialProps } from './withSentryServerSideAppGetInitialProps';
export { withSentryServerSideDocumentGetInitialProps } from './withSentryServerSideDocumentGetInitialProps';
export { withSentryServerSideErrorGetInitialProps } from './withSentryServerSideErrorGetInitialProps';
export { withSentryGetServerSideProps } from './withSentryGetServerSideProps';
export { withSentry, withSentryAPI } from './withSentryAPI';
export {
// eslint-disable-next-line deprecation/deprecation
withSentryGetStaticProps,
wrapGetStaticPropsWithSentry,
} from './wrapGetStaticPropsWithSentry';

export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideGetInitialProps,
wrapGetInitialPropsWithSentry,
} from './wrapGetInitialPropsWithSentry';

export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideAppGetInitialProps,
wrapAppGetInitialPropsWithSentry,
} from './wrapAppGetInitialPropsWithSentry';
export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideDocumentGetInitialProps,
wrapDocumentGetInitialPropsWithSentry,
} from './wrapDocumentGetInitialPropsWithSentry';
export {
// eslint-disable-next-line deprecation/deprecation
withSentryServerSideErrorGetInitialProps,
wrapErrorGetInitialPropsWithSentry,
} from './wrapErrorGetInitialPropsWithSentry';

export {
// eslint-disable-next-line deprecation/deprecation
withSentryGetServerSideProps,
wrapGetServerSidePropsWithSentry,
} from './wrapGetServerSidePropsWithSentry';

export {
// eslint-disable-next-line deprecation/deprecation
withSentry,
// eslint-disable-next-line deprecation/deprecation
withSentryAPI,
wrapApiHandlerWithSentry,
} from './wrapApiHandlerWithSentry';
Loading