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

flapwire

v0.2.3

Published

Local HTTP/HTTPS proxy that degrades traffic realistically for resilience testing.

Readme

Flapwire

Local HTTP/HTTPS proxy that degrades traffic on purpose — jittered latency, random connection drops, periodic blackouts — so you can see what breaks before production does.

Forward proxy (classic)

npx flapwire --profile slow-3g
# then, in another terminal:
curl -x http://127.0.0.1:8080 http://example.com/

Reverse proxy

Point your app at Flapwire instead of the upstream and it'll degrade on the way through — no browser proxy config, no /etc/hosts, no flags. Plain HTTP requests and WebSocket upgrades (e.g. Next.js / Vite HMR) are both forwarded, and the same levers apply to the WebSocket handshake. Upstreams on https:// work too.

Single target:

npx flapwire --target http://localhost:3000 --profile flaky-wifi
# listens on http://127.0.0.1:13000 → http://localhost:3000

Multiple services in one process:

npx flapwire \
  --route 13000=http://localhost:3000 \
  --route 15173=http://localhost:5173 \
  --route 18080=http://localhost:8080 \
  --profile train-wifi

Listen ports are the upstream port with a leading 1 by convention (3000 → 13000). When that doesn't fit (out of range, already taken, duplicated), Flapwire picks a free port and tells you which one.

The proxy logs each request:

GET http://example.com/ → 200 (412ms)
GET http://example.com/favicon.ico → drop
GET /api/me → 504 blackout (380ms)

Profiles

| Name | Latency (base ± σ) | Drop rate | Blackout | | ------------ | ------------------ | --------- | ---------------- | | fast-3g | 100ms ± 50ms | 0% | — | | slow-3g | 400ms ± 200ms | 0.5% | — | | flaky-wifi | 150ms ± 300ms | 2% | — | | train-wifi | 500ms ± 400ms | 2% | 4s every 60s |

How the levers work

Each profile is a mix of three independent levers.

Latency — every request is delayed by a sample drawn from a normal distribution centred on baseMs with standard deviation jitterMs, clamped to zero. Roughly 68% of samples fall within baseMs ± jitterMs, 95% within ±2 × jitterMs. The delay is applied before the response is written, so the client experiences it as time-to-first-byte — exactly what happens on a real slow link.

Drop — before latency kicks in, each incoming connection is independently discarded with probability connectionDropRate (a value between 0 and 1). "Discarded" here means the TCP socket is destroyed with no response at all, the way a client would see a packet-loss or RST event from the network.

Blackout — windows where the proxy stops forwarding entirely. everySeconds is the cycle length, durationSeconds is how much of each cycle the blackout covers. The blackout lands at the end of every cycle: for the last durationSeconds of each window, existing connections are torn down and new requests are answered with 504 Gateway Timeout — after the profile's latency, so the stall feels like a real upstream going unreachable rather than an instant reset. WebSocket upgrade attempts during a blackout are refused the same way: the TCP socket is closed.

A lever with no configured value is simply inactive: no latency, no drops, or no blackout cycle at all.

Options

flapwire [--profile <name>] [--port <number>] [--target <url>] [--route <PORT=URL> ...] [--config <path>]
  • --profile, -p — one of fast-3g, slow-3g, flaky-wifi, train-wifi. Default: slow-3g.
  • --port — port to listen on. Forward mode default is 8080. In --target mode use an explicit number, or auto (or leave it off) to let Flapwire derive it from the upstream port.
  • --target <url> — single reverse-proxy upstream. Mutually exclusive with --route.
  • --route <PORT=URL> — repeatable; open one listen port per route, all sharing the same profile.
  • --config <path>, -c — path to a config file (default: ./flapwire.config.yaml if present).

If neither --target nor --route is given, Flapwire runs as a forward proxy (v0.1 behaviour).

Config file

If flapwire.config.yaml exists in the current directory, Flapwire reads it on startup. CLI flags still work and override the file field by field — same convention as Vite, Next, Playwright.

profile: flaky-wifi
routes:
  - listen: 13000
    target: http://localhost:3000
  - listen: 15173
    target: https://localhost:5173
upstreamCa: ./certs/dev-ca.pem  # optional; trusts a self-signed upstream

Single-target shape:

profile: slow-3g
target: http://localhost:3000
port: 13000

Forward mode is the default — omit both target and routes.

Admin API

Set admin.port in the config (or --admin-port) to expose a small control plane on 127.0.0.1. No auth — it's a localhost-only dev tool. Useful for flipping state during a test run without restarting the proxy.

admin:
  port: 17070
# switch profile live
curl -X POST http://127.0.0.1:17070/admin/profile -d '{"name":"flaky-wifi"}'

# force a 5-second blackout right now
curl -X POST http://127.0.0.1:17070/admin/blackout -d '{"durationSeconds":5}'

# make the next 3 requests fail with 503
curl -X POST http://127.0.0.1:17070/admin/fail -d '{"status":503,"count":3}'

# read current state
curl http://127.0.0.1:17070/admin/status

In multi-route reverse mode, every change is fanned out to all routes at once.

Failure injection

Make Flapwire short-circuit specific requests with an HTTP error or a timeout — useful for verifying that retry, fallback, and timeout-handling paths actually work.

failures:
  - path: "^/api/checkout"
    method: POST
    sample: 0.1           # 10% of matching requests
    status: 503
  - path: "^/api/slow"
    timeout: true         # hold the socket open; client times itself out

Rules match in order — first hit wins. The path field is treated as a case-insensitive regex; method and sample are optional. Exactly one of status or timeout must be set.

You can also push rules at runtime through the admin API:

curl -X POST http://127.0.0.1:17070/admin/failures \
  -d '{"rules":[{"path":"^/api/payment","status":504}]}'

curl http://127.0.0.1:17070/admin/failures

POST /admin/failures replaces the live rule list; GET /admin/failures reads it back.

HTTPS

Flapwire can terminate TLS for both forward-proxied browsers (CONNECT) and reverse-proxy upstreams on https://. TLS termination needs a local CA that the OS trusts; set it up once with:

flapwire trust
# sudo will prompt — the CA is written to ~/.config/flapwire/ca.pem and added to the system trust store

After that, run Flapwire normally. Forward mode: point your browser's HTTP(S) proxy at 127.0.0.1:8080 and visit an HTTPS site. Reverse mode: point --target or --route at an https:// upstream.

The CA is issued for "Flapwire Local CA" (10-year validity) and signs one leaf cert per hostname on demand. flapwire trust --uninstall removes it. The CA's private key never leaves your machine.

Supported trust stores: macOS system keychain (via security), Linux with update-ca-certificates (Debian/Ubuntu) or update-ca-trust (Fedora/RHEL). On Windows, flapwire trust prints the certutil command to run in an elevated shell.

Why not ...

  • Chrome DevTools throttling — lives in the browser, can't be scripted, applies a flat delay. Fine for one manual check; not usable in CI or for non-browser clients.
  • Playwright / Cypress network emulation — same browser-only limitation, no real jitter, loss, or blackout.
  • tc / netem — kernel-level, far more powerful, Linux-only without contortions, steep learning curve. If you need packet-level fidelity, reach for tc.
  • toxiproxy — closest neighbour. More features, more configurability, a running daemon and its own config format. Flapwire is deliberately smaller.

Not in this release

No bandwidth throttling, external community profiles, or CI helpers yet. A web UI and a CI integration are on the way in later milestones.

License

MIT. See LICENSE.


This is a side project maintained in spare time. Issues are read but response time is not guaranteed.