Repository navigation
Description
Have you used AI?
No
Bug Description
When Watchpack is initialized with startTime: Date.now(), it fires the change event for directories / files that were created shortly before.
When startTime is not set, the change event is not fired as desired (fixed with test coverage in #150).
README.md documents startTime as being an optional number, and "Watching can be started in the past. This way watching can start after file reading.". The observed behavior of getting unwanted events is surprising.
Moreover, the source shows that FS_ACCURACY (up to two seconds!) is added to the start time. Any file/directory older than this time will be flagged as changed. This is not documented and surprising (and contributing to this bug):
watchpack/lib/DirectoryWatcher.js
Line 430 in 59adaaa
| const safeTime = initial ? Math.min(now, birthtime) + FS_ACCURACY : now; |
The above source also shows the use of birthtime/btime instead of ctime. This is surprising and not documented in README.
I tried using fs.utimes with a past date as a work-around. This works on macOS but failed on Linux and Windows, because fs.utimes updates mtime but not btime. The use of btime appears to be introduced in #183. The work-around works in [email protected] (which is before 2.1.0 that includes #183).
Link to Minimal Reproduction and step to reproduce
npm install watchpack ( tested with latest version [email protected] and Node 25.9.0)
Save following file as test.mjs and run node test.mjs:
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import Watchpack from "watchpack";
const base = path.join(os.tmpdir(), "watchpack_repro");
await fs.rm(base, { recursive: true }).catch(() => {}); // ignore ENOENT
await fs.mkdir(base);
await fs.mkdir(path.join(base, "subdir"));
const dateInPast = Date.now() / 1000 - 10; // 10 seconds older should be plenty
// await fs.utimes(path.join(base, 'subdir'), dateInPast, dateInPast);
// ^ Works on macOS (changes btime), not on Linux or Windows. Also works in watchpack<=2.0.1
const w = new Watchpack({});
w.on("change", console.log);
w.watch({
directories: [base],
missing: [],
startTime: Date.now(),
});
console.log("Waiting 2 seconds. Should not log anything.");
await new Promise(r => setTimeout(r, 2000));
w.close();Expected Behavior
Should not log change events for files/directories that were created shortly before Watchpack is initialized.
Actual Behavior
Logs a change event for the subdirectory that was created immediately before:
/tmp/watchpack_repro/subdir 1777218474762 scan (dir)
(the minimal STR uses a directory, but this also reproduces for files)
Environment
Node: v25.9.0 (and also tested v20.20.2)
Linux: Ubuntu 24.04.4 LTS
macOS: 15.7.5Is this a regression?
No
Last Working Version
No response
Additional Context
The fs.utimes work-around to get the test to pass works on macOS because it apparently changes the btime as well:
$ mkdir d;node -e 'require("fs/promises").utimes("d", 1234, 5678)';stat -x d
...
Access: Thu Jan 1 01:20:34 1970
Modify: Thu Jan 1 02:34:38 1970
Change: Sun Apr 26 18:19:50 2026
Birth: Thu Jan 1 02:34:38 1970
On Linux, the Birth time is not modified when I run the same command.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Activity
chore: bump #295 changeset to major and document the breaking behavio…
chore: revert #295 changeset to patch