@ -48,6 +48,9 @@ import { TimrDuplicateKeyError } from './errors.ts';
import { cancelTimerEntry , collectTimerKeysInScope } from './timer-cancel.ts' ;
import {
createInternalTimerEntry ,
createTimerTaskContext ,
getLiveTimerEntry ,
hasTimerReachedMaxRuns ,
timerEntrySnapshot ,
type InternalTimerEntry
} from './timer-entry.ts' ;
@ -68,8 +71,7 @@ import type {
TimerIntervalOptions ,
TimerKind ,
TimerOptions ,
TimerTask ,
TimerTaskContext
TimerTask
} from './types.ts' ;
export function createEngineTimers ( options : EngineTimersOptions = { } ) : EngineTimers {
@ -94,19 +96,6 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// ── Entry lifecycle ─────────────────────────────────────────────────────
/ * *
* Look up an entry only if the captured tuple still matches . This is
* the core of the race - safety contract — every callback uses it .
* /
function getLiveEntry ( id : number , key : string , version : number ) : InternalTimerEntry | null {
const current = entries . get ( key ) ;
if ( current === undefined ) return null ;
if ( current . id !== id ) return null ;
if ( current . version !== version ) return null ;
if ( current . controller . signal . aborted ) return null ;
return current ;
}
/ * *
* Arm the native timeout for the given entry . Captures the tuple in
* the closure — ` runEntry ` will reject the callback if the entry has
@ -122,21 +111,8 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
} , delayMs ) ;
}
function makeContext ( entry : InternalTimerEntry , firedAt : number ) : TimerTaskContext {
return {
key : entry.key ,
kind : entry.kind ,
scheduledAt : entry.scheduledAt ,
dueAt : entry.dueAt ,
firedAt ,
driftMs : firedAt - entry . dueAt ,
runCount : entry.runCount ,
signal : entry.controller.signal
} ;
}
async function runEntry ( id : number , key : string , version : number ) : Promise < void > {
const entry = getLive Entry( id , key , version ) ;
const entry = getLiveTimerEntry ( entries , id , key , version ) ;
if ( entry === null ) return ;
if ( entry . status !== TIMER_STATUS_PENDING ) return ;
@ -145,7 +121,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
entry . lastFiredAt = firedAt ;
entry . runCount += 1 ;
entry . native = null ;
const ctx = make Context( entry , firedAt ) ;
const ctx = createTi merT as kContext( entry , firedAt ) ;
emit ( { type : TIMER_EVENT_RUNNING , entry : timerEntrySnapshot ( entry ) } ) ;
const isInterval = entry . kind === TIMER_KIND_INTERVAL ;
@ -154,7 +130,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// Branch A — interval with awaitTask=false: arm the next tick BEFORE
// running so we honour cadence regardless of how long the task
// takes. Stale-callback guard still applies to next tick.
if ( isInterval && ! awaitTask && ! has ReachedMaxRuns( entry ) ) {
if ( isInterval && ! awaitTask && ! has Timer ReachedMaxRuns( entry ) ) {
scheduleNextIntervalTick ( entry ) ;
}
@ -204,7 +180,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// `entry.status` may already be TIMER_STATUS_PENDING if branch A
// already armed the next tick; otherwise schedule it now.
if ( entry . status === TIMER_STATUS_RUNNING ) {
if ( has ReachedMaxRuns( entry ) ) {
if ( has Timer ReachedMaxRuns( entry ) ) {
entry . status = error === null ? TIMER_STATUS_COMPLETED : TIMER_STATUS_FAILED ;
entries . delete ( entry . key ) ;
return ;
@ -221,7 +197,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
function scheduleNextIntervalTick ( entry : InternalTimerEntry ) : void {
if ( entry . intervalMs === null ) return ;
if ( has ReachedMaxRuns( entry ) ) {
if ( has Timer ReachedMaxRuns( entry ) ) {
entry . status = TIMER_STATUS_COMPLETED ;
entries . delete ( entry . key ) ;
return ;
@ -242,10 +218,6 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// ── Public scheduling ───────────────────────────────────────────────────
function hasReachedMaxRuns ( entry : InternalTimerEntry ) : boolean {
return entry . maxRuns !== undefined && entry . runCount >= entry . maxRuns ;
}
function scheduleCommon (
key : string ,
delayMs : number ,