11/* eslint-disable max-lines */
22import { captureException , getCurrentHub } from '@sentry/node' ;
33import { getActiveTransaction } from '@sentry/tracing' ;
4- import {
5- addExceptionMechanism ,
6- fill ,
7- loadModule ,
8- logger ,
9- serializeBaggage ,
10- stripUrlQueryAndFragment ,
11- } from '@sentry/utils' ;
4+ import { addExceptionMechanism , fill , loadModule , logger , serializeBaggage } from '@sentry/utils' ;
125
136// Types vendored from @remix -run/server-runtime@1.6.0:
147// https://github.com/remix-run/remix/blob/f3691d51027b93caa3fd2cdfe146d7b62a6eb8f2/packages/remix-server-runtime/server.ts
@@ -92,6 +85,18 @@ interface DataFunction {
9285 ( args : DataFunctionArgs ) : Promise < Response > | Response | Promise < AppData > | AppData ;
9386}
9487
88+ interface ReactRouterDomPkg {
89+ matchRoutes : ( routes : ServerRoute [ ] , pathname : string ) => RouteMatch < ServerRoute > [ ] | null ;
90+ }
91+
92+ // Taken from Remix Implementation
93+ // https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/routeMatching.ts#L6-L10
94+ export interface RouteMatch < Route > {
95+ params : Params ;
96+ pathname : string ;
97+ route : Route ;
98+ }
99+
95100// Taken from Remix Implementation
96101// https://github.com/remix-run/remix/blob/7688da5c75190a2e29496c78721456d6e12e3abe/packages/remix-server-runtime/responses.ts#L54-L62
97102// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -262,18 +267,61 @@ function makeWrappedMeta(origMeta: MetaFunction | HtmlMetaDescriptor = {}): Meta
262267 } ;
263268}
264269
265- function wrapRequestHandler ( origRequestHandler : RequestHandler ) : RequestHandler {
270+ function createRoutes ( manifest : ServerRouteManifest , parentId ?: string ) : ServerRoute [ ] {
271+ return Object . entries ( manifest )
272+ . filter ( ( [ , route ] ) => route . parentId === parentId )
273+ . map ( ( [ id , route ] ) => ( {
274+ ...route ,
275+ children : createRoutes ( manifest , id ) ,
276+ } ) ) ;
277+ }
278+
279+ // Remix Implementation:
280+ // https://github.com/remix-run/remix/blob/38e127b1d97485900b9c220d93503de0deb1fc81/packages/remix-server-runtime/routeMatching.ts#L12-L24
281+ //
282+ // Changed so that `matchRoutes` function is passed in.
283+ function matchServerRoutes (
284+ routes : ServerRoute [ ] ,
285+ pathname : string ,
286+ pkg ?: ReactRouterDomPkg ,
287+ ) : RouteMatch < ServerRoute > [ ] | null {
288+ if ( ! pkg ) {
289+ return null ;
290+ }
291+
292+ const matches = pkg . matchRoutes ( routes , pathname ) ;
293+ if ( ! matches ) {
294+ return null ;
295+ }
296+
297+ return matches . map ( match => ( {
298+ params : match . params ,
299+ pathname : match . pathname ,
300+ route : match . route ,
301+ } ) ) ;
302+ }
303+
304+ function wrapRequestHandler ( origRequestHandler : RequestHandler , build : ServerBuild ) : RequestHandler {
305+ const routes = createRoutes ( build . routes ) ;
306+ const pkg = loadModule < ReactRouterDomPkg > ( 'react-router-dom' ) ;
266307 return async function ( this : unknown , request : Request , loadContext ?: unknown ) : Promise < Response > {
267308 const hub = getCurrentHub ( ) ;
268309 const currentScope = hub . getScope ( ) ;
310+
311+ const url = new URL ( request . url ) ;
312+ const matches = matchServerRoutes ( routes , url . pathname , pkg ) ;
313+
314+ const match = matches && getRequestMatch ( url , matches ) ;
315+ const name = match === null ? url . pathname : match . route . id ;
316+ const source = match === null ? 'url' : 'route' ;
269317 const transaction = hub . startTransaction ( {
270- name : stripUrlQueryAndFragment ( request . url ) ,
318+ name,
271319 op : 'http.server' ,
272320 tags : {
273321 method : request . method ,
274322 } ,
275323 metadata : {
276- source : 'url' ,
324+ source,
277325 } ,
278326 } ) ;
279327
@@ -290,6 +338,33 @@ function wrapRequestHandler(origRequestHandler: RequestHandler): RequestHandler
290338 } ;
291339}
292340
341+ // https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/server.ts#L573-L586
342+ function isIndexRequestUrl ( url : URL ) : boolean {
343+ for ( const param of url . searchParams . getAll ( 'index' ) ) {
344+ // only use bare `?index` params without a value
345+ // ✅ /foo?index
346+ // ✅ /foo?index&index=123
347+ // ✅ /foo?index=123&index
348+ // ❌ /foo?index=123
349+ if ( param === '' ) {
350+ return true ;
351+ }
352+ }
353+
354+ return false ;
355+ }
356+
357+ // https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/server.ts#L588-L596
358+ function getRequestMatch ( url : URL , matches : RouteMatch < ServerRoute > [ ] ) : RouteMatch < ServerRoute > {
359+ const match = matches . slice ( - 1 ) [ 0 ] ;
360+
361+ if ( ! isIndexRequestUrl ( url ) && match . route . id . endsWith ( '/index' ) ) {
362+ return matches . slice ( - 2 ) [ 0 ] ;
363+ }
364+
365+ return match ;
366+ }
367+
293368function makeWrappedCreateRequestHandler (
294369 origCreateRequestHandler : CreateRequestHandlerFunction ,
295370) : CreateRequestHandlerFunction {
@@ -316,9 +391,11 @@ function makeWrappedCreateRequestHandler(
316391 routes [ id ] = wrappedRoute ;
317392 }
318393
319- const requestHandler = origCreateRequestHandler . call ( this , { ...build , routes, entry : wrappedEntry } , mode ) ;
394+ const newBuild = { ...build , routes, entry : wrappedEntry } ;
395+
396+ const requestHandler = origCreateRequestHandler . call ( this , newBuild , mode ) ;
320397
321- return wrapRequestHandler ( requestHandler ) ;
398+ return wrapRequestHandler ( requestHandler , newBuild ) ;
322399 } ;
323400}
324401
0 commit comments