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

@lionrapid/cli

v0.1.2

Published

LionRapid CLI — sync translation files (iOS, Android, Flutter, JSON, YAML, PO) with the LionRapid backend

Readme

@lionrapid/cli

The LionRapid command-line tool. Syncs translation files in many formats (iOS .strings/.xcstrings, Android strings.xml, Flutter .arb, generic JSON, YAML, PO) with the LionRapid backend, and generates type-safe TypeScript keys from your translations.

This is the non-web integration wedge: it reaches platforms the web surfaces (WordPress, edge proxy, JS snippet, React SDK) can't — mobile apps, backend services, static-site generators, and CI/CD — by speaking the existing /api/integrations/* REST surface instead of the DOM.

Status

Phase 1 (file-sync dev-loop) is implemented. Command surface:

| Command | Status | What it does | | ----------------- | ------ | ------------------------------------------------------------------- | | init | ✅ | Scaffold a lionrapid.yml (detects Flutter/iOS/Android/Rails/JS) | | push | ✅ | Upload source strings to the backend (server handles MT) | | pull [--types] | ✅ | Download translations into target files; optionally regen types | | validate [--ci] | ✅ | Check local files vs the backend for missing/orphan/empty keys | | types generate | ✅ | Generate a typed .d.ts from your source files (offline) | | types check | ✅ | Report ICU issues in your source translations | | scan [--json] | ✅ | Find user-facing strings in source → inventory keyed by auto_key | | scan --push | ✅ | Seed the safe wrap candidates to the backend under their auto_key | | snapshot | ✅ | Write offline-resilience bundles (raw ContentUnit) per locale/ns | | doctor | ✅ | Preflight: config, credentials, server connectivity, source files |

Formats: JSON, YAML, PO (incl. plurals + msgctxt), Flutter .arb, iOS .strings + .xcstrings, Android strings.xml, XLIFF (1.2/2.0, CAT-tool interchange).

Multiple namespaces: give any files entry its own namespace to map different file trees to different backend namespaces (defaults to the top-level namespace). Each is pushed/pulled/validated independently, so the same key name in two namespaces never collides:

namespace: app
files:
  - { format: json, source: common/en.json, target: common/{locale}.json, namespace: common }
  - { format: json, source: app/en.json,    target: app/{locale}.json } # → namespace: app

Reliability & automation

Built for CI and AI agents — every networked command is resilient and scriptable.

  • --json (all commands): emit one result envelope { ok, command, … } on stdout; human prose goes to stderr. On failure, a structured error envelope { ok: false, error: { type, message, status? }, exitCode } is written to stdout. Parse stdout, read stderr.
  • --dry-run (push, pull): report exactly what would happen — counts, keys, target files — without any network mutation (push) or file write (pull). pull --dry-run still does the read-only fetch so the counts are real.
  • Exit codes (stable, gate CI on them): 0 ok · 1 unexpected · 2 validation/config · 3 auth · 4 network/5xx · 5 partial.
  • Automatic retries: transient failures (network error, 5xx, 429) are retried with exponential backoff + jitter; a 429 honors Retry-After. Tune with LIONRAPID_RETRIES (default 3; 0 disables). Writes are safe to retry — the integration endpoints upsert by composite key.
  • Concurrent pull: namespace fetches fan out with bounded concurrency (LIONRAPID_CONCURRENCY, default 6) and show interactive progress on a TTY. Output stays deterministic — only the network fan-out is parallelized.
  • doctor: one command to verify config validity, credential resolution, backend reachability/auth, and that declared source files exist — each checked independently so you get an actionable list, not a stack trace.

Offline resilience (snapshot)

lionrapid snapshot writes the raw ContentUnit bundle ({ meta, translations }) per locale/namespace, byte-shaped like the API response — bypassing the format adapters (which flatten to display strings and drop the styles map). Bundle these with your app and load them via the runtime so translations keep working with the server down:

import bundle from './snapshots/es.app.json' assert { type: 'json' };
import {
  LionRapidBuilder,
  MemoryRepository,
  StaticRepository,
} from '@lionrapid/core';

const core = await LionRapidBuilder.init({
  defaultLocale: 'es',
  namespace: 'app',
})
  .use(new MemoryRepository({ enabled: true }))
  .useStaticBundle({ es: { app: bundle.translations } }) // offline layer (memory → static → network)
  .build();
core.t('welcome'); // works offline, styles intact

Node apps can read a snapshot directory at runtime via new FileRepository('./snapshots') from @lionrapid/storage/node.

No-library localization (scan)

For a codebase with no i18n library (hardcoded strings, no t()), scan finds user-facing strings via the TypeScript AST over a finite allowlist of UI sinks (JSX text + placeholder/alt/aria-label/…), classifies them, and keys each by content-hash auto_key — the same key the web edge proxy / DOM auto-detect produces, so a string already translated on your website is reused in your app.

  • action: wrap — static text/attributes (deterministic, safe).
  • action: review — interpolation / inline markup / dynamic values (left for a human or AI agent to author correctly).

scan --json emits a machine-readable inventory on stdout (human prose on stderr) so an AI coding agent can drive the judgment-heavy wrapping while the CLI owns the correctness-critical parts (the auto_key hash, file writes, sync). scan --push seeds the safe candidates into the translation memory.

Wrapping (done by you / your agent)

The CLI intentionally does not rewrite your source. It hands you the inventory — each candidate carries its autoKey, and the result carries the namespace — and you (or your AI coding agent, e.g. Claude Code / Cursor) wrap using the SDK, which also lets the agent handle the review cases (interpolation, plurals) a deterministic codemod can't:

// inventory: { namespace: "app", autoKey: "auto_2d0f6b8300be", text: "Add to cart", sink: "jsx-text" }
<Text>Add to cart</Text>
//   →
<Text><Trans namespace="app" i18nKey="auto_2d0f6b8300be">Add to cart</Trans></Text>

// inventory: { autoKey: "auto_13348442cc6a", text: "Search", sink: "jsx-attr:placeholder" }
placeholder="Search"  →  placeholder={t('app:auto_13348442cc6a', 'Search')}

Because the key is the same content-hash the web produces, any of these strings already translated on your website are translated in the app for free.

Usage

lionrapid init --project <id> --targets es,fr
lionrapid push
lionrapid pull --types
lionrapid validate --ci

# no-library localization
lionrapid scan --json          # inventory of discovered strings (auto_key-keyed)
lionrapid scan --push          # seed the safe candidates into the TM

The API key is read from LIONRAPID_API_KEY (or ~/.lionrapid/credentials), never from the committed lionrapid.yml.

Development

npm run build -w packages/cli
npm test -w packages/cli