procband 0.2.0 → 0.2.2
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/README.md +3 -1
- package/dist/index.d.mts +14 -4
- package/dist/index.mjs +26 -8
- package/docs/context.md +19 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,6 @@ import process from 'node:process'
|
|
|
20
20
|
import { supervise } from 'procband'
|
|
21
21
|
|
|
22
22
|
const proc = supervise({
|
|
23
|
-
name: 'api',
|
|
24
23
|
command: process.execPath,
|
|
25
24
|
args: ['-e', 'console.log("ready")'],
|
|
26
25
|
})
|
|
@@ -30,6 +29,9 @@ const result = await proc
|
|
|
30
29
|
console.log(result)
|
|
31
30
|
```
|
|
32
31
|
|
|
32
|
+
`stdin` is disabled by default. Set `stdin: true` to write to `proc.stdin`, or
|
|
33
|
+
pass a readable stream to `stdin` to pipe input automatically.
|
|
34
|
+
|
|
33
35
|
## Documentation Map
|
|
34
36
|
|
|
35
37
|
- Concepts and lifecycle: [docs/context.md](docs/context.md)
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChildProcess } from "node:child_process";
|
|
2
|
-
import { Writable } from "node:stream";
|
|
2
|
+
import { Readable, Writable } from "node:stream";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
/**
|
|
@@ -27,8 +27,10 @@ type MatchStream = 'stdout' | 'stderr' | 'both';
|
|
|
27
27
|
interface ProcessConfig {
|
|
28
28
|
/**
|
|
29
29
|
* Stable identifier used in prefixed output and emitted match events.
|
|
30
|
+
*
|
|
31
|
+
* Defaults to the trailing `/[-\w]+$/` match from `command`.
|
|
30
32
|
*/
|
|
31
|
-
name
|
|
33
|
+
name?: string;
|
|
32
34
|
/**
|
|
33
35
|
* Executable or shell-free command name passed to `spawn()`.
|
|
34
36
|
*/
|
|
@@ -65,6 +67,14 @@ interface ProcessConfig {
|
|
|
65
67
|
* `process.stderr`.
|
|
66
68
|
*/
|
|
67
69
|
stderr?: Writable;
|
|
70
|
+
/**
|
|
71
|
+
* Child stdin behavior.
|
|
72
|
+
*
|
|
73
|
+
* Defaults to `false`, which connects the child stdin to the null device.
|
|
74
|
+
* Use `true` to expose a writable `proc.stdin`, or pass a readable stream to
|
|
75
|
+
* pipe bytes into the child automatically.
|
|
76
|
+
*/
|
|
77
|
+
stdin?: boolean | Readable;
|
|
68
78
|
/**
|
|
69
79
|
* Automatic restart behavior for terminal child exits.
|
|
70
80
|
*
|
|
@@ -271,8 +281,8 @@ interface ProcbandProcess extends ChildProcess, PromiseLike<ProcessResult> {
|
|
|
271
281
|
*
|
|
272
282
|
* @param config The subprocess configuration to supervise.
|
|
273
283
|
* @returns A `ChildProcess`-compatible wrapper with procband-specific helpers.
|
|
274
|
-
* @throws When `config` is invalid, such as a missing `
|
|
275
|
-
* `
|
|
284
|
+
* @throws When `config` is invalid, such as a missing `command`, a `command`
|
|
285
|
+
* that does not produce a fallback `name`, or an invalid reserved color.
|
|
276
286
|
* @example
|
|
277
287
|
* ```ts
|
|
278
288
|
* import process from 'node:process'
|
package/dist/index.mjs
CHANGED
|
@@ -352,8 +352,8 @@ function isMissingProcessError(error) {
|
|
|
352
352
|
*
|
|
353
353
|
* @param config The subprocess configuration to supervise.
|
|
354
354
|
* @returns A `ChildProcess`-compatible wrapper with procband-specific helpers.
|
|
355
|
-
* @throws When `config` is invalid, such as a missing `
|
|
356
|
-
* `
|
|
355
|
+
* @throws When `config` is invalid, such as a missing `command`, a `command`
|
|
356
|
+
* that does not produce a fallback `name`, or an invalid reserved color.
|
|
357
357
|
* @example
|
|
358
358
|
* ```ts
|
|
359
359
|
* import process from 'node:process'
|
|
@@ -395,10 +395,10 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
395
395
|
terminalResultObserved = false;
|
|
396
396
|
constructor(config) {
|
|
397
397
|
super();
|
|
398
|
-
validateProcessConfig(config);
|
|
398
|
+
const name = validateProcessConfig(config);
|
|
399
399
|
this.config = config;
|
|
400
|
-
this.name =
|
|
401
|
-
this.label = config.label ??
|
|
400
|
+
this.name = name;
|
|
401
|
+
this.label = config.label ?? name;
|
|
402
402
|
this.color = resolveProcessColor(config.color);
|
|
403
403
|
this.matches = new MatchRegistry(this.name);
|
|
404
404
|
this.restart = new RestartController(config.restart);
|
|
@@ -516,7 +516,7 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
516
516
|
cwd: this.config.cwd,
|
|
517
517
|
env: this.config.env,
|
|
518
518
|
stdio: [
|
|
519
|
-
"pipe",
|
|
519
|
+
this.config.stdin ? "pipe" : "ignore",
|
|
520
520
|
"pipe",
|
|
521
521
|
"pipe"
|
|
522
522
|
]
|
|
@@ -537,13 +537,15 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
537
537
|
text: "",
|
|
538
538
|
flushed: false
|
|
539
539
|
},
|
|
540
|
-
closed: false
|
|
540
|
+
closed: false,
|
|
541
|
+
stdinCleanup: null
|
|
541
542
|
};
|
|
542
543
|
this.attempt = attempt;
|
|
543
544
|
this.attachAttempt(attempt);
|
|
544
545
|
}
|
|
545
546
|
attachAttempt(attempt) {
|
|
546
547
|
const { child } = attempt;
|
|
548
|
+
attempt.stdinCleanup = this.bindAttemptStdin(attempt);
|
|
547
549
|
child.on("spawn", () => {
|
|
548
550
|
if (this.attempt === attempt) this.emit("spawn");
|
|
549
551
|
});
|
|
@@ -556,6 +558,8 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
556
558
|
child.on("close", (code, signal) => {
|
|
557
559
|
if (this.attempt !== attempt) return;
|
|
558
560
|
attempt.closed = true;
|
|
561
|
+
attempt.stdinCleanup?.();
|
|
562
|
+
attempt.stdinCleanup = null;
|
|
559
563
|
this.flushLineBuffer(attempt, "stdout");
|
|
560
564
|
this.flushLineBuffer(attempt, "stderr");
|
|
561
565
|
attempt.settleClose({
|
|
@@ -682,13 +686,27 @@ var ProcbandProcessImpl = class extends EventEmitter {
|
|
|
682
686
|
buffer.text = "";
|
|
683
687
|
this.handleLine(stream, line, false);
|
|
684
688
|
}
|
|
689
|
+
bindAttemptStdin(attempt) {
|
|
690
|
+
const source = this.config.stdin;
|
|
691
|
+
const destination = attempt.child.stdin;
|
|
692
|
+
if (!destination || typeof source !== "object") return null;
|
|
693
|
+
source.pipe(destination);
|
|
694
|
+
return () => {
|
|
695
|
+
source.unpipe(destination);
|
|
696
|
+
};
|
|
697
|
+
}
|
|
685
698
|
};
|
|
686
699
|
const liveProcesses = /* @__PURE__ */ new Set();
|
|
687
700
|
let propagatedFailure = false;
|
|
688
701
|
function validateProcessConfig(config) {
|
|
689
|
-
if (!config.name) throw new Error("ProcessConfig.name is required");
|
|
690
702
|
if (!config.command) throw new Error("ProcessConfig.command is required");
|
|
691
703
|
validateProcessColor(config.color);
|
|
704
|
+
const name = config.name || inferProcessName(config.command);
|
|
705
|
+
if (!name) throw new Error("ProcessConfig.name is required when command does not match /[-\\w]+$/");
|
|
706
|
+
return name;
|
|
707
|
+
}
|
|
708
|
+
function inferProcessName(command) {
|
|
709
|
+
return command.match(/[-\w]+$/)?.[0];
|
|
692
710
|
}
|
|
693
711
|
function getResultExitCode(code, signal) {
|
|
694
712
|
if (code != null) return code;
|
package/docs/context.md
CHANGED
|
@@ -35,8 +35,8 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
35
35
|
# Core Abstractions
|
|
36
36
|
|
|
37
37
|
- `ProcessConfig`
|
|
38
|
-
Declares one supervised subprocess plus its label, color, restart policy,
|
|
39
|
-
optional raw `stderr` tee.
|
|
38
|
+
Declares one supervised subprocess plus its label, color, restart policy,
|
|
39
|
+
optional stdin behavior, and optional raw `stderr` tee.
|
|
40
40
|
- `ProcbandProcess`
|
|
41
41
|
The live wrapper returned by `supervise()`. It is a `ChildProcess`-compatible
|
|
42
42
|
handle, a matching surface, a shutdown surface, and a thenable final result.
|
|
@@ -52,14 +52,17 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
52
52
|
3. Each line is prefixed and written to the parent `process.stdout` or
|
|
53
53
|
`process.stderr`.
|
|
54
54
|
4. `stderr` can also be tee'd as raw bytes to `ProcessConfig.stderr`.
|
|
55
|
-
5.
|
|
55
|
+
5. `stdin` is disconnected by default. Set `ProcessConfig.stdin` to `true` for
|
|
56
|
+
a writable child stdin, or pass a readable stream to pipe input into the
|
|
57
|
+
child automatically.
|
|
58
|
+
6. Future matching lines are delivered through `match()` callbacks or
|
|
56
59
|
`waitFor()`.
|
|
57
|
-
|
|
60
|
+
7. When a child exits, `procband` either finalizes or starts a new attempt,
|
|
58
61
|
depending on the restart policy.
|
|
59
|
-
|
|
62
|
+
8. A terminal failed exit that nobody observed through `await proc` or
|
|
60
63
|
`proc.wait()` sets `process.exitCode` and begins
|
|
61
64
|
stopping any other live `procband` processes in the same parent script.
|
|
62
|
-
|
|
65
|
+
9. `await proc` or `await proc.wait()` resolves only after the process is
|
|
63
66
|
terminal and no further restart will happen.
|
|
64
67
|
|
|
65
68
|
# Common Tasks -> Recommended APIs
|
|
@@ -78,6 +81,10 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
78
81
|
Do not call `wait()` or await the thenable result
|
|
79
82
|
- Capture raw child `stderr` in a file or custom stream:
|
|
80
83
|
`ProcessConfig.stderr`
|
|
84
|
+
- Write to child stdin manually:
|
|
85
|
+
`stdin: true`, then `proc.stdin?.write(...)`
|
|
86
|
+
- Pipe a custom input stream into the child:
|
|
87
|
+
`stdin: readable`
|
|
81
88
|
- Retry failed exits with sane defaults:
|
|
82
89
|
`restart: true`
|
|
83
90
|
- Use explicit retry rules:
|
|
@@ -102,18 +109,21 @@ Supervision adds four behaviors on top of raw `spawn()`:
|
|
|
102
109
|
processes in the same parent script.
|
|
103
110
|
- The wrapper survives restarts, but inherited `pid`, `stdin`, `stdout`,
|
|
104
111
|
`stderr`, and related `ChildProcess` fields always refer to the current active
|
|
105
|
-
child attempt.
|
|
112
|
+
child attempt. `stdin` is `null` unless `ProcessConfig.stdin` is enabled.
|
|
106
113
|
- `kill()` only signals the current direct child. `stop()` disables restart and
|
|
107
114
|
kills the full process tree.
|
|
108
115
|
- Parent cleanup installs both `SIGINT` and `SIGTERM` handlers while any live
|
|
109
116
|
supervised process exists.
|
|
110
117
|
- `stderr` prefixes always use the reserved red, even when a custom process
|
|
111
118
|
color is configured.
|
|
119
|
+
- `ProcessConfig.name` is optional. When omitted, it falls back to the
|
|
120
|
+
trailing `/[-\w]+$/` match from `command`.
|
|
112
121
|
|
|
113
122
|
# Error Model
|
|
114
123
|
|
|
115
|
-
- `supervise()` throws synchronously for invalid config such as missing
|
|
116
|
-
|
|
124
|
+
- `supervise()` throws synchronously for invalid config such as missing
|
|
125
|
+
`command`, a `command` that does not produce a fallback `name`, or an
|
|
126
|
+
invalid reserved color.
|
|
117
127
|
- `waitFor()` rejects on timeout or terminal exit before a future match.
|
|
118
128
|
- A thrown `match()` callback only unsubscribes that callback.
|
|
119
129
|
- Errors from `ProcessConfig.stderr` stop teeing to that sink but do not stop
|
package/package.json
CHANGED