Preview 3 output flush and shutdown
The Preview 3 shim provides host helpers for draining stdout and stderr in Node.js and browser environments. These helpers are useful when a custom host needs to preserve output before exiting or disposing its component. For instance-wide execution and cleanup, see Stopping running instances.
Flush queued destination writes
Await stdout._flush() or stderr._flush() to wait for writes currently queued
on that output destination. cli._flush() waits for both destinations:
import * as cli from '@bytecodealliance/preview3-shim/cli';
await cli._flush();
Flushing leaves the component’s stream readers open and does not wait for guest EOF. It covers writes already queued on stdout or stderr; it does not wait for bytes that have yet to reach those destinations.
Shut down output after production stops
Once a component has stopped producing output, await stdout._shutdown() or
stderr._shutdown() to close that output’s host-owned readers, finish its active
transfers, and await destination completion. cli._shutdown() does this for both
streams. The shared output destinations remain open.
jco run calls this helper after a command returns. A custom host can use the
same sequence:
import { run } from './command.js';
import * as cli from '@bytecodealliance/preview3-shim/cli';
await run.run();
await cli._shutdown();
Producers must stop writing before shutdown begins. New transfers started afterward are not covered by that shutdown call. Shutdown does not require the producer to send EOF.
Destination acknowledgements
On Node.js, the helpers wait for the stdout and stderr writables’ callbacks. In the browser, they call the existing output handlers’ flush operations. The default browser handlers write to the console.
For buffered or asynchronous browser destinations, pass an optional drain
callback to _setStdout(handler, drain) or _setStderr(handler, drain). The
callback must finish after previously queued writes reach the destination’s
acknowledgement boundary, and reject if delivery fails:
import * as cli from '@bytecodealliance/preview3-shim/cli';
/** Route stdout to a host sink and register its delivery acknowledgement. */
function connectBufferedStdout(sink) {
cli._setStdout({ write: (bytes) => sink.enqueue(bytes.slice()) }, () => sink.drain());
}
// After configuring the sink, await cli.stdout._flush() or cli._shutdown().
The copy allows the sink to retain bytes after the synchronous write handler returns. Existing one-argument setters and stream-write completion behavior are unchanged. The drain callback is used only by the new lifecycle helpers.
Without a drain callback, browser flushing retains the synchronous handler’s guarantees. The shim cannot infer completion of asynchronous work hidden inside a handler. A successful flush does not guarantee that the browser rendered the output, or that a downstream consumer processed it.
Exiting immediately
WASI exit and exitWithCode signal exit immediately. Node.js terminates the
process; the browser shim throws its component-exit signal for the host to
handle. Neither path flushes or shuts down output. A custom host can explicitly
shut down output first:
import * as cli from '@bytecodealliance/preview3-shim/cli';
// Stop output production before shutting down the host-owned readers.
await cli._shutdown();
cli.exit.exitWithCode(3);
A completed component-model stream write acknowledges a copy to the receiving side, not a flush to the final output destination. These helpers drain data the host has accepted; they do not guarantee delivery of all guest output on an abrupt exit or implement a guest stream-completion protocol. See Preview 3 streams and backpressure for more on stream acknowledgements.