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

nyrut

v0.1.0

Published

Nyrut from your terminal: invoices, expenses and Spanish tax estimates.

Readme

nyrut

Nyrut from your terminal. Invoices, clients, expenses and a quarterly tax estimate, without leaving the shell.

npm install -g nyrut
nyrut login
nyrut invoices

What it is

The same account, the same data, the same rules. There is no separate CLI backend and no separate CLI logic: this talks to the same database the web app talks to, authorises through the same row-level security, and imports the same modules that compute totals, invoice numbers and taxes. An invoice created here opens in the browser as an ordinary invoice, because it is one.

Commands

nyrut invoices                    list, most urgent first
  --status overdue|unpaid|draft|paid
  --client <name>
  --limit <n> · --all

nyrut invoice <number>            draw the invoice
nyrut invoice new                 create one   (--client --issuer --date --due)
nyrut invoice send <number>       email it     (--to --yes)
nyrut invoice pay <number>        mark it paid (--undo)
nyrut invoice link <number>       public link to share
nyrut invoice open <number>       open it in the browser

nyrut clients                     who owes what
nyrut issuers                     your issuing entities
nyrut expenses                    what you have recorded  (--year)
nyrut summary                     VAT by quarter  (--year --issuer)

nyrut login · logout · whoami

--json works on every listing and is a separate code path: no colour, no padding, no headers. You should never have to regex pretty output.

The invoice, drawn with characters

nyrut invoice 2026-014 draws the document rather than dumping its fields — same regions, same order, in the issuer's own brand colour:

╭──────────────────────────────────────────────────────────────╮
│ ▄▄                                                           │
│                                                              │
│ FACTURA                                      Nafs Signal SLU │
│ nafs-001                                           B88926027 │
│                                                              │
│ FECHA DE EMISIÓN             VENCIMIENTO                     │
│ 3 de agosto de 2026          18 de agosto de 2026            │
├──────────────────────────────────────────────────────────────┤
│ DE                           FACTURAR A                      │
│ Nafs Signal SLU              Etéreo Experience, SL           │
…

It is a preview, and it says so. It exists to check at a glance that the numbers, the parties and the dates are what you meant. The document people archive is the A4 PDF, and it is made in the browser — nyrut invoice open is one keystroke away.

Each document is drawn in its own language and currency format, because that is what the client receives. Lists are drawn in yours.

Signing in

nyrut login opens a loopback server on 127.0.0.1, sends you to the browser you are already signed into, and the web app asks you — on screen, with the port named — whether to hand the session to it.

  • The port is loopback-only and chosen by the OS.
  • A random state travels out and must come back.
  • The server answers one request and dies.
  • The web side refuses any callback that is not literally 127.0.0.1, ::1 or localhost. Not "resolves to loopback": localtest.me points at 127.0.0.1 and somebody else controls its DNS.
  • Handing the session over needs a click. A link alone is never enough.

The refresh token is stored at ~/.config/nyrut/session.json with mode 0600. A keychain would be better and is the obvious next step. nyrut logout removes it.

Piping and scripting

  • Colour never carries meaning. Every line reads correctly through | cat, on a dumb terminal, and under NO_COLOR.
  • Animation stops the moment nobody is watching: not a TTY, piped, CI, NO_COLOR, or --plain. Output that changes shape when piped is output you cannot script.
  • Progress spinners go to stderr. nyrut invoice link X | pbcopy copies the URL and nothing else.
  • Unknown options are an error. --stauts=paid silently ignored would list every invoice and look like it worked.

Taxes

nyrut summary runs the app's own liquidacion303 / liquidacion130, including the carry-forward of a negative quarter and both legs of reverse charge. One issuer at a time, always: VAT is filed per tax ID, so adding two issuers together produces a number matching no return anyone will ever file. Modelo 130 appears only for individuals — a company files corporate income tax instead.

Invoices in a currency other than the workspace's are excluded and counted, because converting them needs the ECB rate for each invoice's date and the app is what fetches it. Two answers to the same question would be worse than one answer with a footnote.

It is an estimate to check against, not a filing.

Configuration

The Supabase URL and publishable key are baked in at build time from the app's own .env.local. Nothing secret is bundled — the publishable key is the one already shipped to every browser, and every row it reaches is reached through RLS with your session.

Environment overrides, for pointing at a staging deployment:

NYRUT_SITE                 default https://www.nyrut.com
NYRUT_SUPABASE_URL
NYRUT_SUPABASE_ANON_KEY

Building

cd cli && npm install && npm run build     # → cli/dist/nyrut.mjs
npx vitest run cli/                        # renderer and parser tests

The renderer is pure — data in, string[] out — which is what makes it testable. The tests check the thing that can break silently: that every line of the card is exactly the same visible width, measured on text rather than bytes, with accents, long names, four currencies and empty data.