/** * merged-calendar-model.ts, normalization of provider (Google Calendar API v3, * Microsoft Graph) events into the ONE merged event model shared with A9's .ics * path: A9's CalendarEvent shape plus a source label and the provider ids. * * Time-anchoring honesty follows A9's contract (this build ships no tz database): * - An all-day value keeps its 'YYYY-MM-DD' date and is `zone: 'floating'`. * - A timed value carrying an explicit numeric offset or a trailing Z is normalized * to a real UTC instant (`zone: 'utc'`), a fixed-offset -> UTC shift is pure * arithmetic, NOT a named-zone conversion, so it is lossless and honest. * - A timed value that only names a zone (no offset) is kept as wall time with the * TZID recorded (`zone: 'tzid'`), never converted. * * Recurrence is delegated to the provider: the API clients request expanded single * instances (Google singleEvents=true, Graph calendarView), so each normalized event * is one concrete occurrence, no rule is fabricated here. */ import type { EventDateTime } from './types.js'; import type { MergedCalendarEvent } from './oauth-types.js'; /** * Normalize one Google event (already a concrete instance from singleEvents=true) * into the merged model. Returns null for an event with no usable start. */ export declare function normalizeGoogleEvent(raw: unknown, calendarId: string, calendarLabel: string): MergedCalendarEvent | null; /** Normalize one Graph event (a concrete instance from calendarView) into the model. */ export declare function normalizeGraphEvent(raw: unknown, calendarId: string, calendarLabel: string): MergedCalendarEvent | null; /** * Normalize a date-time that may carry a numeric offset or trailing Z into a real * UTC instant. A value with only a named zone (no offset) is impossible here (the * Google API always includes an offset on dateTime), but we defend: if Date cannot * parse it, keep the wall value as tzid when a zone was named, else floating. */ export declare function normalizeOffsetDateTime(value: string, namedZone?: string): EventDateTime; /** * Best-effort epoch (ms) for one {@link EventDateTime}, for sorting a mixed list of * merged events across zones/kinds. THIS IS THE ONE DOCUMENTED FUNCTION every * consumer should sort through, a raw `localeCompare`/string sort on `.value` looks * like it works (ISO strings are lexicographically sortable) but silently produces * the wrong order the moment a `zone: 'utc'` value (a real instant) is compared * against a `zone: 'tzid'` or `zone: 'floating'` value (a wall-clock reading with an * unknown or undeclared offset), e.g. a `tzid` event at `01:00` in * `America/New_York` and a `utc` event at `05:00Z` are close to the same real * instant (EDT is UTC-4), but a naive string/localeCompare sort of `'01:00:00'` vs * `'05:00:00Z'` treats them as 4-5 hours apart on the SAME axis, which they are not. * * Documented approximation (this build ships no tz database, so a true conversion is * not possible): * - `kind: 'date'` (all-day) => midnight UTC of that date. * - `zone: 'utc'` => the real epoch, via `Date.parse` of the (already-normalized, * Z-suffixed) ISO value. Authoritative. * - `zone: 'tzid'` or `zone: 'floating'` => the wall-clock digits are read AS IF * they were UTC (no offset applied). This is an approximation, not the true * instant, it keeps events within the SAME zone in correct relative order, and * gives cross-zone comparisons a deterministic (if approximate) answer instead of * an arbitrary one. */ export declare function eventDateTimeEpochMs(dt: EventDateTime): number; /** * Chronological comparator for {@link EventDateTime} values (ascending), suitable * for `Array.prototype.sort`. See {@link eventDateTimeEpochMs} for the documented * cross-zone approximation this is built on, this is the ONE function every * consumer should sort through instead of inventing its own string comparison. */ export declare function compareEventDateTime(a: EventDateTime, b: EventDateTime): number; /** Sort {@link MergedCalendarEvent}s by start time, through {@link compareEventDateTime}. */ export declare function compareMergedCalendarEventsByStart(a: MergedCalendarEvent, b: MergedCalendarEvent): number; //# sourceMappingURL=merged-calendar-model.d.ts.map