Skip to content

Commit f76e06c

Browse files
committed
fix: Do not instrument prototype functions
1 parent 6d31a3f commit f76e06c

2 files changed

Lines changed: 38 additions & 8 deletions

File tree

packages/cloudflare/src/durableobject.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,15 @@ export function instrumentDurableObjectWithSentry<
157157
}
158158

159159
const value = Reflect.get(proxyTarget, prop, receiver);
160-
if (typeof value !== 'function') {
161-
return value;
162-
}
163-
164-
if (Object.prototype.hasOwnProperty.call(proxyTarget, prop)) {
165-
return value;
166-
}
167160

168-
if (allowSet && !allowSet.has(prop)) {
161+
if (
162+
typeof value !== 'function' ||
163+
Object.prototype.hasOwnProperty.call(proxyTarget, prop) ||
164+
(allowSet && !allowSet.has(prop)) ||
165+
// Exclude inherited Object.prototype methods (toString, valueOf, etc.)
166+
// These are not RPC methods and should not create spans
167+
prop in Object.prototype
168+
) {
169169
return value;
170170
}
171171

packages/cloudflare/test/durableobject.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,36 @@ describe('instrumentDurableObjectWithSentry', () => {
212212
expect(getInstrumented(obj.rpcMethod)).toBeFalsy();
213213
expect(obj.rpcMethod()).toBe('result');
214214
});
215+
216+
it('does not wrap Object.prototype methods as RPC methods', () => {
217+
const testClass = class {
218+
rpcMethod() {
219+
return 'rpc-result';
220+
}
221+
};
222+
const instrumented = instrumentDurableObjectWithSentry(
223+
vi.fn().mockReturnValue({ enableRpcTracePropagation: true }),
224+
testClass as any,
225+
);
226+
const obj = Reflect.construct(instrumented, []);
227+
228+
// Object.prototype methods should NOT be wrapped - they should be the original methods
229+
expect(obj.toString).toBe(Object.prototype.toString);
230+
expect(obj.valueOf).toBe(Object.prototype.valueOf);
231+
expect(obj.hasOwnProperty).toBe(Object.prototype.hasOwnProperty);
232+
expect(obj.propertyIsEnumerable).toBe(Object.prototype.propertyIsEnumerable);
233+
expect(obj.isPrototypeOf).toBe(Object.prototype.isPrototypeOf);
234+
expect(obj.toLocaleString).toBe(Object.prototype.toLocaleString);
235+
236+
// They should still work correctly
237+
expect(obj.toString()).toBe('[object Object]');
238+
expect(obj.hasOwnProperty('rpcMethod')).toBe(false); // It's on prototype, not own
239+
expect(obj.valueOf()).toBe(obj);
240+
241+
// Meanwhile, actual RPC methods SHOULD be wrapped (not equal to prototype method)
242+
expect(obj.rpcMethod).not.toBe(testClass.prototype.rpcMethod);
243+
expect(obj.rpcMethod()).toBe('rpc-result');
244+
});
215245
});
216246

217247
it('flush performs after all waitUntil promises are finished', async () => {

0 commit comments

Comments
 (0)