{"version":3,"file":"index.mjs","names":[],"sources":["../src/dnsSrv.mts","../src/minecraftPackets.mts","../src/PacketDecoder.mts","../src/index.mts"],"sourcesContent":["import {Err, type IResult, Ok} from '@luolapeikko/result-option';\nimport {resolveSrv, type SrvRecord} from 'dns';\n\nfunction assertAtLeastOne<T>(data: T[]): asserts data is [T, ...T[]] {\n\tif (data.length === 0) {\n\t\tthrow new Error('Expected at least one element, got none');\n\t}\n}\n\n/**\n * Resolves the SRV records for the given service name.\n * @param {string} srv The service name to resolve.\n * @returns {Promise<Result<SrvRecord[]>>} A promise of Result that resolves to an array of SRV records.\n * @example\n * const res = await srvRecordsResult('_minecraft._tcp.example.com');\n * if (res.isOk) {\n *   console.log(res.ok()); // [ { name: 'example.com', port: 25565, priority: 0, weight: 5 } ]\n * } else {\n *   console.error(res.err());\n * }\n */\nexport function srvRecordsResult(srv: string): Promise<IResult<[SrvRecord, ...SrvRecord[]], NodeJS.ErrnoException>> {\n\treturn new Promise((resolve) => {\n\t\tresolveSrv(srv, (error, result) => {\n\t\t\tif (error) {\n\t\t\t\tresolve(Err(error));\n\t\t\t} else {\n\t\t\t\tassertAtLeastOne(result); // This is safe because resolveSrv will always return at least one element\n\t\t\t\tresolve(Ok(result));\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Resolves the first SRV record for the given service name.\n * @param {string} srv The service name to resolve.\n * @returns {Promise<Result<SrvRecord>>} A promise of Result that resolves to the first SRV record, or Err if no records were found.\n * @example\n * const res = await srvRecordResult('_minecraft._tcp.example.com');\n * if (res.isOk) {\n *   console.log(res.ok()); // { name: 'example.com', port: 25565, priority: 0, weight: 5 }\n * } else {\n *   console.error(res.err());\n * }\n */\nexport async function srvRecordResult(srv: string): Promise<IResult<SrvRecord, NodeJS.ErrnoException>> {\n\tconst res = await srvRecordsResult(srv);\n\tif (res.isOk) {\n\t\treturn Ok(res.ok()[0]);\n\t} else {\n\t\treturn Err(res.err());\n\t}\n}\n","import varInt from 'varint';\nimport type {IAddress} from './interfaces.mjs';\n\nconst PROTOCOL_VERSION = 736; // Minecraft 1.16.1\n\nexport enum MinecraftPackageType {\n\tHANDSHAKE = 0,\n\tPING = 1,\n}\n\n/**\n * Wrapper for creating Minecraft packets\n * @param {MinecraftPackageType} packetId - packet id\n * @param {Buffer} data - packet data\n * @returns {Buffer} packet buffer data\n */\nfunction createPacket(packetId: MinecraftPackageType, data: Buffer): Buffer {\n\treturn Buffer.concat([Buffer.from(varInt.encode(varInt.encodingLength(packetId) + data.length)), Buffer.from(varInt.encode(packetId)), data]);\n}\n\n/**\n * Create Minecraft handshake packet\n * @param {IAddress} address\n * @returns {Buffer} handshake packet buffer data\n */\nexport function createHandshakePacket(address: IAddress): Buffer {\n\tconst portBuffer = Buffer.allocUnsafe(2);\n\tportBuffer.writeUInt16BE(address.port, 0);\n\t// Return handshake packet with request packet\n\treturn Buffer.concat([\n\t\tcreatePacket(\n\t\t\tMinecraftPackageType.HANDSHAKE,\n\t\t\tBuffer.concat([\n\t\t\t\tBuffer.from(varInt.encode(PROTOCOL_VERSION)),\n\t\t\t\tBuffer.from(varInt.encode(address.hostname.length)),\n\t\t\t\tBuffer.from(address.hostname, 'utf8'),\n\t\t\t\tportBuffer,\n\t\t\t\tBuffer.from(varInt.encode(1)),\n\t\t\t]),\n\t\t),\n\t\tcreatePacket(0, Buffer.alloc(0)),\n\t]);\n}\n\n/**\n * Create ping packet\n * @param {bigint} timestamp\n * @returns {Buffer} ping packet buffer data\n */\nexport function createPingPacket(timestamp: bigint): Buffer {\n\tconst pingBuffer = Buffer.allocUnsafe(8);\n\tpingBuffer.writeBigUInt64BE(timestamp);\n\treturn createPacket(MinecraftPackageType.PING, pingBuffer);\n}\n","import {Writable, type WritableOptions} from 'stream';\nimport varInt from 'varint';\nimport {MinecraftPackageType} from './minecraftPackets.mjs';\n\nexport interface IPacketHeader {\n\tid: MinecraftPackageType;\n\tlength: number;\n\toffset: number;\n}\n\nexport class PacketDecoder extends Writable {\n\tprivate packetInfo: IPacketHeader | undefined;\n\tprivate buffer: Buffer;\n\n\tpublic constructor(options?: WritableOptions) {\n\t\tsuper(options);\n\t\tthis.buffer = Buffer.alloc(0);\n\t}\n\n\t/**\n\t * Promise to wait specific packet to be received\n\t */\n\tpublic oncePromise<T>(event: string): Promise<T> {\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.once(event, resolve);\n\t\t});\n\t}\n\n\tpublic _write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {\n\t\tif (!this.packetInfo) {\n\t\t\tthis.packetInfo = this.decodeHeader(chunk);\n\t\t}\n\t\tthis.buffer = Buffer.concat([this.buffer, chunk]);\n\n\t\tif (this.buffer.length < this.packetInfo.length) {\n\t\t\t// do we still need to read more?\n\t\t\t// biome-ignore lint/correctness/noVoidTypeReturn: else have issues\n\t\t\treturn callback();\n\t\t}\n\t\tif (this.buffer.length > this.packetInfo.length) {\n\t\t\t// biome-ignore lint/correctness/noVoidTypeReturn: else have issues\n\t\t\treturn callback(new Error('we did overrun expected data size!'));\n\t\t}\n\n\t\ttry {\n\t\t\tswitch (this.packetInfo.id) {\n\t\t\t\tcase MinecraftPackageType.HANDSHAKE: {\n\t\t\t\t\tthis.emit('handshake', this.decodeHandshake(this.getPayload(this.packetInfo, this.buffer)));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase MinecraftPackageType.PING: {\n\t\t\t\t\tthis.emit('pong', this.decodePong(this.getPayload(this.packetInfo, this.buffer)));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n\t\t\t\t\tthis.emit('error', new Error(`Unknown packet id: ${this.packetInfo.id}`));\n\t\t\t}\n\n\t\t\tthis.buffer = Buffer.alloc(0);\n\t\t\tthis.packetInfo = undefined;\n\t\t} catch (err) {\n\t\t\tthis.emit('error', err);\n\t\t}\n\t\tcallback();\n\t}\n\n\tprivate decodeHeader(buffer: Buffer): IPacketHeader {\n\t\tconst length = varInt.decode(buffer);\n\t\treturn {\n\t\t\tid: buffer.readUInt8(varInt.encodingLength(length)),\n\t\t\tlength: length + varInt.encodingLength(length),\n\t\t\toffset: varInt.encodingLength(length) + 1,\n\t\t};\n\t}\n\n\tprivate getPayload(header: IPacketHeader, data: Buffer) {\n\t\treturn data.subarray(header.offset, data.length);\n\t}\n\n\t/**\n\t * Decodes the handshake JSON data\n\t */\n\tprivate decodeHandshake(buffer: Buffer): Record<string, unknown> {\n\t\tconst length = varInt.decode(buffer);\n\t\tconst data = buffer.subarray(varInt.encodingLength(length), varInt.encodingLength(length) + length);\n\t\treturn JSON.parse(data.toString());\n\t}\n\n\t/**\n\t * Decodes the pong data\n\t */\n\tprivate decodePong(data: Buffer): number {\n\t\tconst pongData = data.readBigUInt64BE(0);\n\t\treturn Number(BigInt(Date.now()) - pongData);\n\t}\n}\n","import type {ILoggerLike} from '@luolapeikko/logger-type';\nimport {Err, type IResult, Ok} from '@luolapeikko/result-option';\nimport {createConnection, isIP, type Socket} from 'net';\nimport {srvRecordResult} from './dnsSrv.mjs';\nimport type {IAddress, IHandshakeData, IMinecraftData} from './interfaces.mjs';\nimport {createHandshakePacket, createPingPacket} from './minecraftPackets.mjs';\nimport {PacketDecoder} from './PacketDecoder.mjs';\n\nexport * from './dnsSrv.mjs';\nexport * from './interfaces.mjs';\nexport * from './minecraftPackets.mjs';\nexport * from './PacketDecoder.mjs';\n\nconst defaultAddress: IAddress = {\n\thostname: 'localhost',\n\tport: 25565,\n};\n\n/**\n * Type to get value directly, from promise or from function\n * @template T type of value\n */\nexport type Loadable<T> = T | Promise<T> | (() => T | Promise<T>);\n\n/**\n * Build Loadable Address type\n */\nexport type LoadableAddress = Loadable<Partial<IAddress>>;\n\n/**\n * Build Loadable URL type\n */\nexport type LoadableUrl = Loadable<URL | string>;\n\n/**\n * Ensure that we have Error object\n */\nfunction ensureError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\tif (typeof error === 'string') {\n\t\treturn new Error(error);\n\t}\n\treturn new Error(`unknown error: ${JSON.stringify(error)}`);\n}\n\n/**\n * Options for ping\n * @interface Options\n * @property {number=} timeout timeout in milliseconds\n */\nexport interface CommonOptions {\n\t/** connection timeout in milliseconds, default is 10000 */\n\ttimeout?: number;\n\tlogger?: ILoggerLike;\n}\n\n/**\n * Check SRV record and return hostname and port (IAddress)\n * @param {string} hostname\n * @returns {Promise<IAddress | undefined>} Promise that resolves to IAddress or undefined\n */\nasync function checkSrvRecord(hostname: string, options: CommonOptions): Promise<IAddress | undefined> {\n\t// if hostname is IP, return undefined\n\tif (isIP(hostname) !== 0) {\n\t\toptions.logger?.debug(`checkSrvRecord: ${hostname} is IP, returning undefined`);\n\t\treturn undefined;\n\t}\n\tconst dnsResult = await srvRecordResult(`_minecraft._tcp.${hostname}`);\n\tif (dnsResult.isErr) {\n\t\toptions.logger?.debug(`checkSrvRecord: ${hostname} has no SRV record, returning undefined`);\n\t\treturn undefined;\n\t}\n\tconst {name, port} = dnsResult.ok();\n\treturn {\n\t\thostname: name,\n\t\tport,\n\t};\n}\n\nfunction urlToAddress(uri: URL | string, options: CommonOptions): Partial<IAddress> {\n\tconst address: Partial<IAddress> = {};\n\tconst {protocol, hostname, port} = typeof uri === 'string' ? new URL(uri) : uri;\n\tif (!hostname || !protocol || protocol !== 'minecraft:') {\n\t\tthrow new TypeError('not correct minecraft URI');\n\t}\n\tconst realPort = port ? parseInt(port, 10) : undefined;\n\tif (realPort && Number.isNaN(realPort)) {\n\t\tthrow new TypeError('not correct minecraft URI');\n\t}\n\tif (hostname) {\n\t\taddress.hostname = hostname;\n\t}\n\tif (realPort) {\n\t\taddress.port = realPort;\n\t}\n\toptions.logger?.debug(`urlToAddress: ${uri.toString()} => ${JSON.stringify(address)}`);\n\treturn address;\n}\n\n/**\n * ping with URI\n * @param {LoadableUrl} uriArg minecraft://server[:port]\n * @param {CommonOptions=} options options\n * @return {Promise<IMinecraftData>}\n */\nexport async function pingUri(uriArg: LoadableUrl, options: CommonOptions = {}): Promise<IMinecraftData> {\n\tconst uri = await (typeof uriArg === 'function' ? uriArg() : uriArg);\n\treturn ping(urlToAddress(uri, options), options);\n}\n\n/**\n * ping with URI, return result object\n * @param {LoadableUrl} uriArg minecraft://server[:port]\n * @param {CommonOptions=} options options\n * @return {Promise<Result<IMinecraftData, Error>>}\n */\nexport async function pingUriResult(uriArg: LoadableUrl, options: CommonOptions = {}): Promise<IResult<IMinecraftData, Error>> {\n\ttry {\n\t\treturn Ok(await pingUri(uriArg, options));\n\t} catch (err) {\n\t\treturn Err(ensureError(err));\n\t}\n}\n\n/**\n * ping with hostname and port\n * @param {LoadableAddress=} addressArg address object (defaults {hostname: 'localhost', port: 25565})\n * @param {CommonOptions=} options options\n * @returns {Promise<IMinecraftData>}\n */\nexport async function ping(addressArg?: LoadableAddress, options: CommonOptions = {}): Promise<IMinecraftData> {\n\tlet address: IAddress = Object.assign({}, defaultAddress, await (typeof addressArg === 'function' ? addressArg() : addressArg));\n\tif (address.hostname !== 'localhost') {\n\t\tconst dnsAddress = await checkSrvRecord(address.hostname, options);\n\t\tif (dnsAddress) {\n\t\t\taddress = dnsAddress;\n\t\t}\n\t}\n\toptions.logger?.info(`ping: ${address.hostname}:${address.port.toString()}`);\n\treturn openConnection(address, options);\n}\n\n/**\n * ping with hostname and port, return result object\n * @param {LoadableAddress=} addressArg address object (defaults {hostname: 'localhost', port: 25565})\n * @param {CommonOptions=} options options\n * @returns {Promise<Result<IMinecraftData>>}\n */\nexport async function pingResult(addressArg?: LoadableAddress, options: CommonOptions = {}): Promise<IResult<IMinecraftData, Error>> {\n\ttry {\n\t\treturn Ok(await ping(addressArg, options));\n\t} catch (err) {\n\t\treturn Err(ensureError(err));\n\t}\n}\n\nfunction openConnection(address: IAddress, options: CommonOptions): Promise<IMinecraftData> {\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\treturn new Promise((resolve, reject) => {\n\t\tconst handleError = (error: Error, thisSocket: Socket) => {\n\t\t\tthisSocket.destroy();\n\t\t\tif (timeout) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\t\t\toptions.logger?.error(`openConnection: error: ${error.message}`);\n\t\t\treject(error);\n\t\t};\n\t\tconst socket = createConnection(address.port, address.hostname, async () => {\n\t\t\toptions.logger?.debug(`openConnection: connected to ${address.hostname}:${address.port.toString()}`);\n\t\t\tconst packetDecoder = new PacketDecoder();\n\t\t\tsocket.pipe(packetDecoder); // attach decoder\n\t\t\tpacketDecoder.once('error', (error) => handleError(error, socket));\n\t\t\t// send handshake\n\t\t\toptions.logger?.debug(`openConnection: => sending handshake`);\n\t\t\tsocket.write(createHandshakePacket(address));\n\t\t\t// wait for handshake data\n\t\t\tconst handshakeData = await packetDecoder.oncePromise<IHandshakeData>('handshake');\n\t\t\toptions.logger?.debug(`openConnection: <= received handshake data`);\n\t\t\t// send ping\n\t\t\toptions.logger?.debug(`openConnection: => sending ping`);\n\t\t\tsocket.write(createPingPacket(BigInt(Date.now())));\n\t\t\t// wait for pong\n\t\t\tconst pingData = await packetDecoder.oncePromise<number>('pong');\n\t\t\toptions.logger?.debug(`openConnection: <= received pong`);\n\t\t\tif (timeout) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\t\t\tsocket.end();\n\t\t\toptions.logger?.debug(`openConnection: end`);\n\n\t\t\tresolve({\n\t\t\t\t...handshakeData,\n\t\t\t\tping: pingData,\n\t\t\t});\n\t\t});\n\t\t// Destroy on error\n\t\tsocket.once('error', (error) => handleError(error, socket));\n\t\t// Destroy on timeout\n\t\tsocket.once('timeout', () => {\n\t\t\tsocket.destroy();\n\t\t\tif (timeout) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\t\t\toptions.logger?.debug(`openConnection: timeout`);\n\t\t\treject(new Error('Timed out'));\n\t\t});\n\t\t// Packet timeout\n\t\tconst timeoutValue = options.timeout ?? 10000;\n\t\ttimeout = setTimeout(() => {\n\t\t\tsocket.end();\n\t\t\treject(new Error(`Timed out (${timeoutValue.toString()} ms)`));\n\t\t}, timeoutValue);\n\t});\n}\n"],"mappings":"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"}