Changelog
All notable changes to this project will be documented in this file. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
4.0.0 (2026-06-30)
Section titled “4.0.0 (2026-06-30)”A 2026 modernization of TaskTimer — ESM-only, zero-dependency, browser-safe, strongly typed — with some new sugar (lead, task.data, typed events, coded errors, silentErrors). The scheduling model is the same; the surface around it is cleaner and more honest. See the migration notes below.
leadtask option — run a task once immediately when the timer starts (the leading edge), in addition to its normal tick schedule, instead of waiting a full interval. A futurestartDatestill defers it. Fixes #41.task.data— attach arbitrary user data to a task, available in the callback and event listeners.Taskis now generic (Task<TData>); type it viatimer.get<MyType>(id). Fixes the ergonomics behind #43.timer.tasks— a getter returning all tasks in insertion order (timer.tasks.map(t => t.id)for every id). Fixes #40.silentErrorstimer option (defaulttrue) — whenfalse, a task error with notaskErrorlistener is surfaced (re-thrown on the next turn) instead of swallowed; the timer keeps running either way.TaskTimerError+ErrorCode— every error the library throws is now aTaskTimerErrorcarrying a stable, machine-readablecode(and acause), so failures can be branched on without matching the message.
Changed
Section titled “Changed”- Breaking — ESM-only (
"type": "module"); no CommonJS entry.import { TaskTimer } from 'tasktimer'. Still runs in the browser via native ESM / a bundler. See the ESM notice. - Breaking — minimum Node.js is now 22.
- Breaking — no more
TaskTimernamespace.Event,State,Task(and the newTaskTimerError,ErrorCode) are named exports:import { TaskTimer, Event, State } from 'tasktimer'.TaskTimer.Event.TICK→Event.TICK. - Breaking — event payload redesigned to
{ name, timer, task, error }(was{ name, source, data }). The related task is alwaysevent.taskand the timer alwaysevent.timer— consistently, including ontaskError. Listeners are now typed (you get anITaskTimerEvent, notany). - Breaking — task option
immediaterenamed todefer— it defers the callback to the next event-loop turn (viasetImmediate); the old name read as the opposite. - Breaking —
timer.get(id)returnsTask | undefined(was typedTask, returnednull), mirroringMap.get. - Zero runtime dependencies —
eventemitter3replaced by a small built-in, typedEventEmitter(sameon/once/off/emitsurface). - Precision now uses the monotonic
performance.now()in every environment (Node and browser), so browser precision is no longer subject to wall-clock drift. - Types compile against TypeScript 6 and ship with declaration maps.
- Task
time.elapsedwas negative while a task was running (stopped - startedwithstoppedstill0); it now counts up live and freezes on completion, mirroring the timer’stime. Fixes #12. - Invalid option values (
NaN/Infinity) no longer slip through: aNaNinterval no longer busy-loops and aNaN/InfinitytickInterval/totalRunsno longer makes a task silently never run — they fall back to their defaults. - A task that throws every run now honors
totalRunsinstead of running forever — an errored run counts toward completion. - Calling
start()from within a tick no longer leaves a second tick chain running (double-speed ticks). - The browser fallback for
setImmediatedefers correctly viasetTimeout(…, 0).
Removed
Section titled “Removed”- Breaking — the bundled UMD
<script>build (tasktimer.min.js). Bundle TaskTimer with your app (Vite, esbuild, Rollup, webpack …) for browser use.
Docs / Tooling
Section titled “Docs / Tooling”- New documentation site at onury.io/tasktimer; rewritten README and example-rich TSDoc across the public API.
- Build is a plain
tscemit tolib/. Adopted Biome (lint + format), Vitest (100% coverage, all four metrics), and Stryker mutation testing (100%); CI on GitHub Actions (Node 22, 24).
Migrating from 3.x
Section titled “Migrating from 3.x”import TaskTimer from 'tasktimer'→import { TaskTimer } from 'tasktimer'; named exports forEvent/State/Task.TaskTimer.Event.TICK→Event.TICK;TaskTimer.State.RUNNING→State.RUNNING.- In event listeners:
event.data→event.task,event.source→event.timer(useevent.taskfor the task ontaskError). - Task option
immediate: true→defer: true. timer.get(id)now returnsundefined(notnull) when absent.- Errors thrown by the library are
TaskTimerError(stillinstanceof Error); branch onerr.codeif you handle them.
3.0.0 (2019-08-02)
Section titled “3.0.0 (2019-08-02)”Changed
Section titled “Changed”- Breaking: TypeScript type definitions now require TypeScript 3.
- Updated dependencies to their latest versions.
- An issue where
timer#time.elapsedwas a timestamp when idle but a timespan when running. Fixes #11.
2.0.1 (2019-01-21)
Section titled “2.0.1 (2019-01-21)”This release includes various breaking changes. Please see the API reference. Also note that this version is completely re-written in TypeScript.
Changed
Section titled “Changed”- Breaking:
TaskTimeris no longer a default export. See Usage section in readme. - Breaking:
TaskTimer#addTask()renamed toTaskTimer#add(). This no longer accepts astringargument. It should either be an options object, aTaskinstance or a callback function. It also accepts an array of these, to add multiple tasks at once. - Breaking:
Task#namerenamed toTask#id. - Breaking: The task ID is optional (auto-generated when omitted) when task is created via
#add(). Butcallbackis now required. - Breaking:
TaskTimer#removeTask()renamed toTaskTimer#remove(). - Breaking:
TaskTimer#getTask()renamed toTaskTimer#get(). - Breaking:
TaskTimer.Stateenumeration type is changed tostring. (meaning enum values are also changed.)
- Timer option:
precision: booleanindicating whether the timer should auto-adjust the delay between ticks if it’s off due to task loads or clock drifts. See more info in readme. Default:true - Timer option:
stopOnCompleted: booleanindicating whether to automatically stop the timer when all tasks are completed. For this to take affect, all added tasks should havetotalRunsand/orstopDateconfigured. Default:false - Support for async tasks. Use
callback(task: Task, done: Function)signature. Either return a promise or calldone()argument within the callback; when the task is done. - Task option:
enabled: booleanindicating whether the task is currently enabled. This essentially gives you a manual control over execution. The task will always bypass the callback while this is set tofalse. - Task option:
tickDelay: numberto specify a number of ticks to allow before running the task for the first time. - Task option:
removeOnCompleted: numberindicating whether to remove the task (to free up memory) when task has completed its executions (runs). For this to take affect, the task should havetotalRunsand/orstopDateconfigured. Default:false - Event:
TaskTimer.Event.TASK_COMPLETED("taskCompleted") Emitted when a task has completed all of its executions (runs) or reached its stopping date/time (if set). Note that this event will only be fired if the tasks has atotalRunslimit or astopDatevalue set. - Event:
TaskTimer.Event.COMPLETED("completed") Emitted when all tasks have completed all of their executions (runs) or reached their stopping date/time (if set). Note that this event will only be fired if each task either have atotalRunslimit or astopDatevalue set, or both. - Event:
TaskTimer.Event.TASK_ERROR("taskError") Catches and emits errors produced (if any) on a task execution. Task#timegetter that returns an object{ started, stopped, elapsed }defining the life-time of a task.TaskTimer#runCount: booleanindicating the total number of timer runs, including resumed runs.TaskTimer#taskRunCount: booleanindicating the total number of all task executions (runs).- TypeScript support.
- An issue where default task options would not be set in some cases. Fixes issue #5.
- An issue where webpack would mock or polyfill Node globals unnecessarily. (v2.0.1 patch)
Removed
Section titled “Removed”- Breaking:
TaskTimer#resetTask()is removed. Use#get(name).reset()to reset a task. - Dropped bower. Please use npm to install.
- (Dev) Removed grunt in favour of npm scripts. Using jest instead of jasmine-core for tests.
1.0.0 (2016-08-16)
Section titled “1.0.0 (2016-08-16)”- Initial release.