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

@d1g1tal/watchr

v1.0.0

Published

A native NodeJS file system watcher with optional rename detection support. Forked from github:fabiospampinato/watcher

Readme

Watchr

npm version License: MIT Node.js Version TypeScript Tests Coverage Status

⚠️ Important Notice: This is a personal fork of Watcher by Fabio Spampinato, modified to fit specific personal needs and experimentation. Most users should use the original Watcher library instead, which is actively maintained, battle-tested, and feature-complete.

A modern, TypeScript-first file system watcher built on Node.js native APIs.

Features

  • Native Performance: Built on Node.js native fs.watch with recursive watching support (Node.js 20.16+)
  • TypeScript First: Written entirely in TypeScript with comprehensive type definitions
  • Event-Driven Architecture: Clean, EventEmitter-based API for handling file system events
  • Rename Detection: Optional detection of file and directory renames with configurable timeouts
  • Abort Signal Support: Built-in AbortController integration for clean cancellation
  • File Statistics: Includes file stats with all events for enhanced metadata access
  • Debouncing: Configurable event debouncing to reduce noise from rapid file changes
  • Cross-Platform: Works reliably on macOS?, Windows??, and Linux! (Honestly haven't tested much on Windows and I don't own a Mac. Please report any issues if you find platform-specific bugs)
  • Zero Native Dependencies: Pure TypeScript implementation with no native binaries

Installation

// pnpm 🎉
pnpm add @d1g1tal/watchr

// npm 🤷🏽‍♂️
npm install @d1g1tal/watchr

Quick Start

import { Watchr } from 'watchr';

// Watch a single directory
const watcher = new Watchr('/path/to/watch');

// Listen for all events
watcher.on('all', (event, stats, targetPath, targetPathNext) => {
  console.log(`${event}: ${targetPath}`);
});

// Listen for specific events
watcher.on('add', (stats, filePath) => {
  console.log(`File added: ${filePath}`);
});

watcher.on('change', (stats, filePath) => {
  console.log(`File changed: ${filePath}`);
});

// Close when done
watcher.close();

Configuration Options

Watchr accepts the following options to customize behavior:

  • persistent: Whether to keep the Node.js process running while watching

    • Default: false
    • When true, prevents the process from exiting while the watcher is active
  • recursive: Enable recursive watching of subdirectories

    • Default: false
    • Uses native recursive watching when available (Node.js 20.16+)
  • encoding: Character encoding for file paths

    • Default: 'utf8'
    • Supports any Node.js BufferEncoding
  • debounce: Debounce delay in milliseconds for event emission

    • Default: 100ms
    • Higher values reduce duplicate events but increase latency
  • ignore: Function to filter out unwanted paths

    • Type: (targetPath: string) => boolean
    • Return true to ignore the path and its children
  • ignoreInitial: Skip initial scan events when starting to watch

    • Default: false
    • When true, only new changes after watching starts will emit events
  • renameTimeout: Timeout in milliseconds for rename detection

    • Default: 250ms
    • How long to wait to detect if separate add/unlink events are actually a rename

Events

Watchr extends Node.js EventEmitter and emits the following events:

Watcher Events

  • ready: Emitted when the watcher has finished initialization
  • close: Emitted when the watcher is closed and all operations stopped
  • error: Emitted when an error occurs
  • all: Emitted before every file system event with (event, stats, targetPath, targetPathNext?)

File System Events

  • add: New file added - (stats, filePath)
  • addDir: New directory added - (stats, directoryPath)
  • change: File content or metadata changed - (stats, filePath)
  • rename: File renamed - (stats, oldPath, newPath)
  • renameDir: Directory renamed - (stats, oldPath, newPath)
  • unlink: File removed - (stats, filePath)
  • unlinkDir: Directory removed - (stats, directoryPath)

All file system events include a WatchrStats object containing file metadata.

API Reference

Constructor

new Watchr(target?: string | string[], options?: WatchrOptions, handler?: Handler)
  • target: Path(s) to watch (file or directory)
  • options: Configuration options (see Configuration Options above)
  • handler: Optional handler for the all event

Public Methods

// Check if the watcher is closed
isClosed(): boolean

// Check if the watcher is ready
isReady(): boolean

// Close the watcher and stop all watching
close(): void

// Check if a path should be ignored
isIgnored(targetPath: string, ignore?: Ignore): boolean

// Access the abort signal for cancellation
get abortSignal(): AbortSignal

// Get a promise that resolves when ready
get readyLock(): Promise<void>

// Access file rename handler
get renameWatchr(): FileRenameHandler

Type Definitions

type WatchrOptions = {
  persistent?: boolean;
  recursive?: boolean;
  encoding?: BufferEncoding;
  debounce?: number;
  ignore?: (targetPath: string) => boolean;
  ignoreInitial?: boolean;
  renameTimeout?: number;
};

type Handler = (
  event: FileSystemEvent,
  stats: WatchrStats,
  targetPath: string,
  targetPathNext?: string
) => void;

type FileSystemEvent =
  | 'add' | 'addDir' | 'change'
  | 'rename' | 'renameDir'
  | 'unlink' | 'unlinkDir';

Usage Examples

Basic File Watching

import { Watchr } from 'watchr';

// Watch a single directory
const watcher = new Watchr('/path/to/watch', { recursive: true });

watcher.on(Watchr.Event.READY, () => {
  console.log('Watcher is ready');
});

watcher.on(Watchr.FileEvent.ADD, (stats, filePath) => {
  console.log(`File added: ${filePath}`);
  console.log(`Size: ${stats.size} bytes`);
});

watcher.on(Watchr.FileEvent.CHANGE, (stats, filePath) => {
  console.log(`File changed: ${filePath}`);
});

watcher.on(Watchr.FileEvent.UNLINK, (stats, filePath) => {
  console.log(`File deleted: ${filePath}`);
});

Watching Multiple Paths

const fileItems = [ '/path/to/src', '/path/to/config', '/path/to/package.json' ];
const watcher = new Watchr(fileItems, { recursive: true, ignore: (path) => path.includes('node_modules') });

Using the Universal Handler

const watcher = new Watchr('/path/to/watch', {}, (event, stats, targetPath, targetPathNext) => {
  switch (event) {
    case Watchr.FileEvent.ADD: {
      console.log(`Added: ${targetPath}`);
      break;
    }
    case Watchr.FileEvent.RENAME: {
      console.log(`Renamed: ${targetPath} -> ${targetPathNext}`);
      break;
    }
    case Watchr.FileEvent.UNLINK: {
      console.log(`Removed: ${targetPath}`);
      break;
    }
  }
});

Advanced Configuration

const watcher = new Watchr('/project', {
  recursive: true,
  debounce: 200,
  ignoreInitial: true,
  ignore: (path) => {
    // Ignore common development artifacts
    return path.includes('node_modules') ||
           path.includes('.git') ||
           path.endsWith('.tmp');
  }
});

// Listen for all events
watcher.on('all', (event, stats, targetPath, targetPathNext) => {
  console.log(`Event: ${event}, Path: ${targetPath}`);
  if (targetPathNext) {
    console.log(`New path: ${targetPathNext}`);
  }
});

// Handle errors
watcher.on('error', (error) => {
  console.error('Watcher error:', error);
});

// Clean shutdown
process.on('SIGINT', () => {
  watcher.close();
  process.exit(0);
});

With AbortController Integration

const watcher = new Watchr('/path/to/watch');

// Use the built-in abort signal
const { abortSignal } = watcher;

abortSignal.addEventListener('abort', () => {
  console.log('Watcher was aborted');
});

// Close the watcher (triggers abort)
setTimeout(() => watcher.close(), 10000);

Requirements

  • Node.js 20.16.0 or higher
  • TypeScript 6.0.0 or higher (for TypeScript projects)

Why Use the Original Watcher Instead?

The original Watcher by Fabio Spampinato is:

  • Production-ready with extensive real-world usage and testing
  • Actively maintained with regular updates and bug fixes
  • Well-documented with comprehensive examples and API documentation
  • Battle-tested across many projects and platforms
  • Feature-complete with robust edge case handling

This fork was created for personal experimentation with alternative architectural approaches (like inode-based rename detection patterns and event flow redesigns) and should be considered experimental. Unless you have specific needs that align with these experimental features, you'll be better served by the original library.

Additional Acknowledgments

  • chokidar - Popular file watcher that helped shape API design decisions
  • node-watch - Minimalist watcher implementation for reference

License

MIT © D1g1talEntr0py