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

glymonir-cli

v0.8.0

Published

Official CLI + Node.js client for the Glymonir image hosting API. Uploads, batch operations, and gallery read in one command.

Readme

glymonir-cli

Official command-line tool for the Glymonir image hosting API.

Upload one picture or ten thousand in a single command — the CLI runs the same client-side preprocessing the web app does (thumb / preview WebP, 512×512 embedding JPEG, thumbhash placeholder, EXIF, colour palette, SHA-256 dedup) and drives the R2 two-stage upload flow end-to-end.

What's new in 0.7.0 (memory — lower peak RSS, no upload-content changes):
Per-picture variant generation now runs serially (one variant at a time) off the single decoded RGBA buffer, instead of fanning all six encodes + extractors out at once. On the low-core hosts these batches typically run on, the old parallel fan-out gave near-zero speed-up (the ops just contended for the same 1-2 cores) while multiplying peak memory — measured ~11% slower but ~40% lower peak RSS on a pinned 2-core box. Parallelism now lives where it belongs: across pictures via --concurrency N (in-process) or xargs -P (OS-isolated). The --low-memory flag is removed — the default is now the memory-safe path. A 50 MB per-file size guard (matching the backend) rejects oversized files before decode.

Install

# Zero-install via npx (recommended):
npx glymonir-cli --help

# Or install globally:
npm install -g glymonir-cli
glymonir --help

Requires Node.js ≥ 20.

Quick start

export GLYMONIR_API_KEY=gly_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Upload a single image to the public gallery
npx glymonir-cli upload photo.jpg

# Upload to a specific library
npx glymonir-cli upload --library 1234 photo.jpg

# Upload with metadata
npx glymonir-cli upload \
  --name "Mt. Fuji at sunrise" \
  --introduction "Captured 2024-09-15 from Hakone" \
  --tags mountain,sunrise,japan \
  photo.jpg

# Batch upload (shell expands the glob, default runs sequentially)
npx glymonir-cli upload ~/photos/*.jpg

Concurrency & memory

Each picture is processed one variant at a time from a single decoded buffer, so a single in-flight task peaks around 60-100 MB resident (the decoded source + one encode working set + Node heap headroom). The CLI defaults to --concurrency 1 — sequential, lowest memory, safe on any laptop or 2 GB VPS with no special flags.

To go faster, pick one of two parallelism models:

1. In-process — --concurrency N (simplest; shared progress bar + resume state). Each extra in-flight task adds another ~60-100 MB, so size N to your RAM:

| Total system RAM | Suggested --concurrency | |---|---| | ≤ 2 GB | 1 (default) | | 4 GB | 2 | | 8 GB | 4 | | 16 GB+ | 8 |

The CLI auto-warns when it detects total RAM < 2 GB and concurrency > 1. On a tight host you can also cap V8's heap: prefix NODE_OPTIONS='--max-old-space-size=512'.

2. Multi-process — xargs -P (maximum isolation; each picture gets its own OS process and heap, so one bad file can never affect another):

# Linux / macOS — one process per core, --concurrency 1 inside each
ls ~/photos/*.jpg | xargs -P "$(nproc)" -n 1 \
  glymonir upload --resume

Use model 1 for the built-in progress bar and resume state; use model 2 when you want hard process-level isolation and already drive parallelism from your shell or CI.

Batch & advanced flags

| Flag | What it does | |---|---| | -c, --concurrency <N> | Run N pictures in parallel inside one process (shared progress bar + resume state). Default 1 (sequential). Each picture is processed serially internally; N scales the number of pictures in flight, so peak memory ≈ N × single-task. For hard process isolation instead, drive parallelism with xargs -P (see above). | | --retries <N> | Retry budget per network call. Only transient errors (HTTP 5xx, 408, 429, classic socket failures) retry; 4xx fails fast. Default 3. | | --retry-backoff <S> | Base seconds for exponential backoff with full jitter. Default 2. | | --manifest <jsonl> | One JSON object per line, {"file":"…","name":"…","intro":"…","tags":[…],"libraryId":N}. Per-file metadata overrides CLI defaults. | | --resume | Skip files already marked ok in .glymonir-state.jsonl. Failed and skipped entries re-attempt. Crash-resumable, latest-status-wins. | | --state-file <path> | Override the default .glymonir-state.jsonl path (e.g. for parallel batches into different libraries). | | --dry-run | Preprocess + /check only — no R2 PUT, no /finalize, no DB write. Reports per-file fresh vs. dedup status + summary. | | --output json | Emit one JSONL line per file to stdout: {file, status, id?, sha?, code?, message?, ts}. Suppresses the progress bar. | | --no-skip-small | Disable the local "skip files < 1 MB when targeting the public gallery" filter. By default the CLI saves a full round-trip on guaranteed-reject files. |

Realistic workflows

Resumable 10k-file batch:

npx glymonir-cli upload \
  --concurrency 2 \
  --retries 3 \
  --resume \
  ~/photos/*.jpg

# Power cut / network drop / Ctrl-C → re-run the same command. Already-
# uploaded files skip instantly; failures retry automatically.

Per-file metadata via manifest:

# batch.jsonl  (relative paths resolve against the manifest's directory)
{"file":"./shot-01.jpg","name":"Mt. Fuji at sunrise","tags":["nature","mountain"]}
{"file":"./shot-02.jpg","name":"Tokyo skyline","intro":"Captured 2024-09 from Tokyo Tower"}
npx glymonir-cli upload \
  --manifest batch.jsonl \
  --concurrency 2 \
  --resume

Machine-readable output (for scripting / CI):

npx glymonir-cli upload --output json ~/photos/*.jpg | jq -c .
# {"file":"/home/me/photos/a.jpg","status":"ok","id":"2059...","sha":"abc…","ts":"2026-…"}
# {"file":"/home/me/photos/b.jpg","status":"fail","code":40000,"message":"…","ts":"2026-…"}

Memory-constrained hosts (≤2 GB RAM):

# The default (--concurrency 1, serial per-picture processing) is already
# memory-safe on a 2 GB box. Optionally cap V8's heap to keep RSS tight:
NODE_OPTIONS='--max-old-space-size=512' \
  npx glymonir-cli upload --resume ~/photos/*.jpg

Where to get an API key

  1. Open your Glymonir profile → Settings → API Keys
  2. Click Create new key
  3. Pick the scopes you need:
    • gallery:upload — required for the upload command (admin only — public gallery uploads bypass the daily count quota)
    • gallery:read — required for reading the public gallery (Pro plan or admin)
  4. Copy the gly_live_… plaintext — it's shown exactly once

Eligibility: API keys require a Pro plan or admin role. Free / Starter accounts cannot issue keys.

Configuration

| Setting | Env variable | CLI flag | Default | | --- | --- | --- | --- | | API key | GLYMONIR_API_KEY | -k, --api-key | (required) | | Backend base URL | GLYMONIR_API_BASE | -b, --api-base | https://api.glymonir.com/api |

Local-dev users with a self-hosted backend: set GLYMONIR_API_BASE=http://localhost:8123/api.

Picture upload requirements

The backend enforces these rules on every upload:

| Rule | Public gallery (no --library) | Library (with --library) | | --- | --- | --- | | Format | JPEG / PNG / WebP | JPEG / PNG / WebP | | Max size | 50 MB | 50 MB | | Min size | 1 MB (quality floor) | none | | Per-user daily quota | 30/day (Pro) · 200/day (whitelist) · ∞ (admin) | none |

A picture that violates a rule produces a non-zero code from /picture/upload/r2/check; the CLI prints it inline and exits non-zero. With --no-skip-small off (default), public-gallery uploads under 1 MB are skipped locally — no round-trip wasted.

Using as a library

The package also exports its primitives so you can build your own flows:

import { preprocess, uploadPicture } from 'glymonir-cli'

const variants = await preprocess('photo.jpg')
const picture = await uploadPicture(
  { variants, name: 'Mt. Fuji', tags: ['nature'] },
  {
    apiBase: 'https://api.glymonir.com/api',
    apiKey: process.env.GLYMONIR_API_KEY!,
    retry: { retries: 3, backoffSeconds: 2 },
  },
)
console.log('uploaded id =', picture.id)

Error codes (subset)

The CLI surfaces the backend's BaseResponse.code directly. The most common ones you'll see:

| Code | What it means | | --- | --- | | 0 | Success | | 40000 | Invalid request (size below 1 MB gallery floor, unsupported format, missing field…) | | 40100 | Missing / wrong / revoked / expired API key | | 40101 | Key doesn't carry the required scope (e.g. upload without gallery:upload) | | 42900 | Per-key rate limit hit — response carries Retry-After in seconds |

See the Glymonir API reference for the complete table.

License

MIT