From 2961cd813f8ff9eca30bbe35c631355befe5bcef Mon Sep 17 00:00:00 2001 From: "tembo-io[bot]" <208362400+tembo-io[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:02:02 +0000 Subject: [PATCH 1/5] fix(api): resolve Google Calendar sequence value conflicts - Preserve sequence numbers when updating Google Calendar events to prevent "Invalid sequence value" errors - Add retry logic to re-fetch events and use current sequence numbers when conflicts occur - Apply fixes to updateEvent, responseToEvent, acceptEvent methods in GoogleCalendarProvider - Add sequence conflict handling to GoogleMeetProvider createConference method - Ensure all Google Calendar API update operations include proper sequence number handling Fixes #59095795 - TRPCError: 400 Invalid sequence value error --- .../providers/calendars/google-calendar.ts | 255 ++++++++++++++---- .../src/providers/conferencing/google-meet.ts | 73 +++-- 2 files changed, 262 insertions(+), 66 deletions(-) diff --git a/packages/api/src/providers/calendars/google-calendar.ts b/packages/api/src/providers/calendars/google-calendar.ts index 14047bce..bc368630 100644 --- a/packages/api/src/providers/calendars/google-calendar.ts +++ b/packages/api/src/providers/calendars/google-calendar.ts @@ -189,58 +189,127 @@ export class GoogleCalendarProvider implements CalendarProvider { event: UpdateEventInput, ): Promise { return this.withErrorHandler("updateEvent", async () => { - const existingEvent = await this.client.calendars.events.retrieve( + let existingEvent = await this.client.calendars.events.retrieve( eventId, { calendarId: calendar.id, }, ); - let eventToUpdate = { - ...existingEvent, - calendarId: calendar.id, - ...toGoogleCalendarEvent(event), - }; + try { + let eventToUpdate = { + ...existingEvent, + calendarId: calendar.id, + ...toGoogleCalendarEvent(event), + // Preserve the sequence number to prevent conflicts + sequence: existingEvent.sequence, + }; - // Handle response status update within the same call for Google Calendar - if (event.response && event.response.status !== "unknown") { - if (!existingEvent.attendees) { - throw new Error("Event has no attendees"); + // Handle response status update within the same call for Google Calendar + if (event.response && event.response.status !== "unknown") { + if (!existingEvent.attendees) { + throw new Error("Event has no attendees"); + } + + const selfIndex = existingEvent.attendees.findIndex( + (attendee) => attendee.self, + ); + + if (selfIndex === -1) { + throw new Error("User is not an attendee"); + } + + const updatedAttendees = [...existingEvent.attendees]; + updatedAttendees[selfIndex] = { + ...updatedAttendees[selfIndex], + responseStatus: toGoogleCalendarAttendeeResponseStatus( + event.response.status, + ), + }; + + eventToUpdate = { + ...eventToUpdate, + attendees: updatedAttendees, + sendUpdates: event.response.sendUpdate ? "all" : "none", + }; } - const selfIndex = existingEvent.attendees.findIndex( - (attendee) => attendee.self, + const updatedEvent = await this.client.calendars.events.update( + eventId, + eventToUpdate, ); - if (selfIndex === -1) { - throw new Error("User is not an attendee"); + return parseGoogleCalendarEvent({ + calendar, + accountId: this.accountId, + event: updatedEvent, + }); + } catch (error) { + // Check if this is a sequence conflict error + if ( + error instanceof Error && + error.message.includes("Invalid sequence value") + ) { + // Re-fetch the event to get the latest sequence number and retry once + existingEvent = await this.client.calendars.events.retrieve( + eventId, + { + calendarId: calendar.id, + }, + ); + + let eventToUpdate = { + ...existingEvent, + calendarId: calendar.id, + ...toGoogleCalendarEvent(event), + // Use the fresh sequence number + sequence: existingEvent.sequence, + }; + + // Handle response status update within the same call for Google Calendar + if (event.response && event.response.status !== "unknown") { + if (!existingEvent.attendees) { + throw new Error("Event has no attendees"); + } + + const selfIndex = existingEvent.attendees.findIndex( + (attendee) => attendee.self, + ); + + if (selfIndex === -1) { + throw new Error("User is not an attendee"); + } + + const updatedAttendees = [...existingEvent.attendees]; + updatedAttendees[selfIndex] = { + ...updatedAttendees[selfIndex], + responseStatus: toGoogleCalendarAttendeeResponseStatus( + event.response.status, + ), + }; + + eventToUpdate = { + ...eventToUpdate, + attendees: updatedAttendees, + sendUpdates: event.response.sendUpdate ? "all" : "none", + }; + } + + const updatedEvent = await this.client.calendars.events.update( + eventId, + eventToUpdate, + ); + + return parseGoogleCalendarEvent({ + calendar, + accountId: this.accountId, + event: updatedEvent, + }); } - const updatedAttendees = [...existingEvent.attendees]; - updatedAttendees[selfIndex] = { - ...updatedAttendees[selfIndex], - responseStatus: toGoogleCalendarAttendeeResponseStatus( - event.response.status, - ), - }; - - eventToUpdate = { - ...eventToUpdate, - attendees: updatedAttendees, - sendUpdates: event.response.sendUpdate ? "all" : "none", - }; + // Re-throw other errors + throw error; } - - const updatedEvent = await this.client.calendars.events.update( - eventId, - eventToUpdate, - ); - - return parseGoogleCalendarEvent({ - calendar, - accountId: this.accountId, - event: updatedEvent, - }); }); } @@ -280,7 +349,7 @@ export class GoogleCalendarProvider implements CalendarProvider { async acceptEvent(calendarId: string, eventId: string): Promise { return this.withErrorHandler("acceptEvent", async () => { - const event = await this.client.calendars.events.retrieve(eventId, { + let event = await this.client.calendars.events.retrieve(eventId, { calendarId, }); @@ -296,12 +365,51 @@ export class GoogleCalendarProvider implements CalendarProvider { attendees.push({ self: true, responseStatus: "accepted" }); } - await this.client.calendars.events.update(eventId, { - ...event, - calendarId, - attendees, - sendUpdates: "all", - }); + try { + await this.client.calendars.events.update(eventId, { + ...event, + calendarId, + attendees, + // Preserve the sequence number to prevent conflicts + sequence: event.sequence, + sendUpdates: "all", + }); + } catch (error) { + // Check if this is a sequence conflict error and retry once + if ( + error instanceof Error && + error.message.includes("Invalid sequence value") + ) { + // Re-fetch the event to get the latest sequence number + event = await this.client.calendars.events.retrieve(eventId, { + calendarId, + }); + + const freshAttendees = event.attendees ?? []; + const freshSelfIndex = freshAttendees.findIndex((a) => a.self); + + if (freshSelfIndex >= 0) { + freshAttendees[freshSelfIndex] = { + ...freshAttendees[freshSelfIndex], + responseStatus: "accepted", + }; + } else { + freshAttendees.push({ self: true, responseStatus: "accepted" }); + } + + await this.client.calendars.events.update(eventId, { + ...event, + calendarId, + attendees: freshAttendees, + // Use the fresh sequence number + sequence: event.sequence, + sendUpdates: "all", + }); + } else { + // Re-throw other errors + throw error; + } + } }); } @@ -315,7 +423,7 @@ export class GoogleCalendarProvider implements CalendarProvider { return; } - const event = await this.client.calendars.events.retrieve(eventId, { + let event = await this.client.calendars.events.retrieve(eventId, { calendarId, }); @@ -334,11 +442,56 @@ export class GoogleCalendarProvider implements CalendarProvider { responseStatus: toGoogleCalendarAttendeeResponseStatus(response.status), }; - await this.client.calendars.events.update(eventId, { - ...event, - calendarId, - sendUpdates: response.sendUpdate ? "all" : "none", - }); + try { + await this.client.calendars.events.update(eventId, { + ...event, + calendarId, + // Preserve the sequence number to prevent conflicts + sequence: event.sequence, + sendUpdates: response.sendUpdate ? "all" : "none", + }); + } catch (error) { + // Check if this is a sequence conflict error and retry once + if ( + error instanceof Error && + error.message.includes("Invalid sequence value") + ) { + // Re-fetch the event to get the latest sequence number + event = await this.client.calendars.events.retrieve(eventId, { + calendarId, + }); + + if (!event.attendees) { + throw new Error("Event has no attendees"); + } + + const freshSelfIndex = event.attendees.findIndex( + (attendee) => attendee.self, + ); + + if (freshSelfIndex === -1) { + throw new Error("User is not an attendee"); + } + + event.attendees[freshSelfIndex] = { + ...event.attendees[freshSelfIndex], + responseStatus: toGoogleCalendarAttendeeResponseStatus( + response.status, + ), + }; + + await this.client.calendars.events.update(eventId, { + ...event, + calendarId, + // Use the fresh sequence number + sequence: event.sequence, + sendUpdates: response.sendUpdate ? "all" : "none", + }); + } else { + // Re-throw other errors + throw error; + } + } }); } diff --git a/packages/api/src/providers/conferencing/google-meet.ts b/packages/api/src/providers/conferencing/google-meet.ts index ad2d503d..72e48580 100644 --- a/packages/api/src/providers/conferencing/google-meet.ts +++ b/packages/api/src/providers/conferencing/google-meet.ts @@ -42,25 +42,68 @@ export class GoogleMeetProvider implements ConferencingProvider { }, ); - const updatedEvent = await this.client.calendars.events.update(eventId, { - calendarId, - ...existingEvent, - conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE - conferenceData: { - createRequest: { - requestId: crypto.randomUUID(), - conferenceSolutionKey: { - type: "hangoutsMeet", + try { + const updatedEvent = await this.client.calendars.events.update(eventId, { + calendarId, + ...existingEvent, + // Preserve the sequence number to prevent conflicts + sequence: existingEvent.sequence, + conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE + conferenceData: { + createRequest: { + requestId: crypto.randomUUID(), + conferenceSolutionKey: { + type: "hangoutsMeet", + }, }, }, - }, - }); + }); - if (!updatedEvent.conferenceData) { - throw new Error("Failed to create conference data"); - } + if (!updatedEvent.conferenceData) { + throw new Error("Failed to create conference data"); + } + + return parseGoogleCalendarConferenceData(updatedEvent)!; + } catch (error) { + // Check if this is a sequence conflict error and retry once + if ( + error instanceof Error && + error.message.includes("Invalid sequence value") + ) { + // Re-fetch the event to get the latest sequence number + const freshEvent = await this.client.calendars.events.retrieve( + eventId, + { + calendarId, + }, + ); - return parseGoogleCalendarConferenceData(updatedEvent)!; + const updatedEvent = await this.client.calendars.events.update(eventId, { + calendarId, + ...freshEvent, + // Use the fresh sequence number + sequence: freshEvent.sequence, + conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE + conferenceData: { + createRequest: { + requestId: crypto.randomUUID(), + conferenceSolutionKey: { + type: "hangoutsMeet", + }, + }, + }, + }); + + if (!updatedEvent.conferenceData) { + throw new Error("Failed to create conference data"); + } + + return parseGoogleCalendarConferenceData(updatedEvent)!; + } + + // Re-throw other errors + throw error; + } }); } From babd5bd43baca4599e85af543c72f1b832791cd4 Mon Sep 17 00:00:00 2001 From: "tembo-io[bot]" <208362400+tembo-io[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:20:51 +0000 Subject: [PATCH 2/5] style: format code for consistent indentation --- .../providers/calendars/google-calendar.ts | 18 +++---- .../src/providers/conferencing/google-meet.ts | 54 ++++++++++--------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/api/src/providers/calendars/google-calendar.ts b/packages/api/src/providers/calendars/google-calendar.ts index bc368630..41912e2f 100644 --- a/packages/api/src/providers/calendars/google-calendar.ts +++ b/packages/api/src/providers/calendars/google-calendar.ts @@ -189,12 +189,9 @@ export class GoogleCalendarProvider implements CalendarProvider { event: UpdateEventInput, ): Promise { return this.withErrorHandler("updateEvent", async () => { - let existingEvent = await this.client.calendars.events.retrieve( - eventId, - { - calendarId: calendar.id, - }, - ); + let existingEvent = await this.client.calendars.events.retrieve(eventId, { + calendarId: calendar.id, + }); try { let eventToUpdate = { @@ -251,12 +248,9 @@ export class GoogleCalendarProvider implements CalendarProvider { error.message.includes("Invalid sequence value") ) { // Re-fetch the event to get the latest sequence number and retry once - existingEvent = await this.client.calendars.events.retrieve( - eventId, - { - calendarId: calendar.id, - }, - ); + existingEvent = await this.client.calendars.events.retrieve(eventId, { + calendarId: calendar.id, + }); let eventToUpdate = { ...existingEvent, diff --git a/packages/api/src/providers/conferencing/google-meet.ts b/packages/api/src/providers/conferencing/google-meet.ts index 72e48580..5b8ca704 100644 --- a/packages/api/src/providers/conferencing/google-meet.ts +++ b/packages/api/src/providers/conferencing/google-meet.ts @@ -43,21 +43,24 @@ export class GoogleMeetProvider implements ConferencingProvider { ); try { - const updatedEvent = await this.client.calendars.events.update(eventId, { - calendarId, - ...existingEvent, - // Preserve the sequence number to prevent conflicts - sequence: existingEvent.sequence, - conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE - conferenceData: { - createRequest: { - requestId: crypto.randomUUID(), - conferenceSolutionKey: { - type: "hangoutsMeet", + const updatedEvent = await this.client.calendars.events.update( + eventId, + { + calendarId, + ...existingEvent, + // Preserve the sequence number to prevent conflicts + sequence: existingEvent.sequence, + conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE + conferenceData: { + createRequest: { + requestId: crypto.randomUUID(), + conferenceSolutionKey: { + type: "hangoutsMeet", + }, }, }, }, - }); + ); if (!updatedEvent.conferenceData) { throw new Error("Failed to create conference data"); @@ -78,21 +81,24 @@ export class GoogleMeetProvider implements ConferencingProvider { }, ); - const updatedEvent = await this.client.calendars.events.update(eventId, { - calendarId, - ...freshEvent, - // Use the fresh sequence number - sequence: freshEvent.sequence, - conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE - conferenceData: { - createRequest: { - requestId: crypto.randomUUID(), - conferenceSolutionKey: { - type: "hangoutsMeet", + const updatedEvent = await this.client.calendars.events.update( + eventId, + { + calendarId, + ...freshEvent, + // Use the fresh sequence number + sequence: freshEvent.sequence, + conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE + conferenceData: { + createRequest: { + requestId: crypto.randomUUID(), + conferenceSolutionKey: { + type: "hangoutsMeet", + }, }, }, }, - }); + ); if (!updatedEvent.conferenceData) { throw new Error("Failed to create conference data"); From d0cd634bc145f6ebbcd9847e715e931ad71bf796 Mon Sep 17 00:00:00 2001 From: "tembo-io[bot]" <208362400+tembo-io[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:27:23 +0000 Subject: [PATCH 3/5] fix(types): resolve crypto.randomUUID type errors - Add proper import for randomUUID from node:crypto in API packages - Use globalThis.crypto.randomUUID in web app for browser compatibility - Fix TypeScript compilation errors in workflow Resolves type checking failures in CI workflow. --- apps/web/src/lib/utils/calendar.ts | 2 +- packages/api/src/providers/conferencing/google-meet.ts | 5 +++-- packages/api/src/routers/events.ts | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/web/src/lib/utils/calendar.ts b/apps/web/src/lib/utils/calendar.ts index c3f1ae6d..8cd27156 100644 --- a/apps/web/src/lib/utils/calendar.ts +++ b/apps/web/src/lib/utils/calendar.ts @@ -28,5 +28,5 @@ export function isDraftEvent( } export function createEventId() { - return `${crypto.randomUUID()}`.replace(/-/g, ""); + return `${globalThis.crypto.randomUUID()}`.replace(/-/g, ""); } diff --git a/packages/api/src/providers/conferencing/google-meet.ts b/packages/api/src/providers/conferencing/google-meet.ts index 72e48580..93ea6ce1 100644 --- a/packages/api/src/providers/conferencing/google-meet.ts +++ b/packages/api/src/providers/conferencing/google-meet.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import GoogleCalendar from "@repo/google-calendar"; import type { Conference } from "../../interfaces"; @@ -51,7 +52,7 @@ export class GoogleMeetProvider implements ConferencingProvider { conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE conferenceData: { createRequest: { - requestId: crypto.randomUUID(), + requestId: randomUUID(), conferenceSolutionKey: { type: "hangoutsMeet", }, @@ -86,7 +87,7 @@ export class GoogleMeetProvider implements ConferencingProvider { conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE conferenceData: { createRequest: { - requestId: crypto.randomUUID(), + requestId: randomUUID(), conferenceSolutionKey: { type: "hangoutsMeet", }, diff --git a/packages/api/src/routers/events.ts b/packages/api/src/routers/events.ts index 94e64580..4bf37b00 100644 --- a/packages/api/src/routers/events.ts +++ b/packages/api/src/routers/events.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import { TRPCError } from "@trpc/server"; import * as R from "remeda"; import { Temporal } from "temporal-polyfill"; @@ -279,7 +280,7 @@ export const eventsRouter = createTRPCRouter({ destinationCalendar, { ...data, - id: crypto.randomUUID(), + id: randomUUID(), accountId: move.destination.accountId, calendarId: destinationCalendar.id, }, @@ -391,7 +392,7 @@ export const eventsRouter = createTRPCRouter({ destinationCalendar, { ...sourceEvent, - id: crypto.randomUUID(), + id: randomUUID(), accountId: input.destination.accountId, calendarId: input.destination.calendarId, providerId: "google", From bf10d500b14f8c85f3696e955bbd571324eae1c3 Mon Sep 17 00:00:00 2001 From: "tembo-io[bot]" <208362400+tembo-io[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:37:44 +0000 Subject: [PATCH 4/5] fix(auth): remove unused secondaryStorage import --- packages/auth/src/server.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/auth/src/server.ts b/packages/auth/src/server.ts index dec11589..c7223db0 100644 --- a/packages/auth/src/server.ts +++ b/packages/auth/src/server.ts @@ -7,7 +7,6 @@ import { db } from "@repo/db"; import type { account as accountTable } from "@repo/db/schema"; import { env } from "@repo/env/server"; -import { secondaryStorage } from "./secondary-storage"; import { createProviderHandler, handleUnlinkAccount, From 52831449ebef86066b4d071b62006c40355fe3b0 Mon Sep 17 00:00:00 2001 From: "tembo-io[bot]" <208362400+tembo-io[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 22:22:21 +0000 Subject: [PATCH 5/5] fix(calendar): resolve merge conflicts & sequence errors --- .../providers/calendars/google-calendar.ts | 41 ++++++++-------- .../src/providers/conferencing/google-meet.ts | 47 +++---------------- 2 files changed, 28 insertions(+), 60 deletions(-) diff --git a/packages/api/src/providers/calendars/google-calendar.ts b/packages/api/src/providers/calendars/google-calendar.ts index 41912e2f..706472e8 100644 --- a/packages/api/src/providers/calendars/google-calendar.ts +++ b/packages/api/src/providers/calendars/google-calendar.ts @@ -19,6 +19,10 @@ import { import { parseGoogleCalendarFreeBusy } from "./google-calendar/freebusy"; import type { CalendarProvider, ResponseToEventInput } from "./interfaces"; +function isInvalidSequenceError(err: unknown): boolean { + return err instanceof Error && /invalid sequence value/i.test(err.message); +} + interface GoogleCalendarProviderOptions { accessToken: string; accountId: string; @@ -204,19 +208,22 @@ export class GoogleCalendarProvider implements CalendarProvider { // Handle response status update within the same call for Google Calendar if (event.response && event.response.status !== "unknown") { - if (!existingEvent.attendees) { + const baseAttendees = + (toGoogleCalendarEvent(event) as any).attendees ?? + existingEvent.attendees; + if (!baseAttendees) { throw new Error("Event has no attendees"); } - const selfIndex = existingEvent.attendees.findIndex( - (attendee) => attendee.self, + const selfIndex = baseAttendees.findIndex( + (attendee: any) => attendee.self, ); if (selfIndex === -1) { throw new Error("User is not an attendee"); } - const updatedAttendees = [...existingEvent.attendees]; + const updatedAttendees = [...baseAttendees]; updatedAttendees[selfIndex] = { ...updatedAttendees[selfIndex], responseStatus: toGoogleCalendarAttendeeResponseStatus( @@ -243,10 +250,7 @@ export class GoogleCalendarProvider implements CalendarProvider { }); } catch (error) { // Check if this is a sequence conflict error - if ( - error instanceof Error && - error.message.includes("Invalid sequence value") - ) { + if (isInvalidSequenceError(error)) { // Re-fetch the event to get the latest sequence number and retry once existingEvent = await this.client.calendars.events.retrieve(eventId, { calendarId: calendar.id, @@ -262,19 +266,22 @@ export class GoogleCalendarProvider implements CalendarProvider { // Handle response status update within the same call for Google Calendar if (event.response && event.response.status !== "unknown") { - if (!existingEvent.attendees) { + const baseAttendees = + (toGoogleCalendarEvent(event) as any).attendees ?? + existingEvent.attendees; + if (!baseAttendees) { throw new Error("Event has no attendees"); } - const selfIndex = existingEvent.attendees.findIndex( - (attendee) => attendee.self, + const selfIndex = baseAttendees.findIndex( + (attendee: any) => attendee.self, ); if (selfIndex === -1) { throw new Error("User is not an attendee"); } - const updatedAttendees = [...existingEvent.attendees]; + const updatedAttendees = [...baseAttendees]; updatedAttendees[selfIndex] = { ...updatedAttendees[selfIndex], responseStatus: toGoogleCalendarAttendeeResponseStatus( @@ -370,10 +377,7 @@ export class GoogleCalendarProvider implements CalendarProvider { }); } catch (error) { // Check if this is a sequence conflict error and retry once - if ( - error instanceof Error && - error.message.includes("Invalid sequence value") - ) { + if (isInvalidSequenceError(error)) { // Re-fetch the event to get the latest sequence number event = await this.client.calendars.events.retrieve(eventId, { calendarId, @@ -446,10 +450,7 @@ export class GoogleCalendarProvider implements CalendarProvider { }); } catch (error) { // Check if this is a sequence conflict error and retry once - if ( - error instanceof Error && - error.message.includes("Invalid sequence value") - ) { + if (isInvalidSequenceError(error)) { // Re-fetch the event to get the latest sequence number event = await this.client.calendars.events.retrieve(eventId, { calendarId, diff --git a/packages/api/src/providers/conferencing/google-meet.ts b/packages/api/src/providers/conferencing/google-meet.ts index 82c13d35..bdb6fc9b 100644 --- a/packages/api/src/providers/conferencing/google-meet.ts +++ b/packages/api/src/providers/conferencing/google-meet.ts @@ -6,6 +6,10 @@ import { parseGoogleCalendarConferenceData } from "../calendars/google-calendar/ import { ProviderError } from "../lib/provider-error"; import type { ConferencingProvider } from "./interfaces"; +function isInvalidSequenceError(err: unknown): boolean { + return err instanceof Error && /invalid sequence value/i.test(err.message); +} + interface GoogleMeetProviderOptions { accessToken: string; accountId: string; @@ -44,7 +48,6 @@ export class GoogleMeetProvider implements ConferencingProvider { ); try { -<<<<<<< HEAD const updatedEvent = await this.client.calendars.events.update(eventId, { calendarId, ...existingEvent, @@ -56,26 +59,10 @@ export class GoogleMeetProvider implements ConferencingProvider { requestId: randomUUID(), conferenceSolutionKey: { type: "hangoutsMeet", -======= - const updatedEvent = await this.client.calendars.events.update( - eventId, - { - calendarId, - ...existingEvent, - // Preserve the sequence number to prevent conflicts - sequence: existingEvent.sequence, - conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE - conferenceData: { - createRequest: { - requestId: crypto.randomUUID(), - conferenceSolutionKey: { - type: "hangoutsMeet", - }, ->>>>>>> babd5bd43baca4599e85af543c72f1b832791cd4 }, }, }, - ); + }); if (!updatedEvent.conferenceData) { throw new Error("Failed to create conference data"); @@ -84,10 +71,7 @@ export class GoogleMeetProvider implements ConferencingProvider { return parseGoogleCalendarConferenceData(updatedEvent)!; } catch (error) { // Check if this is a sequence conflict error and retry once - if ( - error instanceof Error && - error.message.includes("Invalid sequence value") - ) { + if (isInvalidSequenceError(error)) { // Re-fetch the event to get the latest sequence number const freshEvent = await this.client.calendars.events.retrieve( eventId, @@ -96,7 +80,6 @@ export class GoogleMeetProvider implements ConferencingProvider { }, ); -<<<<<<< HEAD const updatedEvent = await this.client.calendars.events.update(eventId, { calendarId, ...freshEvent, @@ -108,26 +91,10 @@ export class GoogleMeetProvider implements ConferencingProvider { requestId: randomUUID(), conferenceSolutionKey: { type: "hangoutsMeet", -======= - const updatedEvent = await this.client.calendars.events.update( - eventId, - { - calendarId, - ...freshEvent, - // Use the fresh sequence number - sequence: freshEvent.sequence, - conferenceDataVersion: 1, // This ensures the conference data is created, DO NOT REMOVE - conferenceData: { - createRequest: { - requestId: crypto.randomUUID(), - conferenceSolutionKey: { - type: "hangoutsMeet", - }, ->>>>>>> babd5bd43baca4599e85af543c72f1b832791cd4 }, }, }, - ); + }); if (!updatedEvent.conferenceData) { throw new Error("Failed to create conference data");