fix(outlook): hydrate recurring occurrences from series master during ingestion#409
Open
valentindiehl wants to merge 1 commit into
Open
fix(outlook): hydrate recurring occurrences from series master during ingestion#409valentindiehl wants to merge 1 commit into
valentindiehl wants to merge 1 commit into
Conversation
… ingestion
Graph's calendarView/delta expands recurring series, but each expanded
occurrence item carries only id, type, seriesMasterId, start, and end.
parseOutlookEvents dropped them for missing iCalUId, so only the series
master (listed with the first occurrence's start/end) was ever stored —
recurring events synced as a single event.
Hydrate occurrences from their series master (metadata from the master,
times from the occurrence), drop the master's own row, and fetch masters
that are absent from a delta payload via /me/events/{id}. Bump the
outlook sync token version to force a full re-sync that backfills
existing calendars.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #407
Problem
Recurring M365 events only ever synced as a single event. Graph's
calendarView/deltaexpands recurring series server-side, but each expandedoccurrenceitem carries onlyid,type,seriesMasterId,start, andend— noiCalUId, subject, or anything else.parseOutlookEventsdropped them for the missingiCalUId, so the only row that survived was the series master itself, which Graph lists with the first occurrence's start/end. (This is also where the ancient ghost events come from — e.g. a yearly series created in 2012 shows up once, on its 2012 date.)Fix
typeandseriesMasterIdin$selectand allow them in the event schema (string | null, Graph sends explicit nulls).GET /me/events/{id}. A 404 means the series was deleted in the meantime; the orphaned occurrence is skipped.OUTLOOK_SYNC_TOKEN_VERSIONso existing calendars do a full re-sync and backfill occurrences that were previously dropped.The hydration gate is
seriesMasterId && !iCalUIdrather thantype === "occurrence", soexceptionitems (modified occurrences) pass through untouched when Graph delivers them with full properties, and still get hydrated with their own (correct) times if a stub ever shows up.Storage-wise this is safe: all occurrences of a series share the master's
iCalUId, but event states are keyed on(calendarId, sourceEventUid, startTime, endTime), so they coexist and series edits update in place.Known limitation
Delta
@removedentries carry only the Graphid, while stored rows are keyed byiCalUId— so cancelling a single occurrence mid-series doesn't remove its row until the next full re-sync (delta token expiry / 410). That mismatch predates this PR and affects non-recurring events too (looks like #137); fixing it properly needs the Graph id persisted alongside the uid, which felt like scope creep here.Verification
bun run types,bun run lint,bun run unused, andbun run testall pass.