ShipStatic Docs llms.txt llms-full.txt

Ship SDK

A universal SDK for ShipStatic. Works in Node.js and the browser. NPM / GIT

npm install @shipstatic/ship

Quick Start

import Ship from '@shipstatic/ship';

const ship = new Ship({ apiKey: 'ship-...' });
const deployment = await ship.deploy('./dist');

Authentication

Anonymous deploys work without authentication. For permanent deploys and management operations, pass an API Key or a deploy token to the constructor.

// Anonymous - public deploys, response includes a claim URL
new Ship({});

// API key - persistent, full account access
new Ship({ apiKey: 'ship-...' });

// Deploy token - scoped to deploys, optional TTL, revocable
new Ship({ deployToken: 'token-...' });

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

Precedence: Deploy token → API key → Cookie (browser only).

Deploy Options

await ship.deploy('./dist', {
  labels: ['production'],
  password: 'hunter2!',
  onProgress: ({ percent }) => console.log(`${percent}%`),
  signal: AbortSignal.timeout(30000),
  spaDetect: false,
  pathDetect: false,
  subdomain: 'my-site',
});

password (6–128 characters) protects the deployment behind an unlock page. The plaintext is sent over TLS, hashed server-side with SHA-256, and never stored. To change or remove a password, redeploy — there is no edit-in-place.

Resources

Deployments

ship.deployments.upload(path, options?)
ship.deployments.list()
ship.deployments.get(id)
ship.deployments.set(id, { labels })
ship.deployments.remove(id)

Domains

ship.domains.set(name, { deployment?, labels? })
ship.domains.list()
ship.domains.get(name)
ship.domains.remove(name)
ship.domains.validate(name)
ship.domains.verify(name)
ship.domains.dns(name)
ship.domains.records(name)
ship.domains.share(name)

domains.set() is a single upsert operation. Omitted fields are preserved on update:

ship.domains.set('www.example.com');                                         // Reserve
ship.domains.set('www.example.com', { deployment: 'happy-cat-abc1234' });    // Link
ship.domains.set('www.example.com', { deployment: 'shy-fox-def5678' });      // Switch
ship.domains.set('www.example.com', { labels: ['prod'] });                   // Label only

Once linked, a domain cannot be unlinked — switch to a different deployment or delete the domain.

Tokens

ship.tokens.create({ ttl?, labels? })
ship.tokens.list()
ship.tokens.remove(token)

Account

ship.account.get()     // or ship.whoami()
ship.ping()            // returns boolean
ship.getLimits()       // { maxFileSize, maxFilesCount, maxTotalSize } — all bytes/counts

Browser

The browser SDK accepts File[] only. Convert FileList from an <input> element with Array.from(). Construct File objects directly when you have raw content.

import Ship from '@shipstatic/ship';

const ship = new Ship({ apiKey: 'ship-...' });

// From file input or drag-and-drop
await ship.deploy(Array.from(fileInput.files));

// From raw content — construct File objects
await ship.deploy([
  new File(['<html>...</html>'], 'index.html', { type: 'text/html' }),
  new File(['body { ... }'], 'styles.css', { type: 'text/css' }),
]);

Events

Subscribe to lifecycle events for logging, metrics, or progress UI.

ship.on('request', (url, init) => console.debug('→', init.method, url));
ship.on('response', (response, url) => console.debug('←', response.status, url));
ship.on('error', (error, url) => console.error('✗', url, error));

Per-deploy progress comes from the onProgress callback in deploy() options, not from events.

Error Handling

@shipstatic/ship re-exports the error types — you don't need to install @shipstatic/types separately.

import Ship, { isShipError, ErrorType } from '@shipstatic/ship';

try {
  await ship.deploy('./dist');
} catch (error) {
  if (isShipError(error)) {
    error.isAuthError();        // semantic category
    error.isNetworkError();     // semantic category
    error.isClientError();      // Business | Config | File | Validation
    error.type === ErrorType.File;        // specific-type check
    error.type === ErrorType.Validation;  // specific-type check
  }
}

TypeScript

Full type safety with exported types:

import type {
  ShipClientOptions, DeploymentOptions, ShipEvents,
  Deployment, Domain, Account, StaticFile,
} from '@shipstatic/ship';

Configuration

The SDK resolves credentials in this order:

  1. Constructor options
  2. Environment variables: SHIP_API_KEY, SHIP_API_URL, SHIP_DEPLOY_TOKEN

The SDK does not read .shiprc or package.json — that's the CLI's job. This means new Ship({}) is safe to use from embedded contexts (MCP, n8n, library wrappers) without inheriting the host developer's ~/.shiprc.

SHIP_PASSWORD is read by the CLI only — pass password directly via the deploy() options when calling the SDK programmatically.