/**
 * @beignet/core/memo
 *
 * Request-scoped memoization for port lookups and other async functions.
 *
 * `createMemo(fn)` deduplicates calls with the same arguments for the
 * lifetime of one request: the server enters a memo scope around every HTTP
 * request and `runServiceContext(...)` execution, and the scope's cache dies
 * with it. There is no TTL and no cross-request state, so memoized reads can
 * never serve data staler than the request that fetched them.
 *
 * Outside any scope — plain scripts, `createServiceContext(...)` callers —
 * memoized functions call straight through without caching.
 */
/**
 * Error thrown when a default cache key cannot be derived from arguments.
 */
export declare class MemoKeyError extends Error {
    constructor(message: string);
}
/**
 * Instrumentation event emitted by memoized functions inside a scope that
 * carries a recorder.
 */
export interface MemoInstrumentationEvent {
    /** Whether the call was served from the scope cache or filled it. */
    kind: "hit" | "miss";
    /** Memo name from `createMemo` options, defaulting to the function name. */
    memo: string;
    /** Encoded argument key for the call. */
    key: string;
    /** Fill duration for misses, rounded to two decimals. */
    durationMs?: number;
    /** Set when a miss's underlying call rejected (the entry is evicted). */
    failed?: boolean;
}
/**
 * Run a function inside a memo scope with an explicit recorder.
 *
 * Internal to the server runtime — apps should use `runMemoScope(...)`.
 * Always uses `AsyncLocalStorage.run` (never `enterWith`), so callers'
 * continuations never resume through a dangling frame.
 */
export declare function runWithMemoScope<T>(options: {
    record?: (event: MemoInstrumentationEvent) => void;
}, fn: () => T): T;
/**
 * Run a function inside a fresh memo scope.
 *
 * Use this in scripts and unit tests to give memoized functions a cache
 * lifetime. Nested scopes start empty; an active recorder is inherited so
 * instrumentation keeps flowing.
 */
export declare function runMemoScope<T>(fn: () => T): T;
/**
 * Memoized function returned by `createMemo(...)`.
 */
export type Memoized<F extends (...args: never[]) => unknown> = F & {
    /**
     * Drop the current scope's entry for these arguments, so the next call
     * re-executes. Call this from mutation methods that make a memoized read
     * stale within the same request.
     *
     * @returns Whether an entry existed.
     */
    invalidate(...args: Parameters<F>): boolean;
    /**
     * Drop all of this function's entries in the current scope.
     */
    clear(): void;
};
/**
 * Options for `createMemo(...)`.
 */
export interface CreateMemoOptions<F extends (...args: never[]) => unknown> {
    /**
     * Name used in instrumentation events and key errors. Defaults to the
     * wrapped function's name.
     */
    name?: string;
    /**
     * Build the cache key from the call arguments. Defaults to a structural,
     * type-tagged encoding of the arguments that throws `MemoKeyError` for
     * values it cannot encode deterministically (functions, symbols, class
     * instances, circular references).
     */
    key?: (...args: Parameters<F>) => string;
}
/**
 * Wrap an async lookup so calls with the same arguments run once per request.
 *
 * Within a memo scope the first call executes and every later call with the
 * same key returns the same value — including the same in-flight promise, so
 * concurrent calls share one execution. Rejected promises are evicted, so a
 * failed lookup is retried by the next call rather than memoized. Outside a
 * scope the function calls through uncached.
 *
 * Memoize reads, not mutations. When a mutation in the same infra module
 * makes a memoized read stale, call `memoized.invalidate(...)` with the
 * read's arguments.
 *
 * @param fn - Function to memoize. `this` is not forwarded.
 * @param options - Optional name and key builder.
 * @returns The function with `invalidate(...)` and `clear()` attached.
 */
export declare function createMemo<F extends (...args: never[]) => unknown>(fn: F, options?: CreateMemoOptions<F>): Memoized<F>;
//# sourceMappingURL=index.d.ts.map