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

@synchain/cli

v0.5.1

Published

Command-line interface for Synchain — the all-in-one music and audio production collaboration platform. Manage project files, scheduling, discussion and members from your terminal.

Downloads

872

Readme

Synchain CLI (synchain)

Command-line interface for Synchain — the all-in-one music and audio production collaboration platform. Manage project files, scheduling, discussion, members, and notifications from your terminal — built for humans and AI agents alike.

Install

npm install -g @synchain/cli        # global `synchain` binary
# or run without installing:
npx @synchain/cli --help

From source (development):

cd cli && npm install && npm run build && npm link

Requires Node.js ≥ 20.

Quickstart

Generate a CLI key in the web app under Settings → CLI Access, then:

synchain login                       # paste the key (or set SYNCHAIN_TOKEN)
synchain project ls                  # list projects, then:
synchain project use <id>            # set the active project
synchain files upload ./mix.wav      # upload a file
synchain notifications ls            # your unread notifications

Commands

login · logout · whoami · project ls|use · files ls|upload|download|mv|rename|rm · folders ls|mkdir|rename|rm · calendar add|ls|edit|rm · discussion ls|read|post|reply · members ls · notifications ls|read (alias notif). Run synchain help or synchain <group> --help. Every command that writes remote data also takes --dry-run (see below).

discussion ls is paginated (--limit, --offset; newest threads first). members ls lists the project roster (read-only) and requires the members scope to be enabled.

--dry-run

Every command that changes remote data accepts --dry-run:

files upload|mv|rm|rename · folders mkdir|rm|rename · calendar add|edit|rm
discussion post|reply · notifications read

A dry run still resolves 8-char id prefixes and validates your input against the server (read-only GETs run as usual), then prints the resolved target, sends no write request, skips the files rm confirmation, and exits 0.

That resolution step is the point. Ids are UUIDs and every command accepts the 8-char prefix printed by ls — a prefix copied from the wrong row deletes someone else's file just as happily. --dry-run shows which full id and which filename your prefix actually landed on, before anything is destroyed:

$ synchain files rm a1b2c3d4 --dry-run
[dry-run] would delete mix_v2.wav (a1b2c3d4, 12.0 MB) from project 1111….
Nothing was sent. Re-run without --dry-run to apply.

$ synchain files rm a1b2c3d4 --dry-run --json
{
  "dryRun": true,
  "action": "files.rm",
  "target": {
    "project": "1111…",
    "file": { "id": "a1b2c3d4-0000-4000-8000-000000000001", "name": "mix_v2.wav", … }
  }
}

dryRun is always true and action is a stable <group>.<command> identifier, so a caller can branch on the plan without parsing prose. target is shaped per action.

Caveats worth knowing: a dry run cannot predict server-side state it never queries — e.g. folders rm --dry-run does not know whether the folder is empty, so the real DELETE can still fail with 409 folder_not_empty. project use deliberately has no --dry-run: it only writes the local config file and touches nothing remote.

Errors in JSON mode

In text mode errors are unchanged (red prose on stderr). Under --json / --format json they become a single-line envelope on stderr (stdout stays reserved for results):

{ "error": { "code": "folder_not_empty", "status": 409, "url": "https://…", "detail": "…" } }

code is the server's own snake_case error code (invalid_project_id, forbidden, storage_key_in_use, …) taken straight from the response body — the same vocabulary the HTTP API uses, so CLI and API callers can share one error table. When the body carries no usable code it falls back to http_<status>; failures with no HTTP response at all (DNS/TLS, timeouts, local file errors, an ambiguous id prefix) report {"code":"client_error","status":0}. All four fields are always present.

Error classes (programmatic use)

When the CLI is imported as a library, every non-2xx response throws a typed error. ApiError is the base class; the subclass is chosen by HTTP status, so callers can catch narrowly instead of re-testing err.status:

| Class | Status | What to do about it | | --- | --- | --- | | AuthError | 401 | Re-authenticate (synchain login / SYNCHAIN_TOKEN). Retrying will not help. | | ForbiddenError | 403 | Usually the key lacks the scope, or you are not a member — retrying will not help. One exception: a files upload whose presigned storage URL expired mid-transfer also lands here, and that one is worth retrying. Branch on the envelope's code, not on the class, when you need to tell them apart. | | NotFoundError | 404 | Re-list to get a current id; the target is gone or invisible to you. | | ConflictError | 409 | Fix the conflicting state (empty the folder, pick a free key), then retry. | | ValidationError | 400, 422 | Correct the input. Retrying the same request always fails. | | RateLimitError | 429 | Back off, honoring Retry-After. | | ServerError | 5xx | Retry with exponential backoff. The body is often gateway HTML, not JSON. |

Every subclass is instanceof ApiError, and all of them keep status, url, and body, so existing err instanceof ApiError && err.status === 404 checks keep working unchanged. Statuses outside the table (402, 451, …) throw the base ApiError rather than being forced into the nearest subclass — use the envelope's code for the fine-grained reason.

import { apiErrorFor, NotFoundError, RateLimitError } from "@synchain/cli";

apiErrorFor(status, url, body, message?) is the same factory the CLI uses internally, exported so callers can classify a status they obtained elsewhere with the identical rules.

Notes

  • The key is stored in the OS config dir (%APPDATA%\synchain / ~/.config/synchain, mode 0600) and is never accepted via an argv flag. Override the server with --base-url (default https://synchain.vercel.app; cleartext http is rejected for non-loopback hosts).
  • Machine-readable output: the global --format text|json (default text) is equivalent to the per-command --json flag, and synchain --help --format json prints the whole command tree as JSON — commands, options, and usage — so agents can discover the surface without scraping the human help text.
  • The package ships type declarations (dist/index.d.ts); buildProgram(), main(), the ApiError hierarchy above, and the ErrorEnvelope type can be imported programmatically from @synchain/cli.
  • Discussion posts made through a CLI key are stamped is_ai_generated=true and show an [AI] badge in the web UI.

Full guide for AI agents: synchain.ca/AGENTS.md — install, non-interactive auth, --json output shapes, and which paths not to crawl.