import * as fs from 'fs/promises';
import * as T from '../../../base/lib/types';
import * as cp from 'child_process';
import { Buffer } from 'node:buffer';
import { Drop } from '../../../base/lib/util/Drop';
import { Mounts } from '../mainFn/Mounts';
import { BackupEffects } from '../backup/Backups';
import { PathBase } from './Volume';
export declare const execFile: typeof cp.execFile.__promisify__;
export type ExecOptions = {
    input?: string | Buffer;
};
/**
 * Interface representing an isolated container environment for running service processes.
 *
 * Provides methods for executing commands, spawning processes, mounting filesystems,
 * and writing files within the container's rootfs. Comes in two flavors:
 * {@link SubContainerOwned} (owns the underlying filesystem) and
 * {@link SubContainerRc} (reference-counted handle to a shared container).
 */
export interface SubContainer<Manifest extends T.SDKManifest, Effects extends T.Effects = T.Effects> extends Drop, PathBase {
    readonly imageId: keyof Manifest['images'] & T.ImageId;
    readonly rootfs: string;
    readonly guid: T.Guid;
    /**
     * Get the absolute path to a file or directory within this subcontainer's rootfs
     * @param path Path relative to the rootfs
     */
    subpath(path: string): string;
    /**
     * Apply filesystem mounts (volumes, assets, dependencies, backups) to this subcontainer.
     * @param mounts - The Mounts configuration to apply
     * @returns This subcontainer instance for chaining
     */
    mount(mounts: Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>): Promise<this>;
    /** Destroy this subcontainer and clean up its filesystem */
    destroy: () => Promise<null>;
    /**
     * @description run a command inside this subcontainer
     * DOES NOT THROW ON NONZERO EXIT CODE (see execFail)
     * @param commands an array representing the command and args to execute
     * @param options
     * @param timeoutMs how long to wait before killing the command in ms
     * @returns
     */
    exec(command: string[], options?: CommandOptions & ExecOptions, timeoutMs?: number | null, abort?: AbortController): Promise<{
        throw: () => {
            stdout: string | Buffer;
            stderr: string | Buffer;
        };
        exitCode: number | null;
        exitSignal: NodeJS.Signals | null;
        stdout: string | Buffer;
        stderr: string | Buffer;
    }>;
    /**
     * @description run a command inside this subcontainer, throwing on non-zero exit status
     * @param commands an array representing the command and args to execute
     * @param options
     * @param timeoutMs how long to wait before killing the command in ms
     * @returns
     */
    execFail(command: string[], options?: CommandOptions & ExecOptions, timeoutMs?: number | null, abort?: AbortController): Promise<{
        stdout: string | Buffer;
        stderr: string | Buffer;
    }>;
    /**
     * Launch a command as the init (PID 1) process of the subcontainer.
     * Replaces the current leader process.
     * @param command - The command and arguments to execute
     * @param options - Optional environment, working directory, and user overrides
     */
    launch(command: string[], options?: CommandOptions): Promise<cp.ChildProcessWithoutNullStreams>;
    /**
     * Spawn a command inside the subcontainer as a non-init process.
     * @param command - The command and arguments to execute
     * @param options - Optional environment, working directory, user, and stdio overrides
     */
    spawn(command: string[], options?: CommandOptions & StdioOptions): Promise<cp.ChildProcess>;
    /**
     * @description Write a file to the subcontainer's filesystem
     * @param path Path relative to the subcontainer rootfs (e.g. "/etc/config.json")
     * @param data The data to write
     * @param options Optional write options (same as node:fs/promises writeFile)
     */
    writeFile(path: string, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView>, options?: Parameters<typeof fs.writeFile>[2]): Promise<void>;
    /**
     * Create a reference-counted handle to this subcontainer.
     * The underlying container is only destroyed when all handles are released.
     */
    rc(): SubContainerRc<Manifest, Effects>;
    /** Returns true if this is an owned subcontainer (not a reference-counted handle) */
    isOwned(): this is SubContainerOwned<Manifest, Effects>;
}
/**
 * Want to limit what we can do in a container, so we want to launch a container with a specific image and the mounts.
 */
export declare class SubContainerOwned<Manifest extends T.SDKManifest, Effects extends T.Effects = T.Effects> extends Drop implements SubContainer<Manifest, Effects> {
    readonly effects: Effects;
    readonly imageId: keyof Manifest['images'] & T.ImageId;
    readonly rootfs: string;
    readonly guid: T.Guid;
    private destroyed;
    rcs: number;
    private leader;
    private leaderExited;
    private waitProc;
    private constructor();
    static of<Manifest extends T.SDKManifest, Effects extends T.Effects>(effects: Effects, image: {
        imageId: keyof Manifest['images'] & T.ImageId;
        sharedRun?: boolean;
    }, mounts: (Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>) | null, name: string): Promise<SubContainerOwned<Manifest, Effects>>;
    static withTemp<Manifest extends T.SDKManifest, T, Effects extends T.Effects>(effects: Effects, image: {
        imageId: keyof Manifest['images'] & T.ImageId;
        sharedRun?: boolean;
    }, mounts: (Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>) | null, name: string, fn: (subContainer: SubContainer<Manifest, Effects>) => Promise<T>): Promise<T>;
    subpath(path: string): string;
    mount(mounts: Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>): Promise<this>;
    private killLeader;
    get destroy(): () => Promise<null>;
    onDrop(): void;
    /**
     * @description run a command inside this subcontainer
     * DOES NOT THROW ON NONZERO EXIT CODE (see execFail)
     * @param commands an array representing the command and args to execute
     * @param options
     * @param timeoutMs how long to wait before killing the command in ms
     * @returns
     */
    exec(command: string[], options?: CommandOptions & ExecOptions, timeoutMs?: number | null, abort?: AbortController): Promise<{
        throw: () => {
            stdout: string | Buffer;
            stderr: string | Buffer;
        };
        exitCode: number | null;
        exitSignal: NodeJS.Signals | null;
        stdout: string | Buffer;
        stderr: string | Buffer;
    }>;
    /**
     * @description run a command inside this subcontainer, throwing on non-zero exit status
     * @param commands an array representing the command and args to execute
     * @param options
     * @param timeoutMs how long to wait before killing the command in ms
     * @returns
     */
    execFail(command: string[], options?: CommandOptions & ExecOptions, timeoutMs?: number | null, abort?: AbortController): Promise<{
        stdout: string | Buffer;
        stderr: string | Buffer;
    }>;
    launch(command: string[], options?: CommandOptions): Promise<cp.ChildProcessWithoutNullStreams>;
    spawn(command: string[], options?: CommandOptions & StdioOptions): Promise<cp.ChildProcess>;
    /**
     * @description Write a file to the subcontainer's filesystem
     * @param path Path relative to the subcontainer rootfs (e.g. "/etc/config.json")
     * @param data The data to write
     * @param options Optional write options (same as node:fs/promises writeFile)
     */
    writeFile(path: string, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView>, options?: Parameters<typeof fs.writeFile>[2]): Promise<void>;
    rc(): SubContainerRc<Manifest, Effects>;
    isOwned(): this is SubContainerOwned<Manifest, Effects>;
}
/**
 * A reference-counted handle to a {@link SubContainerOwned}.
 *
 * Multiple `SubContainerRc` instances can share one underlying subcontainer.
 * The subcontainer is destroyed only when the last reference is released via `destroy()`.
 */
export declare class SubContainerRc<Manifest extends T.SDKManifest, Effects extends T.Effects = T.Effects> extends Drop implements SubContainer<Manifest, Effects> {
    private readonly subcontainer;
    get imageId(): keyof Manifest["images"] & string;
    get rootfs(): string;
    get guid(): string;
    subpath(path: string): string;
    private destroyed;
    private destroying;
    constructor(subcontainer: SubContainerOwned<Manifest, Effects>);
    static of<Manifest extends T.SDKManifest, Effects extends T.Effects>(effects: Effects, image: {
        imageId: keyof Manifest['images'] & T.ImageId;
        sharedRun?: boolean;
    }, mounts: (Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>) | null, name: string): Promise<SubContainerRc<Manifest, Effects>>;
    static withTemp<Manifest extends T.SDKManifest, T, Effects extends T.Effects>(effects: Effects, image: {
        imageId: keyof Manifest['images'] & T.ImageId;
        sharedRun?: boolean;
    }, mounts: (Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>) | null, name: string, fn: (subContainer: SubContainer<Manifest, Effects>) => Promise<T>): Promise<T>;
    mount(mounts: Effects extends BackupEffects ? Mounts<Manifest, {
        subpath: string | null;
        mountpoint: string;
    }> : Mounts<Manifest, never>): Promise<this>;
    get destroy(): () => Promise<null>;
    onDrop(): void;
    /**
     * @description run a command inside this subcontainer
     * DOES NOT THROW ON NONZERO EXIT CODE (see execFail)
     * @param commands an array representing the command and args to execute
     * @param options
     * @param timeoutMs how long to wait before killing the command in ms
     * @returns
     */
    exec(command: string[], options?: CommandOptions & ExecOptions, timeoutMs?: number | null, abort?: AbortController): Promise<{
        throw: () => {
            stdout: string | Buffer;
            stderr: string | Buffer;
        };
        exitCode: number | null;
        exitSignal: NodeJS.Signals | null;
        stdout: string | Buffer;
        stderr: string | Buffer;
    }>;
    /**
     * @description run a command inside this subcontainer, throwing on non-zero exit status
     * @param commands an array representing the command and args to execute
     * @param options
     * @param timeoutMs how long to wait before killing the command in ms
     * @returns
     */
    execFail(command: string[], options?: CommandOptions & ExecOptions, timeoutMs?: number | null, abort?: AbortController): Promise<{
        stdout: string | Buffer;
        stderr: string | Buffer;
    }>;
    launch(command: string[], options?: CommandOptions): Promise<cp.ChildProcessWithoutNullStreams>;
    spawn(command: string[], options?: CommandOptions & StdioOptions): Promise<cp.ChildProcess>;
    /**
     * @description Write a file to the subcontainer's filesystem
     * @param path Path relative to the subcontainer rootfs (e.g. "/etc/config.json")
     * @param data The data to write
     * @param options Optional write options (same as node:fs/promises writeFile)
     */
    writeFile(path: string, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView>, options?: Parameters<typeof fs.writeFile>[2]): Promise<void>;
    rc(): SubContainerRc<Manifest, Effects>;
    isOwned(): this is SubContainerOwned<Manifest, Effects>;
}
export type CommandOptions = {
    /**
     * Environment variables to set for this command
     */
    env?: {
        [variable in string]?: string;
    };
    /**
     * the working directory to run this command in
     */
    cwd?: string;
    /**
     * the user to run this command as
     */
    user?: string;
};
export type StdioOptions = {
    stdio?: cp.IOType;
};
/** UID/GID mapping for mount id-remapping (see kernel idmappings docs) */
export type IdMap = {
    fromId: number;
    toId: number;
    range: number;
};
/** Union of all mount option types supported by the subcontainer runtime */
export type MountOptions = MountOptionsVolume | MountOptionsAssets | MountOptionsPointer | MountOptionsBackup;
/** Mount options for binding a service volume into a subcontainer */
export type MountOptionsVolume = {
    type: 'volume';
    volumeId: string;
    subpath: string | null;
    readonly: boolean;
    filetype: 'file' | 'directory' | 'infer';
    idmap: IdMap[];
};
/** Mount options for binding packaged static assets into a subcontainer */
export type MountOptionsAssets = {
    type: 'assets';
    subpath: string | null;
    filetype: 'file' | 'directory' | 'infer';
    idmap: {
        fromId: number;
        toId: number;
        range: number;
    }[];
};
/** Mount options for binding a dependency package's volume into a subcontainer */
export type MountOptionsPointer = {
    type: 'pointer';
    packageId: string;
    volumeId: string;
    subpath: string | null;
    readonly: boolean;
    idmap: {
        fromId: number;
        toId: number;
        range: number;
    }[];
};
/** Mount options for binding the backup directory into a subcontainer */
export type MountOptionsBackup = {
    type: 'backup';
    subpath: string | null;
    filetype: 'file' | 'directory' | 'infer';
    idmap: {
        fromId: number;
        toId: number;
        range: number;
    }[];
};
/**
 * Error thrown when a subcontainer command exits with a non-zero code or signal.
 * Contains the full result including stdout, stderr, exit code, and exit signal.
 */
export declare class ExitError extends Error {
    readonly command: string;
    readonly result: {
        exitCode: number | null;
        exitSignal: T.Signals | null;
        stdout: string | Buffer;
        stderr: string | Buffer;
    };
    constructor(command: string, result: {
        exitCode: number | null;
        exitSignal: T.Signals | null;
        stdout: string | Buffer;
        stderr: string | Buffer;
    });
}
