
Research
Security News
Malicious PyPI Package Exploits Deezer API for Coordinated Music Piracy
Socket researchers uncovered a malicious PyPI package exploiting Deezer’s API to enable coordinated music piracy through API abuse and C2 server control.
The file system watcher that strives for perfection, with no native dependencies and optional rename detection support.
The file system watcher that strives for perfection, with no native dependencies and optional rename detection support.
You are probably currently using one of the following alternatives for file system watching, here's how they compare against Watcher:
fs.watch
: Node's built-in fs.watch
function is essentially garbage and you never want to use it directly.
fs.watch
are completely useless as they tell you nothing about what actually happened in the file system, so you'll have to poll the file system on your own anyway.fs.watch
doesn't take care of, for example watching non-existent paths is just not supported and EMFILE errors are not handled.chokidar
: this is the most popular file system watcher available, while it may be good enough in some cases it's not perfect.
ignore
option.chokidar
before).node-watch
: in some ways this library is similar to Watcher, but much less mature.
nsfw
: this is a lesser known but pretty good watcher, although it comes with some major drawbacks.
perfection
": if there was a "perfect" file system watcher, it would compare like this against Watcher (i.e. this is pretty much what's currently missing in Watcher):
npm install --save watcher
The following options are provided, you can use them to customize watching to your needs:
debounce
: amount of milliseconds to debounce event emission for.
300
.depth
: maximum depth to watch files at.
20
.ignore
: optional function that if returns true
for a path it will cause that path and all its descendants to not be watched at all.
ignore
function can be very important for performance, you should probably ignore folders like .git
and temporary files like those used when writing atomically to disk.ignore
against a glob with a globbing library of your choosing.ignoreInitial
: whether events for the initial scan should be ignored or not.
false
, so initial events are emitted.native
: whether to use the native recursive watcher if available and needed.
true
.depth
option is ignored.false
can have a positive performance impact if you want to watch recursively a potentially very deep directory with a low depth
value.persistent
: whether to keep the Node process running as long as the watcher is not closed.
false
.pollingInterval
: polling is used as a last resort measure when watching non-existent paths inside non-existent directories, this controls how often polling is performed, in milliseconds.
3000
.pollingTimeout
: sometimes polling will fail, for example if there are too many file descriptors currently open, usually eventually polling will succeed after a few tries though, this controls the amount of milliseconds the library should keep retrying for.
20000
.recursive
: whether to watch recursively or not.
false
.renameDetection
: whether the library should attempt to detect renames and emit rename
/renameDir
events.
false
.add
/addDir
and unlink
/unlinkDir
events will be emitted instead after a rename.add
/unlink
or addDir
/unlinkDir
events are actually rename
or renameDir
events respectively, so it will wait for both of those events to be emitted.renameTimeout
: amount of milliseconds to wait for a potential rename
/renameDir
event to be detected.
1250
.add
/addDir
/unlink
/unlinkDir
events.Watcher returns an EventEmitter
instance, so all the methods inherited from that are supported, and the API is largely event-driven.
The following events are emitted:
error
: Emitted whenever an error occurs.ready
: Emitted after the Watcher has finished instantiating itself. No events are emitted before this events, expect potentially for the error
event.close
: Emitted when the watcher gets explicitly closed and all its watching operations are stopped. No further events will be emitted after this event.all
: Emitted right before a file system event is about to get emitted.add
: Emitted when a new file is added.addDir
: Emitted when a new directory is added.change
: Emitted when an existing file gets changed, maybe its content changed, maybe its metadata changed.rename
: Emitted when a file gets renamed. This is only emitted when renameDetection
is enabled.renameDir
: Emitted when a directory gets renamed. This is only emitted when renameDetection
is enabled.unlink
: Emitted when a file gets removed from the watched tree.unlinkDir
: Emitted when a directory gets removed from the watched tree.Basically it you have used chokidar
in the past Watcher emits pretty much the same exact events, except that it can also emit rename
/renameDir
events, it doesn't provide stats
objects but only paths, and in general it exposes a similar API surface, so switching from (or to) chokidar
should be easy.
The following interface is provided:
type Roots = string[] | string;
type TargetEvent = 'add' | 'addDir' | 'change' | 'rename' | 'renameDir' | 'unlink' | 'unlinkDir';
type WatcherEvent = 'all' | 'close' | 'error' | 'ready';
type Event = TargetEvent | WatcherEvent;
type Options = {
debounce?: number,
depth?: number,
ignore?: ( targetPath: Path ) => boolean,
ignoreInitial?: boolean,
native?: boolean,
persistent?: boolean,
pollingInterval?: number,
pollingTimeout?: number,
recursive?: boolean,
renameDetection?: boolean,
renameTimeout?: number
};
class Watcher {
constructor ( roots: Roots, options?: Options, handler?: Handler ): this;
on ( event: Event, handler: Function ): this;
close (): void;
}
You would use the library like this:
import Watcher from 'watcher';
// Watching a single path
const watcher = new Watcher ( '/foo/bar' );
// Watching multiple paths
const watcher = new Watcher ( ['/foo/bar', '/baz/qux'] );
// Passing some options
const watcher = new Watcher ( '/foo/bar', { renameDetection: true } );
// Passing an "all" handler directly
const watcher = new Watcher ( '/foo/bar', {}, ( event, targetPath, targetPathNext ) => {} );
// Attaching the "all" handler manually
const watcher = new Watcher ( '/foo/bar' );
watcher.on ( 'all', ( event, targetPath, targetPathNext ) => { // This is what the library does internally when you pass it a handler directly
console.log ( event ); // => could be any target event: 'add', 'addDir', 'change', 'rename', 'renameDir', 'unlink' or 'unlinkDir'
console.log ( targetPath ); // => the file system path where the event took place, this is always provided
console.log ( targetPathNext ); // => the file system path "targetPath" got renamed to, this is only provided on 'rename'/'renameDir' events
});
// Listening to individual events manually
const watcher = new Watcher ( '/foo/bar' );
watcher.on ( 'error', error => {
console.log ( error instanceof Error ); // => true, "Error" instances are always provided on "error"
});
watcher.on ( 'ready', () => {
// The app just finished instantiation and may soon emit some events
});
watcher.on ( 'close', () => {
// The app just stopped watching and will not emit any further events
});
watcher.on ( 'all', ( event, targetPath, targetPathNext ) => {
console.log ( event ); // => could be any target event: 'add', 'addDir', 'change', 'rename', 'renameDir', 'unlink' or 'unlinkDir'
console.log ( targetPath ); // => the file system path where the event took place, this is always provided
console.log ( targetPathNext ); // => the file system path "targetPath" got renamed to, this is only provided on 'rename'/'renameDir' events
});
watcher.on ( 'add', filePath => {
console.log ( filePath ); // "filePath" just got created, or discovered by the watcher if this is an initial event
});
watcher.on ( 'addDir', directoryPath => {
console.log ( filePath ); // "directoryPath" just got created, or discovered by the watcher if this is an initial event
});
watcher.on ( 'change', filePath => {
console.log ( filePath ); // "filePath" just got modified
});
watcher.on ( 'rename', ( filePath, filePathNext ) => {
console.log ( filePath, filePathNext ); // "filePath" got renamed to "filePathNext"
});
watcher.on ( 'renameDir', ( directoryPath, directoryPathNext ) => {
console.log ( directoryPath, directoryPathNext ); // "directoryPath" got renamed to "directoryPathNext"
});
watcher.on ( 'unlink', filePath => {
console.log ( filePath ); // "filePath" got deleted, or at least moved outside the watched tree
});
watcher.on ( 'unlinkDir', directoryPath => {
console.log ( directoryPath ); // "directoryPath" got deleted, or at least moved outside the watched tree
});
// Closing the watcher once you are done with it
watcher.close ();
// Updating watched roots by closing a watcher and opening an updated one
watcher.close ();
watcher = new Watcher ( /* Updated options... */ );
atomically
: if you need to read and write files reliably do yourself a favor and use this library. Watcher internally uses this library for polling reliably the file system, so if you are using Watcher already using atomically
too would add 0 extra weight to your bundles.chokidar
: for providing me a largely good-enough file system watcher for a long time.node-watch
: for providing a good base from with to make Watcher, and providing some good ideas for how to write good tests for it.MIT © Fabio Spampinato
FAQs
The file system watcher that strives for perfection, with no native dependencies and optional rename detection support.
The npm package watcher receives a total of 12,675 weekly downloads. As such, watcher popularity was classified as popular.
We found that watcher demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncovered a malicious PyPI package exploiting Deezer’s API to enable coordinated music piracy through API abuse and C2 server control.
Research
The Socket Research Team discovered a malicious npm package, '@ton-wallet/create', stealing cryptocurrency wallet keys from developers and users in the TON ecosystem.
Security News
Newly introduced telemetry in devenv 1.4 sparked a backlash over privacy concerns, leading to the removal of its AI-powered feature after strong community pushback.