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

rcon-htmx

v1.0.1

Published

Source RCON and Rust WebSocket RCON bridge for htmx. Connect your htmx UI to game servers over WSS. Minimal deps: ws.

Readme

rcon-htmx

Source RCON and Rust (WebSocket RCON) bridge for htmx. Uses Node.js built-ins plus the ws package.

Connect your htmx frontend to game servers over secure WebSockets: the library supports the Source RCON binary protocol (CS2, Garry's Mod, ARK, etc.) and Rust WebSocket RCON. You get HTML fragments (e.g. hx-swap-oob) and build the UI however you want.

Why

Browsers can't open raw TCP sockets, so you can't talk RCON directly. If your web panel runs on HTTPS, you also can't use unencrypted WebSockets (mixed content blocking). This package solves both problems:

Browser (HTTPS)  <-- wss:// -->  Node Backend  <-- TCP -->  Game Server
     htmx                        rcon-htmx                  RCON :27015

The WebSocket rides on the same HTTPS server that serves your page — no mixed content, no CORS, no extra ports.

Install

npm install rcon-htmx ws

ws is a peer dependency — you likely already have it if you're using WebSockets.

Quick Start

Server (5 lines)

const express = require('express');
const { createRconBridge } = require('rcon-htmx');

const app = express();
const server = app.listen(3000);

createRconBridge(server, {
  host: '192.168.1.10',
  port: 27015,
  password: process.env.RCON_PASSWORD,
});

HTML (htmx)

<script src="https://unpkg.com/htmx.org@2/dist/htmx.min.js"></script>
<script src="https://unpkg.com/htmx-ext-ws@2/dist/ws.js"></script>

<div hx-ext="ws" ws-connect="/ws/rcon">

  <!-- RCON output appears here automatically via hx-swap-oob -->
  <div id="rcon-output"></div>

  <!-- ws-send serializes the form as JSON and sends over WebSocket -->
  <form ws-send>
    <input type="text" name="command" placeholder="Enter command..." />
    <button type="submit">Run</button>
  </form>

</div>

That's it. Type status and hit Run — the server executes the RCON command and pushes styled HTML back into #rcon-output.

API

createRconBridge(httpServer, options)

Attaches a WebSocket endpoint to your HTTP server that bridges to RCON.

Returns: WebSocketServer instance.

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | host | string | — | RCON server hostname (required if authMode is 'server') | | port | number | 27015 | RCON server port | | password | string | — | RCON password (required if authMode is 'server') | | path | string | '/ws/rcon' | WebSocket endpoint path | | authMode | 'server' \| 'client' | 'server' | Who provides credentials (see below) | | timeout | number | 5000 | Connection and command timeout in ms | | targetId | string | 'rcon-output' | DOM element ID for OOB swap target | | swapStyle | string | 'beforeend' | htmx swap strategy (beforeend, innerHTML, etc.) | | formatLine | function | built-in | Custom formatter: (text, meta) => htmlString | | onConnect | function | — | Called when a session connects: (ws, rcon) => void | | onCommand | function | — | Command filter: (command, ws) => false to block |

Auth Modes

Server-side auth (default)

RCON credentials are in your server config. Every WebSocket connection auto-authenticates. Use this when your web panel has its own auth layer.

createRconBridge(server, {
  host: '192.168.1.10',
  password: process.env.RCON_PASSWORD,
});

Client-side auth

The browser sends credentials as the first WebSocket message. Good for multi-server panels where the user picks which server to connect to.

createRconBridge(server, {
  authMode: 'client',
});

The first message from the client must be:

{ "auth": { "host": "192.168.1.10", "port": 27015, "password": "secret" } }

In htmx, you can do this with a login form:

<div hx-ext="ws" ws-connect="/ws/rcon">
  <!-- Auth form (shown first) -->
  <form ws-send id="auth-form">
    <input type="hidden" name="auth.host" value="192.168.1.10" />
    <input type="hidden" name="auth.port" value="27015" />
    <input type="password" name="auth.password" placeholder="RCON password" />
    <button type="submit">Connect</button>
  </form>

  <div id="rcon-output"></div>

  <form ws-send>
    <input type="text" name="command" />
    <button>Run</button>
  </form>
</div>

Blocking Commands

Use onCommand to filter dangerous commands:

createRconBridge(server, {
  host: '192.168.1.10',
  password: 'secret',
  onCommand: (command) => {
    const blocked = ['quit', 'exit', 'rcon_password', 'changelevel'];
    if (blocked.some((b) => command.toLowerCase().startsWith(b))) {
      return false; // sends error HTML back to the client
    }
  },
});

Custom Formatting

Override the default HTML output:

createRconBridge(server, {
  host: '192.168.1.10',
  password: 'secret',
  formatLine: (text, meta) => {
    // meta.type is 'response', 'error', or 'info'
    // meta.command is the command that was run (for responses)
    // meta.timestamp is the current time string
    return `<pre class="my-line">[${meta.timestamp}] ${text}</pre>`;
  },
});

Advanced: Direct RCON Access

For custom setups, you can use the RCON client directly:

const { RconConnection } = require('rcon-htmx');

const rcon = new RconConnection({
  host: '192.168.1.10',
  port: 27015,
  password: 'secret',
});

await rcon.connect();
const response = await rcon.exec('status');
console.log(response);
rcon.destroy();

HTML Output Format

The default formatter produces HTML like this for each command:

<!-- Appended to #rcon-output via hx-swap-oob="beforeend" -->
<div id="rcon-output" hx-swap-oob="beforeend">
  <div class="rcon-response">
    <div class="rcon-meta">
      <span class="rcon-cmd">> status</span>
      <span class="rcon-time">8:30:15 AM</span>
    </div>
    <div class="rcon-body">
      <span class="rcon-line">hostname: My Server</span>
      <span class="rcon-line">players : 12/24</span>
    </div>
  </div>
</div>

CSS classes you can style:

  • .rcon-response — command + output wrapper
  • .rcon-meta — header row with command and timestamp
  • .rcon-cmd — the command that was run
  • .rcon-time — timestamp
  • .rcon-body — response text container
  • .rcon-line — individual output line
  • .rcon-error — error message
  • .rcon-info — info message (connect, disconnect)
  • .rcon-status — connection status badge (has .connected or .disconnected)

HTTPS / Production

For HTTPS, put the Node server behind a TLS-terminating reverse proxy (nginx, Caddy) or use Node's https module directly. The htmx WS extension automatically upgrades ws:// to wss:// when the page is served over HTTPS — no config needed.

server {
    listen 443 ssl;
    server_name panel.example.com;

    ssl_certificate     /etc/ssl/cert.pem;
    ssl_certificate_key /etc/ssl/key.pem;

    location / {
        proxy_pass http://localhost:3001;
    }

    location /ws/rcon {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

License

MIT