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

@firefly0621/dsh-remote-relay

v0.1.0-rc.14

Published

Standalone WebSocket relay for dsh remote control: device registry, pairing, session routing

Readme

@firefly0621/dsh-remote-relay

English | 中文

Standalone WebSocket relay for the dsh remote-control capability. Devices (dsh hosts running @firefly0621/dsh-remote-control) connect outbound with a long-lived secret; mobile apps pair with a short-lived code; the relay routes request/response messages between them. The PC behind NAT never needs an inbound port — it dials out, exactly like the OpenClaw/Claw mobile-control pattern.

The relay is a single-process Node service with no harness dependency. Device registrations and pairing codes live in memory and clear on restart; app sessions persist when DSH_RELAY_DATA_DIR is set, so a paired phone resumes with its stored token instead of re-pairing.

Configuration (environment variables)

| Variable | Default | Meaning | |---|---|---| | PORT | 8787 | Listening port | | NODE_ENV | — | production requires TLS (refuses plaintext WS) | | DSH_RELAY_DEVICE_SECRETS | — | Comma-separated deviceId:secret pairs; the device registry | | DSH_RELAY_ALLOW_AUTO_REGISTER | — | 1 accepts the first hello for an unknown random deviceId and binds it (the plugin's zero-config mode) | | DSH_RELAY_DATA_DIR | — | Directory for durable session storage; absent keeps sessions in memory | | DSH_RELAY_TRUST_PROXY | — | 1 uses the leftmost X-Forwarded-For address for per-IP rate limits (only behind a trusted reverse proxy) | | TLS_CERT / TLS_KEY | — | PEM cert/key paths; required when NODE_ENV=production |

Deployment (systemd on a VPS)

[Unit]
Description=dsh remote relay
After=network.target

[Service]
WorkingDirectory=/opt/dsh-relay
ExecStart=/usr/bin/node /opt/dsh-relay/lib/bin.js
Environment=NODE_ENV=production
Environment=PORT=8787
Environment=DSH_RELAY_DEVICE_SECRETS=my-pc:CHANGE_ME_LONG_RANDOM
Environment=TLS_CERT=/etc/letsencrypt/live/relay.example.com/fullchain.pem
Environment=TLS_KEY=/etc/letsencrypt/live/relay.example.com/privkey.pem
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Generate the device secret with openssl rand -hex 32. Front with a real certificate (Let's Encrypt) — the relay never serves plaintext WS in production.

Security notes

  • Auth is two-layered: the device secret proves "this is the registered host"; the pairing code proves "the phone user is at the keyboard of that host". The relay forwards requests only between a paired app and its bound device.
  • DSH_RELAY_ALLOW_AUTO_REGISTER is first-seen-wins: an unknown deviceId binds to whatever secret its first hello presents. Plugin-generated deviceIds are random 128-bit values, so claiming a vacant id gains nothing; keep the flag off on shared relays.
  • Session control is device-side: the bound device can list (sessions.list) and revoke (sessions.revoke) its app sessions; a revoked token stops resuming.
  • The relay is a dumb pipe: it never inspects command payloads and never persists message content. Compromising the relay exposes routing metadata, not settings values — though settings reads still transit it, so TLS is mandatory.
  • Pairing codes: 6 digits, 10-minute TTL, one-time use, max 5 wrong attempts. Rotated by the device on every relay (re)registration.
  • Pairing brute-force is rate-limited: failed pair attempts are budgeted per source IP (10 per minute), and an IP over the budget is blocked for 10 minutes. At most 32 concurrent sockets per source IP; device secrets compare in constant time.
  • Sessions are device-scoped: sessions.revoke drops only sessions bound to the requesting device, never another device's tokens.
  • Requests fail fast: a request awaiting a device that disconnects is failed with device.offline, and one unanswered past 30 seconds times out — no app socket hangs and no relay memory leaks.
  • Heartbeats: peers ping every 30s; a silent connection is dropped after 60s.

Protocol

Defined in @firefly0621/dsh-remote-protocol — this package only implements the relay side.