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

tinylogs

v0.3.0

Published

A tiny self-hosted central log receiver + live dashboard.

Readme

tinylogs

A tiny, self-hosted central log receiver + live dashboard. Apps push log lines over HTTP; you watch them in a fast, dense browser dashboard with label filtering. Single Node process, single SQLite file. Runs anywhere npx runs.

Quick start

npx tinylogs init      # wizard: port, admin user/pass, retention → writes tinylogs.config.json + prints an ingest token
npx tinylogs start     # runs the receiver + dashboard (default http://127.0.0.1:4700)

Open the dashboard, log in with the admin user you created.

Non-interactive init (CI/containers):

TINYLOGS_PASSWORD=hunter2 npx tinylogs init --yes --port 4700

Install & run as a service

Install globally so tinylogs is on your PATH (recommended for a long-running server):

npm i -g tinylogs        # puts `tinylogs` on PATH
tinylogs init            # create tinylogs.config.json + tinylogs.db in the current dir
tinylogs start -d        # run in the background (writes tinylogs.pid + tinylogs.log)
tinylogs status          # running? pid, url, uptime, version
tinylogs stop            # stop it
tinylogs restart         # stop + start -d
tinylogs update          # update to the latest published version

npx tinylogs … still works for one-off use. start -d, status, and stop are supported on Linux/macOS; on Windows run the foreground tinylogs start under a service manager (NSSM / Task Scheduler). The PID and log files live next to your config file.

Sending logs

Anything that can make an HTTP request can send logs. service and message are required; labels are arbitrary string key/values. level is just a label with special coloring.

curl -XPOST http://localhost:4700/ingest \
  -H "Authorization: Bearer <INGEST_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"service":"debtors-bot","message":"reminder sent","labels":{"level":"info","user":"12345"}}'

Batch by sending an array. Response: {"accepted": N} (400 if service/message missing, 401 if the token is wrong).

Node client

Install the standalone, zero-dependency client package @tinylogs/client (npm install @tinylogs/client):

import { TinyLogsClient } from '@tinylogs/client';

const logs = new TinyLogsClient({
  url: 'http://localhost:4700',
  token: process.env.TINYLOGS_TOKEN!,
  service: 'debtors-bot',
});

logs.info('reminder sent', { user: '12345' });
logs.error('boom', { user: '12345' });
// fire-and-forget: never throws, never blocks your app, batches automatically.
await logs.close(); // flush on shutdown

Configuration

tinylogs.config.json (created by init, in the current directory by default):

| Field | Meaning | Default | |-------|---------|---------| | port / host | Listen address | 4700 / 127.0.0.1 | | dbPath | SQLite file (relative to the config file) | tinylogs.db | | retentionDays | Delete logs older than this | 14 | | maxSizeMB | Cap the DB file; oldest rows pruned first | 500 | | bufferSize | In-memory live-tail buffer | 2000 | | sessionSecret / ingestTokenHash | Generated at init — do not edit | — |

Override the config location with --config <path> or TINYLOGS_CONFIG. Rotate the ingest token with npx tinylogs rotate-token.

Security

  • No default passwordinit forces you to set one.

  • TLS is delegated to a reverse proxy. tinylogs serves plain HTTP; put nginx or Caddy in front for HTTPS. Example (Caddy):

    logs.example.com {
      reverse_proxy 127.0.0.1:4700
    }
  • Dashboard auth is a signed httpOnly session cookie; /api/* and /ws require it.

  • /api/login is rate-limited against brute force.

  • The ingest token is a separate shared secret, stored hashed; shown only once.

How it works

  • Storage: SQLite in WAL mode. logs holds each line (labels as JSON for one-read render); log_labels explodes labels for index-backed key=value filtering.
  • Live tail: a bounded in-memory ring buffer seeds new browser tabs and feeds the WebSocket stream. The DB is the source of truth for history + search.
  • Retention: a background task prunes by age and by size (whichever hits first) and VACUUMs; failures are logged, never fatal.

Non-goals

Not a clustered/distributed store, not metrics/tracing, not multi-tenant SaaS. One node, one SQLite file, one admin.

License

MIT © 2026 Nikita Medvedev