@@ -13,7 +13,7 @@ import {
13
13
tracingContextFromHeaders ,
14
14
} from '@sentry/utils' ;
15
15
16
- import { getFutureFlagsServer , getRemixVersionFromPkg } from './futureFlags' ;
16
+ import { getFutureFlagsServer , getRemixVersionFromBuild } from './futureFlags' ;
17
17
import { extractData , getRequestMatch , isDeferredData , isResponse , json , matchServerRoutes } from './vendor/response' ;
18
18
import type {
19
19
AppData ,
@@ -33,7 +33,6 @@ import type {
33
33
import { normalizeRemixRequest } from './web-fetch' ;
34
34
35
35
let FUTURE_FLAGS : FutureConfig | undefined ;
36
- let IS_REMIX_V2 : boolean | undefined ;
37
36
38
37
// Flag to track if the core request handler is instrumented.
39
38
export let isRequestHandlerWrapped = false ;
@@ -118,55 +117,60 @@ export async function captureRemixServerException(err: unknown, name: string, re
118
117
} ) ;
119
118
}
120
119
121
- function makeWrappedDocumentRequestFunction (
122
- origDocumentRequestFunction : HandleDocumentRequestFunction ,
123
- ) : HandleDocumentRequestFunction {
124
- return async function (
125
- this : unknown ,
126
- request : Request ,
127
- responseStatusCode : number ,
128
- responseHeaders : Headers ,
129
- context : EntryContext ,
130
- loadContext ?: Record < string , unknown > ,
131
- ) : Promise < Response > {
132
- let res : Response ;
120
+ function makeWrappedDocumentRequestFunction ( remixVersion : number ) {
121
+ return function ( origDocumentRequestFunction : HandleDocumentRequestFunction ) : HandleDocumentRequestFunction {
122
+ return async function (
123
+ this : unknown ,
124
+ request : Request ,
125
+ responseStatusCode : number ,
126
+ responseHeaders : Headers ,
127
+ context : EntryContext ,
128
+ loadContext ?: Record < string , unknown > ,
129
+ ) : Promise < Response > {
130
+ let res : Response ;
133
131
134
- const activeTransaction = getActiveTransaction ( ) ;
135
-
136
- try {
137
- const span = activeTransaction ?. startChild ( {
138
- op : 'function.remix.document_request' ,
139
- origin : 'auto.function.remix' ,
140
- description : activeTransaction . name ,
141
- tags : {
142
- method : request . method ,
143
- url : request . url ,
144
- } ,
145
- } ) ;
132
+ const activeTransaction = getActiveTransaction ( ) ;
146
133
147
- res = await origDocumentRequestFunction . call (
148
- this ,
149
- request ,
150
- responseStatusCode ,
151
- responseHeaders ,
152
- context ,
153
- loadContext ,
154
- ) ;
134
+ try {
135
+ const span = activeTransaction ?. startChild ( {
136
+ op : 'function.remix.document_request' ,
137
+ origin : 'auto.function.remix' ,
138
+ description : activeTransaction . name ,
139
+ tags : {
140
+ method : request . method ,
141
+ url : request . url ,
142
+ } ,
143
+ } ) ;
144
+
145
+ res = await origDocumentRequestFunction . call (
146
+ this ,
147
+ request ,
148
+ responseStatusCode ,
149
+ responseHeaders ,
150
+ context ,
151
+ loadContext ,
152
+ ) ;
153
+
154
+ span ?. finish ( ) ;
155
+ } catch ( err ) {
156
+ if ( ! FUTURE_FLAGS ?. v2_errorBoundary && remixVersion !== 2 ) {
157
+ await captureRemixServerException ( err , 'documentRequest' , request ) ;
158
+ }
155
159
156
- span ?. finish ( ) ;
157
- } catch ( err ) {
158
- if ( ! FUTURE_FLAGS ?. v2_errorBoundary && ! IS_REMIX_V2 ) {
159
- await captureRemixServerException ( err , 'documentRequest' , request ) ;
160
+ throw err ;
160
161
}
161
162
162
- throw err ;
163
- }
164
-
165
- return res ;
163
+ return res ;
164
+ } ;
166
165
} ;
167
166
}
168
167
169
- function makeWrappedDataFunction ( origFn : DataFunction , id : string , name : 'action' | 'loader' ) : DataFunction {
168
+ function makeWrappedDataFunction (
169
+ origFn : DataFunction ,
170
+ id : string ,
171
+ name : 'action' | 'loader' ,
172
+ remixVersion : number ,
173
+ ) : DataFunction {
170
174
return async function ( this : unknown , args : DataFunctionArgs ) : Promise < Response | AppData > {
171
175
let res : Response | AppData ;
172
176
const activeTransaction = getActiveTransaction ( ) ;
@@ -192,7 +196,7 @@ function makeWrappedDataFunction(origFn: DataFunction, id: string, name: 'action
192
196
currentScope . setSpan ( activeTransaction ) ;
193
197
span ?. finish ( ) ;
194
198
} catch ( err ) {
195
- if ( ! FUTURE_FLAGS ?. v2_errorBoundary && ! IS_REMIX_V2 ) {
199
+ if ( ! FUTURE_FLAGS ?. v2_errorBoundary && remixVersion !== 2 ) {
196
200
await captureRemixServerException ( err , name , args . request ) ;
197
201
}
198
202
@@ -204,15 +208,15 @@ function makeWrappedDataFunction(origFn: DataFunction, id: string, name: 'action
204
208
}
205
209
206
210
const makeWrappedAction =
207
- ( id : string ) =>
211
+ ( id : string , remixVersion : number ) =>
208
212
( origAction : DataFunction ) : DataFunction => {
209
- return makeWrappedDataFunction ( origAction , id , 'action' ) ;
213
+ return makeWrappedDataFunction ( origAction , id , 'action' , remixVersion ) ;
210
214
} ;
211
215
212
216
const makeWrappedLoader =
213
- ( id : string ) =>
217
+ ( id : string , remixVersion : number ) =>
214
218
( origLoader : DataFunction ) : DataFunction => {
215
- return makeWrappedDataFunction ( origLoader , id , 'loader' ) ;
219
+ return makeWrappedDataFunction ( origLoader , id , 'loader' , remixVersion ) ;
216
220
} ;
217
221
218
222
function getTraceAndBaggage ( ) : { sentryTrace ?: string ; sentryBaggage ?: string } {
@@ -235,44 +239,46 @@ function getTraceAndBaggage(): { sentryTrace?: string; sentryBaggage?: string }
235
239
return { } ;
236
240
}
237
241
238
- function makeWrappedRootLoader ( origLoader : DataFunction ) : DataFunction {
239
- return async function ( this : unknown , args : DataFunctionArgs ) : Promise < Response | AppData > {
240
- const res = await origLoader . call ( this , args ) ;
241
- const traceAndBaggage = getTraceAndBaggage ( ) ;
242
- const remixVersion = getRemixVersionFromPkg ( ) ;
243
-
244
- if ( isDeferredData ( res ) ) {
245
- return {
246
- ...res . data ,
247
- ...traceAndBaggage ,
248
- remixVersion,
249
- } ;
250
- }
242
+ function makeWrappedRootLoader ( remixVersion : number ) {
243
+ return function ( origLoader : DataFunction ) : DataFunction {
244
+ return async function ( this : unknown , args : DataFunctionArgs ) : Promise < Response | AppData > {
245
+ const res = await origLoader . call ( this , args ) ;
246
+ const traceAndBaggage = getTraceAndBaggage ( ) ;
247
+
248
+ if ( isDeferredData ( res ) ) {
249
+ return {
250
+ ...res . data ,
251
+ ...traceAndBaggage ,
252
+ remixVersion,
253
+ } ;
254
+ }
251
255
252
- if ( isResponse ( res ) ) {
253
- // Note: `redirect` and `catch` responses do not have bodies to extract.
254
- // We skip injection of trace and baggage in those cases.
255
- // For `redirect`, a valid internal redirection target will have the trace and baggage injected.
256
- if ( isRedirectResponse ( res ) || isCatchResponse ( res ) ) {
257
- __DEBUG_BUILD__ && logger . warn ( 'Skipping injection of trace and baggage as the response does not have a body' ) ;
258
- return res ;
259
- } else {
260
- const data = await extractData ( res ) ;
261
-
262
- if ( typeof data === 'object' ) {
263
- return json (
264
- { ...data , ...traceAndBaggage , remixVersion } ,
265
- { headers : res . headers , statusText : res . statusText , status : res . status } ,
266
- ) ;
267
- } else {
256
+ if ( isResponse ( res ) ) {
257
+ // Note: `redirect` and `catch` responses do not have bodies to extract.
258
+ // We skip injection of trace and baggage in those cases.
259
+ // For `redirect`, a valid internal redirection target will have the trace and baggage injected.
260
+ if ( isRedirectResponse ( res ) || isCatchResponse ( res ) ) {
268
261
__DEBUG_BUILD__ &&
269
- logger . warn ( 'Skipping injection of trace and baggage as the response body is not an object ' ) ;
262
+ logger . warn ( 'Skipping injection of trace and baggage as the response does not have a body ' ) ;
270
263
return res ;
264
+ } else {
265
+ const data = await extractData ( res ) ;
266
+
267
+ if ( typeof data === 'object' ) {
268
+ return json (
269
+ { ...data , ...traceAndBaggage , remixVersion } ,
270
+ { headers : res . headers , statusText : res . statusText , status : res . status } ,
271
+ ) ;
272
+ } else {
273
+ __DEBUG_BUILD__ &&
274
+ logger . warn ( 'Skipping injection of trace and baggage as the response body is not an object' ) ;
275
+ return res ;
276
+ }
271
277
}
272
278
}
273
- }
274
279
275
- return { ...res , ...traceAndBaggage , remixVersion } ;
280
+ return { ...res , ...traceAndBaggage , remixVersion } ;
281
+ } ;
276
282
} ;
277
283
}
278
284
@@ -405,6 +411,8 @@ function wrapRequestHandler(origRequestHandler: RequestHandler, build: ServerBui
405
411
export function instrumentBuild ( build : ServerBuild ) : ServerBuild {
406
412
const routes : ServerRouteManifest = { } ;
407
413
414
+ const remixVersion = getRemixVersionFromBuild ( build ) ;
415
+
408
416
const wrappedEntry = { ...build . entry , module : { ...build . entry . module } } ;
409
417
410
418
// Not keeping boolean flags like it's done for `requestHandler` functions,
@@ -413,20 +421,20 @@ export function instrumentBuild(build: ServerBuild): ServerBuild {
413
421
// We should be able to wrap them, as they may not be wrapped before.
414
422
const defaultExport = wrappedEntry . module . default as undefined | WrappedFunction ;
415
423
if ( defaultExport && ! defaultExport . __sentry_original__ ) {
416
- fill ( wrappedEntry . module , 'default' , makeWrappedDocumentRequestFunction ) ;
424
+ fill ( wrappedEntry . module , 'default' , makeWrappedDocumentRequestFunction ( remixVersion ) ) ;
417
425
}
418
426
419
427
for ( const [ id , route ] of Object . entries ( build . routes ) ) {
420
428
const wrappedRoute = { ...route , module : { ...route . module } } ;
421
429
422
430
const routeAction = wrappedRoute . module . action as undefined | WrappedFunction ;
423
431
if ( routeAction && ! routeAction . __sentry_original__ ) {
424
- fill ( wrappedRoute . module , 'action' , makeWrappedAction ( id ) ) ;
432
+ fill ( wrappedRoute . module , 'action' , makeWrappedAction ( id , remixVersion ) ) ;
425
433
}
426
434
427
435
const routeLoader = wrappedRoute . module . loader as undefined | WrappedFunction ;
428
436
if ( routeLoader && ! routeLoader . __sentry_original__ ) {
429
- fill ( wrappedRoute . module , 'loader' , makeWrappedLoader ( id ) ) ;
437
+ fill ( wrappedRoute . module , 'loader' , makeWrappedLoader ( id , remixVersion ) ) ;
430
438
}
431
439
432
440
// Entry module should have a loader function to provide `sentry-trace` and `baggage`
@@ -437,7 +445,7 @@ export function instrumentBuild(build: ServerBuild): ServerBuild {
437
445
}
438
446
439
447
// We want to wrap the root loader regardless of whether it's already wrapped before.
440
- fill ( wrappedRoute . module , 'loader' , makeWrappedRootLoader ) ;
448
+ fill ( wrappedRoute . module , 'loader' , makeWrappedRootLoader ( remixVersion ) ) ;
441
449
}
442
450
443
451
routes [ id ] = wrappedRoute ;
@@ -466,9 +474,7 @@ function makeWrappedCreateRequestHandler(
466
474
* Monkey-patch Remix's `createRequestHandler` from `@remix-run/server-runtime`
467
475
* which Remix Adapters (https://remix.run/docs/en/v1/api/remix) use underneath.
468
476
*/
469
- export function instrumentServer ( isRemixV2 ?: boolean ) : void {
470
- IS_REMIX_V2 = isRemixV2 ;
471
-
477
+ export function instrumentServer ( ) : void {
472
478
const pkg = loadModule < { createRequestHandler : CreateRequestHandlerFunction } > ( '@remix-run/server-runtime' ) ;
473
479
474
480
if ( ! pkg ) {
0 commit comments