/** * earth-now.co * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * File: packages/counter/src/windows.ts * Purpose: Reset-window helpers (today UTC / this year UTC / session) computed from the same model — pure, time is a parameter */ import type { CounterModel } from "./counter-model.js"; import { counterValue } from "./value.js"; export type CounterWindow = "today" | "ytd" | "session" | "total"; /** Start of the UTC day containing t (ms). */ export function startOfUtcDay(tMs: number): number { const d = new Date(tMs); return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()); } /** Start of the UTC year containing t (ms). */ export function startOfUtcYear(tMs: number): number { return Date.UTC(new Date(tMs).getUTCFullYear(), 0, 1); } /** * Value of a cumulative counter over a display window, derived from the SAME * model (same function server/client/badge): v(t) − v(windowStart). * "session" needs the caller-provided session start (user arrival time). */ export function windowValue( model: CounterModel, tMs: number, window: CounterWindow, sessionStartMs?: number, ): number { switch (window) { case "total": return counterValue(model, tMs); case "today": return counterValue(model, tMs) - counterValue(model, startOfUtcDay(tMs)); case "ytd": return counterValue(model, tMs) - counterValue(model, startOfUtcYear(tMs)); case "session": { if (sessionStartMs === undefined) throw new Error("windowValue: 'session' window requires sessionStartMs"); return counterValue(model, tMs) - counterValue(model, sessionStartMs); } } }