Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

node:readline

ImportsImplementation
node:readline, node:readline/promises@bytecodealliance/jco-std/wasi/0.2.x/node/24.x.x/readline and /readline/promises

node:readline and node:readline/promises support callback and promise questions, line events, async iteration, streaming UTF-8/CRLF decoding, prompts, terminal editing and history, keypress events, and cursor actions. Both share a port of Node v24.20.0’s readline implementation.

Applications keep ordinary Node imports and supply readable and writable streams:

import * as readline from 'node:readline/promises';

export async function ask(input, output) {
    const rl = readline.createInterface({ input, output });
    try {
        const answer = await rl.question('What do you think of Node.js? ');
        output.write(`Thank you for your valuable feedback: ${answer}\n`);
    } finally {
        rl.close();
    }
}

Bundle application code with jco componentize app.js --bundle --wit wit -o app.wasm. Readline itself requires no WIT imports. The streams determine where input and output go. node:process resolves inside a component, but its stdin, stdout and stderr are host stream objects that cannot cross the component boundary and throw ERR_JCO_UNSUPPORTED_NODE_API (see process restrictions). The Node documentation’s literal import { stdin, stdout } from 'node:process' example therefore runs unchanged on Node but not in a component; supply streams from the component’s own I/O instead. The test fixture runs that literal example against the shim on Node, and runs the same question/answer flow with supplied streams in QuickJS and StarlingMonkey.

Terminal and scheduling boundaries

Terminal streams may supply setRawMode, columns, and resize events. Terminal mode emits ANSI sequences without inspecting a host TERM variable; an application that wants Node’s TERM=dumb behaviour can read process.env.TERM through node:process and pass terminal: false itself. Ctrl+Z can be handled with a SIGTSTP listener; otherwise it throws ERR_JCO_UNSUPPORTED_NODE_API. Node suspends itself with process.kill(process.pid, 'SIGTSTP') and resumes from a SIGCONT listener; the node:process facade refuses signal listeners, and readline deliberately does not import it, so using readline never adds the process capability to a component.

Cursor widths use Node’s non-ICU tables, with normalization where the engine provides it; some Unicode widths differ from ICU-enabled Node. Deferred callbacks and automatic cursor commits use microtasks rather than Node’s separate next-tick queue. Completion-error text uses portable string formatting.

Timed Escape-key disambiguation requires engine timers; engines without timers throw an explicit ERR_JCO_UNSUPPORTED_NODE_API for that operation. Cancellation accepts supplied AbortSignals; readline does not install missing Abort globals. QuickJS async entry functions must be declared async func in WIT.