Nodevisor Docs

Architecture

How Nodevisor packages compose into a complete infrastructure automation platform.

Layered Package Model

Nodevisor is organized into five layers. Each layer builds on the one below it.

1. Execution Layer

The foundation. Handles command execution, SSH connections, and output parsing.

PackagePurpose
@nodevisor/shellShell proxy, command builder, connections, module base class
@nodevisor/endpointNetwork endpoint definitions (ports, protocols)

2. System Layer

Cross-platform abstractions for common system operations.

PackagePurpose
@nodevisor/osHostname, arch, uptime, command detection
@nodevisor/fsFile read/write, permissions, temp files
@nodevisor/packagesPackage install/remove (apt, yum, brew, winget)
@nodevisor/servicessystemd service start/stop/restart
@nodevisor/envEnvironment variables, env files
@nodevisor/pwshPowerShell command execution

3. Security Layer

User management, authentication, and access control.

PackagePurpose
@nodevisor/usersCreate/remove system users
@nodevisor/groupsManage groups and membership
@nodevisor/authSet user passwords
@nodevisor/authorized-keysManage SSH authorized_keys
@nodevisor/sshInstall/configure OpenSSH server
@nodevisor/ufwUFW firewall management

4. Orchestration Layer

Container management, multi-node deployment, and cloud integrations.

PackagePurpose
@nodevisor/clusterAbstract cluster primitives (nodes, services, users)
@nodevisor/dockerDocker, Compose, Swarm, pre-built services
@nodevisor/awsAWS CLI and ECR integration
@nodevisor/registryAbstract container registry interface
@nodevisor/builderAbstract image builder interface

5. Aggregator

PackagePurpose
nodevisorUmbrella package that re-exports everything
@nodevisor/cliCLI for setup, deploy, connect, run
@nodevisor/schemaShared Zod schemas for admin/runner configs

Core Patterns

The Shell Proxy ($)

The $ function is a Proxy that supports multiple calling conventions:

import $ from 'nodevisor';

// 1. Template literal → execute command
await $`echo hello`;

// 2. $.connect() → create remote shell proxy
const $remote = $.connect({ host: '10.0.0.10', username: 'root' });

// 3. $(Module) → instantiate module with current shell
const packages = $(Packages);

// 4. $remote(Module) → instantiate module on remote shell
const remotePackages = $remote(Packages);

// 5. $.as(user) → switch execution user
const $runner = $.as('runner');

Modules

Every functional package (Users, Packages, FS, Docker, etc.) exports a class that extends Module. Modules receive the shell context and execute commands through it:

import { Module } from '@nodevisor/shell';

class MyModule extends Module {
  async doSomething() {
    // this.$ is bound to the shell context
    return this.$`my-command --flag`.text();
  }
}

// Use it locally
const result = await $(MyModule).doSomething();

// Use it remotely
const remoteResult = await $remote(MyModule).doSomething();

Command Builder

Every template literal call returns a CommandBuilder with a fluent API for output transformation:

// Chain transforms
const name = await $`hostname`.trim().toLowerCase().text();

// Parse different formats
const data = await $`cat config.json`.json();
const lines = await $`cat /etc/hosts`.lines();
const ok = await $`ping -c1 google.com`.noThrow().boolean();

// Control execution
await $`long-command`.timeout(5000);
await $`risky-command`.noThrow();

Package & Service Base Classes

Installable software extends Package. Services (which can be started/stopped) extend Service:

Module          → Base class for all modules
  └─ Package    → Adds install/uninstall/isInstalled
       └─ Service → Adds start/stop/restart/isRunning

Dependency Graph

@nodevisor/shell (foundation)
├── @nodevisor/os → pwsh
├── @nodevisor/fs → pwsh, users, os
├── @nodevisor/env
├── @nodevisor/packages → os
├── @nodevisor/services
├── @nodevisor/users
├── @nodevisor/groups
├── @nodevisor/auth → fs, users
├── @nodevisor/authorized-keys → fs, env
├── @nodevisor/ssh → services, packages
├── @nodevisor/ufw → packages, endpoint
├── @nodevisor/pwsh
├── @nodevisor/docker → groups, packages, services, fs, ufw, cluster, builder, registry
├── @nodevisor/cluster → auth, authorized-keys, users, packages, services, ssh, ufw, builder, registry
├── @nodevisor/aws → packages, fs, os, registry
├── @nodevisor/registry
├── @nodevisor/builder → registry
└── @nodevisor/endpoint

Typical Deployment Flow

import $, {
  Packages, Users, Auth, AuthorizedKeys,
  SSH, UFW, Docker, DockerSwarm, endpoints
} from 'nodevisor';

const $server = $.connect({ host: 'server', username: 'root' });

// 1. System setup
await $server(Packages).updateAndUpgrade();

// 2. User setup
await $server(Users).add('runner');
await $server(Auth).setPassword('runner', 'secure-password');
await $server(AuthorizedKeys).writeFromFile('~/.ssh/id_ed25519.pub');

// 3. Security hardening
await $server(SSH).disablePasswordAuthentication();
await $server(UFW).install();
await $server(UFW).allow([endpoints.ssh, endpoints.web, endpoints.webSecure]);
await $server(UFW).start();

// 4. Container runtime
await $server(Docker).install();
await $server(Docker).allowUser('runner');
await $server(DockerSwarm).start();

On this page