Fix StartOS 0.4 TypeScript packaging to match SDK API
This commit is contained in:
+340
@@ -0,0 +1,340 @@
|
||||
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;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user