1
- import type { RequestEventData } from '@sentry/core' ;
1
+ import type { RequestEventData , WrappedFunction } from '@sentry/core' ;
2
2
import {
3
3
continueTrace ,
4
4
fill ,
@@ -12,14 +12,16 @@ import {
12
12
withIsolationScope ,
13
13
} from '@sentry/core' ;
14
14
import { DEBUG_BUILD } from './debug-build' ;
15
- import { captureRemixServerException } from './errors' ;
15
+ import { captureRemixServerException , errorHandleDataFunction , errorHandleDocumentRequestFunction } from './errors' ;
16
16
import { extractData , isDeferredData , isResponse , isRouteErrorResponse , json } from './vendor/response' ;
17
17
import type {
18
18
AppData ,
19
19
AppLoadContext ,
20
20
CreateRequestHandlerFunction ,
21
21
DataFunction ,
22
22
DataFunctionArgs ,
23
+ EntryContext ,
24
+ HandleDocumentRequestFunction ,
23
25
RemixRequest ,
24
26
RequestHandler ,
25
27
ServerBuild ,
@@ -91,6 +93,45 @@ function getTraceAndBaggage(): {
91
93
return { } ;
92
94
}
93
95
96
+ function makeWrappedDocumentRequestFunction ( ) {
97
+ return function ( origDocumentRequestFunction : HandleDocumentRequestFunction ) : HandleDocumentRequestFunction {
98
+ return async function (
99
+ this : unknown ,
100
+ request : Request ,
101
+ responseStatusCode : number ,
102
+ responseHeaders : Headers ,
103
+ context : EntryContext ,
104
+ loadContext ?: Record < string , unknown > ,
105
+ ) : Promise < Response > {
106
+ return errorHandleDocumentRequestFunction . call ( this , origDocumentRequestFunction , {
107
+ request,
108
+ responseStatusCode,
109
+ responseHeaders,
110
+ context,
111
+ loadContext,
112
+ } ) ;
113
+ } ;
114
+ } ;
115
+ }
116
+
117
+ function makeWrappedDataFunction ( origFn : DataFunction , id : string , name : 'action' | 'loader' ) : DataFunction {
118
+ return async function ( this : unknown , args : DataFunctionArgs ) : Promise < Response | AppData > {
119
+ return errorHandleDataFunction . call ( this , origFn , name , args ) ;
120
+ } ;
121
+ }
122
+
123
+ const makeWrappedAction =
124
+ ( id : string ) =>
125
+ ( origAction : DataFunction ) : DataFunction => {
126
+ return makeWrappedDataFunction ( origAction , id , 'action' ) ;
127
+ } ;
128
+
129
+ const makeWrappedLoader =
130
+ ( id : string ) =>
131
+ ( origLoader : DataFunction ) : DataFunction => {
132
+ return makeWrappedDataFunction ( origLoader , id , 'loader' ) ;
133
+ } ;
134
+
94
135
function makeWrappedRootLoader ( ) {
95
136
return function ( origLoader : DataFunction ) : DataFunction {
96
137
return async function ( this : unknown , args : DataFunctionArgs ) : Promise < Response | AppData > {
@@ -177,9 +218,28 @@ function instrumentBuildCallback(build: ServerBuild): ServerBuild {
177
218
const routes : ServerRouteManifest = { } ;
178
219
const wrappedEntry = { ...build . entry , module : { ...build . entry . module } } ;
179
220
221
+ // Not keeping boolean flags like it's done for `requestHandler` functions,
222
+ // Because the build can change between build and runtime.
223
+ // So if there is a new `loader` or`action` or `documentRequest` after build.
224
+ // We should be able to wrap them, as they may not be wrapped before.
225
+ const defaultExport = wrappedEntry . module . default as undefined | WrappedFunction ;
226
+ if ( defaultExport && ! defaultExport . __sentry_original__ ) {
227
+ fill ( wrappedEntry . module , 'default' , makeWrappedDocumentRequestFunction ( ) ) ;
228
+ }
229
+
180
230
for ( const [ id , route ] of Object . entries ( build . routes ) ) {
181
231
const wrappedRoute = { ...route , module : { ...route . module } } ;
182
232
233
+ const routeAction = wrappedRoute . module . action as undefined | WrappedFunction ;
234
+ if ( routeAction && ! routeAction . __sentry_original__ ) {
235
+ fill ( wrappedRoute . module , 'action' , makeWrappedAction ( id ) ) ;
236
+ }
237
+
238
+ const routeLoader = wrappedRoute . module . loader as undefined | WrappedFunction ;
239
+ if ( routeLoader && ! routeLoader . __sentry_original__ ) {
240
+ fill ( wrappedRoute . module , 'loader' , makeWrappedLoader ( id ) ) ;
241
+ }
242
+
183
243
// Entry module should have a loader function to provide `sentry-trace` and `baggage`
184
244
// They will be available for the root `meta` function as `data.sentryTrace` and `data.sentryBaggage`
185
245
if ( ! wrappedRoute . parentId ) {
0 commit comments