@orkestrel/process 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.d.cts +239 -0
- package/dist/src/core/index.d.ts +239 -0
- package/dist/src/server/index.cjs +650 -216
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +124 -0
- package/dist/src/server/index.d.ts +124 -0
- package/dist/src/server/index.js +649 -217
- package/dist/src/server/index.js.map +1 -1
- package/package.json +12 -11
|
@@ -267,6 +267,10 @@ export declare const PROCESS_TIMER = 2147483647;
|
|
|
267
267
|
* backlog, a byte-bounded stderr tail, a live stderr event, a writable stdin channel, a typed
|
|
268
268
|
* lifecycle {@link ProcessEventMap} emitter, and bounded termination. The low-level streaming
|
|
269
269
|
* primitive.
|
|
270
|
+
* - **{@link SessionInterface}** — the same supervised child observed as raw bytes: an owned
|
|
271
|
+
* `Uint8Array` per stdout chunk, an open stdin channel closed by `end` rather than by a switch,
|
|
272
|
+
* the child's own `ending` beside the terminal `exit`, and a typed {@link SessionEventMap}
|
|
273
|
+
* emitter. The transport primitive, for a child speaking a framed protocol.
|
|
270
274
|
* - **{@link ExecuteResult} / execute** — a one-shot spawn that buffers a child to completion and settles
|
|
271
275
|
* with its output and exit, the ergonomic layer for fire-and-collect commands.
|
|
272
276
|
* - **{@link ProcessManagerInterface}** — a keyed registry of live {@link ProcessInterface}
|
|
@@ -699,6 +703,241 @@ export declare interface ProcessOptions {
|
|
|
699
703
|
readonly signal?: AbortSignal;
|
|
700
704
|
}
|
|
701
705
|
|
|
706
|
+
/**
|
|
707
|
+
* The push observation surface of a {@link SessionInterface} — the moments a byte-oriented observer
|
|
708
|
+
* subscribes to, alongside the `ending` and `exit` promises.
|
|
709
|
+
*
|
|
710
|
+
* @remarks
|
|
711
|
+
* Declared as a `type` alias so it satisfies the emitter's `EventMap` constraint structurally.
|
|
712
|
+
*
|
|
713
|
+
* `stdout` carries one owned `Uint8Array` per chunk the host delivered, in arrival order, framed by
|
|
714
|
+
* nothing and decoded by nothing. The array is the session's own copy and a plain `Uint8Array`
|
|
715
|
+
* rather than the host buffer the read produced, so a consumer keeps it, mutates it, concatenates
|
|
716
|
+
* it, and reads its whole backing buffer without reaching memory the host still manages and without
|
|
717
|
+
* depending on a host type. A chunk boundary is the host's, so one event is not one message and a
|
|
718
|
+
* line feed inside a payload starts no new event; a consumer that needs messages frames the
|
|
719
|
+
* concatenated bytes itself.
|
|
720
|
+
*
|
|
721
|
+
* `stderr` carries decoded text instead, because a diagnostic stream is read rather than parsed, and
|
|
722
|
+
* {@link SessionInterface.evidence} bounds those same bytes. The `error` event carries a child fault
|
|
723
|
+
* — a failure to spawn, a process-level error, or a host-reported standard-input channel fault. A
|
|
724
|
+
* surfaced standard-input fault is wrapped in a {@link ProcessError} coded `protocol` with the host
|
|
725
|
+
* fault as its cause. The event is distinct from the `error` handler in {@link SessionOptions}: a
|
|
726
|
+
* listener throw is isolated by the emitter and routed to that handler, never emitted as this
|
|
727
|
+
* `error` event.
|
|
728
|
+
*/
|
|
729
|
+
export declare type SessionEventMap = {
|
|
730
|
+
/** A standard-output chunk arrived, as an owned `Uint8Array` the consumer may keep and mutate. */
|
|
731
|
+
readonly stdout: readonly [chunk: Uint8Array];
|
|
732
|
+
/** A decoded standard-error chunk arrived. */
|
|
733
|
+
readonly stderr: readonly [chunk: string];
|
|
734
|
+
/** The child or its open standard-input channel reported a fault, carrying the host cause directly or through a `protocol` {@link ProcessError}. */
|
|
735
|
+
readonly error: readonly [error: unknown];
|
|
736
|
+
/** The child settled — its terminal state, delivered once. */
|
|
737
|
+
readonly exit: readonly [exit: ProcessExit];
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* One supervised child process read as raw bytes, with an open standard-input channel and bounded
|
|
742
|
+
* termination.
|
|
743
|
+
*
|
|
744
|
+
* @remarks
|
|
745
|
+
* A session is the transport face of the same supervision {@link ProcessInterface} exposes. It
|
|
746
|
+
* publishes the child's standard output as `stdout` events carrying owned bytes rather than framed
|
|
747
|
+
* lines, so a consumer speaking a length-prefixed or delimiter-framed protocol reads the bytes the
|
|
748
|
+
* child wrote and frames them itself. Nothing here retains output: a session holds no backlog and
|
|
749
|
+
* pauses nothing, so it omits `lines`, `truncated`, `backlog`, and `send` rather than reporting them
|
|
750
|
+
* as facts that do not apply. `evidence` is the decoded, byte-bounded stderr tail — the diagnostic to
|
|
751
|
+
* attach to a failed exit — and the typed `emitter` carries the live `stdout` and `stderr` payloads,
|
|
752
|
+
* the child `error` cause, and the terminal `exit`.
|
|
753
|
+
*
|
|
754
|
+
* **Two endings, named apart.** `ending` settles at the child's own native exit and resolves no
|
|
755
|
+
* value, because `code` and `signal` already carry the terminal facts as soon as the host records
|
|
756
|
+
* them. `exit` settles at the terminal moment, which is the native exit plus at most `drain` when a
|
|
757
|
+
* descendant that inherited the child's stdio still holds the read ends open. A caller racing a
|
|
758
|
+
* cooperative shutdown window therefore awaits `ending`, and a caller collecting the final
|
|
759
|
+
* observation awaits `exit`. `settled`, the `exit` event, and `evidence` freezing all name that same
|
|
760
|
+
* terminal moment, exactly as they do on {@link ProcessInterface}.
|
|
761
|
+
*
|
|
762
|
+
* **`end` is not a termination.** It closes the standard-input channel and leaves the child running,
|
|
763
|
+
* which is how a cooperative protocol asks a child to finish its own work. `stop` and `destroy` are
|
|
764
|
+
* the terminations, they are idempotent, and none of the three rejects.
|
|
765
|
+
*
|
|
766
|
+
* The spawn is eager, so `pid` is fixed by the time construction returns; a spawn that produced no
|
|
767
|
+
* child reports `undefined` for that child's whole lifetime. An assigned id survives the exit and
|
|
768
|
+
* reports no liveness on its own, because the host reuses a dead child's id. Derive liveness as
|
|
769
|
+
* `pid !== undefined && code === null && signal === null`, and derive it again before every use of
|
|
770
|
+
* the id.
|
|
771
|
+
*/
|
|
772
|
+
export declare interface SessionInterface {
|
|
773
|
+
/** The host process id, fixed when construction returns, or `undefined` when the spawn produced none. */
|
|
774
|
+
readonly pid: number | undefined;
|
|
775
|
+
/** The exit code the host recorded, or `null` while the child has not exited and when a signal ended it. A spawn fault reports the host's negative errno. */
|
|
776
|
+
readonly code: number | null;
|
|
777
|
+
/** The terminating signal name the host recorded, or `null` while the child has not exited and when it exited on its own. */
|
|
778
|
+
readonly signal: string | null;
|
|
779
|
+
/** The typed lifecycle observation surface. */
|
|
780
|
+
readonly emitter: EmitterInterface<SessionEventMap>;
|
|
781
|
+
/**
|
|
782
|
+
* The decoded byte-bounded stderr tail.
|
|
783
|
+
*
|
|
784
|
+
* @remarks
|
|
785
|
+
* The live tail before the terminal moment and the frozen value after it, on every path — a
|
|
786
|
+
* natural exit, `stop`, `destroy`, an abort of the `signal` option, and a spawn fault. Every read
|
|
787
|
+
* after that moment returns the same string. When {@link ProcessExit.drained} is false the frozen
|
|
788
|
+
* value is the tail as of the cutoff, and later diagnostics may have existed.
|
|
789
|
+
*/
|
|
790
|
+
readonly evidence: string;
|
|
791
|
+
/**
|
|
792
|
+
* True after the `exit` promise settled.
|
|
793
|
+
*
|
|
794
|
+
* @remarks
|
|
795
|
+
* The terminal moment has arrived: `evidence` is frozen, no further `stdout` or `stderr` event
|
|
796
|
+
* fires, and the {@link ProcessExit} value exists. Reached on every path, including a spawn that
|
|
797
|
+
* produced no child.
|
|
798
|
+
*/
|
|
799
|
+
readonly settled: boolean;
|
|
800
|
+
/**
|
|
801
|
+
* True after a termination began.
|
|
802
|
+
*
|
|
803
|
+
* @remarks
|
|
804
|
+
* Monotonic. It turns true when `stop`, `destroy`, or an abort of the `signal` option begins a
|
|
805
|
+
* termination, and it stays true from then on, including after `settled` turns true. `end` never
|
|
806
|
+
* turns it true, because closing the input channel terminates nothing. A child that exited on its
|
|
807
|
+
* own reports `false` here with `settled` true.
|
|
808
|
+
*/
|
|
809
|
+
readonly stopping: boolean;
|
|
810
|
+
/**
|
|
811
|
+
* The child's own ending, awaited without the terminal moment's drain window.
|
|
812
|
+
*
|
|
813
|
+
* @remarks
|
|
814
|
+
* Never rejects, and resolves no value: `code` and `signal` carry the terminal facts as soon as
|
|
815
|
+
* the host records them, so a second copy of those facts here could only drift from them. It
|
|
816
|
+
* settles at the native exit, and at the terminal moment for a spawn that produced no native exit
|
|
817
|
+
* at all, so it can never outlive the supervision. Await this rather than `exit` when a
|
|
818
|
+
* cooperative shutdown window is racing the child's own exit: `exit` waits out `drain` for a
|
|
819
|
+
* descendant holding the pipe, and a caller racing that promise escalates against a child that
|
|
820
|
+
* already ended.
|
|
821
|
+
*/
|
|
822
|
+
readonly ending: Promise<void>;
|
|
823
|
+
/**
|
|
824
|
+
* The terminal child state, delivered once.
|
|
825
|
+
*
|
|
826
|
+
* @remarks
|
|
827
|
+
* Never rejects. It settles at the terminal moment: when the child's streams close, or when the
|
|
828
|
+
* `drain` bound elapsed first. The native exit arms that bound as well as an initiated
|
|
829
|
+
* termination, so a child nobody terminates still settles it within `drain` of ending.
|
|
830
|
+
*/
|
|
831
|
+
readonly exit: Promise<ProcessExit>;
|
|
832
|
+
/**
|
|
833
|
+
* Write raw bytes to the open standard-input channel.
|
|
834
|
+
*
|
|
835
|
+
* @remarks
|
|
836
|
+
* Never rejects, and adds no framing: the bytes reach the child exactly as given, with no
|
|
837
|
+
* terminator appended, so a caller speaking a framed protocol composes its own header and
|
|
838
|
+
* delimiter. `true` means the host accepted the bytes without reporting a fault; it does not
|
|
839
|
+
* prove that the child read them. An ordinary write settles when the kernel accepts it, and only
|
|
840
|
+
* a full pipe can hold one unconfirmed, which the `delivery` option bounds.
|
|
841
|
+
*
|
|
842
|
+
* It resolves `false` without throwing when the channel was closed by `end`, destroyed by a
|
|
843
|
+
* termination, failed, or left the write unconfirmed through `delivery`, and when `stop` or
|
|
844
|
+
* `destroy` has begun, because teardown cannot confirm delivery for bytes it is about to discard.
|
|
845
|
+
*
|
|
846
|
+
* The host can queue the payload, so treat the array as owned by the channel until the returned
|
|
847
|
+
* promise settles: bytes mutated inside that window are the bytes the child receives.
|
|
848
|
+
*
|
|
849
|
+
* @param bytes - The payload to write, already framed by the caller
|
|
850
|
+
* @returns True when the host accepted the bytes without reporting a fault; false when the channel was closed, destroyed, ended, failed, or remained unconfirmed through `delivery`
|
|
851
|
+
*/
|
|
852
|
+
write(bytes: Uint8Array): Promise<boolean>;
|
|
853
|
+
/**
|
|
854
|
+
* Close the standard-input channel and leave the child running.
|
|
855
|
+
*
|
|
856
|
+
* @remarks
|
|
857
|
+
* Never rejects, and terminates nothing: `stopping` stays false, no signal is sent, no drain
|
|
858
|
+
* window is armed, and the terminal moment does not arrive. The child observes end of input, which
|
|
859
|
+
* is how a cooperative protocol asks it to finish and exit on its own; await `ending` for that
|
|
860
|
+
* exit and `stop` when it does not come.
|
|
861
|
+
*
|
|
862
|
+
* Every call shares one barrier, and it resolves after the host flushes the writes it had already
|
|
863
|
+
* accepted. That flush carries no bound of its own: a child that stops reading its input leaves
|
|
864
|
+
* the accepted bytes in the pipe, and the barrier stays pending for as long as they sit there. A
|
|
865
|
+
* caller that needs a bound races this promise against a window of its own rather than awaiting it
|
|
866
|
+
* bare. A `write` after this call resolves `false`, because the channel is no longer writable.
|
|
867
|
+
* The closed channel then stays quiet for its remaining life: a later host fault on it settles
|
|
868
|
+
* pending writes and emits no `error` event. After `stop` or `destroy` has begun the call resolves
|
|
869
|
+
* and changes nothing.
|
|
870
|
+
*
|
|
871
|
+
* @returns The stable barrier shared by every call
|
|
872
|
+
*/
|
|
873
|
+
end(): Promise<void>;
|
|
874
|
+
/**
|
|
875
|
+
* Terminate the child process tree, await its observed exit, and reach the terminal moment.
|
|
876
|
+
*
|
|
877
|
+
* @remarks
|
|
878
|
+
* Never rejects. On Windows the whole tree is killed immediately through `taskkill`, with a
|
|
879
|
+
* direct kill as the fallback; on a POSIX host the process group receives `SIGTERM`, then
|
|
880
|
+
* `SIGKILL` after `grace`. No signal is initiated after the child's native exit is observed.
|
|
881
|
+
*
|
|
882
|
+
* Observation ends here as well as under `destroy`, bounded by `drain`: `evidence` freezes, the
|
|
883
|
+
* `stdout` and `stderr` events stop, and `exit` settles. A caller that stops a child and keeps
|
|
884
|
+
* listening therefore reaches the end of the stream and needs no second call to release it.
|
|
885
|
+
*
|
|
886
|
+
* @returns True when the child's native exit was observed; false when the confirmation deadline elapsed without it
|
|
887
|
+
*/
|
|
888
|
+
stop(): Promise<boolean>;
|
|
889
|
+
/**
|
|
890
|
+
* Stop the child, close its standard-input channel, reach the terminal moment, and destroy the
|
|
891
|
+
* observation emitter.
|
|
892
|
+
*
|
|
893
|
+
* @remarks
|
|
894
|
+
* Always resolves, including when termination was never confirmed. The barrier settles after the
|
|
895
|
+
* terminal moment, so `evidence` is frozen and `exit` has settled by the time a caller resumes.
|
|
896
|
+
* The wait for the child's streams is bounded by `drain`, so a descendant holding an inherited
|
|
897
|
+
* pipe cannot hold this barrier open, and {@link ProcessExit.drained} reports which way the moment
|
|
898
|
+
* arrived. The emitter is destroyed after the frozen state exists, so a consumer watching the
|
|
899
|
+
* `stderr` event and a consumer reading `evidence` end on the same bytes.
|
|
900
|
+
*
|
|
901
|
+
* @returns The stable barrier shared by every call
|
|
902
|
+
*/
|
|
903
|
+
destroy(): Promise<void>;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Construction options for one raw byte session over a supervised child.
|
|
908
|
+
*
|
|
909
|
+
* @remarks
|
|
910
|
+
* This is {@link ProcessOptions} without `backlog` and without `writable`. A session frames nothing
|
|
911
|
+
* and retains no lines, so no backlog bound applies to it; its standard-input channel is open from
|
|
912
|
+
* the spawn until {@link SessionInterface.end}, so no switch selects whether one exists. `grace`,
|
|
913
|
+
* `drain`, `evidence`, `delivery`, and `signal` carry the meanings {@link ProcessOptions} documents
|
|
914
|
+
* for them, and `command.input` is still written immediately after the spawn. `on` installs initial
|
|
915
|
+
* {@link SessionEventMap} listeners and `error` receives isolated listener failures.
|
|
916
|
+
*
|
|
917
|
+
* Every option and command property is read once, before the child is spawned, so a caller's own
|
|
918
|
+
* getter runs while nothing has started and a getter that throws strands no process. Every numeric
|
|
919
|
+
* option is validated in that same window: a timer value outside `[0, PROCESS_TIMER]`, or a negative
|
|
920
|
+
* or fractional byte value, throws a {@link ProcessError} coded `invalid` before anything is
|
|
921
|
+
* spawned.
|
|
922
|
+
*/
|
|
923
|
+
export declare interface SessionOptions {
|
|
924
|
+
readonly on?: EmitterHooks<SessionEventMap>;
|
|
925
|
+
readonly error?: EmitterErrorHandler;
|
|
926
|
+
readonly command: ProcessCommand;
|
|
927
|
+
/** The working directory the child runs in. */
|
|
928
|
+
readonly workspace: string;
|
|
929
|
+
/** Cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL`. Default: {@link PROCESS_GRACE}. */
|
|
930
|
+
readonly grace?: number;
|
|
931
|
+
/** Milliseconds the package waits for the child's read ends to close after the native exit or an initiated termination, before cutting them off; `0` cuts them off as soon as the bound is armed. Default: {@link PROCESS_DRAIN}. */
|
|
932
|
+
readonly drain?: number;
|
|
933
|
+
/** Maximum retained stderr tail in bytes. Default: {@link PROCESS_EVIDENCE}. */
|
|
934
|
+
readonly evidence?: number;
|
|
935
|
+
/** Milliseconds an unconfirmed {@link SessionInterface.write} waits before resolving `false`. `0` or omitted disables the bound. */
|
|
936
|
+
readonly delivery?: number;
|
|
937
|
+
/** Aborting this signal terminates the child through the same bounded `stop`. */
|
|
938
|
+
readonly signal?: AbortSignal;
|
|
939
|
+
}
|
|
940
|
+
|
|
702
941
|
/**
|
|
703
942
|
* The resolved spawn form of one command: the executable to launch, the argument vector to pass,
|
|
704
943
|
* and whether the host receives that vector verbatim.
|
package/dist/src/core/index.d.ts
CHANGED
|
@@ -267,6 +267,10 @@ export declare const PROCESS_TIMER = 2147483647;
|
|
|
267
267
|
* backlog, a byte-bounded stderr tail, a live stderr event, a writable stdin channel, a typed
|
|
268
268
|
* lifecycle {@link ProcessEventMap} emitter, and bounded termination. The low-level streaming
|
|
269
269
|
* primitive.
|
|
270
|
+
* - **{@link SessionInterface}** — the same supervised child observed as raw bytes: an owned
|
|
271
|
+
* `Uint8Array` per stdout chunk, an open stdin channel closed by `end` rather than by a switch,
|
|
272
|
+
* the child's own `ending` beside the terminal `exit`, and a typed {@link SessionEventMap}
|
|
273
|
+
* emitter. The transport primitive, for a child speaking a framed protocol.
|
|
270
274
|
* - **{@link ExecuteResult} / execute** — a one-shot spawn that buffers a child to completion and settles
|
|
271
275
|
* with its output and exit, the ergonomic layer for fire-and-collect commands.
|
|
272
276
|
* - **{@link ProcessManagerInterface}** — a keyed registry of live {@link ProcessInterface}
|
|
@@ -699,6 +703,241 @@ export declare interface ProcessOptions {
|
|
|
699
703
|
readonly signal?: AbortSignal;
|
|
700
704
|
}
|
|
701
705
|
|
|
706
|
+
/**
|
|
707
|
+
* The push observation surface of a {@link SessionInterface} — the moments a byte-oriented observer
|
|
708
|
+
* subscribes to, alongside the `ending` and `exit` promises.
|
|
709
|
+
*
|
|
710
|
+
* @remarks
|
|
711
|
+
* Declared as a `type` alias so it satisfies the emitter's `EventMap` constraint structurally.
|
|
712
|
+
*
|
|
713
|
+
* `stdout` carries one owned `Uint8Array` per chunk the host delivered, in arrival order, framed by
|
|
714
|
+
* nothing and decoded by nothing. The array is the session's own copy and a plain `Uint8Array`
|
|
715
|
+
* rather than the host buffer the read produced, so a consumer keeps it, mutates it, concatenates
|
|
716
|
+
* it, and reads its whole backing buffer without reaching memory the host still manages and without
|
|
717
|
+
* depending on a host type. A chunk boundary is the host's, so one event is not one message and a
|
|
718
|
+
* line feed inside a payload starts no new event; a consumer that needs messages frames the
|
|
719
|
+
* concatenated bytes itself.
|
|
720
|
+
*
|
|
721
|
+
* `stderr` carries decoded text instead, because a diagnostic stream is read rather than parsed, and
|
|
722
|
+
* {@link SessionInterface.evidence} bounds those same bytes. The `error` event carries a child fault
|
|
723
|
+
* — a failure to spawn, a process-level error, or a host-reported standard-input channel fault. A
|
|
724
|
+
* surfaced standard-input fault is wrapped in a {@link ProcessError} coded `protocol` with the host
|
|
725
|
+
* fault as its cause. The event is distinct from the `error` handler in {@link SessionOptions}: a
|
|
726
|
+
* listener throw is isolated by the emitter and routed to that handler, never emitted as this
|
|
727
|
+
* `error` event.
|
|
728
|
+
*/
|
|
729
|
+
export declare type SessionEventMap = {
|
|
730
|
+
/** A standard-output chunk arrived, as an owned `Uint8Array` the consumer may keep and mutate. */
|
|
731
|
+
readonly stdout: readonly [chunk: Uint8Array];
|
|
732
|
+
/** A decoded standard-error chunk arrived. */
|
|
733
|
+
readonly stderr: readonly [chunk: string];
|
|
734
|
+
/** The child or its open standard-input channel reported a fault, carrying the host cause directly or through a `protocol` {@link ProcessError}. */
|
|
735
|
+
readonly error: readonly [error: unknown];
|
|
736
|
+
/** The child settled — its terminal state, delivered once. */
|
|
737
|
+
readonly exit: readonly [exit: ProcessExit];
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* One supervised child process read as raw bytes, with an open standard-input channel and bounded
|
|
742
|
+
* termination.
|
|
743
|
+
*
|
|
744
|
+
* @remarks
|
|
745
|
+
* A session is the transport face of the same supervision {@link ProcessInterface} exposes. It
|
|
746
|
+
* publishes the child's standard output as `stdout` events carrying owned bytes rather than framed
|
|
747
|
+
* lines, so a consumer speaking a length-prefixed or delimiter-framed protocol reads the bytes the
|
|
748
|
+
* child wrote and frames them itself. Nothing here retains output: a session holds no backlog and
|
|
749
|
+
* pauses nothing, so it omits `lines`, `truncated`, `backlog`, and `send` rather than reporting them
|
|
750
|
+
* as facts that do not apply. `evidence` is the decoded, byte-bounded stderr tail — the diagnostic to
|
|
751
|
+
* attach to a failed exit — and the typed `emitter` carries the live `stdout` and `stderr` payloads,
|
|
752
|
+
* the child `error` cause, and the terminal `exit`.
|
|
753
|
+
*
|
|
754
|
+
* **Two endings, named apart.** `ending` settles at the child's own native exit and resolves no
|
|
755
|
+
* value, because `code` and `signal` already carry the terminal facts as soon as the host records
|
|
756
|
+
* them. `exit` settles at the terminal moment, which is the native exit plus at most `drain` when a
|
|
757
|
+
* descendant that inherited the child's stdio still holds the read ends open. A caller racing a
|
|
758
|
+
* cooperative shutdown window therefore awaits `ending`, and a caller collecting the final
|
|
759
|
+
* observation awaits `exit`. `settled`, the `exit` event, and `evidence` freezing all name that same
|
|
760
|
+
* terminal moment, exactly as they do on {@link ProcessInterface}.
|
|
761
|
+
*
|
|
762
|
+
* **`end` is not a termination.** It closes the standard-input channel and leaves the child running,
|
|
763
|
+
* which is how a cooperative protocol asks a child to finish its own work. `stop` and `destroy` are
|
|
764
|
+
* the terminations, they are idempotent, and none of the three rejects.
|
|
765
|
+
*
|
|
766
|
+
* The spawn is eager, so `pid` is fixed by the time construction returns; a spawn that produced no
|
|
767
|
+
* child reports `undefined` for that child's whole lifetime. An assigned id survives the exit and
|
|
768
|
+
* reports no liveness on its own, because the host reuses a dead child's id. Derive liveness as
|
|
769
|
+
* `pid !== undefined && code === null && signal === null`, and derive it again before every use of
|
|
770
|
+
* the id.
|
|
771
|
+
*/
|
|
772
|
+
export declare interface SessionInterface {
|
|
773
|
+
/** The host process id, fixed when construction returns, or `undefined` when the spawn produced none. */
|
|
774
|
+
readonly pid: number | undefined;
|
|
775
|
+
/** The exit code the host recorded, or `null` while the child has not exited and when a signal ended it. A spawn fault reports the host's negative errno. */
|
|
776
|
+
readonly code: number | null;
|
|
777
|
+
/** The terminating signal name the host recorded, or `null` while the child has not exited and when it exited on its own. */
|
|
778
|
+
readonly signal: string | null;
|
|
779
|
+
/** The typed lifecycle observation surface. */
|
|
780
|
+
readonly emitter: EmitterInterface<SessionEventMap>;
|
|
781
|
+
/**
|
|
782
|
+
* The decoded byte-bounded stderr tail.
|
|
783
|
+
*
|
|
784
|
+
* @remarks
|
|
785
|
+
* The live tail before the terminal moment and the frozen value after it, on every path — a
|
|
786
|
+
* natural exit, `stop`, `destroy`, an abort of the `signal` option, and a spawn fault. Every read
|
|
787
|
+
* after that moment returns the same string. When {@link ProcessExit.drained} is false the frozen
|
|
788
|
+
* value is the tail as of the cutoff, and later diagnostics may have existed.
|
|
789
|
+
*/
|
|
790
|
+
readonly evidence: string;
|
|
791
|
+
/**
|
|
792
|
+
* True after the `exit` promise settled.
|
|
793
|
+
*
|
|
794
|
+
* @remarks
|
|
795
|
+
* The terminal moment has arrived: `evidence` is frozen, no further `stdout` or `stderr` event
|
|
796
|
+
* fires, and the {@link ProcessExit} value exists. Reached on every path, including a spawn that
|
|
797
|
+
* produced no child.
|
|
798
|
+
*/
|
|
799
|
+
readonly settled: boolean;
|
|
800
|
+
/**
|
|
801
|
+
* True after a termination began.
|
|
802
|
+
*
|
|
803
|
+
* @remarks
|
|
804
|
+
* Monotonic. It turns true when `stop`, `destroy`, or an abort of the `signal` option begins a
|
|
805
|
+
* termination, and it stays true from then on, including after `settled` turns true. `end` never
|
|
806
|
+
* turns it true, because closing the input channel terminates nothing. A child that exited on its
|
|
807
|
+
* own reports `false` here with `settled` true.
|
|
808
|
+
*/
|
|
809
|
+
readonly stopping: boolean;
|
|
810
|
+
/**
|
|
811
|
+
* The child's own ending, awaited without the terminal moment's drain window.
|
|
812
|
+
*
|
|
813
|
+
* @remarks
|
|
814
|
+
* Never rejects, and resolves no value: `code` and `signal` carry the terminal facts as soon as
|
|
815
|
+
* the host records them, so a second copy of those facts here could only drift from them. It
|
|
816
|
+
* settles at the native exit, and at the terminal moment for a spawn that produced no native exit
|
|
817
|
+
* at all, so it can never outlive the supervision. Await this rather than `exit` when a
|
|
818
|
+
* cooperative shutdown window is racing the child's own exit: `exit` waits out `drain` for a
|
|
819
|
+
* descendant holding the pipe, and a caller racing that promise escalates against a child that
|
|
820
|
+
* already ended.
|
|
821
|
+
*/
|
|
822
|
+
readonly ending: Promise<void>;
|
|
823
|
+
/**
|
|
824
|
+
* The terminal child state, delivered once.
|
|
825
|
+
*
|
|
826
|
+
* @remarks
|
|
827
|
+
* Never rejects. It settles at the terminal moment: when the child's streams close, or when the
|
|
828
|
+
* `drain` bound elapsed first. The native exit arms that bound as well as an initiated
|
|
829
|
+
* termination, so a child nobody terminates still settles it within `drain` of ending.
|
|
830
|
+
*/
|
|
831
|
+
readonly exit: Promise<ProcessExit>;
|
|
832
|
+
/**
|
|
833
|
+
* Write raw bytes to the open standard-input channel.
|
|
834
|
+
*
|
|
835
|
+
* @remarks
|
|
836
|
+
* Never rejects, and adds no framing: the bytes reach the child exactly as given, with no
|
|
837
|
+
* terminator appended, so a caller speaking a framed protocol composes its own header and
|
|
838
|
+
* delimiter. `true` means the host accepted the bytes without reporting a fault; it does not
|
|
839
|
+
* prove that the child read them. An ordinary write settles when the kernel accepts it, and only
|
|
840
|
+
* a full pipe can hold one unconfirmed, which the `delivery` option bounds.
|
|
841
|
+
*
|
|
842
|
+
* It resolves `false` without throwing when the channel was closed by `end`, destroyed by a
|
|
843
|
+
* termination, failed, or left the write unconfirmed through `delivery`, and when `stop` or
|
|
844
|
+
* `destroy` has begun, because teardown cannot confirm delivery for bytes it is about to discard.
|
|
845
|
+
*
|
|
846
|
+
* The host can queue the payload, so treat the array as owned by the channel until the returned
|
|
847
|
+
* promise settles: bytes mutated inside that window are the bytes the child receives.
|
|
848
|
+
*
|
|
849
|
+
* @param bytes - The payload to write, already framed by the caller
|
|
850
|
+
* @returns True when the host accepted the bytes without reporting a fault; false when the channel was closed, destroyed, ended, failed, or remained unconfirmed through `delivery`
|
|
851
|
+
*/
|
|
852
|
+
write(bytes: Uint8Array): Promise<boolean>;
|
|
853
|
+
/**
|
|
854
|
+
* Close the standard-input channel and leave the child running.
|
|
855
|
+
*
|
|
856
|
+
* @remarks
|
|
857
|
+
* Never rejects, and terminates nothing: `stopping` stays false, no signal is sent, no drain
|
|
858
|
+
* window is armed, and the terminal moment does not arrive. The child observes end of input, which
|
|
859
|
+
* is how a cooperative protocol asks it to finish and exit on its own; await `ending` for that
|
|
860
|
+
* exit and `stop` when it does not come.
|
|
861
|
+
*
|
|
862
|
+
* Every call shares one barrier, and it resolves after the host flushes the writes it had already
|
|
863
|
+
* accepted. That flush carries no bound of its own: a child that stops reading its input leaves
|
|
864
|
+
* the accepted bytes in the pipe, and the barrier stays pending for as long as they sit there. A
|
|
865
|
+
* caller that needs a bound races this promise against a window of its own rather than awaiting it
|
|
866
|
+
* bare. A `write` after this call resolves `false`, because the channel is no longer writable.
|
|
867
|
+
* The closed channel then stays quiet for its remaining life: a later host fault on it settles
|
|
868
|
+
* pending writes and emits no `error` event. After `stop` or `destroy` has begun the call resolves
|
|
869
|
+
* and changes nothing.
|
|
870
|
+
*
|
|
871
|
+
* @returns The stable barrier shared by every call
|
|
872
|
+
*/
|
|
873
|
+
end(): Promise<void>;
|
|
874
|
+
/**
|
|
875
|
+
* Terminate the child process tree, await its observed exit, and reach the terminal moment.
|
|
876
|
+
*
|
|
877
|
+
* @remarks
|
|
878
|
+
* Never rejects. On Windows the whole tree is killed immediately through `taskkill`, with a
|
|
879
|
+
* direct kill as the fallback; on a POSIX host the process group receives `SIGTERM`, then
|
|
880
|
+
* `SIGKILL` after `grace`. No signal is initiated after the child's native exit is observed.
|
|
881
|
+
*
|
|
882
|
+
* Observation ends here as well as under `destroy`, bounded by `drain`: `evidence` freezes, the
|
|
883
|
+
* `stdout` and `stderr` events stop, and `exit` settles. A caller that stops a child and keeps
|
|
884
|
+
* listening therefore reaches the end of the stream and needs no second call to release it.
|
|
885
|
+
*
|
|
886
|
+
* @returns True when the child's native exit was observed; false when the confirmation deadline elapsed without it
|
|
887
|
+
*/
|
|
888
|
+
stop(): Promise<boolean>;
|
|
889
|
+
/**
|
|
890
|
+
* Stop the child, close its standard-input channel, reach the terminal moment, and destroy the
|
|
891
|
+
* observation emitter.
|
|
892
|
+
*
|
|
893
|
+
* @remarks
|
|
894
|
+
* Always resolves, including when termination was never confirmed. The barrier settles after the
|
|
895
|
+
* terminal moment, so `evidence` is frozen and `exit` has settled by the time a caller resumes.
|
|
896
|
+
* The wait for the child's streams is bounded by `drain`, so a descendant holding an inherited
|
|
897
|
+
* pipe cannot hold this barrier open, and {@link ProcessExit.drained} reports which way the moment
|
|
898
|
+
* arrived. The emitter is destroyed after the frozen state exists, so a consumer watching the
|
|
899
|
+
* `stderr` event and a consumer reading `evidence` end on the same bytes.
|
|
900
|
+
*
|
|
901
|
+
* @returns The stable barrier shared by every call
|
|
902
|
+
*/
|
|
903
|
+
destroy(): Promise<void>;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Construction options for one raw byte session over a supervised child.
|
|
908
|
+
*
|
|
909
|
+
* @remarks
|
|
910
|
+
* This is {@link ProcessOptions} without `backlog` and without `writable`. A session frames nothing
|
|
911
|
+
* and retains no lines, so no backlog bound applies to it; its standard-input channel is open from
|
|
912
|
+
* the spawn until {@link SessionInterface.end}, so no switch selects whether one exists. `grace`,
|
|
913
|
+
* `drain`, `evidence`, `delivery`, and `signal` carry the meanings {@link ProcessOptions} documents
|
|
914
|
+
* for them, and `command.input` is still written immediately after the spawn. `on` installs initial
|
|
915
|
+
* {@link SessionEventMap} listeners and `error` receives isolated listener failures.
|
|
916
|
+
*
|
|
917
|
+
* Every option and command property is read once, before the child is spawned, so a caller's own
|
|
918
|
+
* getter runs while nothing has started and a getter that throws strands no process. Every numeric
|
|
919
|
+
* option is validated in that same window: a timer value outside `[0, PROCESS_TIMER]`, or a negative
|
|
920
|
+
* or fractional byte value, throws a {@link ProcessError} coded `invalid` before anything is
|
|
921
|
+
* spawned.
|
|
922
|
+
*/
|
|
923
|
+
export declare interface SessionOptions {
|
|
924
|
+
readonly on?: EmitterHooks<SessionEventMap>;
|
|
925
|
+
readonly error?: EmitterErrorHandler;
|
|
926
|
+
readonly command: ProcessCommand;
|
|
927
|
+
/** The working directory the child runs in. */
|
|
928
|
+
readonly workspace: string;
|
|
929
|
+
/** Cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL`. Default: {@link PROCESS_GRACE}. */
|
|
930
|
+
readonly grace?: number;
|
|
931
|
+
/** Milliseconds the package waits for the child's read ends to close after the native exit or an initiated termination, before cutting them off; `0` cuts them off as soon as the bound is armed. Default: {@link PROCESS_DRAIN}. */
|
|
932
|
+
readonly drain?: number;
|
|
933
|
+
/** Maximum retained stderr tail in bytes. Default: {@link PROCESS_EVIDENCE}. */
|
|
934
|
+
readonly evidence?: number;
|
|
935
|
+
/** Milliseconds an unconfirmed {@link SessionInterface.write} waits before resolving `false`. `0` or omitted disables the bound. */
|
|
936
|
+
readonly delivery?: number;
|
|
937
|
+
/** Aborting this signal terminates the child through the same bounded `stop`. */
|
|
938
|
+
readonly signal?: AbortSignal;
|
|
939
|
+
}
|
|
940
|
+
|
|
702
941
|
/**
|
|
703
942
|
* The resolved spawn form of one command: the executable to launch, the argument vector to pass,
|
|
704
943
|
* and whether the host receives that vector verbatim.
|