import { type Maybe, type Minutes, type TimezoneString } from '@dereekb/util'; import { type DateRange } from '@dereekb/date'; import { type Calendar, type CalendarEventItem, type CalendarRecurringEventItem } from './calendar'; import { type CalendarOccurrenceKey } from './calendar.id'; /** * @module calendar.expand * * The ONE occurrence expansion, shared by ICS generation and by the future dbx-calendar adapter. * * Deliberately free of any Angular dependency, and deliberately not duplicated on the server: an adapter * that expanded recurrences differently from the publisher would render a calendar that disagrees with the * ".ics" the same model produced. * * The adapter is then one line — * `{ id: o.key, start: o.startsAt, end: o.endsAt, allDay: o.allDay, title: o.item.n, meta: o }` — which is a * `CalendarEvent` and feeds straight into `prepareAndSortCalendarEvents()`. */ /** * A single resolved occurrence of a calendar event. * * A one-off event yields exactly one occurrence; a recurring event yields one per instance of its series * within the expansion range. */ export interface CalendarEventOccurrence { /** * The event this occurrence came from. */ readonly item: CalendarEventItem | CalendarRecurringEventItem; /** * Stable identifier for this occurrence. * * The event's id for a one-off; the id plus the occurrence's unix seconds for a recurrence. Stability is * what keeps a published VEVENT's UID the same across republishes, which is what makes a subscriber update * the event it holds rather than create a duplicate. */ readonly key: CalendarOccurrenceKey; readonly startsAt: Date; readonly endsAt: Date; readonly durationMinutes: Minutes; readonly allDay: boolean; readonly timezone: TimezoneString; readonly recurring: boolean; } /** * Builds the {@link CalendarOccurrenceKey} for a single occurrence of a recurring event. * * @param item - The recurring event. * @param startsAt - The occurrence's start instant. * @returns The occurrence key. * * @__NO_SIDE_EFFECTS__ */ export declare function calendarRecurringEventOccurrenceKey(item: Pick, startsAt: Date): CalendarOccurrenceKey; /** * Input for {@link expandCalendarEvents}. */ export interface ExpandCalendarEventsInput { readonly calendar: Pick; /** * The window to expand within. * * REQUIRED: a forever recurrence has no other bound, and expanding one without a range throws. */ readonly range: DateRange; /** * Whether one-off events are included. Defaults to true. */ readonly includeOneOffEvents?: Maybe; /** * Whether recurring events are included. Defaults to true. */ readonly includeRecurringEvents?: Maybe; /** * Caps how many occurrences a single recurring event may contribute. */ readonly maxOccurrencesPerEvent?: Maybe; } /** * Expands a calendar's events into concrete occurrences within a range. * * One-off events are included when their span OVERLAPS the range. Recurring events are expanded through * `DateRRuleUtility`, whose `exclude` slot consumes the event's `rex` exception dates with no extra code; * note that it matches an occurrence by its START, so a recurrence instance that began before the range and * runs into it is not included. * * @param input - The calendar, the range, and optional filters. * @returns The occurrences, ascending by start instant and unique by key. * @throws {Error} If a forever recurrence is expanded without a range. * * @example * ```ts * const occurrences = expandCalendarEvents({ calendar, range: { start: from, end: to } }); * ``` */ export declare function expandCalendarEvents(input: ExpandCalendarEventsInput): CalendarEventOccurrence[];