@@ -3,7 +3,7 @@ import { captureException } from '@sentry/core';
33import type { DurableObject } from 'cloudflare:workers' ;
44import { setAsyncLocalStorageAsyncContextStrategy } from './async' ;
55import type { CloudflareOptions } from './client' ;
6- import { isInstrumented , markAsInstrumented } from './instrument' ;
6+ import { ensureInstrumented , getInstrumented , markAsInstrumented } from './instrument' ;
77import { getFinalOptions } from './options' ;
88import { wrapRequestHandler } from './request' ;
99import { instrumentContext } from './utils/instrumentContext' ;
@@ -67,16 +67,16 @@ export function instrumentDurableObjectWithSentry<
6767
6868 // Any other public methods on the Durable Object instance are RPC calls.
6969
70- if ( obj . fetch && typeof obj . fetch === 'function' && ! isInstrumented ( obj . fetch ) ) {
71- obj . fetch = new Proxy ( obj . fetch , {
72- apply ( target , thisArg , args ) {
73- return wrapRequestHandler ( { options , request : args [ 0 ] , context } , ( ) =>
74- Reflect . apply ( target , thisArg , args ) ,
75- ) ;
76- } ,
77- } ) ;
78-
79- markAsInstrumented ( obj . fetch ) ;
70+ if ( obj . fetch && typeof obj . fetch === 'function' ) {
71+ obj . fetch = ensureInstrumented ( obj . fetch , original =>
72+ new Proxy ( original , {
73+ apply ( target , thisArg , args ) {
74+ return wrapRequestHandler ( { options , request : args [ 0 ] , context } , ( ) => {
75+ return Reflect . apply ( target , thisArg , args ) ;
76+ } ) ;
77+ } ,
78+ } ) ,
79+ ) ;
8080 }
8181
8282 if ( obj . alarm && typeof obj . alarm === 'function' ) {
@@ -177,7 +177,18 @@ function instrumentPrototype<T extends NewableFunction>(target: T, methodsToInst
177177 methodNames . forEach ( methodName => {
178178 const originalMethod = ( proto as Record < string , unknown > ) [ methodName ] ;
179179
180- if ( ! originalMethod || isInstrumented ( originalMethod ) ) {
180+ if ( ! originalMethod ) {
181+ return ;
182+ }
183+
184+ const existingInstrumented = getInstrumented ( originalMethod ) ;
185+ if ( existingInstrumented ) {
186+ Object . defineProperty ( proto , methodName , {
187+ value : existingInstrumented ,
188+ enumerable : false ,
189+ writable : true ,
190+ configurable : true ,
191+ } ) ;
181192 return ;
182193 }
183194
@@ -216,6 +227,11 @@ function instrumentPrototype<T extends NewableFunction>(target: T, methodsToInst
216227 return wrapper . apply ( this , args ) ;
217228 } ;
218229
230+ // Only mark wrappedMethod as instrumented (not originalMethod → wrappedMethod).
231+ // originalMethod must stay unmapped because wrappedMethod calls
232+ // wrapMethodWithSentry(options, originalMethod) on each invocation to create
233+ // a per-instance proxy. If originalMethod mapped to wrappedMethod, that call
234+ // would return wrappedMethod itself, causing infinite recursion.
219235 markAsInstrumented ( wrappedMethod ) ;
220236
221237 // Replace the prototype method
0 commit comments