npm package: @ideadesignmedia/watcher
Description: Filesystem event handler
Author: ideadesignmedia
Latest version: 1.0.6

# @ideadesignmedia/watcher

A lightweight, event-driven file and directory watcher built on top of [chokidar](https://github.com/paulmillr/chokidar), with buffered event queuing, rename detection, and TypeScript typings.

---

## Features

- **Simple setup**: Watch one or more paths with a single class.
- **Buffered events**: Debounced and queued `add`, `change`, and `unlink` events for reliable ordering.
- **Rename detection**: Automatically detects renames by matching file statistics.
- **Configurable**: Fine-tune polling, ignore patterns, atomic writes, and more.
- **TypeScript support**: Bundled `.d.ts` for type-safe development.

---

## Installation

```bash
npm install @ideadesignmedia/watcher chokidar
# or
yarn add @ideadesignmedia/watcher chokidar
```

> **Note:** `chokidar` is a peer dependency and must be installed separately.

---

## Quick Start

```js
const Watcher = require('@ideadesignmedia/watcher');

// Callback to handle file events:
function onFileEvent(eventName, { path, stats }, isRename) {
  console.log(`Event: ${eventName}`, path, stats, 'isRename:', isRename);
}

// Create a new watcher:
const watcher = new Watcher(
  ['./src', './assets'], // paths to watch
  onFileEvent,
  {
    ignored: ['**/*.tmp', 'node_modules'], // ignore patterns
    initialAdd: true,                     // emit add events for existing files on init
    persistent: true,                     // keep the process alive
    pollInterval: 1000,                   // interval for polling (ms)
    binaryInterval: 3000,                 // interval for binary files (ms)
    alwaysStat: true,                     // always stat files
    awaitWriteFinish: {                   // wait for write finish
      stabilityThreshold: 1000,
      pollInterval: 1500
    },
    ignorePermissionErrors: false,        // ignore EACCES errors
    atomic: 800                           // watch atomic writes
  }
);

// Dynamically add another path:
watcher.addPath('/var/logs');

// Manually refresh the folder/file list in console:
watcher.getFolders();

// Stop watching and clean up:
// watcher.close();
```

---

## API

### `new watcher(paths, FileEvent, options?)`

- **`paths`**: `string[]` — An array of file system paths (files or directories) to watch.
- **`FileEvent`**: `function` — A callback invoked for each queued event:
  ```ts
  type EventName = 'addFile' | 'addDir' | 'changeFile' | 'deleteFile' | 'deleteDir';
  type WatcherEvent = { path: string; stats?: Stats };
  (eventName: EventName, eventData: WatcherEvent, isRename: boolean) => void;
  ```
- **`options`**: `WatcherOptions` (all optional):
  ```ts
  interface WatcherOptions {
    ignored?: string[];                // glob or regex patterns to ignore
    initialAdd?: boolean;              // emit existing files as add events on ready
    persistent?: boolean;              // keep process alive after ready
    polling?: boolean;                 // use fs polling (defaults to true)
    pollInterval?: number;             // polling interval in ms (default: 1000)
    binaryInterval?: number;           // polling interval for binary files in ms (default: 3000)
    alwaysStat?: boolean;              // always stat files for change detection
    awaitWriteFinish?: boolean | {     // wait for write finish settings
      stabilityThreshold: number;
      pollInterval: number;
    };
    ignorePermissionErrors?: boolean;  // skip permission errors
    atomic?: number;                   // threshold for atomic writes
  }
  ```
### Methods

- **`addPath(path: string): void`**  
  Add a new path to the existing watcher at runtime.

- **`getFolders(): void`**  
  Refresh and log the list of watched folders and files. Useful for debugging.

- **`close(): void`**  
  Stops watching all paths and releases resources.

---

## Example: TypeScript

```ts
import Watcher, { Stats } from '@ideadesignmedia/watcher';

const watcher = new Watcher(
  ['logs'],
  (eventName, { path, stats }, isRename) => {
    console.log(eventName, path, stats?.size, isRename);
  },
  { initialAdd: true }
);
```

---

## Contributing

1. Fork the repository  
2. Create your feature branch (`git checkout -b feature/foo`)  
3. Commit your changes (`git commit -am 'Add some foo'`)  
4. Push to the branch (`git push origin feature/foo`)  
5. Open a pull request

---

## License

[MIT](LICENSE)