tiero

tiero CLI

Preview

Validate and push catalogs from a repo or a CI job.

@tiero/cli keeps catalogs in a repository next to their images and publishes them from your machine or a CI job. It reads a catalog source, uploads the images it points at and sends the catalog with PUT /api/v1/catalogs/{slug}.

Install

The package is in preview and not on npm yet. Once it is, npx @tiero/cli runs it without an install, or add it to a project with npm install -D @tiero/cli. It needs Node.js 20 or later.

Typical run
npx @tiero/cli validate ./catalogs
export TIERO_API_KEY=tiero_sk_...
npx @tiero/cli push ./catalogs         # dry run
npx @tiero/cli push ./catalogs --live  # upload and publish

Create the key under API keys with the catalogs:write and media:write scopes. The CLI reads it from the environment and never prints it.

tiero validate

tiero validate <dir|file> checks one JSON file, or every .json file in a directory (not its subdirectories), with the same rules the API uses. A file with local or URL images is checked as a catalog source, anything else as a catalog spec. Each problem prints with its JSON Pointer, so you can find the field without counting array items. Nothing is sent over the network.

Output
$ tiero validate catalog.json
catalog.json: /items/0/name too_small Too small: expected string to have >=1 characters

tiero push

tiero push <dir|file> validates each catalog, uploads its images, swaps in the returned media ids and publishes the catalog. An image can be a media id you already uploaded, a file path relative to the catalog file, or an HTTPS URL. Files must stay inside the catalog's folder, and every image is limited to 5 MiB. URLs get 10 seconds to download.

catalogs/cars.json
{
  "spec": "tiero-catalog-source/1",
  "slug": "cars",
  "title": "Cars",
  "items": [
    {
      "id": "comet",
      "name": "Comet",
      "image": { "file": "images/comet.png" }
    },
    {
      "id": "banshee",
      "name": "Banshee",
      "image": { "url": "https://cdn.example.com/banshee.webp" }
    }
  ]
}

A push is a dry run unless you pass --live. The dry run reads your files and the cache, lists the images it would upload or fetch and the catalogs it would publish, and makes no writes. A live push prints one row per catalog: created, updated, unchanged or failed, with its revision, item count, removed count and URL.

Output
$ tiero push ./catalogs --live
slug  status   rev  items  removed  url                          warnings
cars  updated  7    42     1        https://tiero.io/c/acme/cars
FlagWhat it does
--liveUpload and publish. Without it every push is a dry run.
--dry-runThe default, spelled out. Cannot be combined with --live.
--baseThe API origin, default https://tiero.io. HTTPS only (HTTP on localhost).
--key-envThe environment variable that holds the API key, default TIERO_API_KEY.
--cacheThe media cache file, default .tiero/media-cache.json.
--rights-ackSends rightsAck=1 to confirm you hold the rights to the images.

Items you leave out of a catalog are removed, and sending their id again brings them back. When a removed item comes back under a different name, the CLI prints a warning so a reused id does not quietly replace a different item.

Quotas and resuming

The media cache records every finished upload by its content hash, per API origin and account, so the same image is uploaded once across items, catalogs and runs. A short rate_limited answer is retried up to three times after the wait the server asks for. When the daily media quota runs out, the push stops cleanly, publishes nothing that is still missing images and says to resume tomorrow. Run the same command again and it picks up where it stopped. Keep the cache file out of version control.

tiero whoami

tiero whoami calls GET /api/v1/me with your key and prints the username, account id, premium status and, when the API reports them, the key's scopes. A rejected key prints Not signed in and exits with code 1.

Exit codes

CodeMeaning
0Everything validated, or every catalog was pushed (or would be).
1A catalog failed validation or a request failed. Other catalogs still ran.
2The run stopped on a daily or total media quota. Rerun later to resume.