@beignet/core
Version:
Core framework primitives for Beignet
73 lines (67 loc) • 1.75 kB
text/typescript
/**
* App-facing time source.
*
* Use this port anywhere deterministic time matters, such as use-case tests,
* scheduled work, idempotency windows, or audit timestamps.
*/
export interface ClockPort {
/**
* Return the current time according to this clock.
*/
now(): Date;
}
/**
* Mutable clock implementation used by tests.
*/
export interface FrozenClockPort extends ClockPort {
/**
* Replace the current time.
*/
setNow(value: Date | string | number): void;
/**
* Move the current time forward by the given number of milliseconds.
*/
advance(milliseconds: number): void;
}
function toDate(value: Date | string | number): Date {
return value instanceof Date ? new Date(value.getTime()) : new Date(value);
}
/**
* Create a clock backed by `new Date()`.
*
* Use this as the default production `ClockPort` when the app does not need a
* provider-specific time source.
*
* @returns A clock that reads the current system time.
*/
export function createSystemClock(): ClockPort {
return {
now: () => new Date(),
};
}
/**
* Create a mutable clock for deterministic tests.
*
* @example
* ```ts
* const clock = createFrozenClock("2026-01-01T00:00:00.000Z");
* clock.advance(1000);
* ```
*
* @param initial - Initial time for the clock. Defaults to Unix epoch.
* @returns A clock whose time can be replaced or advanced.
*/
export function createFrozenClock(
initial: Date | string | number = new Date(0),
): FrozenClockPort {
let current = toDate(initial);
return {
now: () => new Date(current.getTime()),
setNow: (value) => {
current = toDate(value);
},
advance: (milliseconds) => {
current = new Date(current.getTime() + milliseconds);
},
};
}