/**
 * Recurrence: an RFC 5545 (iCalendar RRULE) subset, hand-rolled.
 *
 * No dependency, for the same reason the icon set is inlined rather than
 * pulling lucide-react — this needs `FREQ`, `INTERVAL`, `BYDAY`, `COUNT` and
 * `UNTIL`, which is a fraction of what a full RRULE library carries, and
 * the behaviour is worth owning outright because it is where the subtle bugs
 * live.
 *
 * ## Why the timezone matters
 *
 * A weekly 9am standup is not "every 604800000 ms". Cross a DST boundary and
 * the UTC offset changes, so instant arithmetic silently drifts the meeting
 * to 8am or 10am. Occurrences are therefore stepped in **wall-clock** terms
 * inside the event's own IANA zone and only then resolved back to an instant.
 * `Intl.DateTimeFormat` is the offset oracle — available everywhere this code
 * runs (Node ≥20 and every browser target), and the only one that doesn't
 * require shipping a tz database.
 *
 * Occurrences are expanded on read, never materialised, so a series is one
 * row no matter how far out it repeats — but that means every read pays for
 * expansion, which is why the window and occurrence count are both capped.
 */
export type RecurrenceFreq = "daily" | "weekly" | "monthly";
/** Two-letter iCalendar weekday codes, in `Date#getDay` order. */
export declare const WEEKDAY_CODES: readonly ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
export type WeekdayCode = (typeof WEEKDAY_CODES)[number];
export interface RecurrenceRule {
    freq: RecurrenceFreq;
    /** Every N periods. Always ≥ 1. */
    interval: number;
    /** Weekly only: which weekdays the series lands on. Empty = the start's own weekday. */
    byDay?: WeekdayCode[];
    /** Stop after N occurrences (mutually exclusive with `until` in practice). */
    count?: number;
    /** Stop at or before this instant (ISO 8601). */
    until?: string;
}
/** Guard rails so an unbounded `FREQ=DAILY` can't produce an unbounded response. */
export declare const MAX_WINDOW_DAYS = 92;
export declare const MAX_OCCURRENCES = 400;
/**
 * Parses the stored rule string. Returns null for anything unrecognised —
 * a malformed rule degrades to "this is a one-off event" rather than
 * throwing on read, since the row is already persisted by then and a broken
 * rule must not be able to take down a whole calendar query.
 */
export declare function parseRecurrenceRule(text: string | null | undefined): RecurrenceRule | null;
/** Serialises back to the stored form. Round-trips with parseRecurrenceRule. */
export declare function formatRecurrenceRule(rule: RecurrenceRule): string;
/** Human summary for the UI ("Weekly on Mon, Wed"). */
export declare function describeRecurrence(rule: RecurrenceRule | null): string;
export interface WallClock {
    year: number;
    month: number;
    day: number;
    hour: number;
    minute: number;
    second: number;
}
/** The wall-clock reading of an instant in a given zone. */
export declare function toWallClock(instant: Date, timeZone: string): WallClock;
/**
 * The instant at which the given wall-clock time occurs in `timeZone`.
 *
 * Solved by iteration rather than a tz table: guess the instant as if the
 * wall clock were UTC, measure how far off the zone's rendering is, correct,
 * and repeat. Converges in one step normally and two across an offset change;
 * the third is belt-and-braces for zones with sub-hour offsets.
 *
 * Nonexistent local times (the DST spring-forward gap) land on the instant
 * just after the jump, and ambiguous ones (the autumn repeat) resolve to the
 * first pass — the same pragmatic choices RFC 5545 implementations make.
 */
export declare function fromWallClock(wall: WallClock, timeZone: string): Date;
export interface SeriesInput {
    /** First occurrence, as a stored instant. */
    startsAt: Date | string;
    endsAt: Date | string;
    timezone: string;
    /** Parsed rule, or the raw string — null/absent means a single occurrence. */
    rule?: RecurrenceRule | string | null;
}
export interface Occurrence {
    start: Date;
    end: Date;
    /** The occurrence's own start date (YYYY-MM-DD) in the series timezone —
     * the stable key an override or cancellation is filed under. */
    occurrenceDate: string;
}
/**
 * Expands a series into the concrete occurrences overlapping
 * [windowFrom, windowTo). A non-recurring series yields at most its single
 * occurrence. Duration is preserved as an instant delta: a 30-minute meeting
 * stays 30 minutes even when it crosses a DST boundary.
 */
export declare function expandOccurrences(series: SeriesInput, windowFrom: Date, windowTo: Date, maxOccurrences?: number): Occurrence[];
//# sourceMappingURL=recurrence.d.ts.map