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

@zalify/cli

v0.26.3

Published

Zalify CLI - command-line interface for Zalify

Readme

@zalify/cli

Zalify CLI — author a brand, launch its shop, run its ads, keep the theme current.

Install

npm i -g zalify
# or
npm i -g @zalify/cli@latest

Already installed? zalify self-update.

The command model

Four nouns, four objects:

| Noun | The object | What lives under it | | --- | --- | --- | | brand | the data | a brand folder: catalog, voice guide, image manifest | | shop | the shop | Zalify-hosted at <slug>.myzalify.com: repo + deployment + domain | | ads | the ad ops | Autopilot brand instance: campaign intent repo (media plans, ads-as-code, policy) | | theme | the code | Shopify-theme model: scaffold a copy, measure drift, upgrade |

Everything acting on a brand folder lives under brand. Brand and theme commands default their directory to the cwd; shop refresh/open resolve their shop from the cwd (.zalify/site.json in a scaffold, store.json in a brand folder); ads commands run arg-free from a checkout carrying .zalify/brand-repo.json.

The golden path (new brand, start to live)

zalify brand init stores/acme        # 1. author the data (no login needed)
zalify login                         # 2. authorize; then: zalify workspace set <workspace>
zalify shop create acme              # 3. live at acme.myzalify.com in ~4 minutes
                                     #    (already scaffolded the dir with
                                     #     `theme create`? → `zalify shop link acme`)
cd stores/acme && zalify brand push --prune
zalify brand images generate && zalify brand images attach
zalify theme status                  # 6. stay current; `theme upgrade` keeps your edits

Authentication

zalify login                                   # opens the browser: authorize once
zalify login --app-url http://localhost:3000   # against a local app.zalify.com
zalify whoami                                  # workspace, plan, and key details
zalify logout                                  # delete local credentials

login runs a loopback flow (like gh auth login): the CLI listens on a random localhost port, the browser opens app.zalify.com/cli/auth, and on approval a user key covering all your workspaces is handed back and stored in ~/.zalify/config.json (0600). Keys are ordinary Zalify Public API keys — list and revoke them in Settings → Developer. One login covers every workspace; zalify workspace set switches between them locally, no re-login.

Inside a brand checkout, the folder decides. ads commands read the checkout's own workspace (its .zalify/brand-repo.json stamp, or identity.yaml for folders AdsBuddy downloaded) and act as that workspace — no workspace set first, and no risk of pulling one brand's campaigns into another's folder. workspace set still matters for commands run outside any checkout, and for ads create, which provisions a NEW brand into the workspace you chose.

Command reference

Auth & workspace

| Command | What it does | | --- | --- | | login [--app-url <url>] | Browser-based authorization; stores a user key locally | | logout | Deletes ~/.zalify/config.json (revoke the key itself in Settings → Developer) | | whoami | Verifies the stored key; shows workspace, plan, app origin, key prefix | | workspace / workspace list | List authorized workspaces (* = active) | | workspace set <slug-or-id> | Switch the active workspace (local, no re-login) |

brand — the data

| Command | What it does | | --- | --- | | brand init [dir] [--name <name>] [--vertical <v>] [--currency <code>] | Scaffold a brand folder: catalog, voice guide, image manifest, AUTHORING.md rules. No login needed | | brand validate [dir] | Lint the brand folder against the authoring rules | | brand push [dir] [--prune] [--shop <slug>] | Push catalog.json to the connected Shopify store — products, smart collections, publish; idempotent. --prune deletes store products (by catalog vendor) absent from the catalog; --shop narrows the post-push refresh to one shop | | brand images generate [dir] | Generate the manifest's missing images on Zalify infrastructure (resumable) | | brand images attach [dir] [--shop <slug>] | Attach generated images to their Shopify products per the manifest (skips already-attached) | | brand images push [dir] | Upload image masters to the Zalify asset library — presigned R2 PUTs, sha256 dedup; writes images/assets.json, the committed index that keeps binaries out of git | | brand images pull [dir] | Download masters listed in images/assets.json that are missing locally (fresh-clone restore) |

shop — the hosted shop

| Command | What it does | | --- | --- | | shop create <dir> [-t <theme>] [--editor] [--to <version>] [--no-install] [--no-git] | One-command launch: provision repo + deployment + domain + storefront token, scaffold locally, push, go live at <slug>.myzalify.com. --editor wires in the Zalify canvas editor (z1). Needs an empty/absent <dir> — an existing scaffold attaches via shop link instead | | shop link <dir> [--slug <slug>] [--no-git] | Attach an existing scaffold (from theme create) to an already-provisioned shop: fill store credentials into .env, write .zalify/site.json + theme/pixel.json, push, wait for the deploy. Also the recovery path if shop create fails after provisioning | | shop / shop list | List the workspace's hosted shops | | shop refresh [slug-or-dir] | Refresh the live shop's data cache (defaults to the shop linked to cwd) | | shop open [slug-or-dir] | Open the live shop in the browser (defaults to the shop linked to cwd) | | shop domain-sync [slug-or-dir] | Re-point the shop at the current root domain (the old domain 308-redirects) |

z1shop … (and site … before it) remain as hidden aliases for one release and print a pointer to their new home under shop.

ads — the ad ops

| Command | What it does | | --- | --- | | ads create <dir> | Provision an Autopilot brand-instance GitHub repo (POST /api/repos, GitHub App), scaffold the starter locally (identity.yaml, brand.yaml, policy/, campaigns/, media-plans/, signals/, decisions/), and push with a short-lived repo-scoped token. Writes .zalify/brand-repo.json so later commands run arg-free. The directory name becomes the slug — use the workspace's store slug so the service's digest writer can find the repo | | ads / ads list | List the workspace's brand instances and their provisioning status | | ads new <name> [--account <folder>] [--objective] [--budget] [--country] [--link] | Scaffold a campaign FOLDER at accounts/<account>/<name>/ (account inferred when only one exists): campaign.yaml for budget/audience/copy defaults, creatives/ for the files that become ads. cp -r an existing folder to duplicate a campaign | | ads pull [--account <act_id>] [--days <n>] [--force] | The existing accounts as a tree: every ingested campaign lands as accounts/<account-name>/<campaign>/campaign.yaml (imported form — names in label:, budgets, statuses, core audience) plus campaigns/.bindings.json mapping YAML nodes to platform ids. A hash ledger protects local edits: unedited files fast-forward, edited ones are kept and named, deletions never happen automatically | | ads creative generate <campaign> --prompt <text> [--orientation] [--ref <url...>] [--name] | One image through the canvas pipeline (safe zones, product fidelity with refs), downloaded INTO the campaign's creatives/ and recorded in its assets.json — the filesystem stays the interface, and the asset is stored once | | ads diff | Desired (your campaign files) vs actual (the ingested account), keyed through bindings: bound nodes compare budget/status, unbound nodes become creations. Folder campaigns upload their creatives/ first (presign + checksum dedup — the brand images push machinery) and derive server-side. Read-only against the platform | | ads apply [-y] [--activate] | Execute the diff after showing it and asking. Creations land PAUSED — always; budget edits apply to bound entities; paused→active is refused without --activate (turning spend on is said twice; active→paused always executes). Created ids merge into the bindings ledger | | ads remove <slug> | Deprecate a brand instance — soft-deletes the record (drops out of ads list and the service's repo-token minting; survives for history). The GitHub repo is deliberately untouched: deleting real campaign intent is a human-on-GitHub decision | | ads status | The instance at a glance: brand + consent, platform access and credential expiry, ingestion freshness (with per-account failures), first-party join coverage, plan and pending-proposal counts. Exits non-zero when the service reports problems | | ads report [--date <YYYY-MM-DD>] [--platform <all\|meta\|google>] | The daily report in the terminal — totals vs the day before, where the money moved, what changed in the account | | ads digest [dir] | Print the repo's signals/latest.json — the curated numbers the service writes daily and agents draft against. Reads the LOCAL checkout | | ads plan / ads plan list | Media plans recorded by the service, newest first | | ads plan show <id> | One plan's content (by id, or slug@version) | | ads open | Open the Structure canvas for the active workspace | | ads doctor [dir] | Checks that have each broken once: checkout↔record link, workspace match, slug alignment (service brand vs repo record — misalignment silently kills digest writes), consent drift, brand-vs-account timezone match, credential expiry and degradation |

The engine commands — plan / apply / creative / report — join this group as @zalify/ads-engine merges in. Until then, drafting and applying happen on the Structure canvas in app.zalify.com; the instance repo is the durable intent layer that work lands in.

theme — the code

| Command | What it does | | --- | --- | | theme create <dir> [-t <template>] [--editor] [--store-domain <domain>] [--storefront-token <token>] [--to <version>] [--no-install] [--no-git] [--tarball <path>] | Scaffold only — no Zalify hosting (the self-host path; shop create is the fully-hosted launch, and a scaffold can move to hosting later via shop link). Templates: liquid | hydrogen | nextjs. Without --store-domain it runs on mock.shop demo data | | theme status [dir] | Which theme files have you edited? Checksums vs .zalify/theme.json | | theme upgrade [dir] [--to <version>] [--dry-run] [--install] [--tarball <path>] [--base-tarball <path>] | Move to a newer theme version: untouched files overwritten, edited files 3-way-merged, theme/ + .env never touched. --dry-run classifies and reports without writing |

Maintenance

| Command | What it does | | --- | --- | | version | Print the CLI version and check npm for a newer one | | self-update | Update the CLI to the latest version (auto-detects pnpm/bun/npm) |

Every invocation also runs a passive, non-blocking update check and prints a one-line notice when a newer version exists.

Development

Requires Bun.

bun install
bun run dev version   # Run CLI from source (TypeScript)
bun run build         # Build to dist/
bun run typecheck     # Type-check only

Publishing

CI publishes automatically (.github/workflows/publish.yml): pushing to main with a package.json version that isn't on npm yet typechecks, builds, publishes @zalify/cli, and tags the commit v<version>. The zalify/ wrapper (for npm i -g zalify) is published in the same run whenever its own version is new. Auth is npm Trusted Publishing (OIDC, no token secret): one-time setup per package on npmjs.com — package → Settings → Publishing access → Add trusted publisher → GitHub Actions → repo zalify/zalify-cli, workflow publish.yml.

Release flow:

npm version minor --no-git-tag-version   # or patch/major
# bump zalify/package.json in step and pin its @zalify/cli dependency
git commit -am "0.x.0" && git push