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

devhop

v0.3.0

Published

Hop local web dev servers onto your phone in seconds with live updates, real HTTPS, and working microphone/camera permissions.

Readme

🐇 devhop

npm version License: MIT Node.js Built for AI Agents smoke

Your phone says "Blocked request. This host is not allowed." npx devhop fixes it.

Hot reload, real HTTPS (mic, camera, passkeys) and a QR code, with no config edits or accounts.

Vite:     Blocked request. This host ("smoke-check.trycloudflare.com") is not allowed.
Next.js:  Blocked cross-origin request to Next.js dev resource /_next/hmr from "smoke-check.trycloudflare.com".
Safari:   TypeError: undefined is not an object (evaluating 'navigator.mediaDevices.getUserMedia')
npx devhop [port]
 🐇 DEVHOP 

  Target:       http://localhost:3000
  Mobile URL:   https://breeze-sunset-vintage-glade.trycloudflare.com
  ⚠ Public link — anyone with it can open your dev server. Ctrl+C when done.

  ✔ Connected to Cloudflare Edge [ARN]

  Scan with your iPhone or Android camera:
  [ QR Code ]

  Press Ctrl+C to stop the tunnel and disconnect.

Your agent built it. Now see it on your phone.

Ask your coding agent "show me this on my phone". It runs npx devhop --json, reads the URL from the first event, and hands it back. You scan it, and the page hot-reloads while the agent keeps editing.

The skill is at skills/devhop/SKILL.md, and the JSON events are below.

Works with

| Framework | Version tested | Page | Hot reload | Without devhop | | :--- | :--- | :---: | :---: | :--- | | Vite + React | Vite 8.3.5 | ✅ | ✅ | 403 Blocked request. This host … is not allowed. | | Next.js | 16.4.3 | ✅ | ✅ | page loads, but the hot-reload WebSocket never connects | | Nuxt | 4.6.2 | ✅ | ✅ | 403 Blocked request. This host … is not allowed. | | SvelteKit | 3.1.0 | ✅ | ✅ | 403 Blocked request. This host … is not allowed. | | Astro | 7.4.2 | ✅ | ✅ | 403 Blocked request. This host … is not allowed. |

Checked nightly in CI; see the smoke workflow. "Without devhop" is the same request sent straight to the dev server with the tunnel's Host header.

Quickstart

Run directly without installing:

# Auto-detects your active dev server (Next.js, Vite, Astro, Nuxt, etc.)
npx devhop

# Or pass a port number
npx devhop 3000

# Or paste whatever your terminal printed
npx devhop http://localhost:5173
npx devhop localhost:3000
npx devhop 0.0.0.0:4321

For an HTTPS dev server, pass the upstream URL including its scheme:

npx devhop https://localhost:8443

Targets accept bare ports, host:port, and http:// or https:// URLs. A bare 443 implies HTTPS. devhop does not verify the upstream certificate, so self-signed dev certificates work; point it only at servers you trust. If the upstream scheme is wrong, devhop returns a 502 with a hint to retry using the matching URL scheme.

Options

npx devhop                   Auto-detect active dev server port
npx devhop [target]          Expose port, host:port, or URL with QR code
npx devhop [target] --no-qr  Expose target without printing QR code
npx devhop [target] --json   Output tunnel JSON (for AI agents & scripts)
npx devhop [target] --http2  Route tunnel over HTTP/2 (corporate firewall bypass)
npx devhop --help            Show help message
npx devhop --version         Show version
npx devhop --doctor          Print diagnostics for bug reports

JSON events for agents and scripts

npx devhop 3000 --json writes one JSON object per line to stdout:

| event | When | Fields | | --- | --- | --- | | ready | The public URL is known | url, inspectUrl, target, port, host, protocol, edgeReady | | reconnecting | The tunnel is retrying | attempt | | error | Before exiting non-zero | code, message | | closed | After Ctrl+C or SIGTERM | none | | doctor | npx devhop --doctor --json | devhop, node, platform, arch, cloudflared, devPorts, cacheDir |

edgeReady is false when Cloudflare hadn't answered after 20 seconds. The URL is still valid; reload after a few seconds.

{"event":"ready","url":"https://example.trycloudflare.com","inspectUrl":"https://example.trycloudflare.com/__devhop/inspect","target":"http://127.0.0.1:3000","port":3000,"host":"127.0.0.1","protocol":"http:","edgeReady":true}
{"event":"reconnecting","attempt":1}
{"event":"error","code":"NO_DEV_SERVER","message":"No active dev server detected on standard dev ports. Pass a port, e.g. npx devhop 3000."}

Error codes: INVALID_ARGUMENT, INVALID_TARGET, NO_DEV_SERVER, CLOUDFLARED_INSTALL_FAILED, PROXY_START_FAILED, TUNNEL_START_FAILED, TUNNEL_EXITED, UNCAUGHT. Machine-readable summary: llms.txt.

cloudflared

On first run devhop downloads a pinned cloudflared release into ~/.cache/devhop/bin/<version>/ and checks its SHA-256 before using it. To use your own binary instead, set DEVHOP_CLOUDFLARED=/path/to/cloudflared; devhop then downloads nothing.

Mobile inspector

Open https://<tunnel>/__devhop/inspect on your phone for an app preview iframe, a one-tap Eruda bookmarklet, and bundler recipes for Vite and Next.js. The inspector leaves your app HTML untouched.

Corporate firewall bypass

On office or cafe networks where UDP/QUIC is blocked, cloudflared may fail to connect. Force the tunnel over TCP port 443 instead:

npx devhop 3000 --http2

What unlocks on your phone

Because the tunnel is genuine HTTPS, the Web APIs that need a secure context work on a real device:

| Feature | Using Wi-Fi IP (http://192.168.x.x) | Using npx devhop | What you can test | | :--- | :---: | :---: | :--- | | Microphone (getUserMedia) | ❌ Blocked | ✅ Works | Speech-to-Text dictation, voice notes, audio recorders | | Camera (getUserMedia) | ❌ Blocked | ✅ Works | QR/barcode scanning, photo uploads, video capture | | FaceID / TouchID (Passkeys) | ❌ Blocked | ✅ Works | Biometric login flows | | WebCrypto (crypto.subtle) | ❌ Blocked | ✅ Works | Client-side encryption and JWT auth tokens | | 1-Click Copy (navigator.clipboard) | ❌ Blocked | ✅ Works | Copy-to-clipboard buttons | | "Add to Home Screen" (PWA) | ❌ Blocked | ✅ Works | Testing full-screen PWA installs on iOS |

How it works

┌─────────────────┐       HTTPS       ┌─────────────────────────────┐
│  iPhone Safari  │ ────────────────▶ │ *.trycloudflare.com (Edge)  │
└─────────────────┘                   └─────────────────────────────┘
                                                     │
                                                     ▼ HTTP
                                      ┌─────────────────────────────┐
                                      │      devhop Micro-Proxy     │
                                      │ (Makes it look like loopback)│
                                      └─────────────────────────────┘
                                                     │
                                                     ▼ Localhost
                                      ┌─────────────────────────────┐
                                      │ Next.js / Vite (Port 3000)  │
                                      └─────────────────────────────┘
  1. Instant trusted link: Creates a temporary HTTPS link via Cloudflare's edge. Your phone sees a genuine, trusted security padlock.
  2. Framework friendly: Relabels incoming requests so Next.js and Vite think your phone is just a regular browser tab running directly on your laptop. No red error screens, no config editing.
  3. Live updates on save: Preserves the live WebSocket connection so your phone screen refreshes instantly when you save code.
  4. Logins & cookies stay intact: Rewrites redirect links and strips localhost cookie restrictions so login flows and session cookies work naturally on your phone.
  5. Survives server restarts: If Vite or Next.js reboots while you're working, devhop recovers automatically without dropping your tunnel or making you scan a new QR code.

Compared to

| | devhop | cloudflared tunnel --url | ngrok | unjs/untun | LocalCan | mkcert | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | Command | npx devhop | cloudflared tunnel --url … | CLI download + login | npx untun | Mac app | brew install | | Account or signup | None | None | Required | None | License key | None | | Real HTTPS padlock | Yes | Yes | Yes | Yes | Yes (local only) | Manual iOS profile | | Hot reload in Vite, Next.js, Nuxt, SvelteKit, Astro | Yes (nightly CI) | ⚠️ Needs allowedHosts / allowedDevOrigins edits | ⚠️ Needs allowedHosts / allowedDevOrigins edits | ⚠️ Needs allowedHosts / allowedDevOrigins edits | ⚠️ Needs allowedHosts / allowedDevOrigins edits | ⚠️ Wi-Fi IP mismatch | | Terminal QR code | Yes | Link only | Link only | Link only | App UI only | None |

FAQ

Why not just cloudflared? cloudflared tunnel --url http://localhost:3000 gets you a URL. Then Vite answers 403 Blocked request. This host … is not allowed. and Next.js refuses the hot-reload socket, because both check the Host and Origin headers. devhop runs cloudflared for you and rewrites those headers so the dev server sees localhost. The table above shows what each framework does without it.

Is it safe? The URL is public and anyone who has it can reach your dev server. See Security & exposure.

navigator.mediaDevices is still undefined. The page must be a secure context in a real browser tab. It is also undefined in home-screen web apps and some in-app browsers, and old code may call the deprecated navigator.getUserMedia. Open the tunnel URL in Safari or Chrome directly.

Can I get a persistent URL? Not on quick tunnels. Every run gets a new random subdomain.

Security & exposure

Read this before running devhop:

  • Your dev server is reachable from the public internet for as long as the tunnel runs. Anyone with the URL can hit it. Close the tunnel (Ctrl+C) when you step away.
  • Header masquerading is intentional. devhop rewrites Host, Origin, and Referer so your dev server treats the phone as trusted loopback — which also means dev-mode origin and CSRF protections (Next.js allowedDevOrigins, Vite allowedHosts) are bypassed for everyone, not just your phone.
  • Run only dev servers you're actively working on. Never point devhop at anything containing real credentials or user data.

Limitations

devhop rides Cloudflare's free quick tunnels (trycloudflare.com), which Cloudflare explicitly labels testing and development only:

  • No SSE. Quick tunnels buffer or drop Server-Sent Events, so token-streaming endpoints will misbehave. HMR (WebSockets) works fine.
  • 200 concurrent in-flight requests. Heavy HMR bursts or many simultaneous devices can hit Cloudflare's request cap and return 429.
  • Ephemeral URLs. Every run gets a new random subdomain; there is no custom-domain option on free quick tunnels.
  • No SLA. Cloudflare can rate-limit or change the free quick-tunnel service at any time. If first-run setup fails intermittently, devhop retries once automatically before giving up.
  • Blocked domains. Some corporate networks and security tools block *.trycloudflare.com, because free tunnel domains get abused for phishing. If the phone shows a block page, try cellular.

License

MIT © Noor Latif · Fullstacked

More tools from Fullstacked Labs.