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

leonspahnweb

v1.0.0

Published

Tunnel-Client: macht einen lokalen Webserver über eine zentrale Proxy-Plattform öffentlich erreichbar.

Readme

@leonspahn/leonspahnweb

Tunnel-Client für die dezentrale Tunnel-Plattform. Macht einen lokal laufenden Webserver (Express, Next.js, Fastify, ...) über eine zentrale Proxy-Instanz öffentlich erreichbar – ohne Portfreigabe und ohne eigene öffentliche IP.

Browser ──HTTPS──▶ Plattform ──WSS-Tunnel──▶ leonspahnweb ──HTTP──▶ localhost:3000

Der Tunnel wird ausgehend vom Admin-Server aufgebaut (WSS). Eingehende Firewall-Regeln sind nicht nötig.

Installation

npm install @leonspahn/leonspahnweb

Voraussetzung: Node.js ≥ 18

Nutzung

const { connect } = require('@leonspahn/leonspahnweb');

const tunnel = connect({
  domain: 'admin1.systemadmin',            // Deine Kennung auf der Plattform
  token: process.env.TUNNEL_TOKEN,         // Auth-Token (nie hart codieren!)
  localPort: 3000,                         // Port Deines lokalen Webservers
  // serverUrl weggelassen -> Standard: ws://194.15.38.137:3001 (vorläufig, unverschlüsselt)
  // Mit Domain + HTTPS später: serverUrl: 'wss://meine-plattform.de'
});

tunnel.on('connected', () => console.log('Tunnel verbunden'));
tunnel.on('ready', ({ url }) => console.log('Erreichbar unter:', url));
tunnel.on('disconnected', (code) => console.log('Getrennt:', code));
tunnel.on('error', (err) => console.error('Tunnel-Fehler:', err.message));

// Sauber beenden:
process.on('SIGINT', () => { tunnel.close(); process.exit(0); });

Die Seite ist danach unter https://meine-plattform.de/admin1.systemadmin/ erreichbar. Die Plattform meldet die genaue URL per ready-Event.

Lokal testen (Server auf Port 3001)

# Terminal 1 – Server aus dem Paket leonspahnweb-server
npm install && npm start

# Terminal 2 – Demo-App (Port 3000) + Tunnel
npm install && node examples/demo.js

Der Client verbindet sich standardmäßig mit dem Server auf 194.15.38.137:3001. Für einen rein lokalen Test: TUNNEL_SERVER_URL=ws://localhost:3001 node examples/demo.js

Danach im Browser: http://194.15.38.137:3001/admin1.systemadmin/ (lokal: http://localhost:3001/...)

Optionen

| Option | Typ | Standard | Beschreibung | |---------------------|----------|---------------|------------------------------------------------------| | domain | string | – (Pflicht) | Tunnel-Kennung, z. B. admin1.systemadmin | | token | string | – (Pflicht) | Authentifizierungs-Token | | localPort | number | – (Pflicht) | Port des lokalen Servers | | serverUrl | string | ws://194.15.38.137:3001 (oder TUNNEL_SERVER_URL) | WebSocket-URL der Plattform; später wss:// | | allowInsecure | boolean | false | erlaubt ws:// zu anderen Hosts (nur localhost und der Standard-Server sind ohnehin erlaubt) | | localHost | string | 127.0.0.1 | Host des lokalen Servers | | reconnectInterval | number | 5000 | Wartezeit (ms) bis zum nächsten Verbindungsversuch | | requestTimeout | number | 30000 | Timeout (ms) für lokale Requests | | maxBodyBytes | number | 52428800 | Maximale Größe einer lokalen Antwort (Bytes) | | logger | object / false | console | Eigener Logger oder false zum Deaktivieren |

Verhalten

  • Auto-Reconnect: Bricht die Verbindung ab, versucht der Client alle 5 Sekunden (konfigurierbar) sich neu zu verbinden.
  • Heartbeat: Ping/Pong erkennt hängende Verbindungen und baut sie neu auf.
  • Auth-Fehler (HTTP 401/403): Es wird nicht erneut versucht – prüfe dann domain und token.
  • Verdrängt (Close-Code 4001): Verbindet sich eine zweite Instanz mit derselben domain, ersetzt der Server die alte. Diese verbindet sich dann nicht erneut (sonst würden sich beide endlos verdrängen) und meldet einen error.
  • Lokaler Server down: Der Browser erhält 502 Bad Gateway, bei Zeitüberschreitung 504 Gateway Timeout.
  • Sicherheit: Aktuell läuft der Tunnel vorläufig über die IP per ws:// – das Token wird dabei im Klartext übertragen (Warnung in der Konsole). Für den echten Betrieb Domain + HTTPS einrichten und wss:// verwenden. ws:// zu anderen Hosts als localhost und dem Standard-Server verlangt allowInsecure: true.

Hinweise

  • Requests und Antworten werden vollständig gepuffert (kein Streaming); Server-Sent-Events und WebSocket-Upgrades werden nicht getunnelt.
  • Das Token gehört in eine Umgebungsvariable oder einen Secret-Store.

Protokoll (für Plattform-Betreiber)

Alle Frames sind JSON-Textnachrichten. Bodies sind Base64-kodiert.

| Richtung | Frame | |-------------------|----------------------------------------------------------------| | Server → Client | { type: "request", requestId, method, path, headers, body } | | Client → Server | { type: "response", requestId, status, headers, body } | | Server → Client | { type: "ready", url? } (optional) |

Beim Handshake werden die Header x-tunnel-domain und x-tunnel-token gesendet. Bei ungültigen Daten sollte der Server mit HTTP 401 oder 403 antworten.

Lizenz

MIT