@mulmoclaude/core 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +49 -0
  2. package/assets/helps/google-calendar-collection.md +13 -2
  3. package/assets/helps/google.md +94 -0
  4. package/assets/helps/index.md +1 -0
  5. package/dist/collection/registry/server/index.cjs +3 -2
  6. package/dist/collection/registry/server/index.cjs.map +1 -1
  7. package/dist/collection/registry/server/index.js +3 -2
  8. package/dist/collection/registry/server/index.js.map +1 -1
  9. package/dist/collection/server/index.cjs +1 -1
  10. package/dist/collection/server/index.js +1 -1
  11. package/dist/collection-watchers/index.cjs +1 -1
  12. package/dist/collection-watchers/index.js +1 -1
  13. package/dist/feeds/server/index.cjs +2 -2
  14. package/dist/feeds/server/index.js +2 -2
  15. package/dist/files/index.cjs +3 -0
  16. package/dist/files/index.cjs.map +1 -1
  17. package/dist/files/index.d.ts +1 -0
  18. package/dist/files/index.js +2 -1
  19. package/dist/files/index.js.map +1 -1
  20. package/dist/files/relPath.d.ts +23 -0
  21. package/dist/google/calendar.d.ts +28 -0
  22. package/dist/google/collectionSync.d.ts +88 -4
  23. package/dist/google/index.cjs +235 -17
  24. package/dist/google/index.cjs.map +1 -1
  25. package/dist/google/index.d.ts +3 -3
  26. package/dist/google/index.js +223 -18
  27. package/dist/google/index.js.map +1 -1
  28. package/dist/google/tasks.d.ts +21 -0
  29. package/dist/relPath-CgGi4-Nv.cjs +46 -0
  30. package/dist/relPath-CgGi4-Nv.cjs.map +1 -0
  31. package/dist/relPath-DW8MC8VO.js +33 -0
  32. package/dist/relPath-DW8MC8VO.js.map +1 -0
  33. package/dist/{server-BZJCw2HU.js → server-D_6FLygK.js} +6 -2
  34. package/dist/server-D_6FLygK.js.map +1 -0
  35. package/dist/{server-w5ZZRLju.cjs → server-gEOeV_Nv.cjs} +6 -2
  36. package/dist/server-gEOeV_Nv.cjs.map +1 -0
  37. package/package.json +10 -1
  38. package/dist/server-BZJCw2HU.js.map +0 -1
  39. package/dist/server-w5ZZRLju.cjs.map +0 -1
@@ -7,9 +7,9 @@ export { brokerBaseUrl, brokerExchange, brokerRefresh, brokerStart, type BrokerS
7
7
  export { authorizeGoogle, commitLinkedTokens, getGoogleAccessToken, unlinkGoogle, waitForAuthCode, GOOGLE_AUTH_CANCELLED, GOOGLE_CALENDAR_SCOPE, GOOGLE_CALENDARLIST_SCOPE, GOOGLE_TASKS_SCOPE, GOOGLE_DRIVE_FILE_SCOPE, GOOGLE_SCOPES, type AuthorizeGoogleOptions, type RevokeFetch, } from './auth.js';
8
8
  export { createGoogleAuthFlow, googleAuthFlow, type GoogleAuthFlow, type GoogleAuthFlowStatus } from './authFlow.js';
9
9
  export { googleApiError, isGoogleApiError, GoogleApiError, DEFAULT_LIST_MAX_RESULTS, MAX_LIST_RESULTS } from './apiClient.js';
10
- export { calendarApiError, collectCalendarPages, createCalendarEvent, getCalendarColors, canonicalCalendarId, listCalendarEvents, listCalendars, syncCalendarEvents, toCalendarSummary, toEventSummary, type CalendarColorEntry, type CalendarColors, type CalendarEventInput, type CalendarEventSummary, type CalendarListPage, type CalendarSummary, type CalendarSyncResult, type ListEventsInput, type SyncEventsInput, } from './calendar.js';
10
+ export { buildEventPatch, calendarApiError, collectCalendarPages, createCalendarEvent, deleteCalendarEvent, getCalendarColors, canonicalCalendarId, listCalendarEvents, listCalendars, syncCalendarEvents, toCalendarSummary, toEventSummary, updateCalendarEvent, type CalendarColorEntry, type CalendarColors, type CalendarEventInput, type CalendarEventSummary, type CalendarListPage, type CalendarSummary, type CalendarSyncResult, type DeleteCalendarEventInput, type ListEventsInput, type SyncEventsInput, type UpdateCalendarEventInput, } from './calendar.js';
11
11
  export { calendarSyncStatePath, clearCalendarSyncToken, loadCalendarSyncToken, saveCalendarSyncToken } from './calendarSyncStore.js';
12
12
  export { toCollectionDateTime } from './collectionDateTime.js';
13
- export { googleCalendarSyncTaskDef, classifyDelete, classifyWrite, groupByCalendar, syncCalendarGroup, syncDueCalendarCollections, toCollectionRecord, GOOGLE_CALENDAR_SYNC_TASK_ID, type CalendarCollectionSyncResult, } from './collectionSync.js';
14
- export { completeTask, createTask, deleteTask, listTaskLists, listTasks, toTaskListSummary, toTaskSummary, type CompleteTaskInput, type CreateTaskInput, type ListTasksInput, type TaskListSummary, type TaskSummary, } from './tasks.js';
13
+ export { googleCalendarSyncTaskDef, classifyDelete, classifyWrite, anySyncedCollectionSurvives, groupByCalendar, orphanedCalendarId, releaseOrphanedCalendarToken, syncCalendarForCollection, syncCalendarGroup, syncDueCalendarCollections, syncNewCalendarCollections, toCollectionRecord, unsyncedGroups, withKeyedLock, GOOGLE_CALENDAR_SYNC_TASK_ID, type CalendarCollectionSyncResult, type CalendarDeclaring, type ManualCalendarSyncDeps, type ManualCalendarSyncOutcome, } from './collectionSync.js';
14
+ export { buildTaskPatch, canonicalTaskListId, completeTask, createTask, deleteTask, listTaskLists, listTasks, toTaskListSummary, toTaskSummary, updateTask, type CompleteTaskInput, type CreateTaskInput, type ListTasksInput, type TaskListSummary, type TaskSummary, type UpdateTaskInput, } from './tasks.js';
15
15
  export { assertSafeMimeType, buildMultipartBody, createDriveFile, deleteDriveFile, isTextMimeType, listDriveFiles, pickBoundary, readDriveFile, toDriveFileSummary, type CreateDriveFileInput, type DriveFileSummary, type ListDriveFilesInput, type ReadDriveFileInput, } from './driveFile.js';
@@ -651,6 +651,34 @@ async function createCalendarEvent(accessToken, input) {
651
651
  body: JSON.stringify(body)
652
652
  }));
653
653
  }
654
+ var eventUrl = (calendarId, eventId) => `${eventsUrl(calendarId)}/${encodeURIComponent(eventId)}`;
655
+ /** PATCH body for an event edit — only the fields the caller actually supplied.
656
+ *
657
+ * `undefined` means "leave as is" and `""` means "clear it", so the two cannot
658
+ * be collapsed: dropping `description: ""` would silently ignore a request to
659
+ * empty the body text. Pure so the distinction is testable without network. */
660
+ var buildEventPatch = (input) => ({
661
+ ...input.summary !== void 0 ? { summary: input.summary } : {},
662
+ ...input.description !== void 0 ? { description: input.description } : {},
663
+ ...input.startDateTime !== void 0 ? { start: { dateTime: input.startDateTime } } : {},
664
+ ...input.endDateTime !== void 0 ? { end: { dateTime: input.endDateTime } } : {},
665
+ ...input.colorId ? { colorId: input.colorId } : {}
666
+ });
667
+ /** Edit an existing event in place. PATCH, not PUT — a PUT would need the whole
668
+ * event and would drop every field the caller never read (attendees,
669
+ * reminders, recurrence). */
670
+ async function updateCalendarEvent(accessToken, input) {
671
+ return toEventSummary(await googleRequest(CALENDAR_API_LABEL, accessToken, eventUrl(input.calendarId, input.eventId), {
672
+ method: "PATCH",
673
+ body: JSON.stringify(buildEventPatch(input))
674
+ }));
675
+ }
676
+ /** Remove an event. Google answers 204 with no body, so there is nothing to
677
+ * return; a second delete of the same id answers 410, which surfaces as a
678
+ * GoogleApiError rather than being swallowed. */
679
+ async function deleteCalendarEvent(accessToken, input) {
680
+ await googleRequest(CALENDAR_API_LABEL, accessToken, eventUrl(input.calendarId, input.eventId), { method: "DELETE" });
681
+ }
654
682
  async function listCalendarEvents(accessToken, input = {}) {
655
683
  const params = new URLSearchParams({
656
684
  timeMin: input.timeMin ?? (/* @__PURE__ */ new Date()).toISOString(),
@@ -879,6 +907,26 @@ async function restartFullSync(accessToken, calendarId, workspaceRoot) {
879
907
  await clearCalendarSyncToken(calendarId, workspaceRoot);
880
908
  return await syncCalendarEvents(accessToken, { calendarId });
881
909
  }
910
+ /** Serialise `run` against whatever is already running for `key`.
911
+ *
912
+ * `locks` is passed in so the queuing rule is testable without module state;
913
+ * the key is dropped once nothing is queued behind it, so the map cannot grow
914
+ * an entry per calendar forever. A failed predecessor still releases the
915
+ * queue — `then(run, run)`. */
916
+ async function withKeyedLock(locks, key, run) {
917
+ const result = (locks.get(key) ?? Promise.resolve()).then(run, run);
918
+ const tail = result.then(() => void 0, () => void 0);
919
+ locks.set(key, tail);
920
+ try {
921
+ return await result;
922
+ } finally {
923
+ if (locks.get(key) === tail) locks.delete(key);
924
+ }
925
+ }
926
+ /** In-flight sync per canonical calendar id. Module state on purpose: the
927
+ * scheduler, the create trigger and the Refresh button are three doors into
928
+ * the same calendar (CodeRabbit review #2566). */
929
+ var calendarLocks = /* @__PURE__ */ new Map();
882
930
  /** Sync ONE calendar and fan its events out to every collection bound to it.
883
931
  *
884
932
  * The fan-out is not an optimisation, it is correctness: the sync token is
@@ -886,8 +934,18 @@ async function restartFullSync(accessToken, calendarId, workspaceRoot) {
886
934
  * first collection advance the shared token and leave every later collection
887
935
  * on the same calendar reading an already-consumed window — silently missing
888
936
  * those events forever. Fetch once, apply to all, then advance the token.
889
- * (Codex + CodeRabbit review on #2184.) */
937
+ * (Codex + CodeRabbit review on #2184.)
938
+ *
939
+ * Queued per calendar for the same reason the fan-out exists: two passes over
940
+ * one calendar (a Refresh click landing during the scheduled run) would each
941
+ * load the SAME stored token and walk the same window. That is idempotent —
942
+ * writes are upserts by event id — but it is a wasted full walk. Queued, the
943
+ * second pass resumes from the token the first just stored and fetches only
944
+ * what is genuinely new. */
890
945
  async function syncCalendarGroup(calendarId, collections, workspaceRoot) {
946
+ return await withKeyedLock(calendarLocks, canonicalCalendarId(calendarId), () => syncCalendarGroupNow(calendarId, collections, workspaceRoot));
947
+ }
948
+ async function syncCalendarGroupNow(calendarId, collections, workspaceRoot) {
891
949
  const accessToken = await getGoogleAccessToken();
892
950
  const first = await syncCalendarEvents(accessToken, {
893
951
  calendarId,
@@ -902,13 +960,47 @@ async function syncCalendarGroup(calendarId, collections, workspaceRoot) {
902
960
  unwritable
903
961
  });
904
962
  const failed = results.flatMap((entry) => entry.errors);
905
- if (result.nextSyncToken && failed.length === 0) await saveCalendarSyncToken(calendarId, result.nextSyncToken, workspaceRoot);
906
- else if (failed.length > 0) log.warn("google", "holding back calendar sync token after failed writes", {
907
- calendarId,
908
- failed: failed.length
909
- });
963
+ if (failed.length > 0) {
964
+ log.warn("google", "holding back calendar sync token after failed writes", {
965
+ calendarId,
966
+ failed: failed.length
967
+ });
968
+ return results;
969
+ }
970
+ if (result.nextSyncToken) await advanceToken(calendarId, result.nextSyncToken, collections, workspaceRoot);
910
971
  return results;
911
972
  }
973
+ /** Save the window's token unless every collection that consumed it was deleted
974
+ * while the sync was in flight.
975
+ *
976
+ * The sync opens with a `discoverCollections()` snapshot, so a delete landing
977
+ * mid-run has already cleared this calendar's token by the time we get here
978
+ * (`releaseOrphanedCalendarToken`). Saving anyway would resurrect exactly the
979
+ * orphan the delete removed, and the next collection on this calendar would
980
+ * resume from a token describing records it never received (#2428).
981
+ *
982
+ * One survivor is enough: it still needs the incremental position. */
983
+ async function advanceToken(calendarId, nextSyncToken, collections, workspaceRoot) {
984
+ if (!await anySyncedCollectionSurvives(collections)) {
985
+ log.info("google", "not advancing the sync token — every collection on this calendar was deleted mid-sync", { calendarId });
986
+ return;
987
+ }
988
+ await saveCalendarSyncToken(calendarId, nextSyncToken, workspaceRoot);
989
+ }
990
+ async function pathExists(absPath) {
991
+ try {
992
+ await stat(absPath);
993
+ return true;
994
+ } catch {
995
+ return false;
996
+ }
997
+ }
998
+ /** Liveness of the collections a sync just wrote to, checked against the skill
999
+ * dir `deleteCollection` removes. `exists` is injected so the rule is testable
1000
+ * without a filesystem. An empty group has no survivor by definition. */
1001
+ async function anySyncedCollectionSurvives(collections, exists = pathExists) {
1002
+ return (await Promise.all(collections.map((collection) => exists(collection.skillDir)))).some(Boolean);
1003
+ }
912
1004
  async function applyEventsToCollection(collection, events, workspaceRoot) {
913
1005
  const outcomes = [];
914
1006
  for (const event of events) outcomes.push(await applyEvent(collection, event, workspaceRoot));
@@ -941,18 +1033,62 @@ function groupByCalendar(collections) {
941
1033
  }
942
1034
  return groups;
943
1035
  }
944
- /** Sync every collection that declares `googleCalendar`. Failures are isolated
945
- * per calendar — one unreachable calendar (or a revoked grant) must not stop
946
- * the others. */
947
- async function syncDueCalendarCollections(workspaceRoot) {
948
- const declaring = (await discoverCollections({ workspaceRoot })).filter((collection) => collection.schema.googleCalendar);
949
- if (declaring.length === 0) return [];
950
- if (!await isGoogleLinked()) {
951
- log.info("google", "skipping calendar sync — no Google account linked on this host", { collections: declaring.length });
952
- return [];
1036
+ /** The canonical calendar whose sync token nothing needs any more, or null.
1037
+ *
1038
+ * Sync tokens are keyed by calendar, NOT by collection, so a deleted
1039
+ * collection's token outlives it. Recreating a collection on the same calendar
1040
+ * then resumes from that token and receives only the delta — the new
1041
+ * collection never gets the history (#2428).
1042
+ *
1043
+ * Returns null while ANY remaining collection still reads that calendar:
1044
+ * clearing a live calendar's token costs a full re-walk on the next sync. The
1045
+ * comparison is on the CANONICAL id for the same reason `groupByCalendar` is —
1046
+ * an omitted `calendarId` and an explicit `"primary"` are one calendar. */
1047
+ function orphanedCalendarId(deleted, remaining) {
1048
+ if (!deleted.googleCalendar) return null;
1049
+ const key = canonicalCalendarId(deleted.googleCalendar.calendarId);
1050
+ return remaining.some((other) => other.googleCalendar && canonicalCalendarId(other.googleCalendar.calendarId) === key) ? null : key;
1051
+ }
1052
+ /** Drop the sync token of a just-deleted collection's calendar, unless another
1053
+ * collection still reads it. Call AFTER the delete lands — the check reads the
1054
+ * collections that survive it.
1055
+ *
1056
+ * Returns the cleared calendar id, or null when nothing was cleared. Never
1057
+ * throws: a failed cleanup must not fail the delete it follows. */
1058
+ async function releaseOrphanedCalendarToken(deleted, workspaceRoot) {
1059
+ try {
1060
+ if (!deleted.googleCalendar) return null;
1061
+ const orphaned = orphanedCalendarId(deleted, (await discoverCollections({ workspaceRoot })).map((collection) => collection.schema));
1062
+ if (orphaned === null) return null;
1063
+ await clearCalendarSyncToken(orphaned, workspaceRoot);
1064
+ log.info("google", "cleared the sync token of a calendar no collection reads any more", { calendarId: orphaned });
1065
+ return orphaned;
1066
+ } catch (error) {
1067
+ log.warn("google", "could not release the deleted collection's calendar sync token", { error: String(error) });
1068
+ return null;
953
1069
  }
1070
+ }
1071
+ /** Every declaring collection, grouped by the calendar it reads. */
1072
+ async function declaringGroups(workspaceRoot) {
1073
+ return groupByCalendar((await discoverCollections({ workspaceRoot })).filter((collection) => collection.schema.googleCalendar));
1074
+ }
1075
+ /** Whether a background sync of these groups may run at all.
1076
+ *
1077
+ * Authoring the collection before linking the account is an expected state,
1078
+ * not a failure. Checking once here keeps it a quiet skip instead of an
1079
+ * access-token throw per calendar, every hour, until the user links (#2188).
1080
+ * A user-triggered sync answers differently — it says so out loud. */
1081
+ async function backgroundSyncAllowed(groups) {
1082
+ if (groups.size === 0) return false;
1083
+ if (await isGoogleLinked()) return true;
1084
+ log.info("google", "skipping calendar sync — no Google account linked on this host", { calendars: groups.size });
1085
+ return false;
1086
+ }
1087
+ /** Run each group, isolating failures per calendar — one unreachable calendar
1088
+ * (or a revoked grant) must not stop the others. */
1089
+ async function runCalendarGroups(groups, workspaceRoot) {
954
1090
  const results = [];
955
- for (const [calendarId, collections] of groupByCalendar(declaring)) try {
1091
+ for (const [calendarId, collections] of groups) try {
956
1092
  results.push(...await syncCalendarGroup(calendarId, collections, workspaceRoot));
957
1093
  } catch (error) {
958
1094
  log.warn("google", "calendar sync failed", {
@@ -969,6 +1105,55 @@ async function syncDueCalendarCollections(workspaceRoot) {
969
1105
  }
970
1106
  return results;
971
1107
  }
1108
+ /** Sync every collection that declares `googleCalendar`. */
1109
+ async function syncDueCalendarCollections(workspaceRoot) {
1110
+ const groups = await declaringGroups(workspaceRoot);
1111
+ return await backgroundSyncAllowed(groups) ? await runCalendarGroups(groups, workspaceRoot) : [];
1112
+ }
1113
+ /** The groups whose calendar has never synced. A missing token IS the "created
1114
+ * since the last sync" signal — nothing else distinguishes a new collection
1115
+ * from an edited one on the write path this feeds (#2427).
1116
+ *
1117
+ * Self-silencing by construction: the first sync stores a token, so a calendar
1118
+ * matches at most once. `loadToken` is injected so the rule is testable without
1119
+ * a workspace on disk. */
1120
+ async function unsyncedGroups(groups, loadToken) {
1121
+ const checked = await Promise.all([...groups].map(async (entry) => await loadToken(entry[0]) === null ? entry : null));
1122
+ return new Map(checked.filter((entry) => entry !== null));
1123
+ }
1124
+ /** Sync only the calendars that have never synced — the first sync for a
1125
+ * just-created collection, which otherwise stays empty until the hourly
1126
+ * scheduler run (#2427). Cheap and safe to call on every config write. */
1127
+ async function syncNewCalendarCollections(workspaceRoot) {
1128
+ const pending = await unsyncedGroups(await declaringGroups(workspaceRoot), (calendarId) => loadCalendarSyncToken(calendarId, workspaceRoot));
1129
+ if (!await backgroundSyncAllowed(pending)) return [];
1130
+ log.info("google", "running the first sync for newly declared calendars", { calendars: [...pending.keys()] });
1131
+ return await runCalendarGroups(pending, workspaceRoot);
1132
+ }
1133
+ var liveManualSyncDeps = {
1134
+ loadGroups: declaringGroups,
1135
+ isLinked: isGoogleLinked,
1136
+ runGroups: runCalendarGroups
1137
+ };
1138
+ /** Sync the calendar ONE collection reads, on demand (the Refresh button).
1139
+ *
1140
+ * Deliberately syncs the whole group, not just `slug`: the sync token is keyed
1141
+ * by calendar, so consuming a window for one collection would leave the others
1142
+ * on that calendar reading an already-consumed one. Returns every result of the
1143
+ * group so the caller can report the requested slug's own counts.
1144
+ *
1145
+ * "Does this collection sync at all" is answered BEFORE "is Google linked":
1146
+ * telling someone to link their account for a collection that never declared a
1147
+ * calendar sends them fixing the wrong thing. */
1148
+ async function syncCalendarForCollection(slug, workspaceRoot, deps = liveManualSyncDeps) {
1149
+ const owning = [...await deps.loadGroups(workspaceRoot)].filter(([, collections]) => collections.some((collection) => collection.slug === slug));
1150
+ if (owning.length === 0) return { kind: "not-a-calendar" };
1151
+ if (!await deps.isLinked()) return { kind: "not-linked" };
1152
+ return {
1153
+ kind: "synced",
1154
+ results: await deps.runGroups(new Map(owning), workspaceRoot)
1155
+ };
1156
+ }
972
1157
  /** Scheduler registration, shaped like `feedRefreshTaskDef` so hosts wire it
973
1158
  * with a single line. */
974
1159
  function googleCalendarSyncTaskDef(opts) {
@@ -1008,7 +1193,12 @@ var toTaskSummary = (value) => {
1008
1193
  notes: stringField(record, "notes")
1009
1194
  };
1010
1195
  };
1011
- var tasksUrl = (taskListId, suffix = "") => `${TASKS_BASE_URL}/lists/${encodeURIComponent(taskListId ?? DEFAULT_TASK_LIST_ID)}/tasks${suffix}`;
1196
+ /** Resolve a declared taskListId to the one the API addresses. `||` (not `??`)
1197
+ * so a blank string also falls back instead of building a malformed
1198
+ * `/lists//tasks` URL — the same rule, and the same reason, as
1199
+ * `canonicalCalendarId`. */
1200
+ var canonicalTaskListId = (taskListId) => taskListId?.trim() || DEFAULT_TASK_LIST_ID;
1201
+ var tasksUrl = (taskListId, suffix = "") => `${TASKS_BASE_URL}/lists/${encodeURIComponent(canonicalTaskListId(taskListId))}/tasks${suffix}`;
1012
1202
  async function listTaskLists(accessToken) {
1013
1203
  return itemsOf(await googleRequest(TASKS_API_LABEL, accessToken, `${TASKS_BASE_URL}/users/@me/lists?maxResults=${MAX_TASK_LISTS}`)).map(toTaskListSummary);
1014
1204
  }
@@ -1030,6 +1220,21 @@ async function createTask(accessToken, input) {
1030
1220
  body: JSON.stringify(body)
1031
1221
  }));
1032
1222
  }
1223
+ /** PATCH body for a task edit — only the fields the caller supplied. As with
1224
+ * events, `undefined` means "leave as is" and `""` means "clear it", so the
1225
+ * two must stay distinct. `status` is deliberately absent: `completeTask`
1226
+ * owns that transition, and two ways to set it would drift apart. */
1227
+ var buildTaskPatch = (input) => ({
1228
+ ...input.title !== void 0 ? { title: input.title } : {},
1229
+ ...input.notes !== void 0 ? { notes: input.notes } : {},
1230
+ ...input.due !== void 0 ? { due: input.due } : {}
1231
+ });
1232
+ async function updateTask(accessToken, input) {
1233
+ return toTaskSummary(await googleRequest(TASKS_API_LABEL, accessToken, tasksUrl(input.taskListId, `/${encodeURIComponent(input.taskId)}`), {
1234
+ method: "PATCH",
1235
+ body: JSON.stringify(buildTaskPatch(input))
1236
+ }));
1237
+ }
1033
1238
  async function completeTask(accessToken, input) {
1034
1239
  return toTaskSummary(await googleRequest(TASKS_API_LABEL, accessToken, tasksUrl(input.taskListId, `/${encodeURIComponent(input.taskId)}`), {
1035
1240
  method: "PATCH",
@@ -1133,6 +1338,6 @@ async function deleteDriveFile(accessToken, input) {
1133
1338
  await googleRequest(DRIVE_API_LABEL, accessToken, `${DRIVE_FILES_URL}/${encodeURIComponent(input.fileId)}`, { method: "DELETE" });
1134
1339
  }
1135
1340
  //#endregion
1136
- export { DEFAULT_LIST_MAX_RESULTS, GOOGLE_AUTH_CANCELLED, GOOGLE_CALENDARLIST_SCOPE, GOOGLE_CALENDAR_SCOPE, GOOGLE_CALENDAR_SYNC_TASK_ID, GOOGLE_DRIVE_FILE_SCOPE, GOOGLE_SCOPES, GOOGLE_TASKS_SCOPE, GoogleApiError, MAX_LIST_RESULTS, assertSafeMimeType, authorizeGoogle, brokerBaseUrl, brokerExchange, brokerRefresh, brokerStart, buildMultipartBody, calendarApiError, calendarSyncStatePath, canonicalCalendarId, classifyDelete, classifyWrite, clearCalendarSyncToken, clientSecretPresence, collectCalendarPages, commitLinkedTokens, completeTask, configureGoogleHost, createCalendarEvent, createDriveFile, createGoogleAuthFlow, createTask, deleteDriveFile, deleteGoogleTokens, deleteTask, findClientSecretPath, getCalendarColors, getGoogleAccessToken, googleApiError, googleAuthFlow, googleCalendarSyncTaskDef, googleConfigDir, googleSecretsDir, googleTokenPath, groupByCalendar, isGoogleApiError, isIsoDateTimeWithOffset, isTextMimeType, legacyGoogleTokenPath, listCalendarEvents, listCalendars, listDriveFiles, listTaskLists, listTasks, loadCalendarSyncToken, loadClientSecret, loadGoogleTokens, mergeGoogleTokens, pickBoundary, readDriveFile, saveCalendarSyncToken, saveGoogleTokens, syncCalendarEvents, syncCalendarGroup, syncDueCalendarCollections, toCalendarSummary, toCollectionDateTime, toCollectionRecord, toDriveFileSummary, toEventSummary, toTaskListSummary, toTaskSummary, unlinkGoogle, waitForAuthCode };
1341
+ export { DEFAULT_LIST_MAX_RESULTS, GOOGLE_AUTH_CANCELLED, GOOGLE_CALENDARLIST_SCOPE, GOOGLE_CALENDAR_SCOPE, GOOGLE_CALENDAR_SYNC_TASK_ID, GOOGLE_DRIVE_FILE_SCOPE, GOOGLE_SCOPES, GOOGLE_TASKS_SCOPE, GoogleApiError, MAX_LIST_RESULTS, anySyncedCollectionSurvives, assertSafeMimeType, authorizeGoogle, brokerBaseUrl, brokerExchange, brokerRefresh, brokerStart, buildEventPatch, buildMultipartBody, buildTaskPatch, calendarApiError, calendarSyncStatePath, canonicalCalendarId, canonicalTaskListId, classifyDelete, classifyWrite, clearCalendarSyncToken, clientSecretPresence, collectCalendarPages, commitLinkedTokens, completeTask, configureGoogleHost, createCalendarEvent, createDriveFile, createGoogleAuthFlow, createTask, deleteCalendarEvent, deleteDriveFile, deleteGoogleTokens, deleteTask, findClientSecretPath, getCalendarColors, getGoogleAccessToken, googleApiError, googleAuthFlow, googleCalendarSyncTaskDef, googleConfigDir, googleSecretsDir, googleTokenPath, groupByCalendar, isGoogleApiError, isIsoDateTimeWithOffset, isTextMimeType, legacyGoogleTokenPath, listCalendarEvents, listCalendars, listDriveFiles, listTaskLists, listTasks, loadCalendarSyncToken, loadClientSecret, loadGoogleTokens, mergeGoogleTokens, orphanedCalendarId, pickBoundary, readDriveFile, releaseOrphanedCalendarToken, saveCalendarSyncToken, saveGoogleTokens, syncCalendarEvents, syncCalendarForCollection, syncCalendarGroup, syncDueCalendarCollections, syncNewCalendarCollections, toCalendarSummary, toCollectionDateTime, toCollectionRecord, toDriveFileSummary, toEventSummary, toTaskListSummary, toTaskSummary, unlinkGoogle, unsyncedGroups, updateCalendarEvent, updateTask, waitForAuthCode, withKeyedLock };
1137
1342
 
1138
1343
  //# sourceMappingURL=index.js.map