Changelog
All notable changes to the Timekeeper Countdown packages are documented here.
The format is based on Keep a Changelog, and these packages adhere to Semantic Versioning. Both packages are versioned in lockstep and always share one version.
@timekeeper-countdown/core
[Unreleased]
[0.3.2] - 2026-07-11
Changed
- Internal refactor only — no public API or behavior change. The
CountdownSnapshottype moved to its own leaf module (still exported from the package root with an identical shape); the three repeated time-validation guards in the safe time provider were consolidated into one helper (restoring aMAX_SAFE_INTEGERupper bound the fallback path had dropped — internal and unreachable in practice); and the publishedbuildSnapshottesting helper now delegates to the engine's canonical implementation, so the test double can no longer drift from production.
[0.3.1] - 2026-06-27
Fixed
- Lowered the published
engines.nodefloor from>=22to>=18. The shippeddisttargets es2022 and uses no Node-22-only API, so the previous floor needlessly warned (or, underengine-strict, blocked) installs on Node 18/20. Building and testing the library still require Node 22 (declared only at the private workspace root).
[0.3.0] - 2026-06-27
Changed
- Single-emit per transition (behavior change): each state transition (
start/pause/resume/stopand natural completion) now emits exactly one snapshot; redundant emissions were removed. Consumers relying on the previous (larger) number ofonSnapshot/onStateChangecallbacks per transition must update. - The unit breakdown (
years/weeks/days/…, the standaloneformatDays/formatWeeks/formatYears, andgetDays/getWeeks/getYears) is now computed by a single lossless successive-subtraction ladder (year = 365 days, week = 7 days), so the parts always reconstruct the total. Behavior change: values around the 52-week / 365-day boundaries are now corrected — e.g. 364 days no longer renders as all-zero. CountdownEngine.setSeconds(n)now validates its argument like the constructor andreset(n): it throws on a negative / non-finite / non-integer / out-of-range value instead of silently coercing it. Valid values behave as before.buildSnapshotnow sanitizes bothinitialSecondsandtotalSeconds(non-finite/negative → 0, floored, capped atMAX_SAFE_INTEGER) and derivesisCompletedfrom the clamped total, so every snapshot is self-consistent. Behavior change: callers that previously read back a raw/oversized/non-integerinitialSecondsnow receive the clamped value.- A single canonical
decompose()is now shared by the engine, the formatters, and the published testing utilities (removing three divergent copies). - Raised the minimum supported Node to
>=22(was>=18), declared via theenginesfield, so installing on older Node emits a warning or fails underengine-strict.
Fixed
- A hostile
timeProvidercan no longer corrupt the countdown. Every provider (default or caller-supplied) is wrapped in a monotonic, finite-enforcing guard, so aNaN/Infinity/backward clock reading (NTP/DST/sleep-wake, or a buggy custom provider) is repaired to the last good value instead of producing aNaNsnapshot, a runaway timer that never completes, a countdown that counts up, or a spurious instant completion. The interval also clamps remaining time to[0, initialValue]. - A non-finite or non-positive
tickIntervalMsnow falls back to the 100 ms default instead of reachingsetIntervalasNaN/Infinity(which degenerated into a ~0 ms CPU tight-loop).
[0.2.0] - 2026-03-03
Changed
- Renamed
onUpdatetoonSnapshot, added anonErrorcallback, and exported theCountdownfaçade. - Added function overloads to all format helpers for better TypeScript DX.
- Removed redundant
try-catchin thesafeFormatandsafeExecutewrappers.
[0.1.4] - 2026-02-17
Added
- Dual CJS+ESM build output for Jest and CJS-consumer compatibility.
[0.1.3] - 2026-02-17
Changed
- Synced core and react package versions.
[0.1.2] - 2026-02-17
Fixed
formatMinutesnow returns the decomposed value (0–59) instead of total minutes.
[0.1.1] - 2025-10-07
Added
- Comprehensive README documentation for the core and react packages.
[0.1.0] - 2025-10-07
Added
- Initial core package for the 0.1.0 React-first release.
@timekeeper-countdown/react
[Unreleased]
[0.3.2] - 2026-07-11
Changed
- Lockstep release with
@timekeeper-countdown/core0.3.2 (internal refactor only — no changes to theuseCountdownhook). Bumps the@timekeeper-countdown/coredependency to^0.3.2.
[0.3.1] - 2026-06-27
Fixed
- Lowered the published
engines.nodefloor from>=22to>=18(the hook adds no Node-22 requirement of its own). Building and testing the library still require Node 22 (declared only at the private workspace root).
[0.3.0] - 2026-06-27
Changed
- The
useCountdownhook inherits the engine hardening (see@timekeeper-countdown/core0.3.0): a hostiletimeProvider(NaN/Infinity/backward clock) can no longer corrupt the countdown,tickIntervalMsis sanitized, and the time decomposition is lossless. Behavior change: the hook'ssetSeconds(value)now throws on an invalid argument (negative / non-finite / non-integer / out-of-range) instead of silently coercing it;reset(value)and construction already threw in 0.2.0 (unchanged). - Single-emit per transition (behavior change):
useCountdownnow receives exactly one snapshot per engine state transition (redundant emissions removed), which can break consumers that relied on the previous number of update callbacks per transition. - Now declares
engines.node>=22(the package previously declared noenginesfield); installing on older Node emits a warning or fails underengine-strict. - Bumped
@timekeeper-countdown/coreto^0.3.0.
[0.2.0] - 2026-03-03
Changed
- Bumped
@timekeeper-countdown/coreto^0.2.0.
[0.1.4] - 2026-02-17
Changed
- Bumped
@timekeeper-countdown/coreto^0.1.4.
[0.1.3] - 2026-02-17
Changed
- Bumped
@timekeeper-countdown/coreto^0.1.3.
[0.1.2] - 2026-02-17
Changed
- Updated the
@timekeeper-countdown/coredependency to 0.1.2.
[0.1.1] - 2025-10-07
Added
- Comprehensive README documentation.
Changed
- Bumped
@timekeeper-countdown/coreto^0.1.1.
[0.1.0] - 2025-10-07
Added
- Initial React adapter (
useCountdown) for the 0.1.0 React-first release.