Modern Source Engine A2S query client for Node.js and Bun. Zero runtime dependencies, fully typed.
Supports A2S_INFO, A2S_PLAYER, and A2S_RULES queries against any Source Engine server (Garry's Mod, CS:GO, CS2, TF2, etc).
npm install @callowayisweird/source-queryimport { SourceQuery } from "@callowayisweird/source-query";
// Static one-shot queries
const info = await SourceQuery.info("play.example.com", 27015);
console.log(`${info.name} - ${info.players}/${info.maxPlayers} on ${info.map}`);
const players = await SourceQuery.players("play.example.com", 27015);
for (const p of players) {
console.log(`${p.name}: ${p.score} pts (${Math.round(p.duration)}s)`);
}
const rules = await SourceQuery.rules("play.example.com", 27015);
console.log(rules);import { SourceQuery } from "@callowayisweird/source-query";
const query = new SourceQuery({
host: "play.example.com",
port: 27015,
timeout: 5000,
});
const info = await query.info();
const players = await query.players();
const rules = await query.rules();
query.close();Query multiple servers concurrently with a configurable concurrency limit:
import { SourceQuery } from "@callowayisweird/source-query";
const results = await SourceQuery.batch(
[
{ host: "server1.example.com", port: 27015 },
{ host: "server2.example.com", port: 27015 },
{ host: "server3.example.com", port: 27015 },
],
{ timeout: 5000, concurrency: 5 },
);
for (const result of results) {
if (result.error) {
console.error(`${result.host}:${result.port} failed: ${result.error.message}`);
} else {
console.log(`${result.host}:${result.port} - ${result.info!.name}`);
}
}import {
SourceQuery,
TimeoutError,
InvalidResponseError,
ChallengeError,
} from "@callowayisweird/source-query";
try {
const info = await SourceQuery.info("play.example.com", 27015);
} catch (err) {
if (err instanceof TimeoutError) {
console.error("Server did not respond");
} else if (err instanceof InvalidResponseError) {
console.error("Malformed packet:", err.raw);
} else if (err instanceof ChallengeError) {
console.error("Challenge handshake failed");
}
}All types are exported for direct use:
import type {
QueryOptions,
ServerInfo,
Player,
Rules,
BatchResult,
BatchOptions,
} from "@callowayisweird/source-query";MIT