UNPKG

ts-ping

Version:

A modern TypeScript library for performing ICMP ping operations with type-safe results and fluent configuration.

456 lines (451 loc) 15.8 kB
import { SpawnSyncReturns } from 'node:child_process'; declare class PingResultLine { readonly rawLine: string; readonly timeInMs: number; constructor(line?: string, timeInMs?: number); static fromLine(line: string): PingResultLine; getRawLine(): string; getTimeInMs(): number; toArray(): { line: string; time_in_ms: number; }; toString(): string; } declare const PingError: { readonly HostnameNotFound: "HostnameNotFound"; readonly HostUnreachable: "HostUnreachable"; readonly PermissionDenied: "PermissionDenied"; readonly Timeout: "Timeout"; readonly UnknownError: "UnknownError"; }; type PingErrorType = typeof PingError[keyof typeof PingError]; declare const PingErrorUtils: { from: (value: string) => PingErrorType; }; interface PingResultOptions { output: string[]; returnCode: number; host: string; timeout: number; interval: number; packetSize: number; ttl: number; ipVersion?: 4 | 6; } interface PingResultArray { success: boolean; error: PingErrorType | null; host: string | null; packet_loss_percentage: number; packets_transmitted: number | null; packets_received: number | null; options: { timeout_in_seconds: number | null; interval: number; packet_size_in_bytes: number; ttl: number; ip_version?: 4 | 6; }; timings: { minimum_time_in_ms: number | null; maximum_time_in_ms: number | null; average_time_in_ms: number | null; standard_deviation_time_in_ms: number | null; }; raw_output: string; lines: { line: string; time_in_ms: number; }[]; } interface SuccessfulPingResult extends PingResult { readonly success: true; readonly error: null; readonly host: string; readonly numberOfPacketsTransmitted: number; readonly numberOfPacketsReceived: number; } interface FailedPingResult extends PingResult { readonly success: false; readonly error: PingErrorType; readonly packetLossPercentage: 100; readonly minimumTimeInMs: null; readonly maximumTimeInMs: null; readonly averageTimeInMs: null; readonly standardDeviationTimeInMs: null; } declare class PingResult { readonly success: boolean; readonly error: PingErrorType | null; readonly host: string | null; readonly packetLossPercentage: number; readonly numberOfPacketsTransmitted: number | null; readonly numberOfPacketsReceived: number | null; readonly timeoutInSeconds: number | null; readonly intervalInSeconds: number; readonly packetSizeInBytes: number; readonly ttl: number; readonly ipVersion?: 4 | 6; readonly minimumTimeInMs: number | null; readonly maximumTimeInMs: number | null; readonly averageTimeInMs: number | null; readonly standardDeviationTimeInMs: number | null; readonly rawOutput: string; readonly lines: PingResultLine[]; private constructor(); isSuccess(): this is SuccessfulPingResult; isFailure(): this is FailedPingResult; static fromPingOutput({ output, returnCode, host, timeout, interval, packetSize, ttl, ipVersion }: PingResultOptions): PingResult; /** * Creates a failed PingResult from an error. * Used when ping operations throw exceptions. */ static fromError(error: Error, host: string, options: { timeout: number; interval: number; packetSize: number; ttl: number; ipVersion?: 4 | 6; }): PingResult; static determineErrorFromMessage(message: string): PingErrorType; static determineErrorFromOutput(output: string): PingErrorType; static parsePingLines(output: string[]): PingResultLine[]; static isPingResponseLine(line: string): boolean; static calculatePacketLossPercentage(transmitted: number, received: number): number; averageResponseTimeInMs(): number; toArray(): PingResultArray; toString(): string; } declare class Ping { readonly hostname: string; timeoutInSeconds: number; count: number; intervalInSeconds: number; packetSizeInBytes: number; ttl: number; ipVersion?: 4 | 6; /** * Optional AbortSignal for external cancellation of ping operations. * When the signal is aborted, all ongoing and future ping operations will be cancelled. * * @example * ```typescript * const abortController = new AbortController() * const ping = new Ping('google.com').setAbortSignal(abortController.signal) * * // Cancel after 5 seconds * setTimeout(() => abortController.abort(), 5000) * * // Or use AbortSignal.timeout for simpler timeout-based cancellation * const ping2 = new Ping('google.com').setAbortSignal(AbortSignal.timeout(5000)) * ``` */ abortSignal?: AbortSignal; private currentCommand; constructor(hostname: string, timeoutInSeconds?: number, count?: number, intervalInSeconds?: number, packetSizeInBytes?: number, ttl?: number); /** * Auto-detects the IP version based on the hostname. * Only sets IP version for IPv6 addresses to ensure proper command selection on macOS. * IPv4 addresses and hostnames default to undefined (system default). */ private autoDetectIPVersion; run(): PingResult; runAsync(): Promise<PingResult>; /** * Creates an async generator that yields ping results in real-time. * Useful for continuous monitoring and streaming ping data. * * @example * ```typescript * const ping = new Ping('google.com').setInterval(1).setCount(0) // infinite * * for await (const result of ping.stream()) { * if (result.isSuccess()) { * console.log(`${new Date().toISOString()}: ${result.averageTimeInMs()}ms`) * } else { * console.error(`Ping failed: ${result.error}`) * } * } * ``` */ stream(): AsyncGenerator<PingResult, void, unknown>; /** * Creates an async generator that yields ping results with filtering and transformation. * * @param filter Optional filter function to include only specific results * @param transform Optional transformation function to modify yielded values * * @example * ```typescript * // Only yield successful pings with latency values * for await (const latency of ping.streamWithFilter( * r => r.isSuccess(), * r => r.averageTimeInMs() * )) { * console.log(`Latency: ${latency}ms`) * } * ``` */ streamWithFilter<T = PingResult>(filter?: (result: PingResult) => boolean, transform?: (result: PingResult) => T): AsyncGenerator<T, void, unknown>; /** * Creates an async generator that yields batches of ping results. * Useful for processing results in chunks or implementing backpressure. * * @param bufferSize Number of results to collect before yielding a batch * * @example * ```typescript * for await (const batch of ping.streamBatched(5)) { * console.log(`Processing batch of ${batch.length} results`) * const avgLatency = batch * .filter(r => r.isSuccess()) * .reduce((sum, r) => sum + r.averageTimeInMs(), 0) / batch.length * console.log(`Average latency: ${avgLatency}ms`) * } * ``` */ streamBatched(bufferSize?: number): AsyncGenerator<PingResult[], void, unknown>; /** * Runs a single ping operation with sequence number. * Used internally by the streaming methods. */ private runSinglePing; /** * Sleep utility for interval timing. */ private sleep; executePingCommand(commandArray: string[]): SpawnSyncReturns<string>; executePingCommandAsync(commandArray: string[]): Promise<SpawnSyncReturns<string>>; calculateProcessTimeout(): number; combineOutputLines(result: SpawnSyncReturns<string>): string[]; setTimeout(timeout: number): Ping; setCount(count: number): Ping; setInterval(interval: number): Ping; setPacketSize(size: number): Ping; setTtl(ttl: number): Ping; setIPVersion(version: 4 | 6): Ping; setIPv4(): Ping; setIPv6(): Ping; /** * Sets an AbortSignal for external cancellation of ping operations. * * @param abortSignal The AbortSignal to use for cancellation * @returns This Ping instance for method chaining * * @example * ```typescript * const abortController = new AbortController() * const ping = new Ping('google.com').setAbortSignal(abortController.signal) * * // Cancel the operation * abortController.abort() * * // Or use timeout-based cancellation * const ping2 = new Ping('google.com').setAbortSignal(AbortSignal.timeout(5000)) * ``` */ setAbortSignal(abortSignal: AbortSignal): Ping; buildPingCommand(): string[]; startWithPingCommand(): Ping; addIPVersionOption(): Ping; getCommand(): string[]; addPacketCountOption(): Ping; addTimeoutOption(): Ping; addOptionalIntervalOption(): Ping; addOptionalPacketSizeOption(): Ping; addOptionalTtlOption(): Ping; addTargetHostname(): Ping; isRunningOnMacOS(): boolean; isRunningOnWindows(): boolean; convertTimeoutToMilliseconds(): number; } /** * Statistics calculated from a window of ping results. */ interface PingStats { /** Number of successful pings in the window */ count: number; /** Average response time in milliseconds */ average: number; /** Minimum response time in milliseconds */ minimum: number; /** Maximum response time in milliseconds */ maximum: number; /** Standard deviation of response times */ standardDeviation: number; /** Network jitter (variance in response times) */ jitter: number; /** Packet loss percentage in the window */ packetLoss: number; /** Timestamp when the stats were calculated */ timestamp: Date; } /** * Enhanced streaming utilities for ping operations. * Provides advanced processing capabilities like windowing, statistics, and filtering. * * @example * ```typescript * const stream = new PingStream(new Ping('google.com').setInterval(0.5)) * * // Get rolling statistics * for await (const stats of stream.rollingStats(10)) { * console.log(`Avg: ${stats.average}ms, Jitter: ${stats.jitter}ms`) * } * ``` */ declare class PingStream { private ping; constructor(ping: Ping); /** * Takes only the first N results from the ping stream. * * @param n Number of results to take * * @example * ```typescript * // Take first 5 ping results * for await (const result of stream.take(5)) { * console.log(`Ping ${result.isSuccess() ? 'success' : 'failed'}`) * } * ``` */ take(n: number): AsyncGenerator<PingResult, void, unknown>; /** * Skips failed ping results and only yields successful ones. * * @example * ```typescript * // Only process successful pings * for await (const result of stream.skipFailures()) { * console.log(`Response time: ${result.averageResponseTimeInMs()}ms`) * } * ``` */ skipFailures(): AsyncGenerator<PingResult, void, unknown>; /** * Skips successful ping results and only yields failed ones. * Useful for monitoring and alerting on failures. * * @example * ```typescript * // Monitor only failures * for await (const failure of stream.skipSuccesses()) { * console.error(`Ping failed: ${failure.error}`) * await sendAlert(failure) * } * ``` */ skipSuccesses(): AsyncGenerator<PingResult, void, unknown>; /** * Creates a sliding window of ping results. * Each yield contains the last N results. * * @param size Size of the sliding window * * @example * ```typescript * // Process results in sliding windows of 5 * for await (const window of stream.window(5)) { * const avgLatency = window * .filter(r => r.isSuccess()) * .reduce((sum, r) => sum + r.averageResponseTimeInMs(), 0) / window.length * console.log(`Window avg: ${avgLatency}ms`) * } * ``` */ window(size: number): AsyncGenerator<PingResult[], void, unknown>; /** * Calculates rolling statistics from a sliding window of ping results. * Only successful pings are included in the statistics. * * @param windowSize Size of the sliding window for calculating stats (default: 10) * * @example * ```typescript * // Monitor network performance with rolling stats * for await (const stats of stream.rollingStats(20)) { * if (stats.jitter > 50) { * console.warn(`High network jitter detected: ${stats.jitter}ms`) * } * if (stats.packetLoss > 5) { * console.error(`Packet loss detected: ${stats.packetLoss}%`) * } * } * ``` */ rollingStats(windowSize?: number): AsyncGenerator<PingStats, void, unknown>; /** * Yields results only when they meet a specific condition. * * @param predicate Function that determines if a result should be yielded * * @example * ```typescript * // Only yield results with high latency * for await (const slowResult of stream.filter(r => * r.isSuccess() && r.averageResponseTimeInMs() > 100 * )) { * console.warn(`Slow response: ${slowResult.averageResponseTimeInMs()}ms`) * } * ``` */ filter(predicate: (result: PingResult) => boolean): AsyncGenerator<PingResult, void, unknown>; /** * Transforms each ping result using a mapping function. * * @param mapper Function to transform each result * * @example * ```typescript * // Extract only latency values * for await (const latency of stream.map(r => * r.isSuccess() ? r.averageResponseTimeInMs() : null * )) { * if (latency !== null) { * console.log(`Latency: ${latency}ms`) * } * } * ``` */ map<T>(mapper: (result: PingResult) => T): AsyncGenerator<T, void, unknown>; /** * Groups results into batches and yields when a batch is full or a timeout occurs. * * @param batchSize Maximum number of results per batch * @param timeoutMs Maximum time to wait before yielding a partial batch (default: 5000ms) * * @example * ```typescript * // Process results in timed batches * for await (const batch of stream.batchWithTimeout(10, 5000)) { * console.log(`Processing batch of ${batch.length} results`) * await processBatch(batch) * } * ``` */ batchWithTimeout(batchSize: number, timeoutMs?: number): AsyncGenerator<PingResult[], void, unknown>; /** * Calculates statistics from a window of ping results. */ private calculateStats; } /** * Utility function to combine multiple async iterators into a single stream. * Results are yielded as soon as they become available from any iterator. * * @param iterators Multiple async iterators to combine * * @example * ```typescript * const ping1 = new Ping('google.com').stream() * const ping2 = new Ping('github.com').stream() * * for await (const result of combineAsyncIterators(ping1, ping2)) { * console.log(`Got result from ${result.host}`) * } * ``` */ declare function combineAsyncIterators<T>(...iterators: AsyncGenerator<T, void, unknown>[]): AsyncGenerator<T, void, unknown>; export { type FailedPingResult, Ping, PingError, type PingErrorType, PingErrorUtils, PingResult, type PingResultArray, PingResultLine, type PingStats, PingStream, type SuccessfulPingResult, combineAsyncIterators };