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

@shipstatic/ship

v0.7.3

Published

SDK & CLI for Shipstatic platform

Readme

@shipstatic/ship

Universal SDK and CLI for deploying static files to Shipstatic.

Installation

# CLI (global)
npm install -g @shipstatic/ship

# SDK (project dependency)
npm install @shipstatic/ship

CLI Usage

# Deploy a directory (shortcut)
ship ./dist

# Deploy with labels
ship ./dist --label production --label v1.0.0

# Disable automatic detection
ship ./dist --no-path-detect --no-spa-detect

Deployments

ship deployments list
ship deployments upload <path>                    # Upload from file or directory
ship deployments upload <path> --label production # Upload with labels
ship deployments get <id>
ship deployments set <id> --label production      # Update labels
ship deployments remove <id>

Domains

ship domains list
ship domains set staging                          # Reserve domain (no deployment yet)
ship domains set staging <deployment-id>          # Link domain to deployment
ship domains set staging --label production       # Update labels only
ship domains get staging
ship domains validate www.example.com             # Check if domain is valid and available
ship domains verify www.example.com               # Trigger DNS verification
ship domains remove staging

Tokens

ship tokens list
ship tokens create --ttl 3600 --label ci
ship tokens remove <token>

Account & Setup

ship whoami                      # Get current account (alias for account get)
ship account get
ship config                      # Create or update ~/.shiprc
ship ping                        # Check API connectivity

Shell Completion

ship completion install
ship completion uninstall

Global Flags

--api-key <key>           API key for authenticated deployments
--deploy-token <token>    Deploy token for single-use deployments
--config <file>           Custom config file path
--label <label>           Add label (repeatable)
--no-path-detect          Disable automatic path optimization and flattening
--no-spa-detect           Disable automatic SPA detection and configuration
--no-color                Disable colored output
--json                    Output results in JSON format
--version                 Show version information

SDK Usage

import Ship from '@shipstatic/ship';

const ship = new Ship({
  apiKey: 'ship-your-api-key'
});

// Deploy (shortcut)
const deployment = await ship.deploy('./dist');
console.log(`Deployed: ${deployment.url}`);

// Deploy with options
const deployment = await ship.deployments.upload('./dist', {
  labels: ['production', 'v1.0'],
  onProgress: ({ percent }) => console.log(`${percent}%`)
});

// Manage domains
await ship.domains.set('staging', { deployment: deployment.id });
await ship.domains.list();

// Update labels
await ship.deployments.set(deployment.id, { labels: ['production', 'v1.0'] });
await ship.domains.set('staging', { labels: ['live'] });

Browser Usage

import Ship from '@shipstatic/ship';

const ship = new Ship({ apiKey: 'ship-your-api-key' });

// From file input
const files = Array.from(fileInput.files);
const deployment = await ship.deploy(files);

// From StaticFile array
const deployment = await ship.deploy([
  { path: 'index.html', content: new Blob(['<html>…</html>']) }
]);

Authentication

// API key (persistent access)
const ship = new Ship({
  apiKey: 'ship-...'  // 69 chars: ship- + 64 hex
});

// Deploy token (single-use)
const ship = new Ship({
  deployToken: 'token-...'  // 70 chars: token- + 64 hex
});

// Set credentials after construction
ship.setApiKey('ship-...');
ship.setDeployToken('token-...');

Configuration

Constructor options (highest priority):

new Ship({ apiUrl: '...', apiKey: '...' })

Environment variables (Node.js):

SHIP_API_URL=https://api.shipstatic.com
SHIP_API_KEY=ship-your-api-key

Config files (Node.js, in order of precedence):

// .shiprc or package.json "ship" key
{ "apiUrl": "...", "apiKey": "..." }

API Reference

Top-level Methods

ship.deploy(input, options?)      // Deploy (shortcut for deployments.upload)
ship.whoami()                     // Get current account (shortcut for account.get)
ship.ping()                       // Check API connectivity (returns boolean)
ship.getConfig()                  // Get platform config and plan limits
ship.on(event, handler)           // Add event listener
ship.off(event, handler)          // Remove event listener
ship.setApiKey(key)               // Set API key after construction
ship.setDeployToken(token)        // Set deploy token after construction

Deployments

ship.deployments.upload(input, options?)  // Upload new deployment
ship.deployments.list()                   // List all deployments
ship.deployments.get(id)                  // Get deployment details
ship.deployments.set(id, { labels })      // Update deployment labels
ship.deployments.remove(id)              // Delete deployment

Domains

ship.domains.set(name, options?)  // Create/update domain (see below)
ship.domains.get(name)            // Get domain details
ship.domains.list()               // List all domains
ship.domains.remove(name)         // Delete domain
ship.domains.validate(name)       // Pre-flight: check if domain is valid and available
ship.domains.verify(name)         // Trigger async DNS verification
ship.domains.dns(name)            // Get required DNS records
ship.domains.records(name)        // Get current live DNS records
ship.domains.share(name)          // Get shareable domain hash

Tokens

ship.tokens.create({ ttl?, labels? })  // Create deploy token
ship.tokens.list()                     // List all tokens
ship.tokens.remove(token)             // Revoke token

Account

ship.account.get()  // Get current account

domains.set() Behavior

domains.set() is a single upsert endpoint. Omitted fields are preserved on update and defaulted on create:

// Reserve domain (no deployment yet)
ship.domains.set('staging');

// Link domain to deployment
ship.domains.set('staging', { deployment: 'abc123' });

// Switch to a different deployment (atomic)
ship.domains.set('staging', { deployment: 'xyz789' });

// Update labels only (deployment preserved)
ship.domains.set('staging', { labels: ['prod', 'v2'] });

// Update both
ship.domains.set('staging', { deployment: 'abc123', labels: ['prod'] });

No unlinking: Once a domain is linked, { deployment: null } returns a 400 error. To take a site offline, deploy a maintenance page. To clean up, delete the domain.

Domain format: Domain names are FQDNs. The SDK accepts any format (case-insensitive, Unicode) — the API normalizes:

ship.domains.set('Example.COM', { deployment: 'abc' });  // → normalized to 'example.com'
ship.domains.set('münchen.de', { deployment: 'abc' });   // → Unicode supported

Deploy Options

ship.deploy('./dist', {
  labels?: string[],         // Labels for the deployment
  onProgress?: (info) => void,  // Progress callback
  signal?: AbortSignal,      // Cancellation
  pathDetect?: boolean,      // Auto-optimize paths (default: true)
  spaDetect?: boolean,       // Auto-detect SPA (default: true)
  maxConcurrency?: number,   // Concurrent uploads (default: 4)
  timeout?: number,          // Request timeout (ms)
  subdomain?: string,        // Suggested subdomain
  via?: string,              // Client identifier (e.g. 'sdk', 'cli')
  apiKey?: string,           // Per-request API key override
  deployToken?: string,      // Per-request deploy token override
})

Events

ship.on('request', (url, init) => console.log(`→ ${url}`));
ship.on('response', (response, url) => console.log(`← ${response.status}`));
ship.on('error', (error, url) => console.error(error));

// Remove listeners
ship.off('request', handler);

Error Handling

import { isShipError } from '@shipstatic/types';

try {
  await ship.deploy('./dist');
} catch (error) {
  if (isShipError(error)) {
    if (error.isAuthError()) { /* ... */ }
    if (error.isValidationError()) { /* ... */ }
    if (error.isNetworkError()) { /* ... */ }
  }
}

TypeScript

Full TypeScript support with exported types:

import type {
  ShipClientOptions,
  DeploymentOptions,
  ShipEvents
} from '@shipstatic/ship';

import type {
  Deployment,
  Domain,
  Account,
  StaticFile
} from '@shipstatic/types';

Part of the Shipstatic platform.