/**
 * Hardened introspection for serializing values that may originate inside a
 * workflow VM (`node:vm`) sandbox realm.
 *
 * Serialization runs on the host, but the values it inspects were
 * constructed by workflow code, so a naive dynamic operation like
 * `value.toISOString()`, `Array.from(map)`, or `Object.prototype.toString`
 * dispatches into the sandbox realm and executes workflow code (patched
 * prototype methods, getters, proxy traps, `Symbol.toStringTag` accessors).
 * That is a determinism hazard: serialization happens exactly once per
 * payload (never again on replay), so any workflow-visible side effect it
 * triggers exists only on the live execution path and diverges from replay.
 *
 * This module makes serialization side-effect free wherever the data allows
 * it, and *observable* where it does not:
 *
 * - **Classification** uses engine-level brand checks (`node:util` `types`,
 *   internal-slot probes) instead of `instanceof` / `Object.prototype.toString`,
 *   which makes it immune to `Symbol.hasInstance`, `Symbol.toStringTag`, and
 *   reassigned globals.
 * - **Extraction** goes through intrinsics captured at module load (host
 *   boot, before any workflow code runs). Internal slots are realm-agnostic,
 *   so host intrinsics read VM-realm objects without touching the sandbox's
 *   (patchable) prototypes.
 * - **Property access** reads through descriptors, so plain data never
 *   invokes anything. Where workflow code *must* run because the data itself
 *   lives behind it (getters, proxies, custom `[WORKFLOW_SERIALIZE]`
 *   methods, `toString()` on toStringTag-branded objects such as Temporal
 *   polyfills), the execution is preserved for compatibility and recorded
 *   in the active {@link GuestCodeStats} sink, so callers (e.g. a retained-VM
 *   gate) can react.
 *
 * **Recording is not prevention.** For the recorded cases the determinism
 * hazard is still live: a getter that calls `Math.random()` advances the
 * run's seeded PRNG during serialization, and because serialization happens
 * exactly once and is never replayed, every subsequent draw (including the
 * correlation ids derived from that stream) shifts relative to replay. The
 * report is the only trace of that; acting on it (warning, demoting a
 * retained VM to replay) is left to the caller.
 *
 * The recorder is ambient module state, set for the duration of a
 * synchronous `stringify` call via {@link withGuestCodeStats}. devalue's
 * `stringify` is fully synchronous, so this is safe without async context.
 */
import type { StringifyOperations } from '../_devalue.js';
/**
 * A single instance of workflow (guest) code executing during serialization.
 */
export interface GuestCodeExecution {
    /**
     * What forced the execution:
     * - `getter`: an accessor property was invoked to read data
     * - `proxy`: a proxy was introspected, firing its traps. Note this also
     *   implies a **shape change**: brand checks answer "not that type" for a
     *   proxy, so a proxied `Map` serializes as a plain object rather than as a
     *   `Map`, and this report is the only evidence of it. (Such values were
     *   never serializable before, since the internal-slot reads in the previous
     *   implementation threw on them, so the shape change replaces a crash,
     *   but it is silent.)
     * - `method`: a workflow-defined function was invoked (e.g. a custom
     *   `[WORKFLOW_SERIALIZE]` serializer, `toString()` on a
     *   `Symbol.toStringTag`-branded object, a duck-typed `getTime()`, or a
     *   `__closureVarsFn` this package did not generate)
     */
    kind: 'getter' | 'proxy' | 'method';
    /** Best-effort context: the property key, method name, or tag involved. */
    detail?: string;
}
/**
 * Mutable sink recording workflow-code execution serialization could not
 * avoid. `executions` contains the first five samples and `totalExecutions`
 * is the exact count.
 */
export interface GuestCodeStats {
    executions: GuestCodeExecution[];
    totalExecutions?: number;
}
export declare const GUEST_CODE_EXECUTION_SAMPLE_LIMIT = 5;
/**
 * Runs `fn` (synchronously) with `stats` as the active guest-code sink.
 * Nested calls stack correctly; a `null`/`undefined` sink disables
 * recording without disabling hardening.
 */
export declare function withGuestCodeStats<T>(stats: GuestCodeStats | undefined, fn: () => T): T;
/** Marks a function as having been passed to `useStep`. */
export declare function markUseStepClosureFn<T extends object>(fn: T): T;
/** Whether `fn` was marked by {@link markUseStepClosureFn}. */
export declare function isUseStepClosureFn(fn: unknown): boolean;
export declare function recordGuestCode(kind: GuestCodeExecution['kind'], detail?: string): void;
/** `Date.prototype.getDate`, for invalid-date checks. */
export declare const dateGetDate: (thisArg: unknown) => number;
/** `Date.prototype.getTime`. */
export declare const dateGetTime: (thisArg: unknown) => number;
/** `Date.prototype.toISOString`. */
export declare const dateToISOString: (thisArg: unknown) => string;
/** `RegExp.prototype.source` getter. */
export declare const regExpSource: (value: unknown) => string;
/** `RegExp.prototype.flags` getter. */
export declare const regExpFlags: (value: unknown) => string;
/** `ArrayBuffer.prototype.byteLength` getter (internal slot read). */
export declare const arrayBufferByteLength: (value: unknown) => number;
/**
 * Reads `value[key]` with `[[Get]]` semantics, but through descriptors:
 * plain data properties never invoke anything; accessor properties are
 * invoked (the data lives behind them) and recorded; proxies fall back to
 * a plain read (their traps are the only access path) and are recorded.
 */
export declare function readProperty(value: unknown, key: PropertyKey): unknown;
/**
 * `key in value` semantics without firing proxy traps for ordinary
 * objects. Proxies fall back to the `in` operator and are recorded.
 */
export declare function hasProperty(value: unknown, key: PropertyKey): boolean;
/**
 * `value instanceof C` semantics for a known `C.prototype`, without
 * consulting `Symbol.hasInstance` (which workflow code can define). Used
 * for host classes that are injected into the sandbox (Headers, URL,
 * URLSearchParams, DOMException), where the instances (from any realm the
 * host handed the class to) carry the host prototype in their chain.
 *
 * Proxies are walked rather than rejected: `Reflect.getPrototypeOf` fires
 * the proxy's `getPrototypeOf` trap, matching `instanceof` semantics, and
 * real values depend on that: Next.js hands the runtime a proxied
 * `NextRequest`, and answering "not a Request" for it would silently break
 * webhooks. The traps are guest-observable, so the proxy is recorded.
 */
export declare function isInstanceOfPrototype(value: unknown, prototype: object | undefined): boolean;
/** `URL.prototype.href` getter. */
export declare function urlHref(value: URL): string;
/** `URLSearchParams.prototype.toString`: returns `''` iff empty. */
export declare function urlSearchParamsToString(value: URLSearchParams): string;
/**
 * Iterates a Headers instance through the captured host iterator, so the
 * iterator object, and its `next`, are host-realm.
 */
export declare function headersToEntries(value: Headers): [string, string][];
/**
 * Iterates a genuine Map's entries entirely through host intrinsics: the
 * iterator object is created by the host `Map.prototype.entries`, so its
 * realm, and therefore its `next`, is the host's, not the sandbox's.
 */
export declare function mapToEntries(value: Map<unknown, unknown>): [unknown, unknown][];
/** See {@link mapToEntries}. */
export declare function setToValues(value: Set<unknown>): unknown[];
/**
 * The bytes of an `ArrayBufferView`, read via internal-slot getters, so
 * own-property shadowing and prototype patches cannot change which bytes
 * are serialized.
 */
export declare function viewInfo(value: ArrayBufferView): {
    buffer: ArrayBufferLike;
    byteOffset: number;
    byteLength: number;
};
export declare const hardenedStringifyOperations: Partial<StringifyOperations>;
//# sourceMappingURL=hardened.d.ts.map