1
1
/* eslint-disable max-lines */
2
2
import { captureException , getCurrentHub } from '@sentry/node' ;
3
3
import { 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' ;
12
5
13
6
// Types vendored from @remix -run/[email protected] :
14
7
// https://github.com/remix-run/remix/blob/f3691d51027b93caa3fd2cdfe146d7b62a6eb8f2/packages/remix-server-runtime/server.ts
@@ -92,6 +85,18 @@ interface DataFunction {
92
85
( args : DataFunctionArgs ) : Promise < Response > | Response | Promise < AppData > | AppData ;
93
86
}
94
87
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
+
95
100
// Taken from Remix Implementation
96
101
// https://github.com/remix-run/remix/blob/7688da5c75190a2e29496c78721456d6e12e3abe/packages/remix-server-runtime/responses.ts#L54-L62
97
102
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -262,18 +267,61 @@ function makeWrappedMeta(origMeta: MetaFunction | HtmlMetaDescriptor = {}): Meta
262
267
} ;
263
268
}
264
269
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' ) ;
266
307
return async function ( this : unknown , request : Request , loadContext ?: unknown ) : Promise < Response > {
267
308
const hub = getCurrentHub ( ) ;
268
309
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' ;
269
317
const transaction = hub . startTransaction ( {
270
- name : stripUrlQueryAndFragment ( request . url ) ,
318
+ name,
271
319
op : 'http.server' ,
272
320
tags : {
273
321
method : request . method ,
274
322
} ,
275
323
metadata : {
276
- source : 'url' ,
324
+ source,
277
325
} ,
278
326
} ) ;
279
327
@@ -290,6 +338,33 @@ function wrapRequestHandler(origRequestHandler: RequestHandler): RequestHandler
290
338
} ;
291
339
}
292
340
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
+
293
368
function makeWrappedCreateRequestHandler (
294
369
origCreateRequestHandler : CreateRequestHandlerFunction ,
295
370
) : CreateRequestHandlerFunction {
@@ -316,9 +391,11 @@ function makeWrappedCreateRequestHandler(
316
391
routes [ id ] = wrappedRoute ;
317
392
}
318
393
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 ) ;
320
397
321
- return wrapRequestHandler ( requestHandler ) ;
398
+ return wrapRequestHandler ( requestHandler , newBuild ) ;
322
399
} ;
323
400
}
324
401
0 commit comments