@@ -101,13 +101,12 @@ export const googleCalendarPollingHandler: PollingProviderHandler = {
101101
102102 const config = webhookData . providerConfig as unknown as GoogleCalendarWebhookConfig
103103 const calendarId = config . calendarId || config . manualCalendarId || 'primary'
104- const now = new Date ( )
105104
106105 // First poll: seed timestamp, emit nothing
107106 if ( ! config . lastCheckedTimestamp ) {
108107 await updateWebhookProviderConfig (
109108 webhookId ,
110- { lastCheckedTimestamp : now . toISOString ( ) } ,
109+ { lastCheckedTimestamp : new Date ( ) . toISOString ( ) } ,
111110 logger
112111 )
113112 await markWebhookSuccess ( webhookId , logger )
@@ -119,11 +118,10 @@ export const googleCalendarPollingHandler: PollingProviderHandler = {
119118 const events = await fetchChangedEvents ( accessToken , calendarId , config , requestId , logger )
120119
121120 if ( ! events . length ) {
122- await updateWebhookProviderConfig (
123- webhookId ,
124- { lastCheckedTimestamp : now . toISOString ( ) } ,
125- logger
126- )
121+ // Do not advance the timestamp when no events are found — only server-side timestamps
122+ // from actual event responses are used to advance the cursor. Advancing to the client
123+ // clock risks skipping events whose server-side updated timestamp falls in any clock
124+ // skew gap between the client and Google's servers.
127125 await markWebhookSuccess ( webhookId , logger )
128126 logger . info ( `[${ requestId } ] No changed events for webhook ${ webhookId } ` )
129127 return 'success'
@@ -146,7 +144,7 @@ export const googleCalendarPollingHandler: PollingProviderHandler = {
146144 ? config . lastCheckedTimestamp
147145 : latestUpdated
148146 ? new Date ( new Date ( latestUpdated ) . getTime ( ) + 1 ) . toISOString ( )
149- : now . toISOString ( )
147+ : config . lastCheckedTimestamp
150148 await updateWebhookProviderConfig ( webhookId , { lastCheckedTimestamp : newTimestamp } , logger )
151149
152150 if ( failedCount > 0 && processedCount === 0 ) {
0 commit comments