npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ts-ping

v1.5.0

Published

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

Readme

ts-ping

npm version CI codecov TypeScript License: MIT

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 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

Installation

# Using pnpm (recommended)
pnpm add ts-ping

# Using npm
npm install ts-ping

# Using yarn
yarn add ts-ping

Quick 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 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:

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.

// 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-detection

Platform 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:

// 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 any AbortSignal
  • All methods supported: Works with runAsync(), stream(), streamWithFilter(), and streamBatched()

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 ping

IP 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) // undefined

Error 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 -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)

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 build

Testing

pnpm test                # Run all tests
pnpm run test:watch      # Run tests in watch mode
pnpm run test:coverage   # Run tests with coverage

Linting

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

v1.5.0 (2025-08-06)

  • 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

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 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

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(), 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

v1.2.0 (2025-07-28)

  • 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

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