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




A modern TypeScript library for performing ICMP ping operations with type-safe results and fluent configuration.
- 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 AbortSignal API 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
``bashUsing pnpm (recommended)
pnpm add ts-ping
Quick Start
`typescript
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:
`typescript
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
}
`$3
`typescript
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)
}
`$3
`typescript
// 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:
`typescript
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
$3
#### Constructor
`typescript
new Ping(
hostname: string,
timeoutInSeconds?: number,
count?: number,
intervalInSeconds?: number,
packetSizeInBytes?: number,
ttl?: number
)
`Parameters:
-
hostname - The target hostname or IP address to ping
- timeoutInSeconds - 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:`typescript
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 cancellation
`#### IPv4/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.
`typescript
// 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() and setIPv6() override auto-detectionPlatform Support:
- macOS: Uses
ping for IPv4 and ping6 for IPv6
- Linux/Windows: Uses ping -4 for IPv4 and ping -6 for IPv6
- Default: When no IP version is specified, uses the system default (usually IPv4)Streaming with IP Version:
`typescript
// 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:`typescript
// 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)
}
``typescript
// 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 secondsfor 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 any AbortSignal
- All methods supported: Works with runAsync(), stream(), streamWithFilter(), and streamBatched()#### Method Chaining Example
`typescript
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.`typescript
const result = ping.run()
`#### runAsync()
Executes the ping command asynchronously and returns a
Promise.`typescript
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:
`typescript
// 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:
`typescript
// 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:
`typescript
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()})
})
}
`$3
Advanced streaming utilities for processing ping results:
`typescript
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:
`typescript
// Get exactly 10 results
for await (const result of stream.take(10)) {
console.log(result.isSuccess())
}
`#### skipFailures() / skipSuccesses()
Filter results by success status:
`typescript
// 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:
`typescript
// 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:
`typescript
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:
`typescript
// 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:
`typescript
// 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)
}
`$3
Rolling statistics provided by
rollingStats():`typescript
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
}
`$3
Utility function to merge multiple async iterators:
`typescript
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()})
}
`$3
The result object uses discriminated unions for type safety. Use type guards to access specific properties:
#### Successful Results
`typescript
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
`typescript
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:
`typescript
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 ping
`#### IP Version Information
When IPv4 or IPv6 is explicitly set, the result includes the IP version:
`typescript
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) // undefined
`$3
`typescript
type PingErrorType
= | 'HostnameNotFound'
| 'HostUnreachable'
| 'PermissionDenied'
| 'Timeout'
| 'UnknownError'
`$3
Individual ping response lines with parsed timing information:
`typescript
line.getRawLine() // string - original ping output line
line.getTimeInMs() // number - parsed response time in milliseconds
line.toArray() // { line: string, time_in_ms: number }
`Examples
$3
`typescript
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)
}
`$3
`typescript
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()
`$3
`typescript
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()
`$3
`typescript
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()
`$3
`typescript
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()
`$3
`typescript
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()
`$3
`typescript
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()
`$3
`typescript
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()
`$3
`typescript
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})
}
`$3
`typescript
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)
})
}
`$3
`typescript
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
$3
- Uses -n instead of -c for ping count
- Uses -w (lowercase) for timeout in milliseconds
- Uses -l for packet size instead of -s
- Uses -i for TTL instead of -t
- Does not support custom intervals (handled by streaming interval timing)$3
- Uses milliseconds for timeout values (-W 5000)$3
- 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:
`typescript
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 = stream.take(5)
const stats: AsyncGenerator = stream.rollingStats(10)
const latencies: AsyncGenerator = stream
.filter(r => r.isSuccess())
.map(r => r.averageResponseTimeInMs())
}
`Development
$3
`bash
pnpm run build
`$3
`bash
pnpm test # Run all tests
pnpm run test:watch # Run tests in watch mode
pnpm run test:coverage # Run tests with coverage
`$3
`bash
pnpm run lint # Check for linting issues
pnpm run lint:fix # Fix linting issues automatically
`Requirements
- 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
$3
- AbortSignal Support: Added external cancellation control with standard AbortSignal API
- 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(), and streamBatched()
- Multiple Sources: Compatible with AbortController, AbortSignal.timeout(), or any AbortSignal
- 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$3
- 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 ping6 command 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() and setIPv6() 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$3
- IPv4/IPv6 Support: Full dual-stack networking support with platform-specific command handling
- New IP Version Methods: Added setIPVersion(4|6), setIPv4(), and setIPv6() for explicit IP version control
- Enhanced Results: Added ipVersion property to PingResult with IP version information
- Platform-Specific Commands:
- macOS: Uses ping for IPv4 and ping6 for IPv6
- Linux/Windows: Uses ping -4 for IPv4 and ping -6 for IPv6
- 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$3
- Enhanced Windows Support: Improved Windows compatibility with correct ping command arguments
- Platform-Specific Commands: Windows uses -n for count, -w for timeout, -l for packet size, -i for TTL
- Code Cleanup: Removed non-existent -O flag functionality
- Comprehensive Testing: Added dedicated Windows support tests with platform detection
- Updated Documentation: Clarified platform-specific ping command differences$3
- 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$3
- 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