Event APIs report output and lifecycle signals as work progresses.
Category: Streaming
Languages: JavaScript, Rust
API: $, ProcessRunner#on, ProcessRunner#off
Verified in: Node.js, Bun
js/examples/features/events.mjs
// Commands are EventEmitters: 'stdout', 'stderr', 'data' and 'end'.
import { $ } from '../../src/$.mjs';
import { example } from './_harness.mjs';
const $q = $({ mirror: false });
await example(
{ id: 'events', title: 'EventEmitter interface' },
async ({ record }) => {
const events = [];
await new Promise((resolve, reject) => {
$q`sh -c 'echo out; echo err >&2'`
.on('stdout', (data) => events.push(['stdout', data.toString().trim()]))
.on('stderr', (data) => events.push(['stderr', data.toString().trim()]))
.on('end', (result) => {
events.push(['end', result.code]);
resolve();
})
.on('error', reject)
.start();
});
record(
'events (sorted: stdout/stderr order is up to the OS)',
events.sort()
);
// The 'data' event receives both streams with a type tag.
const tagged = [];
await new Promise((resolve) => {
$q`echo tagged`
.on('data', (chunk) =>
tagged.push([chunk.type, chunk.data.toString().trim()])
)
.on('end', () => resolve())
.start();
});
record('data events', tagged);
}
);Identical in Node.js and Bun:
# events — EventEmitter interface
events (sorted: stdout/stderr order is up to the OS): [["end",0],["stderr","err"],["stdout","out"]]
data events: [["stdout","tagged"]]
API: StreamEmitter, EventType, EventData
rust/examples/language_features.rs
async fn events() -> ExampleResult {
let emitter = StreamEmitter::new();
let count = Arc::new(AtomicUsize::new(0));
let listener_count = Arc::clone(&count);
emitter
.on(EventType::Stdout, move |_| {
listener_count.fetch_add(1, Ordering::SeqCst);
})
.await;
emitter
.emit(EventType::Stdout, EventData::String("hello".to_string()))
.await;
Ok(vec![observation(
"stdout events",
count.load(Ordering::SeqCst),
)])
}# events — Rust
stdout events: 1
Not supported — a ShellPromise is not an EventEmitter and exposes no streams.
$`echo hi`.stdout.on('data', (chunk) => {
/* Node stream events */
});execa`echo hi`.stdout.on('data', (chunk) => {
/* Node stream events */
});shell.exec('echo hi', { async: true }).stdout.on('data', (chunk) => {});spawn('echo', ['hi']).stdout.on('data', (chunk) => {});