Magic Apps

Documentation

macmagic.app

Google Tasks

Google Calendar's range prefetch (sync.prefetcheventrange) surfaces task entries in the primary calendar feed (eventType = 7), but does not carry task completion state. Completed and open tasks look identical on the calendar wire.

To show tasks accurately in the popover and widgets, Magical polls Google Tasks' internal web sync endpoint and overlays completion state onto the calendar event cache.

Wire protocol and authentication

Tuple indices

The response is a JSON-encoded Protocol Buffer array. response[0] is a flat run of change records, each wrapped in a sparse list, and the run holds task lists, recurrence definitions and tasks side by side:

Records are matched by shape, not by position. The wrapper's populated slot moves between records: measured against a live account, a task sat at index 2 of its wrapper in one response and at index 5 in another. A task is known by carrying a string id and a details tuple whose title is a string; a task list carries its own id where a task carries details, and a recurrence definition carries the list id there, so neither is mistaken for a task.

Integration with the event cache and UI

Recurring tasks come from the Tasks sync

A recurring task appears on Google Calendar's own grid, but not in anything Magical polls as a calendar. The range prefetch does not carry it: searched for a recurring task's title across a live account's whole payload, 211 KB on one account and 6.9 MB on another, it is absent from both, while a one-off task on the same day arrives as an ordinary eventType = 7 entry. Google's own web client draws these from the Tasks service rather than from the event feed.

The Tasks sync carries them already expanded: one record per occurrence, each with its own Tasks id, the shared title, a due date, and a schedule holding the start as epoch seconds. A live account's monthly task returned 31 of them in one response, covering a month. So there is no recurrence rule to expand locally, and calendar-recurrence.ts is not involved.

occurrencesInRange builds an event from each occurrence that falls in the range being fetched, and syncTasksCompletion appends them to what the caller folds into the cache. They are filed under tasks@tasks.google.com, which is what gives them the Tasks calendar's name and colour and lets hiding that calendar hide them. The start is taken from the epoch seconds rather than rebuilt from the date and time parts, which would reintroduce every question about the zone they are in; the [h, m] tuple is read only to tell a timed occurrence from a date with no time of day. A timed one is drawn for an hour, the way Google draws a task.

The grid names an occurrence's chip by its Tasks id. There is no Calendar event id and no webUrl to read an eid out of, but Google still draws a chip and calls it tasks_<taskId>. Measured on a live account: the occurrence the sync called O7mOrHptGofMR7Dj is the chip [data-eventid="tasks_O7mOrHptGofMR7Dj"], beside a one-off task drawn as ttb_ and the base64 of <eventId> <address>. So the occurrence carries that id in chipEid, extractEid prefers it, and a link reaches the occurrence rather than the day it sits on. Everything driven through a chip works from there, reveal and the completion control alike.

An occurrence alerts at its own time. The record says nothing about notifications, so it is given reminders: [0], which is what a one-off task carries from the calendar wire: a task is due at a moment rather than starting at one, and the account's global lead would warn some minutes before that. Nothing else is needed, because an occurrence is an ordinary event to AlertScheduler from there, and MAX_TIMER_MS keeps the far ones unarmed until a later poll, exactly as it does for the occurrences of a recurring meeting.