Core
Clock
Runtime-agnostic time and scheduling interface.
A Clock supplies monotonic time and a schedule/cancel pair. Stopwatch never calls setTimeout or requestAnimationFrame directly.
Interface
interface Clock {
now(): number
schedule(callback: () => void): unknown
cancel(handle: unknown): void
}Export this type from @watchstop/core as Clock.
Method contracts
now(): number
- Returns a monotonic timestamp in milliseconds.
- Prefer
performance.now()in all shipped clocks. - Values must be comparable with subtraction (
later - earlier) to produce elapsed ms. - Must not jump backward under normal operation (wall-clock
Date.now()is not acceptable for production clocks).
schedule(callback: () => void): unknown
- Arranges for
callbackto run once in the future (next animation frame, next timer interval, or mock queue). - Returns an opaque
handlethatcancelunderstands. - Must not invoke
callbacksynchronously insideschedule. - Clocks have no
destroymethod. Factories document missing-API failures (e.g. browser clock throws whenrequestAnimationFrameis absent). Cancel remains safe on expired or unknown handles.
cancel(handle: unknown): void
- Cancels a pending callback from
schedule. - Must be idempotent: canceling twice, or canceling an unknown/expired handle, must not throw.
- After cancel,
callbackmust not run (unless it already started).
Invariants
now()is side-effect free regarding scheduled callbacks.- Each successful
schedulehas at most one corresponding callback invocation unless re-scheduled. - Stopwatch owns the loop: clocks do not auto-repeat. Repeating ticks are
schedule→ callback →scheduleagain inside Stopwatch. - Handles are opaque to Stopwatch; never inspect handle type in Stopwatch beyond passing to
cancel.
Factories (see Runtimes)
| Export | Page |
|---|---|
createBrowserClock() | Browser |
createTimerClock(options?) | Timer |
createMockClock() | Testing |
detectClock() | chooses browser vs timer |
Install + import
pnpm add @watchstop/coreimport {
type Clock,
createBrowserClock,
createTimerClock,
createMockClock,
detectClock,
} from '@watchstop/core'