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

@hasna/shortlinks

v0.2.10

Published

Shortlink manager for custom domains and click tracking, with local SQLite or hosted /v1 API (bearer key) storage and Cloudflare setup helpers

Readme

@hasna/shortlinks

Shortlink management for custom domains — CLI, MCP server, REST API, and a generated SDK.

shortlinks creates Bitly-style short URLs, supports multiple domains, records click analytics, can run a tiny redirect server, and includes helper commands for Cloudflare DNS/Workers and @hasna/domains. It defaults to local SQLite and serves from an app-owned PostgreSQL database when HASNA_SHORTLINKS_DATABASE_URL is configured.

Surfaces

Four surfaces share one core library:

| Surface | Bin / package | Purpose | | --- | --- | --- | | CLI | shortlinks | Interactive/scriptable link + domain management (--json for agents). | | MCP | shortlinks-mcp | Model Context Protocol server (stdio or --http) exposing link/domain tools to agents. | | REST API | shortlinks-serve | HTTP service: GET /health, /ready, /version, /openapi.json, and a versioned /v1 CRUD API guarded by API-key auth. | | SDK | @hasna/shortlinks-sdk (+ @hasna/shortlinks/sdk) | Typed fetch client generated from the serve OpenAPI (bun run sdk:generate). |

Hosted service

shortlinks-serve reads/writes PostgreSQL directly via the vendored @hasna/contracts storage kit — no sync engine or cache in the service. A configured HASNA_SHORTLINKS_DATABASE_URL selects the postgresql server data backend; the pool factory fails closed without it. API-key auth comes from @hasna/contracts/auth; mint keys with contracts issue-key --app shortlinks --scopes 'shortlinks:read,shortlinks:write'.

HASNA_SHORTLINKS_DATABASE_URL=$DATABASE_URL \
HASNA_SHORTLINKS_API_SIGNING_KEY=... \
shortlinks-serve            # migrate (idempotent) then serve on :8080
shortlinks-serve migrate    # one-shot migration task

Clients use SHORTLINKS_API_URL + SHORTLINKS_API_KEY (never a DSN).

npm License

Install

bun install -g @hasna/shortlinks

The local database lives at:

~/.hasna/shortlinks/shortlinks.db

Quick Start

shortlinks init --domain has.na
shortlinks create https://example.com --slug docs
shortlinks serve --host 127.0.0.1 --port 8787

Then a request for https://has.na/docs redirects to https://example.com and records a click.

Agent-Friendly JSON

Every operational command supports --json:

shortlinks --json create https://example.com --domain has.na
shortlinks --json link list
shortlinks --json stats docs --domain has.na
shortlinks --json doctor

Errors are emitted as:

{ "error": "message" }

Compact Defaults and Details

Human output is compact by default so agent terminals do not fill with full records. List and status commands show essential fields, truncate long URLs or text, cap human rows, and print the next command to use for details.

Use these gradual disclosure paths when you need more:

shortlinks link list --limit 50
shortlinks link get home --verbose
shortlinks stats home --verbose
shortlinks doctor --verbose
shortlinks domain check has.na --verbose
shortlinks events list --limit 50
shortlinks webhooks list --limit 50
shortlinks --json link get home

--json remains the machine-readable path and keeps full objects where commands already returned them. Prefer --json for automation and --verbose for human debugging.

Example compact output:

https://has.na/home -> https://example.com/landing-page-with-a-very-long-path... active
Showing 1 link(s).
Use `shortlinks link get <slug>` for details.

Before this behavior, detail/status commands such as shortlinks link get home, shortlinks stats home, and shortlinks doctor printed full JSON-like objects by default.

CLI

shortlinks init --domain has.na
shortlinks domain add has.na --default
shortlinks domain setup go.example.com --cloudflare --target shortlinks.example.com --dry-run
shortlinks domain check example.ai
shortlinks domain buy example.ai --dry-run

shortlinks create https://example.com --slug home
shortlinks link create https://example.com/docs --domain has.na --title Docs
shortlinks link list
shortlinks link get home --domain has.na
shortlinks link disable home --domain has.na
shortlinks link enable home --domain has.na
shortlinks stats home --domain has.na

shortlinks serve --port 8787
shortlinks doctor

Local Domain Setup

Record a local mapping with the machines CLI and print the remaining hosts/proxy setup:

shortlinks local setup has.na --port 8787
shortlinks local plan has.na --port 8787

The command emits the /etc/hosts line, a Caddy reverse-proxy snippet, and certificate paths. Writing /etc/hosts still requires sudo on macOS.

Custom Domains

Add as many domains as you need:

shortlinks domain add has.na --default
shortlinks domain add go.example.com --provider cloudflare

Generated links use the default domain unless --domain is passed.

Remove a domain (this also deletes all of its links and clicks):

shortlinks domain remove go.example.com

Cloudflare

Create a dry-run plan:

shortlinks cloudflare plan has.na \
  --target shortlinks.example.com \
  --origin https://shortlinks.example.com

Write a Cloudflare Worker that forwards requests to the redirect server while preserving the original host:

shortlinks cloudflare worker \
  --worker shortlinks \
  --origin https://shortlinks.example.com

Upsert DNS when CLOUDFLARE_API_TOKEN is available. Global API key auth is also supported with CLOUDFLARE_API_KEY plus CLOUDFLARE_EMAIL.

shortlinks cloudflare dns has.na --target shortlinks.example.com

Buying Domains

Domain purchasing goes through the domains CLI from @hasna/domains:

shortlinks domain check new-short-domain.ai
shortlinks domain buy new-short-domain.ai --dry-run

This package does not install or call any removed connect-* packages.

Storage selection

The client resolves ONE Store from the environment — there is no DSN on any client:

  • on-box SQLite (default): every command, MCP tool, and SDK call reads and writes the local database.
  • hosted /v1 HTTP API: set HASNA_SHORTLINKS_API_URL + HASNA_SHORTLINKS_API_KEY to route every call to the hosted /v1 API with a bearer key. Setting only one of the two is a configuration error and fails loudly — never silent local drift.
# Route the client to the hosted API (bearer key, never a DSN):
export HASNA_SHORTLINKS_API_URL=https://shortlinks.example.com
export HASNA_SHORTLINKS_API_KEY=hsk_...
shortlinks doctor

The server (shortlinks-serve) is the only component that holds a Postgres connection, and it opens its pool server-side through the sanctioned storage kit — the raw RDS DSN is never distributed to clients.

Development

bun install
bun test
bun run typecheck
bun run build

Repository

The OSS repository is expected to be:

hasna/shortlinks

The local workspace folder is named shortlinks; the published package and GitHub repo use bare names without the retired open- prefix.

License

Apache-2.0. See LICENSE.