npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sohumsuthar/anvil

v0.1.0

Published

Anvil Connector — bridges lab instruments to the hosted Anvil web app via WebSocket. Discovers VISA instruments, executes SCPI commands, and includes a 5-instrument simulator for development.

Readme

Anvil Connector

A lightweight connector agent that runs on your desktop and bridges lab instruments to the hosted Anvil web app at anvil.sohumsuthar.com.

How It Works

The connector discovers VISA-compatible instruments on your machine using PyVISA, then maintains a persistent WebSocket connection to the Anvil cloud. When the web app sends a SCPI command, the connector executes it locally against the target instrument and returns the result.

┌─────────────┐     WebSocket      ┌──────────────────┐     SCPI/VISA     ┌─────────────┐
│  Anvil Web   │ ◄──────────────► │  Anvil Connector  │ ◄──────────────► │  Instruments │
│  (Cloud)     │                   │  (Local Agent)    │                   │  (Lab)       │
└─────────────┘                    └──────────────────┘                    └─────────────┘

Prerequisites

  • Node.js 20+nodejs.org
  • Python 3 — for instrument discovery (optional)
  • PyVISApip3 install pyvisa pyvisa-py (optional)

Simulation Mode

If Python or PyVISA is not installed, the connector automatically runs in simulation mode with 5 dummy instruments (VNA, PSU, DMM, Scope, SigGen). Each dummy returns physically plausible measurements and responds to the full SCPI command set. No PyVISA installation is needed to develop against Anvil or test workflows.

Quick Start

# Install
npm install
npm link          # makes "anvil" available globally

# First-time setup (saves credentials + starts):
anvil setup --id <CONNECTOR_ID> --secret <CONNECTOR_SECRET>

# Check status:
anvil status

# Or run manually in foreground (debug):
anvil run

Authentication Flow

First-time setup

  1. Register a connector from the Anvil web UI (Settings > Connectors).
  2. Run anvil setup --id <CONNECTOR_ID> --secret <SECRET>.
  3. Credentials are saved to ~/.anvil/connector.json.

Ongoing authentication

  1. The connector loads connectorId + connectorSecret from the config file.
  2. Heartbeat and poll requests use Authorization: Bearer <connectorId>:<connectorSecret>.
  3. HTTP polling is the primary transport (works on Vercel). WebSocket is a legacy fallback.
  4. No session token is involved.

Alternative: direct credentials

If you already have a connector ID and secret (e.g., from the web dashboard):

anvil setup --id <ID> --secret <SECRET>

This saves credentials to ~/.anvil/connector.json and starts the connector.

CLI

After npm link, the anvil command is available globally:

anvil <command>

  start              Start the connector in the background
  stop               Stop the running connector
  status             Check connector status
  setup --id <id> --secret <secret>
                     First-time setup with credentials
  run                Run connector in foreground (debug)
  uninstall          Remove background service registration
  help               Show help

Config is loaded from ~/.anvil/connector.json automatically.

Advanced: anvild options

anvild [OPTIONS]

  --port <PORT>                  Local HTTP server port (default: 7400)
  --token <TOKEN>                Session token for initial registration only
  --connector-id <ID>            Connector ID (from prior registration)
  --connector-secret <SECRET>    Connector secret (from prior registration)
  --cloud-url <URL>              Cloud API base URL (default: https://anvil.sohumsuthar.com)
  --config <PATH>                Path to config JSON file (default: ~/.anvil/connector.json)
  --simulation, --sim            Force simulation mode (5 dummy instruments, skip PyVISA)
  -h, --help                     Show help
  -v, --version                  Show version

Environment Variables

| Variable | Description | |----------|-------------| | ANVIL_TOKEN | Session token for initial registration (same as --token) | | ANVIL_CONNECTOR_ID | Connector ID (same as --connector-id) | | ANVIL_CONNECTOR_SECRET | Connector secret (same as --connector-secret) | | ANVIL_PORT | Local server port (same as --port) | | ANVIL_CLOUD_URL | Cloud URL (same as --cloud-url) | | ANVIL_SIMULATION | Force simulation mode (1 or true, same as --simulation) |

Config File

After registration, ~/.anvil/connector.json looks like:

{
  "connectorId": "clxyz...",
  "connectorSecret": "a1b2c3d4...",
  "port": 7400,
  "cloudUrl": "https://anvil.sohumsuthar.com",
  "heartbeatInterval": 30000,
  "scanInterval": 30000
}

Note: The connectorSecret is sensitive. Keep this file secure.

Local Endpoints

The connector runs a local HTTP server (default port 7400):

| Endpoint | Description | |----------|-------------| | GET /health | Health check: { status, instruments, uptime, cloudConnected } | | GET /instruments | List discovered instruments | | GET /status | Detailed status including memory usage |

Architecture

src/
  cli.js                Unified CLI entry point (anvil start/stop/status/setup/run)
  index.js              Connector daemon, orchestrates all components
  setup.js              Background process management (start/stop/status/uninstall)
  config.js             Configuration from CLI flags + env + config file
  auth.js               Registration (session token) + credential management
  instrument-scanner.js Discovers VISA instruments via PyVISA, enriches with name/type from *IDN?
  scpi-bridge.js        Executes SCPI commands (real or simulated)
  cloud-client.js       WebSocket client with reconnect logic
  heartbeat.js          Periodic heartbeat with device inventory
  server.js             Local HTTP health/status server
  stateful-simulator.js Stateful instrument simulator (used when PyVISA unavailable)

WebSocket Protocol

Messages between the connector and cloud are JSON:

Connector -> Cloud (authentication):

{ "type": "authenticate", "connectorId": "...", "secret": "..." }

Cloud -> Connector (auth response):

{ "type": "authenticated", "connectorId": "..." }

Cloud -> Connector:

{ "type": "command_request", "id": "uuid", "address": "TCPIP::...", "command": "*IDN?" }
{ "type": "list_instruments", "id": "uuid" }
{ "type": "ping", "id": "uuid" }

Connector -> Cloud:

{ "type": "command_response", "id": "uuid", "ok": true, "result": "Keysight..." }
{ "type": "instrument_list", "id": "uuid", "instruments": [...] }
{ "type": "pong", "id": "uuid" }

Start / Stop

anvil start
anvil stop
anvil status

Logs (macOS/Linux): ~/.anvil/logs/connector.log

Dummy Instruments

When no real instruments are detected (or PyVISA is not installed), the connector provides 5 dummy instruments that emulate real popular models:

| Type | Model | Key Specs | |------|-------|-----------| | VNA | Keysight E5071C | 9kHz–8.5GHz, 2-port | | PSU | Rigol DP832 | 3ch: 30V/3A, 30V/3A, 5V/3A | | DMM | Keysight 34465A | 6.5 digit, 30ppm DCV | | Scope | Rigol DS1054Z | 50MHz, 4ch, 1GSa/s | | SigGen | Rigol DG1022Z | 25MHz, 2ch, 200MSa/s |

Each returns its real *IDN? string with accurate firmware version format and responds to the full SCPI command set with physically plausible measurements.