This page covers how to configure a stack (timezone, rules, baseline), how time units work (including rounding), and how the update() pipeline handles versions and time‑unit changes with notices.
export interface RRStackOptions {
version?: string; // ignored by constructor; written by toJson()
timezone: string; // IANA time zone (validated at runtime)
timeUnit?: 'ms' | 's'; // default 'ms'
defaultEffect?: 'active' | 'blackout' | 'auto'; // default 'auto'
rules?: RuleJson[]; // default []
}
timezone: All coverage is computed in this IANA zone (DST‑aware).timeUnit:
'ms' — millisecond timestamps for inputs/outputs.'s' — integer seconds; ends are rounded up (see below).defaultEffect (baseline):
'auto' (default): opposite of the first rule’s effect, or 'active' if no rules.'active' | 'blackout': use exactly that baseline anywhere uncovered.isActiveAt, getSegments, classifyRange, getEffectiveBounds.See all rule shapes in Core API and Types.
[start, end).'s'):
's' mode return integer seconds (via truncation for conversions; via rounding up for occurrence end).Use update() to ingest changes to timezone/rules/timeUnit and to run the version pipeline. It returns an array of Notice and also calls policy.onNotice for each.
const policy = {
onVersionDown: 'warn',
onTimeUnitChange: 'warn',
onNotice: console.info,
};
const notices = stack.update(incomingJson, policy);
toJson() and used for comparisons.version may be older, newer, or invalid:Defaults:
onVersionUp (incoming older than engine): 'off' (accept; upgrader runs, currently no‑op).onVersionDown (incoming newer): 'error' (reject; set 'warn'/'off' to accept “as current”).onVersionInvalid (invalid semver): 'error' (reject; set 'warn'/'off' to accept “as current”).Actions:
When timeUnit changes:
rules are provided in the same update:
rules are not provided:
options.starts/options.ends) are converted:
Math.trunc(ms / 1000)s * 1000'timeUnitChange' notice is produced (policy default 'warn').type Notice =
| { kind: 'versionUp' | 'versionDown' | 'versionInvalid'; ... }
| { kind: 'timeUnitChange'; ... }
See the full union and UpdatePolicy options in Core API and Types.
'auto' (default): behaves like a virtual open‑ended span whose effect is the opposite of the first real rule, or 'active' if there are no rules.'active' | 'blackout': use exactly that effect where no rule covers.Implications:
isActiveAt) and streams (getSegments) seamlessly include baseline coverage.classifyRange reflects baseline coverage appropriately (e.g., “active” when the entire window is uncovered but baseline is 'active').getEffectiveBounds returns open‑sided bounds for open‑ended baseline coverage.0 (in the configured unit).const seen: Notice[] = [];
const policy: UpdatePolicy = {
onVersionDown: 'warn',
onNotice: (n) => seen.push(n),
};
const notices = stack.update({ version: '999.0.0' }, policy);
// both arrays contain 'versionDown' with action 'ingestAsCurrent'
// Clamps on retained rules convert ms → s (trunc)
stack.update({ timeUnit: 's' }, { onTimeUnitChange: 'warn' });
const rulesInSeconds = [
{ effect: 'active', options: { starts: 1_700_000_000, ends: 1_700_000_600 } },
];
stack.update(
{ timeUnit: 's', rules: rulesInSeconds },
{ onTimeUnitChange: 'warn' },
);