An awaitable stopwatch/timer with cancellation, handler execution, reset/refresh, and remaining-time inspection.
npm install --save 'git+ssh://git@github.com/MatrixAI/js-timer.git#v3.0.0'import { Timer } from '@matrixai/timer';
const timer = new Timer({
delay: 100,
handler: (signal) => (signal.aborted ? 'cancelled' : 'done'),
});
const remaining = timer.getTimeout();
timer.refresh();
const result = await timer;The existing positional constructor is also supported. Cancellation rejects the timer with the supplied reason; lazy cancellation waits for a running handler. Custom controllers retain their existing cancellation policy. Infinite delays remain pending until cancelled or reset to a finite delay. Reset and refresh reject changes after the timer starts settling or settles.
Timer source uses the global Performance API when usable, with a synchronous wall-clock fallback for missing, incomplete, restricted, non-finite, or out-of-range clocks. Construction, remaining-time reads, and reset/refresh all use the same internal clock. There are no Node builtin imports in timer source, no asynchronous clock initialization, and no separate runtime-specific builds.
Timestamps and deadlines are epoch milliseconds, not raw relative performance readings. Clock readings are weakly nondecreasing within one loaded clock module instance. Millisecond precision permits equality. A backwards wall-clock change can pause the estimated countdown until the clock catches up. This is not a cross-worker/process clock, a unique ID, or a promise of accurate elapsed time when falling back to a wall clock. A shorter reset delay may move a deadline earlier; the creation timestamp does not change.
Scheduling still uses the host's native timeouts/intervals. Browser numeric handles and Node timer objects do not require separate implementations. Host scheduling delays, throttling, suspension, and clock precision remain outside the timer's control. Pending timers keep the Node event loop alive like native timers. Remaining time becomes zero once settling begins, even if a handler has not completed.
Timer 3.0.0 selects the released errors 3.0.0 Git tag over SSH. Its lockfile pins the exact producer revision, and Nix consumes that revision's prepared archive. Neither an unpublished checkout nor a Node clock alias is used. These releases are Git-only; an npm registry install without the Git URL selects an older registry release instead. The named browser check exercises the full packed dependency graph in document and dedicated-worker realms.
Use Node.js 24 or newer. The flake provides integrated
flake-parts/devenv and direnv activation. Review the configuration and
run direnv allow .. The prepared-dependency npm adapter serializes
installation and restores canonical manifests after install-only source
overrides. Activation does not load credentials or change persistent shell
options. Once activated, run project commands directly.
git submodule update --init --depth 1
nix run './.matrixai/matrixai-standards#skills-materializer' -- --standards-root ./.matrixai/matrixai-standards
npm run lintfix
npm run build
npm run typecheck
npm test -- --runInBand
npm run check:package
npm run check:portable
npm run checkTests compile first and use Jest/SWC in ESM mode against emitted modules.
Arguments pass through npm test. JUnit is written under tmp/junit; optional
V8/Cobertura coverage is produced with npm test -- --runInBand --coverage. Use
npm run lintfix for active development and npm run lint for non-mutating
verification. Documentation is handwritten at the repository root; there is no
TypeDoc dependency, generated documentation directory, or installer test suite.
MatrixAI lint comes from the selected public nixpkgs-matrixai package set, not
an npm dependency or a direct js-lint flake input. One configured tool
environment is shared by the development shell, flake formatter, and independent
hermetic lint check. The bundled CLI owns configuration; TypeScript remains a
consumer development dependency. The packaged-consumer type fixture is compiled
independently by npm run check:package, not against the main lint TypeScript
project.
nix fmt
npm run lintfix
npm run lint
nix build '.#checks.x86_64-linux.lint'The first two commands share the formatting authority across applicable domains, including TypeScript, Markdown, shell, and Nix. The last two are non-mutating verification; the Nix lint gate works without an activated development shell.
nix build '.#npm-package'
nix build '.#npm-package-unpacked'
nix build '.#checks.x86_64-linux.default'
nix build '.#checks.x86_64-linux.runtime'The default package and npm-package are the archive file itself. The unpacked
output contains the exact package contents at its root. Compiled ESM,
declarations, source maps, canonical metadata, README, and license are included;
dependencies, Node, and Nix paths are not bundled into the package metadata.
Source and packed manifests preserve dependency declarations and lifecycle
scripts verbatim.
Schema-v1 package/distribution descriptors expose manifest metadata and honest source provenance. Errors is advertised as a selected direct runtime provider; its archive is selected from its exact locked Git revision and validated against its descriptors. Lint is supplied separately by the package set. Other registry dependencies retain their integrity-pinned tarballs. Hermetic installs use importNpmLock with the matching Node installation hook.
The check layout follows the container repository:
routine verify and independent lint gates compose default, separate from
integration-browser and its runtime aggregate. Checks call the same npm
scripts without depending on the active development shell. Successful outputs
retain report.json and artifacts.
npm run check:package inspects a packed consumer reconstructed from the
lockfile-installed runtime dependency tree; it does not test npm installation.
npm run check:portable rejects Node builtins in timer source and reports
transitive builtins separately. It is not a browser execution claim.
npm run test:browser attempts a real packed-package Chromium document and
dedicated-worker run without aliases.
See verification evidence for executed results. Consumer updates require a new authorized release/tag. Git-only releases do not publish to npm; the obsolete tag-triggered npm publisher is removed.