import type { DynamicCore } from '../../../client/core/types/DynamicCore';
import type { InstrumentationPayloadSelectors } from '../instrumentation.types';
type InstrumentFunctionParams<Args extends unknown[], Result> = {
    /** The original function to wrap. */
    fn: (...args: Args) => Result;
    /** Human-readable name recorded in every emitted event. */
    functionName: string;
    /**
     * Returns the current `DynamicCore` instance, or `undefined` when the SDK
     * has not yet been initialised. Instrumentation is skipped when this returns
     * `undefined` or when `core.instrumentation.config.enabled` is `false`.
     */
    getCore: () => DynamicCore | undefined;
    /**
     * Optional explicit payload selectors. When provided, their returned
     * {@link SafePayload} is attached to the corresponding event. When omitted,
     * events carry only the safe envelope.
     */
    selectors?: InstrumentationPayloadSelectors<Args, Result>;
};
/**
 * Wraps a function so that each invocation emits a structured
 * `FunctionInstrumentationEvent` at three lifecycle points:
 *
 * - **started** — immediately before the function body executes.
 * - **resolved** — after the function (or its returned Promise) settles
 *   successfully, with the call duration.
 * - **rejected** — if the function throws synchronously or its returned
 *   Promise rejects, with the duration and the error's class name/code.
 *
 * Events carry only the safe envelope (function name, phase, timing, error
 * class, SDK/runtime metadata, identifiers). **Raw arguments and return values
 * are never captured.** A function that needs additional fields supplies
 * `selectors` that build an explicit, primitive-only {@link SafePayload} — the
 * only path from arguments/return value into a log.
 *
 * The original return value (or thrown error) is always forwarded to the
 * caller unchanged — instrumentation is purely observational, and a throwing
 * selector cannot change that.
 *
 * ## Providing selectors
 *
 * A function opts into a payload by supplying selectors that map its arguments
 * (`started`) and/or its awaited return value (`resolved`) to a primitive-only
 * {@link SafePayload}. Pick individual known-safe fields — never spread a whole
 * object, which is exactly what the model prevents.
 *
 * ```ts
 * const transfer = instrumentFunction({
 *   fn: rawTransfer,
 *   functionName: 'transfer',
 *   getCore: () => core,
 *   selectors: {
 *     // `args` is the argument tuple the wrapped function was called with.
 *     started: ([{ chainId, amount }]) => ({ amount, chainId }),
 *     // `result` is the awaited return value (never the Promise).
 *     resolved: ({ txHash }) => ({ txHash }),
 *   },
 * });
 * ```
 *
 * A selector that throws (or whose output fails scrubbing) is swallowed: the
 * event is still emitted without a payload, and the error is logged at `debug`.
 *
 * ## How functions are wrapped
 *
 * `instrumentFunction` is not called manually in application code. The esbuild
 * instrumentation plugin (`tools/instrumentation-plugin`) injects it at build
 * time for any exported function annotated with `@instrumented` in its JSDoc.
 *
 * ## Opting out
 *
 * Instrumentation is skipped entirely when `getCore()` returns `undefined`
 * (SDK not initialised) or when `core.instrumentation.config.enabled` is
 * `false`; in both cases the original function is called directly.
 * @notInstrumented
 */
export declare const instrumentFunction: <Args extends unknown[], Result>({ fn, functionName, getCore, selectors, }: InstrumentFunctionParams<Args, Result>) => ((...args: Args) => Result);
export {};
//# sourceMappingURL=instrumentFunction.d.ts.map