import { HealthCheckResult } from '../health/checkFns'; import { Trigger } from '../trigger'; import * as T from '../../../base/lib/types'; import { SubContainer } from '../util/SubContainer'; import * as CP from 'node:child_process'; export { Daemon } from './Daemon'; export { CommandController } from './CommandController'; import { HealthDaemon } from './HealthDaemon'; import { Daemon } from './Daemon'; import { CommandController } from './CommandController'; /** Promisified version of `child_process.exec` */ export declare const cpExec: typeof CP.exec.__promisify__; /** Promisified version of `child_process.execFile` */ export declare const cpExecFile: typeof CP.execFile.__promisify__; /** * Configuration for a daemon's health-check readiness probe. * * Determines how the system knows when a daemon is healthy and ready to serve. */ export type Ready = { /** A human-readable display name for the health check. If null, the health check itself will be from the UI */ display: string | null; /** * @description The function to determine the health status of the daemon * * The SDK provides some built-in health checks. To see them, type sdk.healthCheck. * * @example * ``` fn: () => sdk.healthCheck.checkPortListening(effects, 80, { successMessage: 'service listening on port 80', errorMessage: 'service is unreachable', }) * ``` */ fn: () => Promise | HealthCheckResult; /** * A duration in milliseconds to treat a failing health check as "starting" * * defaults to 5000 */ gracePeriod?: number; trigger?: Trigger; }; /** * Options for running a daemon as a shell command inside a subcontainer. * Includes the command to run, optional signal/timeout, environment, user, and stdio callbacks. */ export type ExecCommandOptions = { command: T.CommandType; sigtermTimeout?: number; runAsInit?: boolean; env?: { [variable in string]?: string; } | undefined; cwd?: string | undefined; user?: string | undefined; onStdout?: (chunk: Buffer | string | any) => void; onStderr?: (chunk: Buffer | string | any) => void; }; /** * Options for running a daemon via an async function that may optionally return * a command to execute in the subcontainer. The function receives an `AbortSignal` * for cooperative cancellation. */ export type ExecFnOptions | null> = { fn: (subcontainer: C, abort: AbortSignal) => Promise; sigtermTimeout?: number; }; /** * The execution specification for a daemon: either an {@link ExecFnOptions} (async function) * or an {@link ExecCommandOptions} (shell command, only valid when a subcontainer is provided). */ export type DaemonCommandType | null> = ExecFnOptions | (C extends null ? never : ExecCommandOptions); type NewDaemonParams | null> = { /** What to run as the daemon: either an async fn or a commandline command to run in the subcontainer */ exec: DaemonCommandType; /** The subcontainer in which the daemon runs */ subcontainer: C; }; type OptionalParamSync = T | (() => T | null); type OptionalParamAsync = () => Promise; type AddDaemonParams | null> = (NewDaemonParams | { daemon: Daemon; }) & { ready: Ready; /** An array of IDs of prior daemons whose successful initializations are required before this daemon will initialize */ requires: Exclude[]; }; type AddOneshotParams | null> = NewDaemonParams & { exec: DaemonCommandType; /** An array of IDs of prior daemons whose successful initializations are required before this daemon will initialize */ requires: Exclude[]; }; type AddHealthCheckParams = { ready: Ready; /** An array of IDs of prior daemons whose successful initializations are required before this daemon will initialize */ requires: Exclude[]; }; type ErrorDuplicateId = `The id '${Id}' is already used`; export declare const runCommand: () => (effects: T.Effects, subcontainer: SubContainer, exec: DaemonCommandType>) => Promise>>; /** * A class for defining and controlling the service daemons ```ts Daemons.of({ effects, started, interfaceReceipt, // Provide the interfaceReceipt to prove it was completed healthReceipts, // Provide the healthReceipts or [] to prove they were at least considered }).addDaemon('webui', { command: 'hello-world', // The command to start the daemon ready: { display: 'Web Interface', // The function to run to determine the health status of the daemon fn: () => checkPortListening(effects, 80, { successMessage: 'The web interface is ready', errorMessage: 'The web interface is not ready', }), }, requires: [], }) ``` */ export declare class Daemons implements T.DaemonBuildable { readonly effects: T.Effects; readonly ids: Ids[]; readonly healthDaemons: HealthDaemon[]; private termPromise; private constructor(); /** * Returns an empty new Daemons class with the provided inputSpec. * * Call .addDaemon() on the returned class to add a daemon. * * Daemons run in the order they are defined, with latter daemons being capable of * depending on prior daemons * * @param effects * * @param started * @returns */ static of(options: { effects: T.Effects; }): Daemons; private addDaemonImpl; /** * Returns the complete list of daemons, including the one defined here * @param id * @param options * @returns a new Daemons object */ addDaemon | null>(id: "" extends Id ? never : ErrorDuplicateId extends Id ? never : Id extends Ids ? ErrorDuplicateId : Id, options: OptionalParamSync>): Daemons; addDaemon | null>(id: "" extends Id ? never : ErrorDuplicateId extends Id ? never : Id extends Ids ? ErrorDuplicateId : Id, options: OptionalParamAsync>): Promise>; /** * Returns the complete list of daemons, including a "oneshot" daemon one defined here * a oneshot daemon is a command that executes once when started, and is considered "running" once it exits successfully * @param id * @param options * @returns a new Daemons object */ addOneshot | null>(id: "" extends Id ? never : ErrorDuplicateId extends Id ? never : Id extends Ids ? ErrorDuplicateId : Id, options: OptionalParamSync>): Daemons; addOneshot | null>(id: "" extends Id ? never : ErrorDuplicateId extends Id ? never : Id extends Ids ? ErrorDuplicateId : Id, options: OptionalParamAsync>): Promise>; /** * Returns the complete list of daemons, including a new HealthCheck defined here * @param id * @param options * @returns a new Daemons object */ addHealthCheck(id: "" extends Id ? never : ErrorDuplicateId extends Id ? never : Id extends Ids ? ErrorDuplicateId : Id, options: OptionalParamSync>): Daemons; addHealthCheck(id: "" extends Id ? never : ErrorDuplicateId extends Id ? never : Id extends Ids ? ErrorDuplicateId : Id, options: OptionalParamAsync>): Promise>; /** * Runs the entire system until all daemons have returned `ready`. * @param id * @param options * @returns a new Daemons object */ runUntilSuccess(timeout: number | null): Promise; /** * Gracefully terminate all daemons in reverse dependency order. * * Daemons with no remaining dependents are shut down first, proceeding * until all daemons have been terminated. Falls back to a bulk shutdown * if a dependency cycle is detected. */ term(): Promise; private _term; /** * Start all registered daemons and their health checks. * @returns This `Daemons` instance, now running */ build(): Promise; }