chore(providers): improve provider structure and add notifications#452
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
3 issues found across 30 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/providers/src/calendars/microsoft-calendar/events/index.ts">
<violation number="1" location="packages/providers/src/calendars/microsoft-calendar/events/index.ts:135">
P1: `move` returns a synthetic event with destination calendar metadata but never persists a move, causing state to diverge from Microsoft Calendar.</violation>
</file>
<file name="packages/providers/src/calendars/google-calendar/events/index.ts">
<violation number="1" location="packages/providers/src/calendars/google-calendar/events/index.ts:225">
P2: Calling `this.update()` here causes double error-wrapping and double logging. Both `create`'s and `update`'s `withErrorHandler` will catch, `console.error`, and wrap the same failure in nested `ProviderError` instances. Consider calling the client directly (as `update` does internally) or stripping the inner handler to avoid losing the original error in a `ProviderError` → `ProviderError` chain.</violation>
</file>
<file name="packages/providers/src/calendars/microsoft-calendar/utils.ts">
<violation number="1" location="packages/providers/src/calendars/microsoft-calendar/utils.ts:71">
P1: `dateTime` is serialized with a UTC `Z` offset for `ZonedDateTime`, which can cause Microsoft Graph to ignore the provided `timeZone` and store shifted times.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| syncToken = response["@odata.deltaLink"]; | ||
| } while (pageToken); | ||
|
|
||
| return { |
There was a problem hiding this comment.
P1: move returns a synthetic event with destination calendar metadata but never persists a move, causing state to diverge from Microsoft Calendar.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/providers/src/calendars/microsoft-calendar/events/index.ts, line 135:
<comment>`move` returns a synthetic event with destination calendar metadata but never persists a move, causing state to diverge from Microsoft Calendar.</comment>
<file context>
@@ -0,0 +1,273 @@
+ syncToken = response["@odata.deltaLink"];
+ } while (pageToken);
+
+ return {
+ changes,
+ syncToken,
</file context>
| } | ||
|
|
||
| return { | ||
| dateTime: value.toInstant().toString(), |
There was a problem hiding this comment.
P1: dateTime is serialized with a UTC Z offset for ZonedDateTime, which can cause Microsoft Graph to ignore the provided timeZone and store shifted times.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/providers/src/calendars/microsoft-calendar/utils.ts, line 71:
<comment>`dateTime` is serialized with a UTC `Z` offset for `ZonedDateTime`, which can cause Microsoft Graph to ignore the provided `timeZone` and store shifted times.</comment>
<file context>
@@ -28,3 +28,50 @@ export function parseDateTime(dateTime: string, timeZone: string) {
+ }
+
+ return {
+ dateTime: value.toInstant().toString(),
+ timeZone:
+ originalTimeZone?.parsed === value.timeZoneId
</file context>
| dateTime: value.toInstant().toString(), | |
| dateTime: value.toPlainDateTime().toString(), |
| } catch (error) { | ||
| // If the event already exists, update it instead of throwing an error | ||
| if (error instanceof ConflictError) { | ||
| return await this.update({ |
There was a problem hiding this comment.
P2: Calling this.update() here causes double error-wrapping and double logging. Both create's and update's withErrorHandler will catch, console.error, and wrap the same failure in nested ProviderError instances. Consider calling the client directly (as update does internally) or stripping the inner handler to avoid losing the original error in a ProviderError → ProviderError chain.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/providers/src/calendars/google-calendar/events/index.ts, line 225:
<comment>Calling `this.update()` here causes double error-wrapping and double logging. Both `create`'s and `update`'s `withErrorHandler` will catch, `console.error`, and wrap the same failure in nested `ProviderError` instances. Consider calling the client directly (as `update` does internally) or stripping the inner handler to avoid losing the original error in a `ProviderError` → `ProviderError` chain.</comment>
<file context>
@@ -0,0 +1,446 @@
+ } catch (error) {
+ // If the event already exists, update it instead of throwing an error
+ if (error instanceof ConflictError) {
+ return await this.update({
+ calendar,
+ eventId: event.id,
</file context>
Description
Briefly describe what you did and why.
Screenshots / Recordings
Add screenshots or recordings here to help reviewers understand your changes.
Type of Change
Related Areas
Testing
Checklist
Notes
(Optional) Add anything else you'd like to share.
By submitting, I confirm I understand and stand behind this code. If AI was used, I’ve reviewed and verified everything myself.
Summary by cubic
Refactored calendar and task providers into clear sub-APIs and added Google Calendar webhook notifications. This simplifies integrations and makes provider methods consistent across Google and Microsoft.
New Features
notifications.subscribeandnotifications.unsubscribe.freeBusy.query({ schedules, timeMin, timeMax })for Google and Microsoft.Migration
calendars()→calendars.list(),calendar(id)→calendars.get({ calendarId: id }),createCalendar(data)→calendars.create({ calendar: data }),updateCalendar(id, data)→calendars.update({ calendarId: id, calendar: data }),deleteCalendar(id)→calendars.delete({ calendarId: id }).events(calendar, timeMin, timeMax, tz)→events.list({ calendar, timeMin, timeMax, timeZone: tz });sync(...)→events.sync({...});event(calendar, id, tz)→events.get({ calendar, eventId: id, timeZone: tz });createEvent(calendar, input)→events.create({ calendar, event: input });updateEvent(calendar, id, input)→events.update({ calendar, eventId: id, event: input });deleteEvent(calendarId, id, send)→events.delete({ calendarId, eventId: id, sendUpdate: send });moveEvent(src, dst, id, send)→events.move({ sourceCalendar: src, destinationCalendar: dst, eventId: id, sendUpdate: send });responseToEvent(calendarId, id, response)→events.respond({ calendarId, eventId: id, response }).createConference(agenda, start, end, tz?, calendarId?, eventId?)→createConference({ agenda, startTime: start, endTime: end, timeZone: tz, calendarId, eventId }).tasks()→tasks.list(),taskCollections()→collections.list(),tasksForTaskCollection(id)→collections.tasks({ taskCollectionId: id }),createTask(task)→tasks.create({ task }),updateTask(task)→tasks.update({ task }),deleteTask(listId, taskId)→tasks.delete({ taskCollectionId: listId, taskId }).Written for commit 1607bf2. Summary will update on new commits.