import { type RuntimeFiles } from '../../../files.ts';
import type { SetAttrFields } from '../../../../types.ts';
/**
 * One guest change to names or metadata, recorded in the order the script
 * performed it. A file's bytes are not here: its stream writes through
 * its core handle (`SyncVFS.pwrite`).
 */
export type MirageMutation = {
    readonly kind: 'create';
    readonly path: string;
} | {
    readonly kind: 'truncate';
    readonly path: string;
    readonly length: number;
} | {
    readonly kind: 'mkdir';
    readonly path: string;
} | {
    readonly kind: 'unlink';
    readonly path: string;
} | {
    readonly kind: 'rmdir';
    readonly path: string;
} | {
    readonly kind: 'rename';
    readonly path: string;
    readonly dst: string;
} | {
    readonly kind: 'symlink';
    readonly path: string;
    readonly target: string;
} | {
    readonly kind: 'setattr';
    readonly path: string;
    readonly attrs: SetAttrFields;
};
/**
 * The write-ahead log a pyodide guest records into.
 *
 * Every mark is deliberately synchronous: the guest's os.mkdir() and
 * os.rename() run inside sync WASM frames where awaiting a mount op
 * needs JSPI stack switching, which most engines do not enable. The guest
 * records here and the runtime replays after the script returns, where
 * awaiting is free. This is the one thing pyodide needs that the other
 * runtimes do not: quickjs suspends at the call and monty runs the op on
 * its own worker.
 */
export interface MutationJournal {
    markCreate(path: string): void;
    /**
     * Take back the create of `path` the journal ends with, which the open
     * right after it makes instead; false when it ends with no such create.
     */
    takeCreate(path: string): boolean;
    /**
     * Args:
     *   path: mount-prefixed path the mutation names.
     *   length: the length the file is left at.
     */
    markTruncate(path: string, length: number): void;
    markMkdir(path: string): void;
    markUnlink(path: string): void;
    markRmdir(path: string): void;
    markRename(src: string, dst: string): void;
    /**
     * Args:
     *   path: guest-absolute path of the link.
     *   target: what it points at, stored verbatim.
     */
    markSymlink(path: string, target: string): void;
    /**
     * Args:
     *   path: guest-absolute path whose metadata changed.
     *   attrs: only the fields the guest wrote, already in the op's own
     *     terms (ISO stamps), because the unit Emscripten passes is the
     *     caller's fact and not the journal's.
     */
    markSetattr(path: string, attrs: SetAttrFields): void;
    /** Drain the journal: every mutation in guest order, cleared. */
    takeMutations(): MirageMutation[];
    /**
     * Record nothing more until `reopen`: the guest called `os._exit`, and
     * a process that exited writes nothing after it, even when the guest
     * catches the exit and runs on.
     */
    seal(): void;
    /** Whether the guest exited since the last `reopen`: its streams read and write nothing more either. */
    readonly sealed: boolean;
    /** Record again, for the next run. */
    reopen(): void;
}
export declare function createJournal(): MutationJournal;
/**
 * Replay one recorded guest mutation against the mounts.
 *
 * Args:
 *   files: the runtime's mount vocabulary to apply through.
 *   mutation: the journal entry to apply.
 */
export declare function applyMutation(files: RuntimeFiles, mutation: MirageMutation): Promise<void>;
//# sourceMappingURL=journal.d.ts.map