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

@volter/twin-bitly

v0.1.37

Published

Local Bitly twin — a faithful, stateful local Bitly v4 API your link integration talks to unmodified. Mirror, simulate, and fork. Built on @volter/world-core.

Readme

@volter/twin-bitly

The Bitly twin — a local, stateful, vendor-faithful replica of the Bitly v4 API on the shared @volter/world-core kernel. An unmodified integration (plain fetch against api-ssl.bitly.com/v4, which is how every real Bitly consumer talks to it — Dub's link importer included) points at the twin and gets vendor-correct responses.

State lives in the kernel's append-only action/event log — a write appends an action that projects into visible state; reads use the kernel’s tree. No real Bitly is ever called (the only network path is the connector, over an injected client). Auth is a faked-locally Bearer access token — Bitly's API auth is a plain bearer token, so there is NO JWT, NO JWKS, NO request signing.

Usage

bun run src/cli.ts serve            # the Bitly v4 API twin (writable)
bun run src/cli.ts serve --read-only
bun run src/cli.ts mirror           # the React link dashboard mirror
bun run src/cli.ts conformance      # offline, failable endpoint-probe check

Responses are the vendor's own shapes, taken from Bitly's first-party OpenAPI document. Errors use Bitly's Error envelope — { message, resource, description, errors?[{ field, error_code }] } — where message is the status name the spec itself declares (NOT_FOUND, BAD_REQUEST, FORBIDDEN, GONE, UNPROCESSABLE_ENTITY, CONFLICT).

Coverage

The capability manifest (src/bitly-capabilities.ts) is the real Bitly v4 surface as the denominator, enumerated top-down from Bitly's own published OpenAPI 3.0.0 document (https://dev.bitly.com/v4/v4.json, fetched 2026-09-02: 113 paths / 132 route operations) plus the OAuth token exchange that lives outside /v4. Coverage is honest and partial. Run bun scripts/manifest-baseline-one.ts bitly for the live count. As of writing: done=86 / total=163 (regressions=0). The spec census (bitly-spec-census.json) reads 47 capability / 85 unmapped (one ruled) of the 132 spec operations.

Modeled (proven done, each with a failable offline verify):

  • OAuth — POST /oauth/access_token, the authorization-code exchange, answering form-encoded text/plain (not JSON) exactly as the vendor does; a token is derived from the code, so the same code always exchanges to the same token. Missing code → 400 error=invalid_request.
  • Bitlinks — POST /v4/shorten (deduplicating per group+domain+URL, 201 new / 200 existing, force_new_link to override), POST /v4/bitlinks (title, tags, keyword back-half), GET/PATCH/DELETE /v4/bitlinks/{domain}/{hash}, POST /v4/expand. Negatives are modeled: a non-http(s) long_url is a field-level 400, a foreign domain 403, an unknown group 404, a deleted link 410 GONE, a keyword collision 409, an empty patch 422.
  • Click analytics — a deterministic modelled surface, not a stub: /clicks, /clicks/summary, /countries, /cities, /devices, /referrers, /referring_domains and the group-level /clicks all FOLD stored click observations, honouring unit / units / unit_reference. See the note below on how clicks get into the twin.
  • Groups — list (with organization_guid filter), get, rename; the group link list with Bitly's size + opaque search_after pagination, tags, archived and created_before filters; tags, clicks, shorten_counts and the group QR list.
  • User + organizations — GET/PATCH /v4/user, GET /v4/user/platform_limits (whose count moves as links are minted, which is what Dub's importer polls), GET /v4/organizations, GET /v4/organizations/{guid}, /plan_limits, and GET /v4/bsds.
  • Webhooks — registration CRUD (201 create with per-field 400s, get, patch, 204-with-empty-body delete) and the org hook list. Registration only — no delivery.
  • QR codes — create over a bitlink or a raw long URL, get/patch/delete, group listing.
  • Custom bitlinks — attach a keyword back-half, resolve it, 409 on reuse.
  • Campaigns + channels — create/list/get/update.
  • Protocol — unmodeled ops fail like the vendor (404 with the Error envelope, never a fabricated success); read-only rejects writes (405); a re-read of the same state serves the same bytes.
  • Connector — pull the account (the token owner and its organization roster), groups, every group's bitlinks (walking search_after) and their QR codes into the observed log (idempotent re-pull; a refused pull throws rather than folding an empty account over real state, and so does a 200 that carries no login); push local creates/updates to the real API and confirm them. A local delete is never translated into a real DELETE — a twin-minted id is not a link the account owns. A pulled owner is served WHOLESALE (no seeded field survives underneath it) and a pulled organization roster REPLACES the seeded constant for that root, so a pulled group's organization_guid resolves. A pull observes: a local PATCH /v4/user is folded on top of the observation and survives every later re-pull.
  • UI mirror — the Links, analytics-panel and QR Codes screens are data-coupled (seed through the twin's own write path → fetch the same /v4 endpoint the screen reads → render the dashboard's own exported component over the served rows → assert the seeded values in the markup).

On the clock. Bitly's metrics endpoints take unit / units / unit_reference. unit_reference is what the vendor says it is — "the most recent time for which to pull metrics", a ceiling, always — and it defaults to the request's world instant, exactly as the vendor's "now" does. units: -1 (all units of time, and the default) removes the floor and nothing else. Coherence comes from the other end instead: the twin-only seed route refuses to record a click dated after the instant recording it, so stored state can never hold an observation an honest ceiling would have to hide. bitly.clicks.unit_reference_is_a_real_ceiling pins all three halves — floor removed, ceiling honoured, future observation refused.

An earlier revision of this pack removed the ceiling for units: -1 in the name of determinism. That made a declared parameter a silent no-op on the default request — a future-dated click leaked into every answer while the ignored ceiling was echoed back verbatim — and adversarial review caught it. The lesson is recorded here because the fix looked like a determinism win: when a twin and its vendor disagree about a declared parameter, the twin is wrong.

How clicks get into the twin. A Bitly click is created by a human following a bit.ly redirect on Bitly-operated edge infrastructure — no vendor endpoint creates one, and a local twin cannot originate real traffic. So the twin exposes ONE clearly-namespaced twin-only control route, POST /v4/_twin/clicks, which a test or a world seed uses to record click observations; every metrics endpoint is then a deterministic fold over them. That route is deliberately outside the capability manifest and outside the spec census — it is scaffolding, not vendor surface, and counting it would pad the denominator (the same convention as figma's and openweather's seed routes).

Todo (real Bitly surface, not yet modeled — 84 of the 132 spec operations): the whole Bitly Sites product (link-in-bio pages, blocks, appearance, templates, images, and both the per-site and /aggregate/sites analytics families — 37 operations); the engagement family combining clicks with QR scans; the group-level metric rollups (/groups/{guid}/{countries,cities,devices, referrers,referring_networks}, /links/clicks/*, /codes/scans/*, agentic traffic); group administration (preferences, exports, feature and historical usage); QR scan metrics and the customization surface (render customizations, static codes, redirect, to-bitlink, bulk update); bitlink bulk update and sorted listings; the custom-bitlink update and per-destination click split; deeplinks, dynamic routing and expiration; the OAuth app lookup; and, on the connector side, pulls for webhooks, campaigns and real click metrics.

Also todo, because "we did not build it" is not "a local twin cannot":

  • Serving bitly.com/oauth/authorize as a protocol participant (the human consent leg — the recipe's "vendor UI is protocol" class, with googleoauth as the exemplar; a second host is a wiring decision, not an impossibility). Without it, Dub's OAuth flow cannot run end to end against the twin.
  • Local webhook delivery over an injected offline deliverer, which is exactly what resend does.
  • The shortlink redirect — GET /<hash> on the twin answering with a 301 to the bitlink destination, so the short URLs the twin mints resolve against it.
  • QR image bytes — deterministic PNG/SVG for a QR resource (today only the QR record is modeled).

Fidelity

src/bitly-sdk.integration.test.ts drives the twin with unmodified real-transport fetch. Bitly ships no first-party npm SDK — every real integration calls /v4 with plain fetch, so that is the unmodified client. The test issues the exact request shapes Dub's Bitly importer sends (apps/web/app/(ee)/api/cron/import/bitly/, apps/web/lib/middleware/utils/crawl-bitly.ts, apps/web/lib/integrations/bitly/oauth.ts) and asserts the vendor's own response shapes come back — including that the OAuth exchange parses with new URLSearchParams(await res.text()), which is literally what Dub does with it.

Files

  • src/bitly-twin.ts — the v4 request handler (routes → kernel writes/reads).
  • src/bitly-server.ts — createBitlyTwinFetch / createBitlyTwinServer.
  • src/bitly-mirror-ui.ts + client/bitly-mirror.tsx — the React link dashboard mirror.
  • src/bitly-connector.ts — pull/push over an injected executor (liveBitlyExecute for real I/O).
  • src/bitly-conformance.ts — offline, failable endpoint-probe check (dev-only; lazy-imported).
  • src/bitly-capabilities.ts — the capability manifest (the real vendor surface).
  • src/bitly-journey.uitest.ts — the two registered Playwright UI journeys.

Rate budget — the fail-closed backstop on live calls

liveBitlyExecute is the one place this pack issues a live request, so every call it makes is charged against a persistent, fail-closed spend ledger before the request goes out. Past the ceiling, or while a Retry-After/429 cooldown is armed, it throws instead of calling. The ledger is keyed by vendor and a hash of the credential (limits are per credential, so it is deliberately not cwd-scoped) and persists across processes, so a fresh process does not get a fresh allowance; a corrupt ledger counts as a full window rather than zero spend. There is no option to disable it, and no value you can pass for budget that yields an unguarded client — an injected budget is validated by method identity, so a subclass or a Proxy that replaces checkBudget is refused.

The declared numbers: 60 weighted units / 60s at defaultWeight 2 — 30 calls a minute, EXACTLY the kernel's undeclared fallback. Bitly publishes no scalar rate limit: its rate-limits page (https://dev.bitly.com/docs/getting-started/rate-limits, read 2026-09-02) states only that the per-minute limit is one-tenth of the hourly limit, illustrates it with a hypothetical, and directs callers to read their own plan-specific numbers from GET /v4/user/platform_limits and GET /v4/organizations/{guid}/plan_limits. With no first-party number to justify being more permissive, this declaration is more permissive than the fallback nowhere. POST /v4/shorten and POST /v4/bitlinks cost 5 because each spends an encode from the account's monthly quota — a finite resource a throttle does not give back; that weighting is a judgement call, not a published cost.

The mechanism is shared and vendor-agnostic — it lives in the kernel (@volter/world-core → packages/world-core/src/rateBudget.ts); what lives here in src/bitly-budget.ts is this vendor's declaration (window, ceiling, per-endpoint weights, and a reason citing the source above) plus the vendor-bound BitlyBudget. The rule is ratified as ../../../docs/contributing/architecture.md D8, and the kernel module's header documents what the guard does not guarantee — read that before trusting it.