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

@suble/cli

v0.3.0

Published

Suble CLI — deploy and manage cloud infrastructure from your terminal.

Downloads

266

Readme

suble

The Suble CLI — deploy and manage cloud infrastructure from your terminal.

# run without installing
npx @suble/cli deploy

# or install once, then use the short command
npm i -g @suble/cli
suble deploy

deploy walks you through it interactively (sign in via your browser — OAuth 2.1, the same login as the dashboard and MCP server), then writes a suble.yaml describing what you launched. After that, suble update (in CI) reconciles that file with no prompts — rebuild, redeploy, re-assert everything.

suble.yaml

One file per project folder describes a single instance. The source key you set picks the type — there's no kind: field:

| key | what it deploys | |---|---| | build: | a Docker container built from your local Dockerfile, shipped over SSH | | image: | a published Docker image | | app: | a managed 1-click app or database (postgresql, mysql, …) | | os: | a plain OS image | | template: | an instance from a saved template |

# a built container, exposed at a domain with automatic SSL
name: web-01
plan: BXS.s1
build:
  dockerfile: Dockerfile
  tag: web:latest
  container: web
ports:
  - "80:8080"
env:                     # ${VAR} = local/CI env · %{project.NAME}% = a shared Suble variable
  NODE_ENV: production
volumes:                 # persistent named volumes (survive container recreate)
  - "data:/var/lib/app"
expose:
  domain: app.example.com
  port: 80
loadbalancer:            # optional: front the app with a managed load balancer
  size: lb.xs            #   lb.xs | lb.s | lb.m | lb.l
  ha: false              #   true = HA pair with a floating IP
  # protocol: https      #   https (default, auto-TLS on expose.domain) | http | tcp
firewall: smart          # off | smart | strict
backup: basic            # none | basic | extended

loadbalancer: requires expose: (the listener + backend target are derived from it). On suble deploy the CLI creates a managed LB named <name>-lb if it doesn't exist, then reconciles its listener + this instance as a target — idempotent, so redeploys never duplicate. loadbalancer: true uses all defaults. It's a managed entrypoint (stable IP, auto-TLS, health checks) in front of the in-instance ingress; removing the block does not delete the LB.

Block or inline flow style both parse, so ports: ["80:80"] and firewall: { mode: strict, allow: ["10.0.0.0/8"] } are fine too.

# a managed Postgres, locked to a private network
name: db-main
plan: CRA.m1
app: postgresql
password: ${ROOT_PASSWORD}      # OS root login — env-interpolated, never a literal
databases:
  - app_production              # created on first deploy (db.create_database)
users:
  - name: app_user
    password: ${APP_DB_PASSWORD}
    database: app_production
networks:
  - my-private-net              # attach by name or uid
firewall:
  mode: strict
  allow:                        # source CIDRs (required for strict)
    - 10.20.0.0/16
# a published image with direct port publishing
name: edge
plan: BXS.s1
image: nginx:1.27
ports: ["80:80", "443:443"]

Firewall is off / smart / strict, or a block. With off you can list explicit rules; with strict you must give an allow: list of source CIDRs so a headless run can't lock you out:

firewall:
  mode: off
  rules:
    - direction: in
      action: ACCEPT
      proto: tcp
      dport: "443"
    - direction: in
      action: ACCEPT
      proto: tcp
      dport: "22"
      source: 203.0.113.0/24
      comment: ssh from office

With smart (or off) SSH stays reachable, so suble instance ssh just works. Under strict, SSH is locked to the allow: list plus a guard IP — so suble instance ssh checks your current IP and, if it isn't covered, offers to arm SSH access for it before connecting (it never widens the DB-port allowlist).

Secrets

${VAR} is expanded from the environment when the file is read — never commit literal passwords (the CLI warns if you do). A database's root credentials are generated server-side; fetch them anytime with suble app info. Secret values are masked unless you're on an interactive terminal, or pass --show-credentials.

Shared variables. For a secret several services share, reference a project- or cluster-scoped Suble variable inside any env value: API_KEY: "%{project.stripeKey}%". Unlike ${VAR} (your local/CI env, expanded here), %{project.NAME}% and %{cluster.NAME}% are resolved server-side at deploy — the value lives in Suble, never in your suble.yml, and rotating it updates every consumer on the next deploy. Manage them in the dashboard under Project → Settings → Shared variables, or on a cluster's page.

How reconcile works

deploy (interactive, first run writes the file) and update (CI, no prompts) share one reconciler:

  • Find or create the instance by name — never recreated once it exists.
  • Containers are rebuilt/re-pulled and recreated to deploy the latest version (named volumes persist; keep stateful data in a managed app database).
  • Firewall, expose (ingress + SSL), and private networks are re-asserted every run — networks are attach-if-missing and never auto-detached.
  • Databases/users are provisioned on first create.
  • Plan changes are warned about, not auto-resized.

Commands

# Deploy lifecycle (driven by ./suble.yaml)
suble init                                Scaffold a commented suble.yaml (no deploy)
suble deploy                              Reconcile ./suble.yaml (first run: interactive, writes it)
suble update                              Reconcile ./suble.yaml non-interactively (CI; needs SUBLE_API_KEY)
suble plan                                Preview what deploy/update would change (also: update --dry-run)
suble destroy [name]                      Delete the instance (from suble.yaml or named); --yes to skip confirm

# Instance ops
suble status <uid|name>                   State, job progress, IPs, firewall, networks, app health
suble logs <uid|name> [container]         Container logs (--tail N, --follow)
suble app info <uid|name>                 App/db connection details (--show-credentials)
suble resize <uid|name> <plan>            Change plan (reboots; --yes to skip confirm)
suble backup ls|create|restore <uid|name> [backup-uid]
suble db create <uid|name> <db>           Create a database (managed DB apps)
suble db user-add <uid|name> <user>       Create a DB user (--password … --database …)

# Networks
suble network ls | create <name> | show <ref> | rm <ref>
suble network connect <inst> <net> [--ip <ipv4>]
suble network disconnect <inst> <net>

# Instances / account
suble instance list | create | info <ref> | delete <ref> | power <ref> <action> | ssh <ref>
suble login | logout | projects | apps | plans

instance is the canonical name (vm still works as an alias). Every <ref> accepts an instance name or uid — names are unique within a project. Add --project <uid> (or set SUBLE_PROJECT) to skip the picker.

CI / preview environments

# .github/workflows — on push: rebuild + redeploy; on PR close: tear down
- run: npx @suble/cli update     # idempotent; rebuilds container, re-asserts everything
  env: { SUBLE_API_KEY: ${{ secrets.SUBLE_API_KEY }} }
# teardown step:
- run: npx @suble/cli destroy --yes
  env: { SUBLE_API_KEY: ${{ secrets.SUBLE_API_KEY }} }

Run suble update --dry-run (or suble plan) first to preview changes — it flags when a container would be recreated before it happens.

Authentication

Interactive commands open your browser and sign you in with OAuth 2.1 (PKCE); the token is cached in ~/.config/suble/credentials.json and refreshed automatically.

For CI / non-interactive use, create a project API key (dashboard → Project → API keys). suble update never opens a browser — it requires a key:

export SUBLE_API_KEY=sk_proj_…
suble update

| Env | | |---|---| | SUBLE_API_KEY | a sk_proj_… project key (skips the browser login) | | SUBLE_PROJECT | default project uid | | SUBLE_API_URL | API base (default https://api.v3.suble.io) |

Develop

npm install
npm run build      # tsc → dist/
npm test           # build + parser/spec round-trip tests
node dist/cli.js --help

Zero runtime dependencies — just Node ≥ 18.