Fix StartOS 0.4 TypeScript packaging to match SDK API

This commit is contained in:
MacPro
2026-04-09 15:10:44 -05:00
parent 68ec875ee7
commit 8298c083c7
3436 changed files with 867051 additions and 92 deletions
+340
View File
@@ -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;
});
}