Skip to content

Commit

Permalink
fix(nextjs): Make all wrappers isomorphic and available in all runtim…
Browse files Browse the repository at this point in the history
…es (#8743)
  • Loading branch information
lforst authored Aug 8, 2023
1 parent 5044e6b commit fac2be8
Show file tree
Hide file tree
Showing 34 changed files with 130 additions and 395 deletions.
36 changes: 1 addition & 35 deletions packages/nextjs/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,38 +130,4 @@ export function withSentryConfig<T>(exportedUserNextConfig: T): T {
return exportedUserNextConfig;
}

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
withSentryGetStaticProps,
wrapGetStaticPropsWithSentry,
} from './wrapGetStaticPropsWithSentry';
export * from '../common';
20 changes: 0 additions & 20 deletions packages/nextjs/src/client/wrapAppGetInitialPropsWithSentry.ts

This file was deleted.

This file was deleted.

23 changes: 0 additions & 23 deletions packages/nextjs/src/client/wrapErrorGetInitialPropsWithSentry.ts

This file was deleted.

20 changes: 0 additions & 20 deletions packages/nextjs/src/client/wrapGetInitialPropsWithSentry.ts

This file was deleted.

18 changes: 0 additions & 18 deletions packages/nextjs/src/client/wrapGetServerSidePropsWithSentry.ts

This file was deleted.

20 changes: 0 additions & 20 deletions packages/nextjs/src/client/wrapGetStaticPropsWithSentry.ts

This file was deleted.

41 changes: 41 additions & 0 deletions packages/nextjs/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 { wrapServerComponentWithSentry } from './wrapServerComponentWithSentry';

export { wrapApiHandlerWithSentryVercelCrons } from './wrapApiHandlerWithSentryVercelCrons';

export { wrapMiddlewareWithSentry } from './wrapMiddlewareWithSentry';
51 changes: 51 additions & 0 deletions packages/nextjs/src/common/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { Transaction, WrappedFunction } from '@sentry/types';
import type { NextApiRequest, NextApiResponse } from 'next';

export type ServerComponentContext = {
componentRoute: string;
componentType: string;
Expand All @@ -6,3 +9,51 @@ export type ServerComponentContext = {
};

export type VercelCronsConfig = { path?: string; schedule?: string }[] | undefined;

// The `NextApiHandler` and `WrappedNextApiHandler` types are the same as the official `NextApiHandler` type, except:
//
// a) The wrapped version returns only promises, because wrapped handlers are always async.
//
// b) Instead of having a return types based on `void` (Next < 12.1.6) or `unknown` (Next 12.1.6+), both the wrapped and
// unwrapped versions of the type have both. This doesn't matter to users, because they exist solely on one side of that
// version divide or the other. For us, though, it's entirely possible to have one version of Next installed in our
// local repo (as a dev dependency) and have another Next version installed in a test app which also has the local SDK
// linked in.
//
// In that case, if those two versions are on either side of the 12.1.6 divide, importing the official `NextApiHandler`
// type here would break the test app's build, because it would set up a situation in which the linked SDK's
// `withSentry` would refer to one version of the type (from the local repo's `node_modules`) while any typed handler in
// the test app would refer to the other version of the type (from the test app's `node_modules`). By using a custom
// version of the type compatible with both the old and new official versions, we can use any Next version we want in a
// test app without worrying about type errors.
//
// c) These have internal SDK flags which the official Next types obviously don't have, one to allow our auto-wrapping
// function, `withSentryAPI`, to pass the parameterized route into `withSentry`, and the other to prevent a manually
// wrapped route from being wrapped again by the auto-wrapper.

export type NextApiHandler = {
(req: NextApiRequest, res: NextApiResponse): void | Promise<void> | unknown | Promise<unknown>;
__sentry_route__?: string;

/**
* A property we set in our integration tests to simulate running an API route on platforms that don't support streaming.
*/
__sentry_test_doesnt_support_streaming__?: true;
};

export type WrappedNextApiHandler = {
(req: NextApiRequest, res: NextApiResponse): Promise<void> | Promise<unknown>;
__sentry_route__?: string;
__sentry_wrapped__?: boolean;
};

export type AugmentedNextApiRequest = NextApiRequest & {
__withSentry_applied__?: boolean;
};

export type AugmentedNextApiResponse = NextApiResponse & {
__sentryTransaction?: Transaction;
};

export type ResponseEndMethod = AugmentedNextApiResponse['end'];
export type WrappedResponseEndMethod = AugmentedNextApiResponse['end'] & WrappedFunction;
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { captureException, getCurrentHub, hasTracingEnabled, startTransaction } from '@sentry/core';
import { captureException, flush, getCurrentHub, hasTracingEnabled, startTransaction } from '@sentry/core';
import type { Span } from '@sentry/types';
import { addExceptionMechanism, logger, objectify, tracingContextFromHeaders } from '@sentry/utils';

import type { EdgeRouteHandler } from '../types';
import { flush } from './flush';
import type { EdgeRouteHandler } from '../../edge/types';

/**
* Wraps a function on the edge runtime with error and performance monitoring.
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { flush } from '@sentry/node';
import { flush } from '@sentry/core';
import type { Transaction } from '@sentry/types';
import { fill, logger } from '@sentry/utils';
import type { ServerResponse } from 'http';
Expand Down Expand Up @@ -41,18 +41,7 @@ export function autoEndTransactionOnResponseEnd(transaction: Transaction, res: S
export async function finishTransaction(transaction: Transaction | undefined, res: ServerResponse): Promise<void> {
if (transaction) {
transaction.setHttpStatus(res.statusCode);

// If any open spans are set to finish when the response ends, it sets up a race condition between their `finish`
// calls and the transaction's `finish` call - and any spans which lose the race will get dropped from the
// transaction. To prevent this, push `transaction.finish` to the next event loop so that it's guaranteed to lose
// the race, and wait for it to be done before flushing events.
const transactionFinished: Promise<void> = new Promise(resolve => {
setImmediate(() => {
transaction.finish();
resolve();
});
});
await transactionFinished;
transaction.finish();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { getCurrentHub, hasTracingEnabled, runWithAsyncContext } from '@sentry/core';
import { captureException, startTransaction } from '@sentry/node';
import {
captureException,
getCurrentHub,
hasTracingEnabled,
runWithAsyncContext,
startTransaction,
} from '@sentry/core';
import type { Transaction } from '@sentry/types';
import {
addExceptionMechanism,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { hasTracingEnabled } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type App from 'next/app';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { hasTracingEnabled } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import type Document from 'next/document';

import { isBuild } from './utils/isBuild';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { hasTracingEnabled } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type { NextPageContext } from 'next';
import type { ErrorProps } from 'next/error';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { hasTracingEnabled } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type { NextPage } from 'next';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { hasTracingEnabled } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type { GetServerSideProps } from 'next';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { hasTracingEnabled } from '@sentry/core';
import { getCurrentHub } from '@sentry/node';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import type { GetStaticProps } from 'next';

import { isBuild } from './utils/isBuild';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { EdgeRouteHandler } from './types';
import type { EdgeRouteHandler } from '../edge/types';
import { withEdgeWrapping } from './utils/edgeWrapperUtils';

/**
Expand Down
5 changes: 1 addition & 4 deletions packages/nextjs/src/config/templates/apiWrapperTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import * as origModule from '__SENTRY_WRAPPING_TARGET_FILE__';
import * as Sentry from '@sentry/nextjs';
import type { PageConfig } from 'next';

import type { VercelCronsConfig } from '../../common/types';
// We import this from `wrappers` rather than directly from `next` because our version can work simultaneously with
// multiple versions of next. See note in `wrappers/types` for more.
import type { NextApiHandler } from '../../server/types';
import type { NextApiHandler, VercelCronsConfig } from '../../common/types';

type NextApiModule = (
| {
Expand Down
Loading

0 comments on commit fac2be8

Please sign in to comment.