Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/nextjs/src/common/_error.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { captureException, withScope } from '@sentry/core';
import { vercelWaitUntil } from '@sentry/utils';
import type { NextPageContext } from 'next';
import { flushSafelyWithTimeout } from './utils/responseEnd';
import { vercelWaitUntil } from './utils/vercelWaitUntil';

type ContextOrProps = {
req?: NextPageContext['req'];
Expand Down
3 changes: 1 addition & 2 deletions packages/nextjs/src/common/utils/edgeWrapperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import {
startSpan,
withIsolationScope,
} from '@sentry/core';
import { winterCGRequestToRequestData } from '@sentry/utils';
import { vercelWaitUntil, winterCGRequestToRequestData } from '@sentry/utils';

import type { EdgeRouteHandler } from '../../edge/types';
import { flushSafelyWithTimeout } from './responseEnd';
import { commonObjectToIsolationScope, escapeNextjsTracing } from './tracingUtils';
import { vercelWaitUntil } from './vercelWaitUntil';

/**
* Wraps a function on the edge runtime with error and performance monitoring.
Expand Down
3 changes: 1 addition & 2 deletions packages/nextjs/src/common/utils/wrapperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ import {
withIsolationScope,
} from '@sentry/core';
import type { Span } from '@sentry/types';
import { isString } from '@sentry/utils';
import { isString, vercelWaitUntil } from '@sentry/utils';

import { autoEndSpanOnResponseEnd, flushSafelyWithTimeout } from './responseEnd';
import { commonObjectToIsolationScope, escapeNextjsTracing } from './tracingUtils';
import { vercelWaitUntil } from './vercelWaitUntil';

declare module 'http' {
interface IncomingMessage {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import {
withIsolationScope,
} from '@sentry/core';
import { captureException, continueTrace, getClient, handleCallbackErrors, startSpan } from '@sentry/core';
import { logger } from '@sentry/utils';
import { logger, vercelWaitUntil } from '@sentry/utils';

import { DEBUG_BUILD } from './debug-build';
import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils';
import { flushSafelyWithTimeout } from './utils/responseEnd';
import { escapeNextjsTracing } from './utils/tracingUtils';
import { vercelWaitUntil } from './utils/vercelWaitUntil';

interface Options {
formData?: FormData;
Expand Down
3 changes: 1 addition & 2 deletions packages/nextjs/src/common/wrapApiHandlerWithSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import {
startSpanManual,
withIsolationScope,
} from '@sentry/core';
import { consoleSandbox, isString, logger, objectify } from '@sentry/utils';
import { consoleSandbox, isString, logger, objectify, vercelWaitUntil } from '@sentry/utils';

import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
import type { AugmentedNextApiRequest, AugmentedNextApiResponse, NextApiHandler } from './types';
import { flushSafelyWithTimeout } from './utils/responseEnd';
import { escapeNextjsTracing } from './utils/tracingUtils';
import { vercelWaitUntil } from './utils/vercelWaitUntil';

/**
* Wrap the given API route handler for tracing and error capturing. Thin wrapper around `withSentry`, which only
Expand Down
3 changes: 1 addition & 2 deletions packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
withIsolationScope,
withScope,
} from '@sentry/core';
import { propagationContextFromHeaders, winterCGHeadersToDict } from '@sentry/utils';
import { propagationContextFromHeaders, vercelWaitUntil, winterCGHeadersToDict } from '@sentry/utils';
import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils';
import type { RouteHandlerContext } from './types';
import { flushSafelyWithTimeout } from './utils/responseEnd';
Expand All @@ -19,7 +19,6 @@ import {
commonObjectToPropagationContext,
escapeNextjsTracing,
} from './utils/tracingUtils';
import { vercelWaitUntil } from './utils/vercelWaitUntil';

/**
* Wraps a Next.js App Router Route handler with Sentry error and performance instrumentation.
Expand Down
3 changes: 1 addition & 2 deletions packages/nextjs/src/common/wrapServerComponentWithSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ import {
withIsolationScope,
withScope,
} from '@sentry/core';
import { propagationContextFromHeaders, uuid4, winterCGHeadersToDict } from '@sentry/utils';
import { propagationContextFromHeaders, uuid4, vercelWaitUntil, winterCGHeadersToDict } from '@sentry/utils';

import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
import { isNotFoundNavigationError, isRedirectNavigationError } from '../common/nextNavigationErrorUtils';
import type { ServerComponentContext } from '../common/types';
import { flushSafelyWithTimeout } from './utils/responseEnd';
import { commonObjectToIsolationScope, commonObjectToPropagationContext } from './utils/tracingUtils';
import { vercelWaitUntil } from './utils/vercelWaitUntil';

/**
* Wraps an `app` directory server component with Sentry error instrumentation.
Expand Down
1 change: 1 addition & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ export * from './anr';
export * from './lru';
export * from './buildPolyfills';
export * from './propagationContext';
export * from './vercelWaitUntil';
export * from './version';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GLOBAL_OBJ } from '@sentry/utils';
import { GLOBAL_OBJ } from './worldwide';

interface VercelRequestContextGlobal {
get?(): {
Expand All @@ -16,6 +16,12 @@ export function vercelWaitUntil(task: Promise<unknown>): void {
// @ts-expect-error This is not typed
GLOBAL_OBJ[Symbol.for('@vercel/request-context')];

const ctx = vercelRequestContextGlobal?.get?.() ?? {};
ctx.waitUntil?.(task);
const ctx =
vercelRequestContextGlobal && vercelRequestContextGlobal.get && vercelRequestContextGlobal.get()
? vercelRequestContextGlobal.get()
: {};

if (ctx && ctx.waitUntil) {
ctx.waitUntil(task);
}
}
40 changes: 40 additions & 0 deletions packages/utils/test/vercelWaitUntil.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it, vi } from 'vitest';
import { vercelWaitUntil } from '../src/vercelWaitUntil';
import { GLOBAL_OBJ } from '../src/worldwide';

describe('vercelWaitUntil', () => {
it('should do nothing if GLOBAL_OBJ does not have the @vercel/request-context symbol', () => {
const task = Promise.resolve();
vercelWaitUntil(task);
// No assertions needed, just ensuring no errors are thrown
});

it('should do nothing if get method is not defined', () => {
// @ts-expect-error - Not typed
GLOBAL_OBJ[Symbol.for('@vercel/request-context')] = {};
const task = Promise.resolve();
vercelWaitUntil(task);
// No assertions needed, just ensuring no errors are thrown
});

it('should do nothing if waitUntil method is not defined', () => {
// @ts-expect-error - Not typed
GLOBAL_OBJ[Symbol.for('@vercel/request-context')] = {
get: () => ({}),
};
const task = Promise.resolve();
vercelWaitUntil(task);
// No assertions needed, just ensuring no errors are thrown
});

it('should call waitUntil method if it is defined', () => {
const waitUntilMock = vi.fn();
// @ts-expect-error - Not typed
GLOBAL_OBJ[Symbol.for('@vercel/request-context')] = {
get: () => ({ waitUntil: waitUntilMock }),
};
const task = Promise.resolve();
vercelWaitUntil(task);
expect(waitUntilMock).toHaveBeenCalledWith(task);
});
});
Loading