import { noop } from './utils/functionUtils'; /** * Object passed to the callback of an instrumented method call. See `instrumentMethod` for more * info. */ export interface InstrumentedMethodCall { /** * The target object on which the method was called. */ target: TARGET; /** * The parameters with which the method was called. * * Note: if needed, parameters can be mutated by the instrumentation */ parameters: Parameters; /** * Registers a callback that will be called after the original method is called, with the method * result passed as argument. */ onPostCall: (callback: PostCallCallback) => void; /** * The stack trace of the method call. */ handlingStack?: string; } type PostCallCallback = (result: ReturnType) => void; type ConstructorParametersOf = CONSTRUCTOR extends new (...args: infer P) => any ? P : never; type ConstructorInstanceOf = CONSTRUCTOR extends new (...args: any[]) => infer R ? R : never; /** * Object passed to the callback of an instrumented constructor call. See `instrumentConstructor` * for more info. */ export interface InstrumentedConstructorCall { /** * The parameters with which the constructor was called. * * Note: if needed, parameters can be mutated by the instrumentation */ parameters: ConstructorParametersOf; /** * Registers a callback that will be called after the original constructor is called, with the * constructed instance passed as argument. */ onPostCall: (callback: (result: ConstructorInstanceOf) => void) => void; /** * The stack trace of the constructor call. */ handlingStack?: string; } /** * Instruments a method on a object, calling the given callback before the original method is * invoked. The callback receives an object with information about the method call. * * This function makes sure that we are "good citizens" regarding third party instrumentations: when * removing the instrumentation, the original method is usually restored, but if a third party * instrumentation was set after ours, we keep it in place and just replace our instrumentation with * a noop. * * Note: it is generally better to instrument methods that are "owned" by the object instead of ones * that are inherited from the prototype chain. Example: * * do: `instrumentMethod(Array.prototype, 'push', ...)` * * don't: `instrumentMethod([], 'push', ...)` * * This method is also used to set event handler properties (ex: window.onerror = ...), as it has * the same requirements as instrumenting a method: * * if the event handler is already set by a third party, we need to call it and not just blindly * override it. * * if the event handler is set by a third party after us, we need to keep it in place when * removing ours. * * To instrument a constructor @see {@link instrumentConstructor}. * * @example * * instrumentMethod(window, 'fetch', ({ target, parameters, onPostCall }) => { * console.log('Before calling fetch on', target, 'with parameters', parameters) * * onPostCall((result) => { * console.log('After fetch calling on', target, 'with parameters', parameters, 'and result', result) * }) * }) */ export declare function instrumentMethod(targetPrototype: TARGET, method: METHOD, onPreCall: (this: null, callInfos: InstrumentedMethodCall) => void, { computeHandlingStack }?: { computeHandlingStack?: boolean; }): { stop: typeof noop; }; /** * Instruments a constructor on an object (typically a global, e.g. `window.WebSocket`), calling the * given callback before the original constructor is invoked. The callback receives an object with * information about the constructor call, and can register an `onPostCall` callback to be notified * with the constructed instance. * * Like `instrumentMethod`, this is a "good citizen" regarding third party instrumentations: stopping * restores the original constructor unless a third party replaced it afterwards. * * The wrapper preserves the original prototype (so `instanceof` keeps working), the original * `new.target` (so constructors that inspect it behave as if not instrumented), the original * static members (e.g. `WebSocket.OPEN`), and `instance.constructor ===` so checks like * `new WebSocket(url).constructor === WebSocket` stay true. * * @see {@link preserveConstructorShape} for limitations on static members preservation. * @example * * instrumentConstructor(window, 'WebSocket', ({ parameters, onPostCall }) => { * console.log('Before constructing WebSocket with parameters', parameters) * * onPostCall((instance) => { * console.log('Constructed WebSocket instance', instance) * }) * }) */ export declare function instrumentConstructor(container: CONTAINER, constructor: CONSTRUCTOR, onPreCall: (this: null, callInfos: InstrumentedConstructorCall) => void, { computeHandlingStack }?: { computeHandlingStack?: boolean; }): { stop: typeof noop; }; export declare function instrumentSetter(targetPrototype: TARGET, property: PROPERTY, after: (target: TARGET, value: TARGET[PROPERTY]) => void): { stop: typeof noop; }; export {};