import type { Readable } from 'node:stream';
import { ProgressEmitter } from '../server/serverHelpers/progressEmitter.ts';
export declare function getActiveEmitter(deploymentId: string): ProgressEmitter | undefined;
type DeploymentStatus = 'pending' | 'extracting' | 'installing' | 'loading' | 'replicating' | 'restarting' | 'success' | 'failed' | 'rolled_back';
interface CreateOptions {
    project?: string;
    package_identifier?: string;
    user?: string;
    restart_mode?: 'immediate' | 'rolling' | null;
    rollback_of?: string | null;
    emitter?: ProgressEmitter;
}
export declare class DeploymentRecorder {
    readonly deploymentId: string;
    private readonly record;
    private hash;
    private byteCount;
    private finished;
    private unsubscribe;
    private pendingPut;
    private dirty;
    private sealed;
    private constructor();
    static create(options: CreateOptions): Promise<DeploymentRecorder>;
    /**
     * Subscribe to a ProgressEmitter. Each event is appended (bounded) to event_log; phase
     * events also update the row's `status` and `phase` fields. Writes coalesce: a put is
     * always pending after the first event in a burst, so chatty install output collapses
     * to one row update per ~100ms instead of one per line.
     */
    private subscribeTo;
    private appendEvent;
    private scheduleFlush;
    /**
     * Drain a payload source (Buffer or Readable) into the row's payload_blob attribute,
     * computing sha256 and byte count alongside. After this resolves the row has been
     * committed once with the final hash and size, and `this.row.payload_blob.stream()`
     * yields a fresh Readable that callers can pass to extraction.
     *
     * Buffers the payload in memory (subject to PAYLOAD_BUFFER_CAP_BYTES) so the
     * hash/size are known synchronously before we commit and so the blob's `saveBlob`
     * lifecycle doesn't race with our digest() call. A streaming variant is a planned
     * follow-up that uses the unused `hash`/`byteCount` instance fields below.
     */
    ingestPayload(source: Readable | Buffer | string): Promise<void>;
    transitionPhase(phase: string, status?: DeploymentStatus): Promise<void>;
    /**
     * Upsert a single peer outcome by node name. Called per-peer as each replication
     * target settles, so the row reflects in-flight progress rather than only the
     * final aggregate. Routes through `scheduleFlush()` so the write coalesces with
     * the emitter-driven puts and the latest in-memory state always wins.
     *
     * Tolerates unknown shapes — anything we can't interpret becomes a plain
     * stringified entry so the audit trail at least records that a peer was contacted.
     */
    recordPeer(result: unknown): void;
    /**
     * Bulk-record a final aggregate of peer outcomes. Equivalent to calling recordPeer()
     * for each entry. Useful for replication layers that surface results all-at-once
     * via Promise.allSettled rather than via a per-peer callback.
     */
    recordPeers(results: unknown): void;
    /**
     * Stop persisting intermediate row updates; accumulate them in memory so finish() writes
     * the terminal state in a single put. Called before the replicate phase, where the row
     * otherwise receives a tight burst of puts (replicate phase + per-peer + finish) within
     * a few ms. That burst can commit out of order on a loaded peer, where an older full
     * update reverts the terminal `success` write — the row stays stuck at `replicating` and
     * never converges (harperdb/harper#1170). Collapsing to one terminal write isolates it
     * from any concurrent same-key write so the receiver converges.
     *
     * Tradeoff: the origin's get_deployment *polling* view skips the transient `replicating`
     * status and incremental peer_results during the final phase; live SSE tailing is
     * unaffected (the emitter still emits in real time). Once #1170 lands this seal can be
     * removed to restore incremental peer_results persistence.
     */
    seal(): void;
    finish(status: 'success' | 'failed' | 'rolled_back', error?: unknown): Promise<void>;
    get row(): Record<string, any>;
    private put;
}
/**
 * Peer-side helper — wait for the hdb_deployment row to arrive via table replication,
 * then return it. The row is committed on origin before `replicateOperation` is
 * called, so peers normally find it immediately; this polling loop is for the rare
 * case where the operation arrives faster than the table-replication channel.
 *
 * The payload_blob's chunks may still be in flight after the row arrives — that's
 * fine, the Blob's `stream()` / `bytes()` API blocks on incomplete writes
 * (resources/blob.ts).
 */
export declare function awaitDeploymentRow(deploymentId: string, options?: {
    timeoutMs?: number;
    pollIntervalMs?: number;
    initialPollIntervalMs?: number;
}): Promise<Record<string, any>>;
export {};
