/**
 * The trace transport: a {@link TraceSignal} union and the {@link SignalChannel}
 * that streams it.
 *
 * Rather than a `Set` of push subscribers with a manually-drained `flush()`,
 * trace data flows through a single backpressure-free queue exposed as an
 * `AsyncIterable<TraceSignal>`. A producer calls {@link SignalChannel.emit} as
 * segments open, change, and close; one or more consumers pull with
 * `for await … of channel`. The drain semantics are therefore the language's
 * own async-iteration protocol — no iteration cap, no subscriber bookkeeping.
 *
 * Exactly one signal is emitted per state transition of a {@link import('../signal/handle').SegmentHandle}:
 * `open` when a segment is created, `update` when attributes are noted, and
 * `close` carrying the terminal {@link TraceRecord}.
 */
import type { Segment, TraceRecord } from "../signal/segment";
/** Emitted once, when a segment is first opened. Carries the full open value. */
export interface OpenSignal {
    readonly type: "open";
    readonly segment: Segment;
}
/** Emitted when an open segment's attributes are amended in place (by id). */
export interface UpdateSignal {
    readonly type: "update";
    readonly id: string;
    readonly attributes: Readonly<Record<string, unknown>>;
}
/** Emitted once, when a segment reaches a terminal state. Carries the record. */
export interface CloseSignal {
    readonly type: "close";
    readonly record: TraceRecord;
}
/** The tagged union every consumer of a {@link SignalChannel} branches on. */
export type TraceSignal = OpenSignal | UpdateSignal | CloseSignal;
/**
 * Optional behaviour for a {@link SignalChannel}.
 *
 * `bound` caps the number of signals buffered while no consumer is pulling;
 * once exceeded the *oldest* unread signal is dropped (newest data wins). Left
 * unset, the buffer is unbounded.
 */
export interface SignalChannelOptions {
    readonly bound?: number;
}
/**
 * A single-stream, multi-emit, async-iterable transport for {@link TraceSignal}s.
 *
 * Producers push with {@link emit}; a consumer drains with `for await`. When the
 * channel is faster than its consumer, signals queue (subject to `bound`); when
 * the consumer is faster, its pull parks on a promise the next `emit` resolves.
 * {@link close} ends the stream — the active iterator completes after draining
 * whatever is already queued, and further `emit`s are ignored.
 *
 * The channel is *cold-tolerant but single-consumer*: a second concurrent
 * `[Symbol.asyncIterator]()` pull shares the same queue (signals are not
 * fanned out / cloned). For fan-out, compose multiple channels upstream.
 */
export declare class SignalChannel implements AsyncIterable<TraceSignal> {
    /** Buffered signals awaiting a consumer, oldest first. */
    private readonly buffer;
    /** A parked consumer's resolver, set while a pull awaits the next signal. */
    private waiting;
    /** Once true, no further signals are accepted and pulls drain then end. */
    private closed;
    /** Upper bound on the unread buffer; `Infinity` means unbounded. */
    private readonly bound;
    constructor(options?: SignalChannelOptions);
    /**
     * Publish a signal onto the stream.
     *
     * If a consumer is parked, the signal is handed to it directly; otherwise it
     * is buffered (dropping the oldest entry past `bound`). A no-op once closed.
     */
    emit(signal: TraceSignal): void;
    /**
     * End the stream.
     *
     * A parked consumer is completed immediately; a consumer that later pulls
     * receives any still-buffered signals before the terminal `done`. Idempotent.
     */
    close(): void;
    /** Whether {@link close} has been called. */
    get isClosed(): boolean;
    /** Count of signals buffered but not yet consumed. */
    get pending(): number;
    /**
     * The async-iteration entrypoint.
     *
     * Yields buffered signals immediately, then parks awaiting the next `emit`,
     * and returns `{ done: true }` once the channel is closed and drained.
     */
    [Symbol.asyncIterator](): AsyncIterator<TraceSignal>;
}
