@hytaleone/query 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -2
- package/dist/index.cjs +415 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -1
- package/dist/index.d.ts +101 -1
- package/dist/index.js +409 -17
- package/dist/index.js.map +1 -1
- package/package.json +12 -4
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/query.ts","../src/protocol.ts"],"sourcesContent":["export { query } from './query.js';\nexport type {\n ServerInfo,\n ServerInfoFull,\n Player,\n Plugin,\n QueryOptions,\n} from './types.js';\n","import dgram from 'node:dgram';\nimport {\n buildRequest,\n parseBasicResponse,\n parseFullResponse,\n TYPE_BASIC,\n TYPE_FULL,\n} from './protocol.js';\nimport type { QueryOptions, ServerInfo, ServerInfoFull } from './types.js';\n\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * Send a UDP query and wait for response.\n */\nfunction sendQuery(\n host: string,\n port: number,\n type: number,\n timeout: number\n): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const socket = dgram.createSocket('udp4');\n let timeoutHandle: NodeJS.Timeout;\n let closed = false;\n\n const cleanup = () => {\n if (closed) return;\n closed = true;\n clearTimeout(timeoutHandle);\n try {\n socket.close();\n } catch {\n // Already closed\n }\n };\n\n socket.on('message', (msg) => {\n cleanup();\n resolve(msg);\n });\n\n socket.on('error', (err) => {\n cleanup();\n reject(err);\n });\n\n timeoutHandle = setTimeout(() => {\n cleanup();\n reject(new Error(`Query timeout after ${timeout}ms`));\n }, timeout);\n\n const request = buildRequest(type);\n socket.send(request, port, host, (err) => {\n if (err) {\n cleanup();\n reject(err);\n }\n });\n });\n}\n\n/**\n * Query a Hytale server for information.\n *\n * @param host - Server hostname or IP address\n * @param port - Server port (default: 5520)\n * @param options - Query options\n * @returns Server information (full if options.full is true)\n *\n * @example\n * ```typescript\n * // Basic query\n * const info = await query('play.example.com', 5520);\n * console.log(`${info.serverName}: ${info.currentPlayers}/${info.maxPlayers}`);\n *\n * // Full query (includes players + plugins)\n * const full = await query('play.example.com', 5520, { full: true });\n * console.log('Players:', full.players.map(p => p.name).join(', '));\n * ```\n */\nexport async function query(\n host: string,\n port?: number,\n options?: QueryOptions & { full?: false }\n): Promise<ServerInfo>;\nexport async function query(\n host: string,\n port: number,\n options: QueryOptions & { full: true }\n): Promise<ServerInfoFull>;\nexport async function query(\n host: string,\n port = 5520,\n options: QueryOptions & { full?: boolean } = {}\n): Promise<ServerInfo | ServerInfoFull> {\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n const type = options.full ? TYPE_FULL : TYPE_BASIC;\n const response = await sendQuery(host, port, type, timeout);\n\n if (options.full) {\n return parseFullResponse(response);\n }\n return parseBasicResponse(response);\n}\n","import type { Player, Plugin, ServerInfo, ServerInfoFull } from './types.js';\n\n// Protocol constants\nexport const REQUEST_MAGIC = Buffer.from('HYQUERY\\0', 'ascii');\nexport const RESPONSE_MAGIC = Buffer.from('HYREPLY\\0', 'ascii');\nexport const TYPE_BASIC = 0x00;\nexport const TYPE_FULL = 0x01;\n\n/**\n * Build a query request packet.\n */\nexport function buildRequest(type: number): Buffer {\n const buf = Buffer.alloc(REQUEST_MAGIC.length + 1);\n REQUEST_MAGIC.copy(buf, 0);\n buf[REQUEST_MAGIC.length] = type;\n return buf;\n}\n\n/**\n * Buffer reader helper for parsing responses.\n */\nclass BufferReader {\n private offset = 0;\n\n constructor(private buf: Buffer) {}\n\n readBytes(length: number): Buffer {\n const slice = this.buf.subarray(this.offset, this.offset + length);\n this.offset += length;\n return slice;\n }\n\n readUInt16LE(): number {\n const value = this.buf.readUInt16LE(this.offset);\n this.offset += 2;\n return value;\n }\n\n readInt32LE(): number {\n const value = this.buf.readInt32LE(this.offset);\n this.offset += 4;\n return value;\n }\n\n readBigInt64BE(): bigint {\n const value = this.buf.readBigInt64BE(this.offset);\n this.offset += 8;\n return value;\n }\n\n readBoolean(): boolean {\n return this.buf[this.offset++] !== 0;\n }\n\n readString(): string {\n const length = this.readUInt16LE();\n const bytes = this.readBytes(length);\n return bytes.toString('utf8');\n }\n\n readUUID(): string {\n const msb = this.readBigInt64BE();\n const lsb = this.readBigInt64BE();\n return formatUUID(msb, lsb);\n }\n\n get remaining(): number {\n return this.buf.length - this.offset;\n }\n}\n\n/**\n * Format UUID from most/least significant bits.\n */\nfunction formatUUID(msb: bigint, lsb: bigint): string {\n const toHex = (n: bigint): string => {\n if (n < 0n) {\n n = BigInt.asUintN(64, n);\n }\n return n.toString(16).padStart(16, '0');\n };\n\n const hex = toHex(msb) + toHex(lsb);\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Validate response magic bytes.\n */\nexport function validateResponse(buf: Buffer): boolean {\n if (buf.length < RESPONSE_MAGIC.length + 1) {\n return false;\n }\n return buf.subarray(0, RESPONSE_MAGIC.length).equals(RESPONSE_MAGIC);\n}\n\n/**\n * Parse a basic query response.\n */\nexport function parseBasicResponse(buf: Buffer): ServerInfo {\n if (!validateResponse(buf)) {\n throw new Error('Invalid response: magic mismatch');\n }\n\n const reader = new BufferReader(buf);\n\n // Skip magic\n reader.readBytes(RESPONSE_MAGIC.length);\n\n // Skip type\n reader.readBytes(1);\n\n return {\n serverName: reader.readString(),\n motd: reader.readString(),\n currentPlayers: reader.readInt32LE(),\n maxPlayers: reader.readInt32LE(),\n hostPort: reader.readUInt16LE(),\n version: reader.readString(),\n protocolVersion: reader.readInt32LE(),\n protocolHash: reader.readString(),\n };\n}\n\n/**\n * Parse a full query response.\n */\nexport function parseFullResponse(buf: Buffer): ServerInfoFull {\n if (!validateResponse(buf)) {\n throw new Error('Invalid response: magic mismatch');\n }\n\n const reader = new BufferReader(buf);\n\n // Skip magic\n reader.readBytes(RESPONSE_MAGIC.length);\n\n // Skip type\n reader.readBytes(1);\n\n // Base info\n const serverName = reader.readString();\n const motd = reader.readString();\n const currentPlayers = reader.readInt32LE();\n const maxPlayers = reader.readInt32LE();\n const hostPort = reader.readUInt16LE();\n const version = reader.readString();\n const protocolVersion = reader.readInt32LE();\n const protocolHash = reader.readString();\n\n // Player list\n const playerCount = reader.readInt32LE();\n const players: Player[] = [];\n for (let i = 0; i < playerCount; i++) {\n players.push({\n name: reader.readString(),\n uuid: reader.readUUID(),\n });\n }\n\n // Plugin list\n const pluginCount = reader.readInt32LE();\n const plugins: Plugin[] = [];\n for (let i = 0; i < pluginCount; i++) {\n plugins.push({\n id: reader.readString(),\n version: reader.readString(),\n enabled: reader.readBoolean(),\n });\n }\n\n return {\n serverName,\n motd,\n currentPlayers,\n maxPlayers,\n hostPort,\n version,\n protocolVersion,\n protocolHash,\n players,\n plugins,\n };\n}\n"],"mappings":"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","names":["dgram"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/query.ts","../src/protocol.ts","../src/query-v2.ts","../src/types-v2.ts","../src/protocol-v2.ts"],"sourcesContent":["export { query } from './query.js';\nexport { queryV2, clearChallengeCache } from './query-v2.js';\nexport type {\n ServerInfo,\n ServerInfoFull,\n Player,\n Plugin,\n QueryOptions,\n} from './types.js';\nexport type {\n ServerInfoV2,\n ServerInfoV2WithPlayers,\n QueryV2Options,\n} from './types-v2.js';\nexport { V2QueryType, V2ResponseFlag, V2TLVType } from './types-v2.js';\n","import dgram from 'node:dgram';\nimport {\n buildRequest,\n parseBasicResponse,\n parseFullResponse,\n TYPE_BASIC,\n TYPE_FULL,\n} from './protocol.js';\nimport type { QueryOptions, ServerInfo, ServerInfoFull } from './types.js';\n\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * Send a UDP query and wait for response.\n */\nfunction sendQuery(\n host: string,\n port: number,\n type: number,\n timeout: number\n): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const socket = dgram.createSocket('udp4');\n let timeoutHandle: NodeJS.Timeout;\n let closed = false;\n\n const cleanup = () => {\n if (closed) return;\n closed = true;\n clearTimeout(timeoutHandle);\n try {\n socket.close();\n } catch {\n // Already closed\n }\n };\n\n socket.on('message', (msg) => {\n cleanup();\n resolve(msg);\n });\n\n socket.on('error', (err) => {\n cleanup();\n reject(err);\n });\n\n timeoutHandle = setTimeout(() => {\n cleanup();\n reject(new Error(`Query timeout after ${timeout}ms`));\n }, timeout);\n\n const request = buildRequest(type);\n socket.send(request, port, host, (err) => {\n if (err) {\n cleanup();\n reject(err);\n }\n });\n });\n}\n\n/**\n * Query a Hytale server for information.\n *\n * @param host - Server hostname or IP address\n * @param port - Server port (default: 5520)\n * @param options - Query options\n * @returns Server information (full if options.full is true)\n *\n * @example\n * ```typescript\n * // Basic query\n * const info = await query('play.example.com', 5520);\n * console.log(`${info.serverName}: ${info.currentPlayers}/${info.maxPlayers}`);\n *\n * // Full query (includes players + plugins)\n * const full = await query('play.example.com', 5520, { full: true });\n * console.log('Players:', full.players.map(p => p.name).join(', '));\n * ```\n */\nexport async function query(\n host: string,\n port?: number,\n options?: QueryOptions & { full?: false }\n): Promise<ServerInfo>;\nexport async function query(\n host: string,\n port: number,\n options: QueryOptions & { full: true }\n): Promise<ServerInfoFull>;\nexport async function query(\n host: string,\n port = 5520,\n options: QueryOptions & { full?: boolean } = {}\n): Promise<ServerInfo | ServerInfoFull> {\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n const type = options.full ? TYPE_FULL : TYPE_BASIC;\n const response = await sendQuery(host, port, type, timeout);\n\n if (options.full) {\n return parseFullResponse(response);\n }\n return parseBasicResponse(response);\n}\n","import type { Player, Plugin, ServerInfo, ServerInfoFull } from './types.js';\n\n// Protocol constants\nexport const REQUEST_MAGIC = Buffer.from('HYQUERY\\0', 'ascii');\nexport const RESPONSE_MAGIC = Buffer.from('HYREPLY\\0', 'ascii');\nexport const TYPE_BASIC = 0x00;\nexport const TYPE_FULL = 0x01;\n\n// Capability flags (V1 extension)\nexport const CAP_V2_PROTOCOL = 0x01;\nexport const CAP_NETWORK_MODE = 0x02;\n\n/**\n * Build a query request packet.\n */\nexport function buildRequest(type: number): Buffer {\n const buf = Buffer.alloc(REQUEST_MAGIC.length + 1);\n REQUEST_MAGIC.copy(buf, 0);\n buf[REQUEST_MAGIC.length] = type;\n return buf;\n}\n\n/**\n * Buffer reader helper for parsing responses.\n */\nexport class BufferReader {\n private offset = 0;\n\n constructor(private buf: Buffer) {}\n\n private checkBounds(needed: number): void {\n if (this.offset + needed > this.buf.length) {\n throw new RangeError(\n `Buffer underflow: need ${needed} bytes at offset ${this.offset}, but buffer is ${this.buf.length} bytes`\n );\n }\n }\n\n readBytes(length: number): Buffer {\n this.checkBounds(length);\n const slice = this.buf.subarray(this.offset, this.offset + length);\n this.offset += length;\n return slice;\n }\n\n readUInt8(): number {\n this.checkBounds(1);\n return this.buf[this.offset++];\n }\n\n readUInt16LE(): number {\n this.checkBounds(2);\n const value = this.buf.readUInt16LE(this.offset);\n this.offset += 2;\n return value;\n }\n\n readUInt32LE(): number {\n this.checkBounds(4);\n const value = this.buf.readUInt32LE(this.offset);\n this.offset += 4;\n return value;\n }\n\n readInt32LE(): number {\n this.checkBounds(4);\n const value = this.buf.readInt32LE(this.offset);\n this.offset += 4;\n return value;\n }\n\n readBigInt64BE(): bigint {\n this.checkBounds(8);\n const value = this.buf.readBigInt64BE(this.offset);\n this.offset += 8;\n return value;\n }\n\n readBoolean(): boolean {\n this.checkBounds(1);\n return this.buf[this.offset++] !== 0;\n }\n\n readString(): string {\n const length = this.readUInt16LE();\n if (length > this.remaining) {\n throw new RangeError(\n `Invalid string length ${length} at offset ${this.offset - 2}, only ${this.remaining} bytes remaining`\n );\n }\n const bytes = this.readBytes(length);\n return bytes.toString('utf8');\n }\n\n readUUID(): string {\n const msb = this.readBigInt64BE();\n const lsb = this.readBigInt64BE();\n return formatUUID(msb, lsb);\n }\n\n readBigInt64LE(): bigint {\n this.checkBounds(8);\n const value = this.buf.readBigInt64LE(this.offset);\n this.offset += 8;\n return value;\n }\n\n readUUIDLE(): string {\n const msb = this.readBigInt64LE();\n const lsb = this.readBigInt64LE();\n return formatUUID(msb, lsb);\n }\n\n get remaining(): number {\n return this.buf.length - this.offset;\n }\n\n get position(): number {\n return this.offset;\n }\n}\n\n/**\n * Format UUID from most/least significant bits.\n */\nfunction formatUUID(msb: bigint, lsb: bigint): string {\n const toHex = (n: bigint): string => {\n if (n < 0n) {\n n = BigInt.asUintN(64, n);\n }\n return n.toString(16).padStart(16, '0');\n };\n\n const hex = toHex(msb) + toHex(lsb);\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Validate response magic bytes.\n */\nexport function validateResponse(buf: Buffer): boolean {\n if (buf.length < RESPONSE_MAGIC.length + 1) {\n return false;\n }\n return buf.subarray(0, RESPONSE_MAGIC.length).equals(RESPONSE_MAGIC);\n}\n\n/**\n * Parse capability extension from remaining bytes (3 bytes: 2 caps + 1 version).\n * Only parses if exactly 3 bytes remain to avoid misinterpreting other data.\n */\nfunction parseCapabilities(reader: BufferReader): {\n supportsV2: boolean;\n isNetworkMode: boolean;\n v2Version: number;\n} {\n if (reader.remaining === 3) {\n const caps = reader.readUInt16LE();\n const v2Version = reader.readUInt8();\n return {\n supportsV2: (caps & CAP_V2_PROTOCOL) !== 0,\n isNetworkMode: (caps & CAP_NETWORK_MODE) !== 0,\n v2Version,\n };\n }\n return { supportsV2: false, isNetworkMode: false, v2Version: 0 };\n}\n\n/**\n * Check if hostPort is encoded as int32 (legacy) vs uint16 (extended).\n * Returns true if int32, false if uint16.\n */\nfunction isLegacyPortFormat(buf: Buffer, offsetAfterMaxPlayers: number): boolean {\n const versionLenOffset = offsetAfterMaxPlayers + 2; // assuming uint16 port\n if (versionLenOffset + 2 > buf.length) return true;\n\n const versionLen = buf.readUInt16LE(versionLenOffset);\n // If version length is 0 or invalid, port is likely int32 (legacy format)\n return versionLen === 0 || versionLen > 500;\n}\n\n/**\n * Parse a basic query response.\n * Supports both extended format (uint16 port + protocolVersion/Hash) and legacy format (int32 port).\n */\nexport function parseBasicResponse(buf: Buffer): ServerInfo {\n if (!validateResponse(buf)) {\n throw new Error('Invalid response: magic mismatch');\n }\n\n const reader = new BufferReader(buf);\n\n // Skip magic + type\n reader.readBytes(RESPONSE_MAGIC.length + 1);\n\n const serverName = reader.readString();\n const motd = reader.readString();\n const currentPlayers = reader.readInt32LE();\n const maxPlayers = reader.readInt32LE();\n\n // Detect format: legacy uses int32 for port, extended uses uint16\n const legacy = isLegacyPortFormat(buf, reader.position);\n\n const hostPort = legacy ? reader.readInt32LE() : reader.readUInt16LE();\n const version = reader.readString();\n const protocolVersion = legacy ? 0 : reader.readInt32LE();\n const protocolHash = legacy ? '' : reader.readString();\n\n const capabilities = parseCapabilities(reader);\n\n return {\n serverName,\n motd,\n currentPlayers,\n maxPlayers,\n hostPort,\n version,\n protocolVersion,\n protocolHash,\n ...capabilities,\n };\n}\n\n/**\n * Parse a full query response.\n * Supports both extended and legacy formats.\n */\nexport function parseFullResponse(buf: Buffer): ServerInfoFull {\n if (!validateResponse(buf)) {\n throw new Error('Invalid response: magic mismatch');\n }\n\n const reader = new BufferReader(buf);\n\n // Skip magic + type\n reader.readBytes(RESPONSE_MAGIC.length + 1);\n\n const serverName = reader.readString();\n const motd = reader.readString();\n const currentPlayers = reader.readInt32LE();\n const maxPlayers = reader.readInt32LE();\n\n // Detect format\n const legacy = isLegacyPortFormat(buf, reader.position);\n\n const hostPort = legacy ? reader.readInt32LE() : reader.readUInt16LE();\n const version = reader.readString();\n const protocolVersion = legacy ? 0 : reader.readInt32LE();\n const protocolHash = legacy ? '' : reader.readString();\n\n // Player list\n const playerCount = reader.readInt32LE();\n const players: Player[] = [];\n for (let i = 0; i < playerCount; i++) {\n players.push({\n name: reader.readString(),\n uuid: reader.readUUID(),\n });\n }\n\n // Plugin list\n const pluginCount = reader.readInt32LE();\n const plugins: Plugin[] = [];\n for (let i = 0; i < pluginCount; i++) {\n plugins.push({\n id: reader.readString(),\n version: reader.readString(),\n enabled: reader.readBoolean(),\n });\n }\n\n const capabilities = parseCapabilities(reader);\n\n return {\n serverName,\n motd,\n currentPlayers,\n maxPlayers,\n hostPort,\n version,\n protocolVersion,\n protocolHash,\n players,\n plugins,\n ...capabilities,\n };\n}\n","import dgram from 'node:dgram';\nimport type { Player } from './types.js';\nimport type { QueryV2Options, ServerInfoV2, ServerInfoV2WithPlayers } from './types-v2.js';\nimport { V2QueryType, V2ResponseFlag, V2TLVType } from './types-v2.js';\nimport {\n buildChallengeRequest,\n buildV2Request,\n findTLVEntry,\n parseChallengeResponse,\n parseTLVPlayerList,\n parseTLVServerInfo,\n parseV2Response,\n} from './protocol-v2.js';\n\nconst DEFAULT_TIMEOUT = 5000;\n\n// Challenge token cache configuration\nconst TOKEN_TTL_MS = 30_000;\nconst TOKEN_REFRESH_BUFFER_MS = 5_000;\nconst CLEANUP_INTERVAL_MS = 60_000;\n\ninterface CachedChallenge {\n token: Buffer;\n expiresAt: number;\n requestId: number;\n}\n\n// Module-level cache\nconst challengeCache = new Map<string, CachedChallenge>();\nlet cleanupScheduled = false;\n\nfunction scheduleCleanup(): void {\n if (cleanupScheduled) return;\n cleanupScheduled = true;\n\n setTimeout(() => {\n const now = Date.now();\n for (const [key, entry] of challengeCache) {\n if (now >= entry.expiresAt) {\n challengeCache.delete(key);\n }\n }\n cleanupScheduled = false;\n if (challengeCache.size > 0) {\n scheduleCleanup();\n }\n }, CLEANUP_INTERVAL_MS).unref();\n}\n\n/**\n * Clear the challenge token cache.\n * Useful for testing or forcing fresh challenges.\n */\nexport function clearChallengeCache(): void {\n challengeCache.clear();\n}\n\n/**\n * Send a UDP packet and wait for response.\n */\nfunction sendUDP(host: string, port: number, data: Buffer, timeout: number): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const socket = dgram.createSocket('udp4');\n let timeoutHandle: NodeJS.Timeout;\n let closed = false;\n\n const cleanup = () => {\n if (closed) return;\n closed = true;\n clearTimeout(timeoutHandle);\n try {\n socket.close();\n } catch {\n // Already closed\n }\n };\n\n socket.on('message', (msg) => {\n cleanup();\n resolve(msg);\n });\n\n socket.on('error', (err) => {\n cleanup();\n reject(err);\n });\n\n timeoutHandle = setTimeout(() => {\n cleanup();\n reject(new Error(`Query timeout after ${timeout}ms`));\n }, timeout);\n\n socket.send(data, port, host, (err) => {\n if (err) {\n cleanup();\n reject(err);\n }\n });\n });\n}\n\n/**\n * Fetch a new challenge token from the server.\n */\nasync function fetchChallenge(host: string, port: number, timeout: number): Promise<Buffer> {\n const request = buildChallengeRequest();\n const response = await sendUDP(host, port, request, timeout);\n return parseChallengeResponse(response);\n}\n\n/**\n * Get or refresh a challenge token for a host:port.\n */\nasync function ensureChallenge(\n host: string,\n port: number,\n timeout: number\n): Promise<CachedChallenge> {\n const key = `${host}:${port}`;\n const cached = challengeCache.get(key);\n const now = Date.now();\n\n // Return cached if still valid (with buffer time)\n if (cached && now < cached.expiresAt - TOKEN_REFRESH_BUFFER_MS) {\n cached.requestId++;\n return cached;\n }\n\n // Fetch new challenge token\n const token = await fetchChallenge(host, port, timeout);\n const entry: CachedChallenge = {\n token,\n expiresAt: now + TOKEN_TTL_MS,\n requestId: 1,\n };\n\n challengeCache.set(key, entry);\n scheduleCleanup();\n\n return entry;\n}\n\n/**\n * Perform a V2 query request.\n */\nasync function performV2Query(\n host: string,\n port: number,\n type: number,\n offset: number,\n timeout: number,\n authToken?: string\n): Promise<{ header: ReturnType<typeof parseV2Response>['header']; entries: ReturnType<typeof parseV2Response>['entries'] }> {\n const challenge = await ensureChallenge(host, port, timeout);\n\n const request = buildV2Request(type, challenge.token, challenge.requestId, 0, offset, authToken);\n const response = await sendUDP(host, port, request, timeout);\n\n return parseV2Response(response);\n}\n\n/**\n * Query a Hytale server using V2 protocol (basic info only).\n */\nexport async function queryV2(\n host: string,\n port?: number,\n options?: QueryV2Options & { players?: false }\n): Promise<ServerInfoV2>;\n\n/**\n * Query a Hytale server using V2 protocol with player list.\n */\nexport async function queryV2(\n host: string,\n port: number,\n options: QueryV2Options & { players: true | 'all' }\n): Promise<ServerInfoV2WithPlayers>;\n\n/**\n * Query a Hytale server using V2 protocol.\n *\n * @param host - Server hostname or IP address\n * @param port - Server port (default: 5520)\n * @param options - Query options\n * @returns Server information (with players if requested)\n *\n * @example\n * ```typescript\n * // Basic V2 query\n * const info = await queryV2('play.example.com', 5520);\n * console.log(`${info.serverName}: ${info.currentPlayers}/${info.maxPlayers}`);\n *\n * // V2 query with players\n * const full = await queryV2('play.example.com', 5520, { players: true });\n * console.log('Players:', full.players.map(p => p.name).join(', '));\n *\n * // V2 query with all players (auto-pagination)\n * const all = await queryV2('play.example.com', 5520, { players: 'all' });\n * console.log(`All ${all.totalPlayers} players:`, all.players.map(p => p.name).join(', '));\n * ```\n */\nexport async function queryV2(\n host: string,\n port = 5520,\n options: QueryV2Options = {}\n): Promise<ServerInfoV2 | ServerInfoV2WithPlayers> {\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n const wantPlayers = options.players === true || options.players === 'all';\n const offset = options.playerOffset ?? 0;\n\n // First, always do a BASIC query to get server info\n const { header: basicHeader, entries: basicEntries } = await performV2Query(\n host,\n port,\n V2QueryType.BASIC,\n 0,\n timeout,\n options.authToken\n );\n\n const hasAddress = (basicHeader.flags & V2ResponseFlag.HAS_ADDRESS) !== 0;\n const isNetwork = (basicHeader.flags & V2ResponseFlag.IS_NETWORK) !== 0;\n\n // Parse server info\n const serverInfoEntry = findTLVEntry(basicEntries, V2TLVType.SERVER_INFO);\n if (!serverInfoEntry) {\n throw new Error('Response missing SERVER_INFO TLV');\n }\n const serverInfo = parseTLVServerInfo(serverInfoEntry, hasAddress, isNetwork);\n\n // If players not requested, return basic info\n if (!wantPlayers) {\n return serverInfo;\n }\n\n // Do a PLAYERS query to get player list\n const { header: playersHeader, entries: playersEntries } = await performV2Query(\n host,\n port,\n V2QueryType.PLAYERS,\n offset,\n timeout,\n options.authToken\n );\n\n const hasMorePlayers = (playersHeader.flags & V2ResponseFlag.HAS_MORE_PLAYERS) !== 0;\n\n // Parse player list\n const playerListEntry = findTLVEntry(playersEntries, V2TLVType.PLAYER_LIST);\n if (!playerListEntry) {\n throw new Error('Response missing PLAYER_LIST TLV');\n }\n const playerList = parseTLVPlayerList(playerListEntry);\n\n let players = playerList.players;\n let currentOffset = playerList.offset + players.length;\n let hasMore = hasMorePlayers;\n\n // If 'all' mode, paginate through remaining players\n if (options.players === 'all' && hasMore) {\n const allPlayers: Player[] = [...players];\n\n while (hasMore) {\n const nextResult = await performV2Query(\n host,\n port,\n V2QueryType.PLAYERS,\n currentOffset,\n timeout,\n options.authToken\n );\n\n const nextHasMore = (nextResult.header.flags & V2ResponseFlag.HAS_MORE_PLAYERS) !== 0;\n const nextPlayerEntry = findTLVEntry(nextResult.entries, V2TLVType.PLAYER_LIST);\n\n if (!nextPlayerEntry) {\n break;\n }\n\n const nextPlayerList = parseTLVPlayerList(nextPlayerEntry);\n allPlayers.push(...nextPlayerList.players);\n currentOffset = nextPlayerList.offset + nextPlayerList.players.length;\n hasMore = nextHasMore;\n }\n\n players = allPlayers;\n hasMore = false;\n }\n\n return {\n ...serverInfo,\n players,\n totalPlayers: playerList.totalPlayers,\n offset: playerList.offset,\n hasMore,\n };\n}\n","import type { Player } from './types.js';\n\n/**\n * V2 query type constants.\n */\nexport const V2QueryType = {\n CHALLENGE: 0x00,\n BASIC: 0x01,\n PLAYERS: 0x02,\n} as const;\n\n/**\n * V2 response flag constants.\n */\nexport const V2ResponseFlag = {\n HAS_MORE_PLAYERS: 0x0001,\n AUTH_REQUIRED: 0x0002,\n IS_NETWORK: 0x0010,\n HAS_ADDRESS: 0x0020,\n} as const;\n\n/**\n * V2 TLV type constants.\n */\nexport const V2TLVType = {\n SERVER_INFO: 0x0001,\n PLAYER_LIST: 0x0002,\n} as const;\n\n/**\n * Basic server information from V2 protocol.\n */\nexport interface ServerInfoV2 {\n /** Server display name */\n serverName: string;\n /** Message of the day */\n motd: string;\n /** Current number of players online */\n currentPlayers: number;\n /** Maximum player capacity */\n maxPlayers: number;\n /** Server version string */\n version: string;\n /** Protocol version number */\n protocolVersion: number;\n /** Protocol hash string */\n protocolHash: string;\n /** Server host (if FLAG_RESPONSE_HAS_ADDRESS) */\n host?: string;\n /** Server port (if FLAG_RESPONSE_HAS_ADDRESS) */\n hostPort?: number;\n /** Whether the server is in network aggregation mode */\n isNetwork: boolean;\n}\n\n/**\n * V2 server info combined with player list.\n */\nexport interface ServerInfoV2WithPlayers extends ServerInfoV2 {\n /** List of online players */\n players: Player[];\n /** Total players on server */\n totalPlayers: number;\n /** Offset used for this response */\n offset: number;\n /** Whether more players are available */\n hasMore: boolean;\n}\n\n/**\n * Options for V2 query function.\n */\nexport interface QueryV2Options {\n /** Timeout in milliseconds (default: 5000) */\n timeout?: number;\n /** Request player list: false=basic only, true=single page, 'all'=paginate all */\n players?: boolean | 'all';\n /** Starting offset for player pagination */\n playerOffset?: number;\n /** Optional auth token for private servers */\n authToken?: string;\n}\n","import type { Player } from './types.js';\nimport type { ServerInfoV2 } from './types-v2.js';\nimport { V2QueryType, V2ResponseFlag, V2TLVType } from './types-v2.js';\nimport { BufferReader } from './protocol.js';\n\n// Magic bytes for V2 protocol\nexport const V2_REQUEST_MAGIC = Buffer.from('ONEQUERY', 'ascii');\nexport const V2_RESPONSE_MAGIC = Buffer.from('ONEREPLY', 'ascii');\n\n// Challenge token size\nexport const CHALLENGE_TOKEN_SIZE = 32;\n\n/**\n * Build a challenge request packet.\n * Format: Magic (8) + Type (1)\n */\nexport function buildChallengeRequest(): Buffer {\n const buf = Buffer.alloc(V2_REQUEST_MAGIC.length + 1);\n V2_REQUEST_MAGIC.copy(buf, 0);\n buf[V2_REQUEST_MAGIC.length] = V2QueryType.CHALLENGE;\n return buf;\n}\n\n/**\n * Build a V2 request packet.\n * Format: Magic (8) + Type (1) + Token (32) + RequestID (4) + Flags (2) + Offset (4) + [AuthToken]\n */\nexport function buildV2Request(\n type: number,\n token: Buffer,\n requestId: number,\n flags: number,\n offset: number,\n authToken?: string\n): Buffer {\n const authBuf = authToken ? Buffer.from(authToken, 'utf8') : null;\n const authLength = authBuf ? 2 + authBuf.length : 0;\n const totalLength = V2_REQUEST_MAGIC.length + 1 + 32 + 4 + 2 + 4 + authLength;\n\n const buf = Buffer.alloc(totalLength);\n let pos = 0;\n\n // Magic\n V2_REQUEST_MAGIC.copy(buf, pos);\n pos += V2_REQUEST_MAGIC.length;\n\n // Type\n buf[pos++] = type;\n\n // Token\n token.copy(buf, pos);\n pos += 32;\n\n // Request ID (LE)\n buf.writeUInt32LE(requestId, pos);\n pos += 4;\n\n // Flags (LE)\n buf.writeUInt16LE(flags, pos);\n pos += 2;\n\n // Offset (LE)\n buf.writeUInt32LE(offset, pos);\n pos += 4;\n\n // Auth token (optional)\n if (authBuf) {\n buf.writeUInt16LE(authBuf.length, pos);\n pos += 2;\n authBuf.copy(buf, pos);\n }\n\n return buf;\n}\n\n/**\n * Parsed TLV entry.\n */\nexport interface TLVEntry {\n type: number;\n value: Buffer;\n}\n\n/**\n * Parsed V2 response header.\n */\nexport interface V2ResponseHeader {\n protocolVersion: number;\n flags: number;\n requestId: number;\n payloadLength: number;\n}\n\n/**\n * Validate V2 response magic bytes.\n */\nexport function validateV2Response(buf: Buffer): boolean {\n if (buf.length < V2_RESPONSE_MAGIC.length) {\n return false;\n }\n return buf.subarray(0, V2_RESPONSE_MAGIC.length).equals(V2_RESPONSE_MAGIC);\n}\n\n/**\n * Parse challenge response to extract 32-byte token.\n * Format: Magic (8) + Status (1) + Token (32) + [padding]\n */\nexport function parseChallengeResponse(buf: Buffer): Buffer {\n if (!validateV2Response(buf)) {\n throw new Error('Invalid V2 response: magic mismatch');\n }\n\n // Challenge response: Magic (8) + Status (1) + Token (32)\n const tokenOffset = V2_RESPONSE_MAGIC.length + 1; // Skip magic and status byte\n if (buf.length < tokenOffset + CHALLENGE_TOKEN_SIZE) {\n throw new Error('Invalid challenge response: too short');\n }\n\n return Buffer.from(buf.subarray(tokenOffset, tokenOffset + CHALLENGE_TOKEN_SIZE));\n}\n\n/**\n * Parse V2 response header.\n */\nexport function parseV2ResponseHeader(buf: Buffer): V2ResponseHeader {\n if (!validateV2Response(buf)) {\n throw new Error('Invalid V2 response: magic mismatch');\n }\n\n const reader = new BufferReader(buf);\n\n // Skip magic\n reader.readBytes(V2_RESPONSE_MAGIC.length);\n\n const protocolVersion = reader.readUInt8();\n const flags = reader.readUInt16LE();\n const requestId = reader.readUInt32LE();\n const payloadLength = reader.readUInt16LE();\n\n return { protocolVersion, flags, requestId, payloadLength };\n}\n\n/**\n * Parse TLV entries from payload.\n */\nexport function parseTLVEntries(payload: Buffer): TLVEntry[] {\n const entries: TLVEntry[] = [];\n const reader = new BufferReader(payload);\n\n while (reader.remaining >= 4) {\n const type = reader.readUInt16LE();\n const length = reader.readUInt16LE();\n\n if (reader.remaining < length) {\n throw new Error('Invalid TLV: truncated value');\n }\n\n const value = reader.readBytes(length);\n entries.push({ type, value });\n }\n\n return entries;\n}\n\n/**\n * Parse full V2 response (header + TLV payload).\n */\nexport function parseV2Response(buf: Buffer): { header: V2ResponseHeader; entries: TLVEntry[] } {\n const header = parseV2ResponseHeader(buf);\n\n // Header is 17 bytes: Magic (8) + Version (1) + Flags (2) + RequestID (4) + PayloadLength (2)\n const headerSize = V2_RESPONSE_MAGIC.length + 1 + 2 + 4 + 2;\n const payload = buf.subarray(headerSize, headerSize + header.payloadLength);\n\n const entries = parseTLVEntries(payload);\n\n return { header, entries };\n}\n\n/**\n * Parse SERVER_INFO TLV into ServerInfoV2.\n * Note: isNetwork is determined from response flags, not from the TLV data.\n */\nexport function parseTLVServerInfo(entry: TLVEntry, hasAddress: boolean, isNetwork: boolean): ServerInfoV2 {\n if (entry.type !== V2TLVType.SERVER_INFO) {\n throw new Error(`Expected SERVER_INFO TLV (${V2TLVType.SERVER_INFO}), got ${entry.type}`);\n }\n\n const reader = new BufferReader(entry.value);\n\n const serverName = reader.readString();\n const motd = reader.readString();\n const currentPlayers = reader.readInt32LE();\n const maxPlayers = reader.readInt32LE();\n const version = reader.readString();\n const protocolVersion = reader.readInt32LE();\n const protocolHash = reader.readString();\n\n const result: ServerInfoV2 = {\n serverName,\n motd,\n currentPlayers,\n maxPlayers,\n version,\n protocolVersion,\n protocolHash,\n isNetwork,\n };\n\n if (hasAddress && reader.remaining >= 2) {\n result.host = reader.readString();\n if (reader.remaining >= 2) {\n result.hostPort = reader.readUInt16LE();\n }\n }\n\n return result;\n}\n\n/**\n * Parsed player list from TLV.\n */\nexport interface ParsedPlayerList {\n players: Player[];\n totalPlayers: number;\n offset: number;\n}\n\n/**\n * Parse PLAYER_LIST TLV.\n * Format: totalPlayers (4) + playersInResponse (4) + offset (4) + player entries\n */\nexport function parseTLVPlayerList(entry: TLVEntry): ParsedPlayerList {\n if (entry.type !== V2TLVType.PLAYER_LIST) {\n throw new Error(`Expected PLAYER_LIST TLV (${V2TLVType.PLAYER_LIST}), got ${entry.type}`);\n }\n\n const reader = new BufferReader(entry.value);\n\n const totalPlayers = reader.readInt32LE();\n const playersInResponse = reader.readInt32LE();\n const offset = reader.readInt32LE();\n\n const players: Player[] = [];\n for (let i = 0; i < playersInResponse; i++) {\n const name = reader.readString();\n const uuid = reader.readUUIDLE(); // UUIDs are little-endian in V2\n players.push({ name, uuid });\n }\n\n return { players, totalPlayers, offset };\n}\n\n/**\n * Find a TLV entry by type.\n */\nexport function findTLVEntry(entries: TLVEntry[], type: number): TLVEntry | undefined {\n return entries.find((e) => e.type === type);\n}\n"],"mappings":"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","names":["dgram","import_node_dgram","DEFAULT_TIMEOUT","dgram"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -18,6 +18,12 @@ interface ServerInfo {
|
|
|
18
18
|
protocolVersion: number;
|
|
19
19
|
/** Protocol hash string */
|
|
20
20
|
protocolHash: string;
|
|
21
|
+
/** Whether the server supports V2 protocol */
|
|
22
|
+
supportsV2: boolean;
|
|
23
|
+
/** Whether the server is in network aggregation mode */
|
|
24
|
+
isNetworkMode: boolean;
|
|
25
|
+
/** V2 protocol version (0 if not supported) */
|
|
26
|
+
v2Version: number;
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
29
|
* Player information included in full query response.
|
|
@@ -84,4 +90,98 @@ declare function query(host: string, port: number, options: QueryOptions & {
|
|
|
84
90
|
full: true;
|
|
85
91
|
}): Promise<ServerInfoFull>;
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
/**
|
|
94
|
+
* V2 query type constants.
|
|
95
|
+
*/
|
|
96
|
+
declare const V2QueryType: {
|
|
97
|
+
readonly CHALLENGE: 0;
|
|
98
|
+
readonly BASIC: 1;
|
|
99
|
+
readonly PLAYERS: 2;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* V2 response flag constants.
|
|
103
|
+
*/
|
|
104
|
+
declare const V2ResponseFlag: {
|
|
105
|
+
readonly HAS_MORE_PLAYERS: 1;
|
|
106
|
+
readonly AUTH_REQUIRED: 2;
|
|
107
|
+
readonly IS_NETWORK: 16;
|
|
108
|
+
readonly HAS_ADDRESS: 32;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* V2 TLV type constants.
|
|
112
|
+
*/
|
|
113
|
+
declare const V2TLVType: {
|
|
114
|
+
readonly SERVER_INFO: 1;
|
|
115
|
+
readonly PLAYER_LIST: 2;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Basic server information from V2 protocol.
|
|
119
|
+
*/
|
|
120
|
+
interface ServerInfoV2 {
|
|
121
|
+
/** Server display name */
|
|
122
|
+
serverName: string;
|
|
123
|
+
/** Message of the day */
|
|
124
|
+
motd: string;
|
|
125
|
+
/** Current number of players online */
|
|
126
|
+
currentPlayers: number;
|
|
127
|
+
/** Maximum player capacity */
|
|
128
|
+
maxPlayers: number;
|
|
129
|
+
/** Server version string */
|
|
130
|
+
version: string;
|
|
131
|
+
/** Protocol version number */
|
|
132
|
+
protocolVersion: number;
|
|
133
|
+
/** Protocol hash string */
|
|
134
|
+
protocolHash: string;
|
|
135
|
+
/** Server host (if FLAG_RESPONSE_HAS_ADDRESS) */
|
|
136
|
+
host?: string;
|
|
137
|
+
/** Server port (if FLAG_RESPONSE_HAS_ADDRESS) */
|
|
138
|
+
hostPort?: number;
|
|
139
|
+
/** Whether the server is in network aggregation mode */
|
|
140
|
+
isNetwork: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* V2 server info combined with player list.
|
|
144
|
+
*/
|
|
145
|
+
interface ServerInfoV2WithPlayers extends ServerInfoV2 {
|
|
146
|
+
/** List of online players */
|
|
147
|
+
players: Player[];
|
|
148
|
+
/** Total players on server */
|
|
149
|
+
totalPlayers: number;
|
|
150
|
+
/** Offset used for this response */
|
|
151
|
+
offset: number;
|
|
152
|
+
/** Whether more players are available */
|
|
153
|
+
hasMore: boolean;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Options for V2 query function.
|
|
157
|
+
*/
|
|
158
|
+
interface QueryV2Options {
|
|
159
|
+
/** Timeout in milliseconds (default: 5000) */
|
|
160
|
+
timeout?: number;
|
|
161
|
+
/** Request player list: false=basic only, true=single page, 'all'=paginate all */
|
|
162
|
+
players?: boolean | 'all';
|
|
163
|
+
/** Starting offset for player pagination */
|
|
164
|
+
playerOffset?: number;
|
|
165
|
+
/** Optional auth token for private servers */
|
|
166
|
+
authToken?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Clear the challenge token cache.
|
|
171
|
+
* Useful for testing or forcing fresh challenges.
|
|
172
|
+
*/
|
|
173
|
+
declare function clearChallengeCache(): void;
|
|
174
|
+
/**
|
|
175
|
+
* Query a Hytale server using V2 protocol (basic info only).
|
|
176
|
+
*/
|
|
177
|
+
declare function queryV2(host: string, port?: number, options?: QueryV2Options & {
|
|
178
|
+
players?: false;
|
|
179
|
+
}): Promise<ServerInfoV2>;
|
|
180
|
+
/**
|
|
181
|
+
* Query a Hytale server using V2 protocol with player list.
|
|
182
|
+
*/
|
|
183
|
+
declare function queryV2(host: string, port: number, options: QueryV2Options & {
|
|
184
|
+
players: true | 'all';
|
|
185
|
+
}): Promise<ServerInfoV2WithPlayers>;
|
|
186
|
+
|
|
187
|
+
export { type Player, type Plugin, type QueryOptions, type QueryV2Options, type ServerInfo, type ServerInfoFull, type ServerInfoV2, type ServerInfoV2WithPlayers, V2QueryType, V2ResponseFlag, V2TLVType, clearChallengeCache, query, queryV2 };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ interface ServerInfo {
|
|
|
18
18
|
protocolVersion: number;
|
|
19
19
|
/** Protocol hash string */
|
|
20
20
|
protocolHash: string;
|
|
21
|
+
/** Whether the server supports V2 protocol */
|
|
22
|
+
supportsV2: boolean;
|
|
23
|
+
/** Whether the server is in network aggregation mode */
|
|
24
|
+
isNetworkMode: boolean;
|
|
25
|
+
/** V2 protocol version (0 if not supported) */
|
|
26
|
+
v2Version: number;
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
29
|
* Player information included in full query response.
|
|
@@ -84,4 +90,98 @@ declare function query(host: string, port: number, options: QueryOptions & {
|
|
|
84
90
|
full: true;
|
|
85
91
|
}): Promise<ServerInfoFull>;
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
/**
|
|
94
|
+
* V2 query type constants.
|
|
95
|
+
*/
|
|
96
|
+
declare const V2QueryType: {
|
|
97
|
+
readonly CHALLENGE: 0;
|
|
98
|
+
readonly BASIC: 1;
|
|
99
|
+
readonly PLAYERS: 2;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* V2 response flag constants.
|
|
103
|
+
*/
|
|
104
|
+
declare const V2ResponseFlag: {
|
|
105
|
+
readonly HAS_MORE_PLAYERS: 1;
|
|
106
|
+
readonly AUTH_REQUIRED: 2;
|
|
107
|
+
readonly IS_NETWORK: 16;
|
|
108
|
+
readonly HAS_ADDRESS: 32;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* V2 TLV type constants.
|
|
112
|
+
*/
|
|
113
|
+
declare const V2TLVType: {
|
|
114
|
+
readonly SERVER_INFO: 1;
|
|
115
|
+
readonly PLAYER_LIST: 2;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Basic server information from V2 protocol.
|
|
119
|
+
*/
|
|
120
|
+
interface ServerInfoV2 {
|
|
121
|
+
/** Server display name */
|
|
122
|
+
serverName: string;
|
|
123
|
+
/** Message of the day */
|
|
124
|
+
motd: string;
|
|
125
|
+
/** Current number of players online */
|
|
126
|
+
currentPlayers: number;
|
|
127
|
+
/** Maximum player capacity */
|
|
128
|
+
maxPlayers: number;
|
|
129
|
+
/** Server version string */
|
|
130
|
+
version: string;
|
|
131
|
+
/** Protocol version number */
|
|
132
|
+
protocolVersion: number;
|
|
133
|
+
/** Protocol hash string */
|
|
134
|
+
protocolHash: string;
|
|
135
|
+
/** Server host (if FLAG_RESPONSE_HAS_ADDRESS) */
|
|
136
|
+
host?: string;
|
|
137
|
+
/** Server port (if FLAG_RESPONSE_HAS_ADDRESS) */
|
|
138
|
+
hostPort?: number;
|
|
139
|
+
/** Whether the server is in network aggregation mode */
|
|
140
|
+
isNetwork: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* V2 server info combined with player list.
|
|
144
|
+
*/
|
|
145
|
+
interface ServerInfoV2WithPlayers extends ServerInfoV2 {
|
|
146
|
+
/** List of online players */
|
|
147
|
+
players: Player[];
|
|
148
|
+
/** Total players on server */
|
|
149
|
+
totalPlayers: number;
|
|
150
|
+
/** Offset used for this response */
|
|
151
|
+
offset: number;
|
|
152
|
+
/** Whether more players are available */
|
|
153
|
+
hasMore: boolean;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Options for V2 query function.
|
|
157
|
+
*/
|
|
158
|
+
interface QueryV2Options {
|
|
159
|
+
/** Timeout in milliseconds (default: 5000) */
|
|
160
|
+
timeout?: number;
|
|
161
|
+
/** Request player list: false=basic only, true=single page, 'all'=paginate all */
|
|
162
|
+
players?: boolean | 'all';
|
|
163
|
+
/** Starting offset for player pagination */
|
|
164
|
+
playerOffset?: number;
|
|
165
|
+
/** Optional auth token for private servers */
|
|
166
|
+
authToken?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Clear the challenge token cache.
|
|
171
|
+
* Useful for testing or forcing fresh challenges.
|
|
172
|
+
*/
|
|
173
|
+
declare function clearChallengeCache(): void;
|
|
174
|
+
/**
|
|
175
|
+
* Query a Hytale server using V2 protocol (basic info only).
|
|
176
|
+
*/
|
|
177
|
+
declare function queryV2(host: string, port?: number, options?: QueryV2Options & {
|
|
178
|
+
players?: false;
|
|
179
|
+
}): Promise<ServerInfoV2>;
|
|
180
|
+
/**
|
|
181
|
+
* Query a Hytale server using V2 protocol with player list.
|
|
182
|
+
*/
|
|
183
|
+
declare function queryV2(host: string, port: number, options: QueryV2Options & {
|
|
184
|
+
players: true | 'all';
|
|
185
|
+
}): Promise<ServerInfoV2WithPlayers>;
|
|
186
|
+
|
|
187
|
+
export { type Player, type Plugin, type QueryOptions, type QueryV2Options, type ServerInfo, type ServerInfoFull, type ServerInfoV2, type ServerInfoV2WithPlayers, V2QueryType, V2ResponseFlag, V2TLVType, clearChallengeCache, query, queryV2 };
|