ts-ping
v1.5.0
Published
A modern TypeScript library for performing ICMP ping operations with type-safe results and fluent configuration.
Maintainers
Readme
ts-ping
A modern TypeScript library for performing ICMP ping operations with type-safe results and fluent configuration.
Features
- Type-Safe: Built with TypeScript and discriminated union types for reliable type checking
- Fluent Interface: Chainable methods for easy configuration
- Cross-Platform: Works on Windows, macOS, and Linux with platform-specific optimizations
- IPv4/IPv6 Support: Full dual-stack support with automatic IPv6 detection and platform-specific command handling
- AbortSignal Support: External cancellation with standard
AbortSignalAPI for graceful operation control - Comprehensive Results: Detailed ping statistics including packet loss, timing, and error information
- Streaming Support: Real-time ping monitoring with async generators and advanced utilities
- Live Statistics: Rolling statistics calculation with jitter, packet loss, and performance metrics
- Memory Efficient: Generator-based streaming that doesn't load all results into memory
- Zero Dependencies: No external dependencies - lightweight and secure
- Well-Tested: 90%+ test coverage with comprehensive test suite
- Modern: Uses ES modules and modern JavaScript features
Installation
# Using pnpm (recommended)
pnpm add ts-ping
# Using npm
npm install ts-ping
# Using yarn
yarn add ts-pingQuick Start
import { Ping } from 'ts-ping'
const ping = new Ping('google.com').setCount(3).setTimeout(3)
const result = ping.run()
if (result.isSuccess()) {
console.log(`Successfully pinged ${result.host}`)
console.log(
`Packets: ${result.numberOfPacketsTransmitted} sent, ${result.numberOfPacketsReceived} received`,
)
console.log(`Packet loss: ${result.packetLossPercentage}%`)
}
else if (result.isFailure()) {
console.error(`Ping failed: ${result.error}`)
console.error(`Host: ${result.host || 'unknown'}`)
}Streaming Support
The library provides powerful async generator-based streaming for real-time ping monitoring:
import { Ping, PingStream } from 'ts-ping'
// Basic streaming - continuous ping monitoring
const ping = new Ping('google.com').setInterval(0.5) // Ping every 500ms
for await (const result of ping.stream()) {
console.log(`${result.host}: ${result.isSuccess() ? result.averageResponseTimeInMs() + 'ms' : 'failed'}`)
// Break after 10 results or run indefinitely
if (someCondition) break
}Stream Processing with PingStream
import { PingStream } from 'ts-ping'
const ping = new Ping('example.com').setInterval(0.5)
const stream = new PingStream(ping)
// Get rolling statistics every 10 pings
for await (const stats of stream.rollingStats(10)) {
console.log(`Avg: ${stats.average.toFixed(1)}ms`)
console.log(`Jitter: ${stats.jitter.toFixed(1)}ms`)
console.log(`Packet Loss: ${stats.packetLoss.toFixed(1)}%`)
console.log(`Std Dev: ${stats.standardDeviation.toFixed(1)}ms`)
}Advanced Streaming Examples
// Take only the first 5 successful pings
for await (const result of stream.skipFailures().take(5)) {
console.log(`Success: ${result.averageResponseTimeInMs()}ms`)
}
// Monitor only failures for alerting
for await (const failure of stream.skipSuccesses()) {
console.error(`Ping failed: ${failure.error}`)
await sendAlert(failure)
}
// Process in sliding windows of 3 results
for await (const window of stream.window(3)) {
const avgLatency = window
.filter(r => r.isSuccess())
.map(r => r.averageResponseTimeInMs())
.reduce((a, b) => a + b, 0) / window.length
console.log(`Window average: ${avgLatency}ms`)
}
// Batch results with timeout
for await (const batch of stream.batchWithTimeout(5, 2000)) {
console.log(`Processed batch of ${batch.length} results`)
}
// External cancellation with AbortSignal
const abortController = new AbortController()
const cancelablePing = new Ping('google.com')
.setCount(0) // infinite
.setInterval(1)
.setAbortSignal(abortController.signal)
// Cancel after 30 seconds
setTimeout(() => abortController.abort(), 30000)
for await (const result of cancelablePing.stream()) {
console.log(`Ping: ${result.isSuccess() ? result.averageResponseTimeInMs() + 'ms' : 'failed'}`)
// Will automatically stop when aborted
}Async Support
The library supports both synchronous and asynchronous execution:
import { Ping } from 'ts-ping'
// Synchronous (blocks until complete)
const result = new Ping('google.com').run()
// Asynchronous (returns a Promise)
const asyncResult = await new Ping('google.com').runAsync()
// Error handling with async
try {
const result = await new Ping('example.com').runAsync()
console.log('Ping completed:', result.isSuccess())
}
catch (error) {
console.error('Ping failed with error:', error)
}API Reference
Ping Class
Constructor
new Ping(
hostname: string,
timeoutInSeconds?: number,
count?: number,
intervalInSeconds?: number,
packetSizeInBytes?: number,
ttl?: number
)Parameters:
hostname- The target hostname or IP address to pingtimeoutInSeconds- Timeout for each ping in seconds (default: 5)count- Number of ping packets to send (default: 1)intervalInSeconds- Interval between pings in seconds (default: 1.0)packetSizeInBytes- Size of ping packets in bytes (default: 56)ttl- Time To Live value (default: 64)
Fluent Interface Methods
All methods return this for method chaining:
ping.setTimeout(10) // Set timeout in seconds
ping.setCount(5) // Set number of pings
ping.setInterval(2.0) // Set interval between pings
ping.setPacketSize(128) // Set packet size in bytes
ping.setTtl(32) // Set Time To Live
ping.setIPVersion(4) // Set IP version (4 or 6)
ping.setIPv4() // Force IPv4 (convenience method)
ping.setIPv6() // Force IPv6 (convenience method)
ping.setAbortSignal(signal) // Set AbortSignal for cancellationIPv4/IPv6 Support
Control which IP version to use for ping operations. ts-ping automatically detects IPv6 addresses and uses the appropriate ping command on all platforms.
// Auto-detection: IPv6 addresses are automatically detected
const ping6Auto = new Ping('2001:4860:4860::8888') // Auto-detects IPv6
const result6Auto = ping6Auto.run() // Uses ping6 on macOS, ping -6 on Linux/Windows
// IPv4 addresses and hostnames use system default
const ping4 = new Ping('8.8.8.8') // No auto-detection, uses system default
const pingHost = new Ping('google.com') // Uses system default
// Force IPv4 (overrides auto-detection)
const ping4Force = new Ping('google.com').setIPv4()
const result4 = ping4Force.run()
// Force IPv6 (overrides auto-detection)
const ping6Force = new Ping('google.com').setIPv6()
const result6 = ping6Force.run()
// Or use setIPVersion method
const ping = new Ping('google.com').setIPVersion(6)
// Works with all other options
const result = new Ping('2001:4860:4860::8888') // Auto-detects IPv6
.setCount(3)
.setTimeout(5)
.run()
if (result.isSuccess()) {
console.log(`IPv${result.ipVersion} ping successful`)
console.log(`Host: ${result.host}`)
}Auto-Detection Behavior:
- IPv6 addresses: Automatically detected and use appropriate IPv6 ping command
- IPv4 addresses: Use system default ping command (no version forcing)
- Hostnames: Use system default ping command (no version forcing)
- Explicit methods:
setIPv4()andsetIPv6()override auto-detection
Platform Support:
- macOS: Uses
pingfor IPv4 andping6for IPv6 - Linux/Windows: Uses
ping -4for IPv4 andping -6for IPv6 - Default: When no IP version is specified, uses the system default (usually IPv4)
Streaming with IP Version:
// Monitor IPv6 connectivity
const ping = new Ping('ipv6.google.com').setIPv6().setInterval(1)
for await (const result of ping.stream()) {
if (result.isSuccess()) {
console.log(`IPv6 ping: ${result.averageResponseTimeInMs()}ms`)
} else {
console.log(`IPv6 ping failed: ${result.error}`)
}
}AbortSignal Support
Control ping operations with external cancellation using the standard AbortSignal API:
// Manual cancellation with AbortController
const abortController = new AbortController()
const ping = new Ping('google.com')
.setCount(0) // infinite pings
.setInterval(1)
.setAbortSignal(abortController.signal)
// Cancel after 10 seconds
setTimeout(() => abortController.abort(), 10000)
try {
for await (const result of ping.stream()) {
console.log(`Ping: ${result.averageTimeInMs ?? 'failed'}ms`)
}
} catch (error) {
console.log('Ping cancelled:', error.message)
}// Timeout-based cancellation with AbortSignal.timeout()
const ping = new Ping('google.com')
.setCount(0) // infinite pings
.setInterval(0.5)
.setAbortSignal(AbortSignal.timeout(5000)) // Cancel after 5 seconds
for await (const result of ping.stream()) {
console.log(`Ping: ${result.averageTimeInMs ?? 'failed'}ms`)
// Automatically stops after 5 seconds
}AbortSignal Features:
- External cancellation: Stop ping operations from outside the ping logic
- Graceful shutdown: Operations stop cleanly without throwing errors
- Standard API: Uses the same pattern as
fetch()and other modern APIs - Multiple sources: Works with
AbortController,AbortSignal.timeout(), or anyAbortSignal - All methods supported: Works with
runAsync(),stream(),streamWithFilter(), andstreamBatched()
Method Chaining Example
const result = new Ping('example.com')
.setTimeout(10)
.setCount(5)
.setInterval(1.5)
.setPacketSize(128)
.setIPv6()
.run()run()
Executes the ping command synchronously and returns a PingResult.
const result = ping.run()runAsync()
Executes the ping command asynchronously and returns a Promise<PingResult>.
const result = await ping.runAsync()
// With error handling
try {
const result = await ping.runAsync()
if (result.isSuccess()) {
console.log('Ping successful!')
}
}
catch (error) {
console.error('Ping failed:', error)
}Benefits of async:
- Non-blocking execution
- Better for multiple concurrent pings
- Integrates well with async/await patterns
- Proper timeout handling with Promise rejection
stream()
Creates an async generator that yields ping results continuously:
// Infinite stream (count = 0)
const ping = new Ping('google.com').setCount(Infinity).setInterval(1)
for await (const result of ping.stream()) {
console.log(result.isSuccess() ? 'Success' : 'Failed')
if (shouldStop) break
}
// Finite stream
const ping = new Ping('google.com').setCount(5).setInterval(0.5)
for await (const result of ping.stream()) {
console.log(`Result ${result.host}: ${result.isSuccess()}`)
}streamWithFilter()
Creates a filtered and optionally transformed stream:
// Filter successful pings and get latencies
const latencies = ping.streamWithFilter(
result => result.isSuccess(),
result => result.averageResponseTimeInMs()
)
for await (const latency of latencies) {
console.log(`Latency: ${latency}ms`)
}
// Filter failures and get error messages
const errors = ping.streamWithFilter(
result => result.isFailure(),
result => result.error
)
for await (const error of errors) {
console.error(`Error: ${error}`)
}streamBatched()
Creates a stream that yields arrays of results in batches:
const ping = new Ping('google.com').setCount(10).setInterval(0.2)
for await (const batch of ping.streamBatched(3)) {
console.log(`Batch of ${batch.length} results:`)
batch.forEach(result => {
console.log(` ${result.host}: ${result.isSuccess()}`)
})
}PingStream
Advanced streaming utilities for processing ping results:
import { PingStream } from 'ts-ping'
const ping = new Ping('example.com').setInterval(0.5)
const stream = new PingStream(ping)take(n)
Limits the stream to the first N results:
// Get exactly 10 results
for await (const result of stream.take(10)) {
console.log(result.isSuccess())
}skipFailures() / skipSuccesses()
Filter results by success status:
// Only successful pings
for await (const success of stream.skipFailures()) {
console.log(`Success: ${success.averageResponseTimeInMs()}ms`)
}
// Only failed pings
for await (const failure of stream.skipSuccesses()) {
console.error(`Failed: ${failure.error}`)
}window(size)
Creates a sliding window of results:
// Process results in windows of 5
for await (const window of stream.window(5)) {
const successRate = window.filter(r => r.isSuccess()).length / window.length
console.log(`Success rate: ${(successRate * 100).toFixed(1)}%`)
}rollingStats(windowSize)
Calculates rolling statistics over a window of results:
for await (const stats of stream.rollingStats(20)) {
console.log(`Average: ${stats.average.toFixed(1)}ms`)
console.log(`Jitter: ${stats.jitter.toFixed(1)}ms`)
console.log(`Packet Loss: ${stats.packetLoss.toFixed(1)}%`)
console.log(`Std Dev: ${stats.standardDeviation.toFixed(1)}ms`)
console.log(`Min/Max: ${stats.minimum}ms/${stats.maximum}ms`)
console.log(`Count: ${stats.count}`)
console.log(`Timestamp: ${stats.timestamp}`)
}filter(predicate) / map(transform)
Standard functional programming operations:
// Filter and transform
const highLatencies = stream
.filter(result => result.isSuccess() && result.averageResponseTimeInMs() > 100)
.map(result => ({
host: result.host,
latency: result.averageResponseTimeInMs(),
timestamp: new Date()
}))
for await (const data of highLatencies) {
console.log(`High latency detected: ${data.latency}ms`)
}batchWithTimeout(batchSize, timeoutMs)
Batches results by size or timeout:
// Batch up to 5 results or every 2 seconds
for await (const batch of stream.batchWithTimeout(5, 2000)) {
console.log(`Processing batch of ${batch.length} results`)
const avgLatency = batch
.filter(r => r.isSuccess())
.map(r => r.averageResponseTimeInMs())
.reduce((sum, lat) => sum + lat, 0) / batch.length
console.log(`Batch average: ${avgLatency}ms`)
}PingStats Interface
Rolling statistics provided by rollingStats():
interface PingStats {
count: number // Number of successful pings
average: number // Average response time in ms
minimum: number // Minimum response time in ms
maximum: number // Maximum response time in ms
standardDeviation: number // Standard deviation of response times
jitter: number // Network jitter (variance in response times)
packetLoss: number // Packet loss percentage (0-100)
timestamp: Date // When the stats were calculated
}combineAsyncIterators()
Utility function to merge multiple async iterators:
import { combineAsyncIterators } from 'ts-ping'
const stream1 = new Ping('google.com').stream()
const stream2 = new Ping('github.com').stream()
const combined = combineAsyncIterators(stream1, stream2)
for await (const result of combined) {
console.log(`${result.host}: ${result.isSuccess()}`)
}PingResult
The result object uses discriminated unions for type safety. Use type guards to access specific properties:
Successful Results
if (result.isSuccess()) {
// TypeScript knows these properties are available and non-null
console.log(result.host) // string
console.log(result.numberOfPacketsTransmitted) // number
console.log(result.numberOfPacketsReceived) // number
console.log(result.packetLossPercentage) // number
console.log(result.averageTimeInMs) // number | null
console.log(result.minimumTimeInMs) // number | null
console.log(result.maximumTimeInMs) // number | null
}Failed Results
if (result.isFailure()) {
// TypeScript knows the error property is available
console.log(result.error) // PingErrorType
console.log(result.host) // string | null
console.log(result.packetLossPercentage) // 100
}Common Properties
Available on both success and failure results:
result.rawOutput // string - full ping command output
result.lines // PingResultLine[] - parsed ping response lines
result.timeoutInSeconds // number | null
result.intervalInSeconds // number
result.packetSizeInBytes // number
result.ttl // number
result.ipVersion // 4 | 6 | undefined - IP version used for the pingIP Version Information
When IPv4 or IPv6 is explicitly set, the result includes the IP version:
const ping4 = new Ping('google.com').setIPv4()
const result4 = ping4.run()
if (result4.isSuccess()) {
console.log(`Used IPv${result4.ipVersion}`) // "Used IPv4"
}
const ping6 = new Ping('google.com').setIPv6()
const result6 = ping6.run()
if (result6.isSuccess()) {
console.log(`Used IPv${result6.ipVersion}`) // "Used IPv6"
}
// When no IP version is specified, ipVersion is undefined
const pingDefault = new Ping('google.com')
const resultDefault = pingDefault.run()
console.log(resultDefault.ipVersion) // undefinedError Types
type PingErrorType
= | 'HostnameNotFound'
| 'HostUnreachable'
| 'PermissionDenied'
| 'Timeout'
| 'UnknownError'PingResultLine
Individual ping response lines with parsed timing information:
line.getRawLine() // string - original ping output line
line.getTimeInMs() // number - parsed response time in milliseconds
line.toArray() // { line: string, time_in_ms: number }Examples
Basic Ping
import { Ping } from 'ts-ping'
const result = new Ping('google.com').run()
if (result.isSuccess()) {
console.log('Ping successful!')
}
else {
console.log('Ping failed:', result.error)
}Async Ping
import { Ping } from 'ts-ping'
async function pingExample() {
try {
const result = await new Ping('google.com').runAsync()
if (result.isSuccess()) {
console.log('Async ping successful!')
console.log(`Average time: ${result.averageResponseTimeInMs()}ms`)
}
else {
console.log('Async ping failed:', result.error)
}
}
catch (error) {
console.error('Ping threw an error:', error)
}
}
pingExample()Real-time Network Monitoring
import { Ping, PingStream } from 'ts-ping'
async function networkMonitor() {
const ping = new Ping('google.com').setInterval(0.5) // Ping every 500ms
const stream = new PingStream(ping)
// Monitor with rolling statistics
for await (const stats of stream.rollingStats(10)) {
console.clear()
console.log('Network Monitor - Last 10 pings:')
console.log(`Average Latency: ${stats.average.toFixed(1)}ms`)
console.log(`Jitter: ${stats.jitter.toFixed(1)}ms`)
console.log(`Packet Loss: ${stats.packetLoss.toFixed(1)}%`)
console.log(`Min/Max: ${stats.minimum}ms/${stats.maximum}ms`)
console.log(`Timestamp: ${stats.timestamp.toLocaleTimeString()}`)
// Alert on high latency
if (stats.average > 100) {
console.log('WARNING: High latency detected!')
}
// Alert on packet loss
if (stats.packetLoss > 5) {
console.log('ALERT: Packet loss detected!')
}
}
}
networkMonitor()Streaming with Filtering
import { Ping, PingStream } from 'ts-ping'
async function monitorFailures() {
const ping = new Ping('example.com').setInterval(1)
const stream = new PingStream(ping)
console.log('Monitoring for failures...')
// Only process failures for alerting
for await (const failure of stream.skipSuccesses().take(5)) {
console.error(`Ping failed: ${failure.error}`)
console.error(` Host: ${failure.host}`)
console.error(` Time: ${new Date().toISOString()}`)
// Send alert (example)
await sendSlackAlert(`Ping to ${failure.host} failed: ${failure.error}`)
}
}
async function sendSlackAlert(message: string) {
// Implementation would send to Slack/Discord/etc
console.log(`Alert: ${message}`)
}
monitorFailures()Batched Processing
import { Ping, PingStream } from 'ts-ping'
async function batchProcessor() {
const ping = new Ping('github.com').setInterval(0.2)
const stream = new PingStream(ping)
// Process in batches of 5 or every 3 seconds
for await (const batch of stream.batchWithTimeout(5, 3000)) {
console.log(`\nProcessing batch of ${batch.length} results:`)
const successful = batch.filter(r => r.isSuccess())
const failed = batch.filter(r => r.isFailure())
console.log(`Successful: ${successful.length}`)
console.log(`Failed: ${failed.length}`)
if (successful.length > 0) {
const avgLatency = successful
.map(r => r.averageResponseTimeInMs())
.reduce((sum, lat) => sum + lat, 0) / successful.length
console.log(`Average latency: ${avgLatency.toFixed(1)}ms`)
}
// Save to database, send metrics, etc.
await saveToDatabase(batch)
}
}
async function saveToDatabase(batch: any[]) {
console.log(`Saved ${batch.length} results to database`)
}
batchProcessor()Multi-host Monitoring
import { Ping, PingStream, combineAsyncIterators } from 'ts-ping'
async function multiHostMonitor() {
const hosts = ['google.com', 'github.com', 'stackoverflow.com']
// Create streams for each host
const streams = hosts.map(host =>
new Ping(host).setInterval(1).stream()
)
// Combine all streams into one
const combined = combineAsyncIterators(...streams)
console.log('Monitoring multiple hosts...')
for await (const result of combined) {
const status = result.isSuccess()
? `${result.averageResponseTimeInMs()}ms`
: `${result.error}`
console.log(`${result.host}: ${status}`)
// Take only first 20 results total
if (Math.random() > 0.9) break // Example break condition
}
}
multiHostMonitor()Advanced Filtering and Transformation
import { Ping, PingStream } from 'ts-ping'
async function advancedProcessing() {
const ping = new Ping('example.com').setInterval(0.5)
const stream = new PingStream(ping)
// Chain multiple operations
const processedStream = stream
.filter(result => result.isSuccess()) // Only successful pings
.map(result => ({
host: result.host,
latency: result.averageResponseTimeInMs(),
timestamp: new Date(),
quality: result.averageResponseTimeInMs() < 50 ? 'excellent' :
result.averageResponseTimeInMs() < 100 ? 'good' : 'poor'
}))
.take(10) // Only process first 10 successful pings
for await (const data of processedStream) {
console.log(`${data.host}: ${data.latency}ms (${data.quality})`)
}
}
advancedProcessing()Multiple Concurrent Pings
import { Ping } from 'ts-ping'
async function pingMultipleHosts() {
const hosts = ['google.com', 'github.com', 'stackoverflow.com']
const promises = hosts.map(host =>
new Ping(host).setTimeout(5).runAsync()
)
try {
const results = await Promise.all(promises)
results.forEach((result, index) => {
const host = hosts[index]
if (result.isSuccess()) {
console.log(`${host}: ${result.averageResponseTimeInMs()}ms`)
}
else {
console.log(`${host}: ${result.error}`)
}
})
}
catch (error) {
console.error('One or more pings failed:', error)
}
}
pingMultipleHosts()Advanced Configuration
import { Ping } from 'ts-ping'
const ping = new Ping('example.com')
.setTimeout(10) // 10 second timeout
.setCount(5) // Send 5 pings
.setInterval(2.0) // 2 second interval
.setPacketSize(128) // 128 byte packets
.setTtl(32) // TTL of 32
const result = ping.run()
if (result.isSuccess()) {
console.log(`Host: ${result.host}`)
console.log(`Packets sent: ${result.numberOfPacketsTransmitted}`)
console.log(`Packets received: ${result.numberOfPacketsReceived}`)
console.log(`Packet loss: ${result.packetLossPercentage}%`)
if (result.averageTimeInMs) {
console.log(`Average time: ${result.averageTimeInMs}ms`)
}
if (result.minimumTimeInMs && result.maximumTimeInMs) {
console.log(`Time range: ${result.minimumTimeInMs}ms - ${result.maximumTimeInMs}ms`)
}
}
else {
console.error(`Ping failed with error: ${result.error}`)
}Processing Individual Lines
import { Ping } from 'ts-ping'
const result = new Ping('google.com').setCount(3).run()
if (result.isSuccess()) {
console.log('Individual ping times:')
result.lines.forEach((line, index) => {
console.log(`${index + 1}: ${line.getTimeInMs()}ms`)
})
}Error Handling
import { Ping, PingError } from 'ts-ping'
const result = new Ping('nonexistent.example.com').run()
if (result.isFailure()) {
switch (result.error) {
case PingError.HostnameNotFound:
console.error('Hostname could not be resolved')
break
case PingError.HostUnreachable:
console.error('Host is unreachable')
break
case PingError.PermissionDenied:
console.error('Permission denied - try running as administrator')
break
case PingError.Timeout:
console.error('Ping timed out')
break
default:
console.error('Unknown error occurred')
}
}Platform Support
Windows
- Uses
-ninstead of-cfor ping count - Uses
-w(lowercase) for timeout in milliseconds - Uses
-lfor packet size instead of-s - Uses
-ifor TTL instead of-t - Does not support custom intervals (handled by streaming interval timing)
macOS
- Uses milliseconds for timeout values (
-W 5000)
Linux
- Uses seconds for timeout values (
-W 5)
The library automatically detects the platform and adjusts command parameters accordingly.
TypeScript Integration
This library is built with TypeScript and provides excellent type safety:
import { FailedPingResult, Ping, PingResult, PingStream, SuccessfulPingResult } from 'ts-ping'
function handlePingResult(result: PingResult) {
if (result.isSuccess()) {
// result is automatically narrowed to SuccessfulPingResult
const host: string = result.host // string
const transmitted: number = result.numberOfPacketsTransmitted // number
}
else {
// result is automatically narrowed to FailedPingResult
const error: PingErrorType = result.error // PingErrorType
const loss: 100 = result.packetLossPercentage // exactly 100
}
}
// Streaming types are also fully typed
async function typedStreaming() {
const ping = new Ping('example.com')
const stream = new PingStream(ping)
// Async generators are properly typed
const results: AsyncGenerator<PingResult> = stream.take(5)
const stats: AsyncGenerator<PingStats> = stream.rollingStats(10)
const latencies: AsyncGenerator<number> = stream
.filter(r => r.isSuccess())
.map(r => r.averageResponseTimeInMs())
}Development
Building
pnpm run buildTesting
pnpm test # Run all tests
pnpm run test:watch # Run tests in watch mode
pnpm run test:coverage # Run tests with coverageLinting
pnpm run lint # Check for linting issues
pnpm run lint:fix # Fix linting issues automaticallyRequirements
- Node.js 20+
- pnpm 8+ (recommended) or npm/yarn
- TypeScript 5+
- macOS, Linux, or Windows (ping command must be available)
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please read the contributing guidelines and ensure all tests pass before submitting a pull request.
Changelog
v1.5.0 (2025-08-06)
- AbortSignal Support: Added external cancellation control with standard
AbortSignalAPI - New Method: Added
setAbortSignal(signal)for fluent interface configuration - Graceful Cancellation: Operations stop cleanly without throwing errors when aborted
- Universal Support: Works with
runAsync(),stream(),streamWithFilter(), andstreamBatched() - Multiple Sources: Compatible with
AbortController,AbortSignal.timeout(), or anyAbortSignal - Modern API Pattern: Follows the same pattern as
fetch()and other modern JavaScript APIs - Comprehensive Testing: 13 new tests covering all abort scenarios and edge cases
- Enhanced Documentation: Added AbortSignal section with usage examples and API reference
- Integration Examples: Demonstrated timeout-based and manual cancellation patterns
v1.4.0 (2025-07-28)
- IPv6 Auto-Detection: Automatically detects IPv6 addresses and uses appropriate ping commands on all platforms
- macOS IPv6 Fix: Resolves IPv6 ping failures on macOS by auto-selecting
ping6command for IPv6 addresses - Smart IP Detection: Uses Node.js
isIPv6()to intelligently detect IPv6 addresses without manual configuration - Backward Compatible: All existing code continues to work; auto-detection only applies to IPv6 addresses
- Override Support:
setIPv4()andsetIPv6()methods can still override auto-detection when needed - Enhanced Testing: Added 8 new test cases covering IPv6 auto-detection scenarios and edge cases
- Updated Documentation: Enhanced IPv4/IPv6 section with auto-detection examples and behavior explanation
- Example Updates: Added IPv6 auto-detection demonstration to existing examples
v1.3.0 (2025-07-28)
- IPv4/IPv6 Support: Full dual-stack networking support with platform-specific command handling
- New IP Version Methods: Added
setIPVersion(4|6),setIPv4(), andsetIPv6()for explicit IP version control - Enhanced Results: Added
ipVersionproperty toPingResultwith IP version information - Platform-Specific Commands:
- macOS: Uses
pingfor IPv4 andping6for IPv6 - Linux/Windows: Uses
ping -4for IPv4 andping -6for IPv6
- macOS: Uses
- Streaming IP Support: IP version information preserved in streaming results
- Comprehensive Testing: 30+ new tests covering all IPv4/IPv6 platform scenarios
- Enhanced Documentation: New IPv4/IPv6 section with usage examples and API reference
v1.2.0 (2025-07-28)
- Enhanced Windows Support: Improved Windows compatibility with correct ping command arguments
- Platform-Specific Commands: Windows uses
-nfor count,-wfor timeout,-lfor packet size,-ifor TTL - Code Cleanup: Removed non-existent
-Oflag functionality - Comprehensive Testing: Added dedicated Windows support tests with platform detection
- Updated Documentation: Clarified platform-specific ping command differences
v1.1.0 (2025-07-28)
- New Streaming Support: Added async generator-based streaming for real-time ping monitoring
- PingStream Utilities: Advanced stream processing with filtering, mapping, windowing, and statistics
- Rolling Statistics: Live calculation of latency, jitter, packet loss, and performance metrics
- Memory Efficient: Generator-based streaming that doesn't load all results into memory
- Windows Support: Full Windows compatibility with platform-specific ping command handling
- Type-Safe Streams: Full TypeScript support for async generators and streaming operations
- Stream Utilities:
combineAsyncIterators, batching, filtering, and transformation utilities - Enhanced Documentation: Comprehensive examples for streaming and real-time monitoring
- Improved Coverage: Test coverage increased to 92%+ with extensive streaming tests
v1.0.0 (2025-07-28)
- Initial release with TypeScript support
- Discriminated union types for type-safe results
- Fluent interface for configuration
- Cross-platform support (Windows/macOS/Linux)
- Async support with
runAsync()method - Comprehensive test suite with 94%+ coverage
- Complete documentation with examples
- Security policy and contribution guidelines
