Node 24 SSH client library (TypeScript). Open a session, run commands on an
interactive shell, and read output. Works with any SSH server that exposes an
interactive shell: prompt detection is configurable and --- MORE --- pager
output is handled automatically.
v1.3.0 — interactive-shell SSH client with host-key pinning, attempt isolation, lossless command output, and DrayOS pager support.
The package stays private ("private": true) and is not published to npm;
consume it from the checkout or a Git tag. See CHANGELOG.md.
import { SshClient } from '@jooservices/ssh-client';
const client = new SshClient({
host: '192.168.1.1',
port: 22,
username: 'admin',
password: '…', // keep real credentials in a gitignored .env
hostFingerprint: 'SHA256:…', // required unless insecureSkipVerify (tests only)
});
await client.connect();
const { stdout, durationMs, sendAt, recvAt, connectMs } = await client.exec('sys version');
await client.disconnect();exec() returns { stdout, durationMs, sendAt, recvAt, connectMs }, accepts
{ timeoutMs, idleTimeoutMs, signal, maxPages, maxOutputBytes }, auto-reconnects
if the session was dropped, and serializes concurrent commands on one shell.
Disconnecting twice is safe.
- Interactive shell —
execwrites one raw line (command\r) on a PTY shell and rejects control characters, DEL, and tabs. There is no exit code and no separate stderr. The ready prompt is confirmed, then later commands must repeat that exact line.promptRegex, when set, is anchored to the whole line. Output keeps indentation and blank lines, treats CR as an overwrite, and strips ANSI sequences. A--- MORE ---pager is space-scrolled up tomaxPages(default 60) only while the marker is the current tail. - Host-key pinning — connections fail closed unless
hostFingerprint(OpenSSHSHA256:…or 64 hex digits) is pinned and matched. A mismatch ishostkey.insecureSkipVerifyis a lab/test hatch only.fingerprintSha256()computes fingerprints. The password is not visible throughutil.inspectorJSON.stringify. - Transport hygiene — one ready budget covers handshake, shell open, and
the first prompt. Disconnect rejects in-flight and queued
execwithclosedand waits for the socket to close. A failed prompt resync closes the session. Output and pager caps reject withlimit. This library does not enable TCP keepalive and does not narrow ssh2 algorithms.
nvm use # Node 24.21.0 (.nvmrc)
npm install
npm run lint # tsc --noEmit
npm test # vitest unit tests (fakes only, no live host)
npm run build # emit dist/
npm run ci # lint + test types + coverage (aggregate ≥90%, per file ≥85%) + build + consumer types
npm run test:e2e # local and CI Docker Ubuntu sshd E2E — Docker daemon, OpenSSH client, openssl, Node 24.21Full embedder + operator guide: docs/usage.md.
Host keys are pinned by default — set hostFingerprint for every non-test
connection. Keep credentials in a gitignored .env; template:
.env.example. See SECURITY.md.
MIT — see LICENSE.