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

@darco2903/rcon-ts

v1.1.0

Published

Minimal TypeScript client for the Source RCON protocol (Source engine games, Minecraft, ...), built on neverthrow

Readme

RCON

A minimal TypeScript client for the Source RCON protocol, built on top of neverthrow for explicit error handling and Node's native net.Socket.

Features

  • Promise-based API via ResultAsync<T, string>, every call resolves to either a value or an error message, never throws
  • Sequential command pipeline: commands are queued and sent one at a time, matched to their response by packet id
  • Automatic packet framing/deframing via a Transform stream (SplitterTransform), so partial or batched TCP reads are handled transparently
  • Simple state machine (idle → connecting → ready → closing → closed) exposed via currentState / isReady
  • Optional reassembly of long responses split across several packets (multiPacketResponses)

Installation

npm install @darco2903/rcon-ts

Usage

import { RCON } from "@darco2903/rcon-ts";

const rcon = new RCON("127.0.0.1", 27015, "my-rcon-password");

const connectResult = await rcon.connect();
if (connectResult.isErr()) {
    console.error("Connection failed:", connectResult.error);
    process.exit(1);
}

const commandResult = await rcon.sendCommand("status");
commandResult.match(
    (output) => console.log(output),
    (error) => console.error("Command failed:", error),
);

await rcon.disconnect();

If you need the raw response packet (id, type, and payload buffer) instead of a decoded string, use sendCommandRaw instead of sendCommand.

const result = await rcon.sendCommandRaw("status");
result.andTee((packet) => {
    console.log(packet.id, packet.type, packet.payload);
});

API

new RCON(host: string, port: number, password: string, options?: RCONOptions)

Creates a client instance. Does not connect automatically.

| Option | Default | Description | | ---------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | connectTimeout | 10000 | Max time in ms for connect() to open the socket and authenticate. | | multiPacketResponses | false | Joins responses split across several packets into one. Works by sending an empty SERVERDATA_RESPONSE_VALUE after each command, so only enable it if the server answers those (Source and Minecraft servers do), otherwise commands never resolve. |

connect(): ResultAsync<void, string>

Opens the TCP connection and performs the RCON authentication handshake. Resolves to Ok once the client is ready to send commands. Fails if:

  • the socket cannot connect (unreachable host, refused connection, etc.)
  • the password is rejected by the server
  • the server closes the connection or doesn't answer within connectTimeout
  • connect() is called while already connecting, ready or closing

On failure, the socket is destroyed and the state moves to closed.

disconnect(): ResultAsync<void, string>

Gracefully closes the connection. Any command still waiting for a response, or queued behind it, is rejected with an error. While connecting, cancels the attempt instead (the pending connect() resolves to an error). Fails if the client is already closing or closed, if it has no socket at all, or if the socket fails to close gracefully (it is destroyed anyway).

sendCommand(command: string): ResultAsync<string, string>

Sends a command and resolves with the response payload decoded as a UTF-8 string. Fails if the client is not in the ready state.

sendCommandRaw(command: string): ResultAsync<Packet, string>

Same as sendCommand, but resolves with the full Packet (id, type, raw payload buffer) instead of a decoded string.

currentState: RCONState

Read-only getter exposing the current connection state: "idle" | "connecting" | "ready" | "closing" | "closed".

isReady: boolean

Shorthand for currentState === "ready".

Events

RCON is an EventEmitter. The library never logs to the console, it emits these events instead:

  • socketError (err: Error): the socket failed. The connection is closed right after, failing any pending command.
  • unexpectedPacket (packet: Packet): a packet arrived that doesn't belong to the pending command (e.g. the extra packets of a split response when multiPacketResponses is off).
rcon.on("socketError", (err) => console.error("RCON socket error:", err.message));

Known limitations

  • No automatic reconnection. If the connection drops, currentState moves to closed and the caller is responsible for calling connect() again.
  • No per-command timeout. If a server accepts a command but never responds, the corresponding sendCommand call will hang indefinitely until disconnect() is called.
  • Multi-packet responses are only reassembled with multiPacketResponses: true. Without it, sendCommand resolves with the first packet and the rest are emitted as unexpectedPacket.