@@ -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,18 @@ 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 (
72+ obj . fetch ,
73+ original =>
74+ new Proxy ( original , {
75+ apply ( target , thisArg , args ) {
76+ return wrapRequestHandler ( { options, request : args [ 0 ] , context } , ( ) => {
77+ return Reflect . apply ( target , thisArg , args ) ;
78+ } ) ;
79+ } ,
80+ } ) ,
81+ ) ;
8082 }
8183
8284 if ( obj . alarm && typeof obj . alarm === 'function' ) {
@@ -177,7 +179,18 @@ function instrumentPrototype<T extends NewableFunction>(target: T, methodsToInst
177179 methodNames . forEach ( methodName => {
178180 const originalMethod = ( proto as Record < string , unknown > ) [ methodName ] ;
179181
180- if ( ! originalMethod || isInstrumented ( originalMethod ) ) {
182+ if ( ! originalMethod ) {
183+ return ;
184+ }
185+
186+ const existingInstrumented = getInstrumented ( originalMethod ) ;
187+ if ( existingInstrumented ) {
188+ Object . defineProperty ( proto , methodName , {
189+ value : existingInstrumented ,
190+ enumerable : false ,
191+ writable : true ,
192+ configurable : true ,
193+ } ) ;
181194 return ;
182195 }
183196
@@ -216,6 +229,11 @@ function instrumentPrototype<T extends NewableFunction>(target: T, methodsToInst
216229 return wrapper . apply ( this , args ) ;
217230 } ;
218231
232+ // Only mark wrappedMethod as instrumented (not originalMethod → wrappedMethod).
233+ // originalMethod must stay unmapped because wrappedMethod calls
234+ // wrapMethodWithSentry(options, originalMethod) on each invocation to create
235+ // a per-instance proxy. If originalMethod mapped to wrappedMethod, that call
236+ // would return wrappedMethod itself, causing infinite recursion.
219237 markAsInstrumented ( wrappedMethod ) ;
220238
221239 // Replace the prototype method
0 commit comments