Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 19 additions & 8 deletions packages/react-router/src/server/createSentryHandleRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ export interface SentryHandleRequestOptions {
botRegex?: RegExp;
}

type HandleRequestWithoutMiddleware = (
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
loadContext: AppLoadContext,
) => Promise<unknown>;

type HandleRequestWithMiddleware = (
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
loadContext: RouterContextProvider,
) => Promise<unknown>;

/**
* A complete Sentry-instrumented handleRequest implementation that handles both
* route parametrization and trace meta tag injection.
Expand All @@ -62,13 +78,7 @@ export interface SentryHandleRequestOptions {
*/
export function createSentryHandleRequest(
options: SentryHandleRequestOptions,
): (
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
loadContext: AppLoadContext | RouterContextProvider,
) => Promise<unknown> {
): HandleRequestWithoutMiddleware & HandleRequestWithMiddleware {
const {
streamTimeout = 10000,
renderToPipeableStream,
Expand Down Expand Up @@ -135,5 +145,6 @@ export function createSentryHandleRequest(
};

// Wrap the handle request function for request parametrization
return wrapSentryHandleRequest(handleRequest);
return wrapSentryHandleRequest(handleRequest as HandleRequestWithoutMiddleware) as HandleRequestWithoutMiddleware &
HandleRequestWithMiddleware;
}
65 changes: 61 additions & 4 deletions packages/react-router/src/server/wrapSentryHandleRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,20 @@ import {
} from '@sentry/core';
import type { AppLoadContext, EntryContext, RouterContextProvider } from 'react-router';

type OriginalHandleRequest = (
type OriginalHandleRequestWithoutMiddleware = (
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
loadContext: AppLoadContext | RouterContextProvider,
loadContext: AppLoadContext,
) => Promise<unknown>;

type OriginalHandleRequestWithMiddleware = (
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
loadContext: RouterContextProvider,
) => Promise<unknown>;

/**
Expand All @@ -24,7 +32,27 @@ type OriginalHandleRequest = (
* @param originalHandle - The original handleRequest function to wrap
* @returns A wrapped version of the handle request function with Sentry instrumentation
*/
export function wrapSentryHandleRequest(originalHandle: OriginalHandleRequest): OriginalHandleRequest {
export function wrapSentryHandleRequest(
originalHandle: OriginalHandleRequestWithoutMiddleware,
): OriginalHandleRequestWithoutMiddleware;
/**
* Wraps the original handleRequest function to add Sentry instrumentation.
*
* @param originalHandle - The original handleRequest function to wrap
* @returns A wrapped version of the handle request function with Sentry instrumentation
*/
export function wrapSentryHandleRequest(
originalHandle: OriginalHandleRequestWithMiddleware,
): OriginalHandleRequestWithMiddleware;
/**
* Wraps the original handleRequest function to add Sentry instrumentation.
*
* @param originalHandle - The original handleRequest function to wrap
* @returns A wrapped version of the handle request function with Sentry instrumentation
*/
export function wrapSentryHandleRequest(
originalHandle: OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware,
): OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware {
return async function sentryInstrumentedHandleRequest(
request: Request,
responseStatusCode: number,
Expand Down Expand Up @@ -57,10 +85,39 @@ export function wrapSentryHandleRequest(originalHandle: OriginalHandleRequest):
}

try {
return await originalHandle(request, responseStatusCode, responseHeaders, routerContext, loadContext);
// Type guard to call the correct overload based on loadContext type
if (isRouterContextProvider(loadContext)) {
// loadContext is RouterContextProvider
return await (originalHandle as OriginalHandleRequestWithMiddleware)(
request,
responseStatusCode,
responseHeaders,
routerContext,
loadContext,
);
} else {
// loadContext is AppLoadContext
return await (originalHandle as OriginalHandleRequestWithoutMiddleware)(
request,
responseStatusCode,
responseHeaders,
routerContext,
loadContext,
);
}
} finally {
await flushIfServerless();
}

/**
* Helper type guard to determine if the context is a RouterContextProvider.
*
* @param ctx - The context to check
* @returns True if the context is a RouterContextProvider
*/
function isRouterContextProvider(ctx: AppLoadContext | RouterContextProvider): ctx is RouterContextProvider {
return typeof (ctx as RouterContextProvider)?.get === 'function';
}
};
}

Expand Down