-
Notifications
You must be signed in to change notification settings - Fork 10.4k
feat: implement Google Calendar sync tokens for incremental webhook updates #22508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…pdates (#22366) Co-authored-by: keith@cal.com <keithwillcode@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Omar López <zomars@me.com>
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Skipped Deployments
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the """ WalkthroughThis update introduces incremental synchronization for Google Calendar availability caching using sync tokens. It adds new methods for incremental event fetching, cache management, and sibling calendar refresh. The database schema and cache repository are extended to store sync tokens. Comprehensive unit and integration tests validate incremental sync, cache merging, and sibling refresh behaviors. Changes
Suggested labels
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
✅ No security or compliance issues detected. Reviewed everything up to 494e7bf. Security Overview
Detected Code ChangesThe diff is too large to display a summary of code changes. Reply to this PR with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
packages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts (1)
764-764
: Remove debug console.log statements.Debug logging should be removed from test code.
- console.log({ calendarCachesAfter });
- console.log({ error });
Also applies to: 783-783
🧹 Nitpick comments (8)
packages/app-store/googlecalendar/api/webhook.ts (1)
46-50
: Improve type safety while maintaining backward compatibility.The conditional logic correctly implements the incremental sync fallback, but the
any
type casting reduces type safety.Consider using a type guard or interface method checking instead:
- if ((calendarServiceForCalendarCache as any)?.fetchAvailabilityAndSetCacheIncremental) { - await (calendarServiceForCalendarCache as any).fetchAvailabilityAndSetCacheIncremental(selectedCalendars); + if ('fetchAvailabilityAndSetCacheIncremental' in calendarServiceForCalendarCache) { + await calendarServiceForCalendarCache.fetchAvailabilityAndSetCacheIncremental(selectedCalendars); } else { await calendarServiceForCalendarCache?.fetchAvailabilityAndSetCache?.(selectedCalendars); }This approach maintains the same functionality while providing better type safety.
packages/app-store/googlecalendar/lib/__tests__/sibling-refresh.integration-test.ts (1)
355-355
: Consider increasing the performance threshold to reduce test flakiness.The 1-second threshold for database operations might be too strict and could cause intermittent test failures in CI/CD environments with variable performance.
- expect(duration).toBeLessThan(1000); // Should complete within 1 second + expect(duration).toBeLessThan(5000); // Should complete within 5 secondspackages/app-store/googlecalendar/lib/__tests__/round-robin-individual-caches.integration-test.ts (1)
501-501
: Consider increasing the performance threshold for consistency.Similar to the sibling refresh tests, the 1-second threshold might be too strict.
- expect(duration).toBeLessThan(1000); // Should complete within 1 second + expect(duration).toBeLessThan(5000); // Should complete within 5 secondspackages/app-store/googlecalendar/lib/__tests__/google-calendar-sync-tokens.integration-test.ts (2)
39-57
: Consider removing redundant pre-test cleanup.The cleanup operations in
beforeEach
appear redundant sinceafterEach
already handles data cleanup. This could slow down test execution unnecessarily.- // Don't delete seeded data - only clean up specific test records - await prisma.selectedCalendar.deleteMany({ - where: { - user: { - email: { contains: testUniqueId }, - }, - }, - }); - await prisma.credential.deleteMany({ - where: { - user: { - email: { contains: testUniqueId }, - }, - }, - }); - await prisma.user.deleteMany({ - where: { - email: { contains: testUniqueId }, - }, - });
501-501
: Align performance threshold with other test files.For consistency across all integration tests, consider using the same performance threshold.
- expect(duration).toBeLessThan(1000); // Should complete within 1 second + expect(duration).toBeLessThan(5000); // Should complete within 5 secondspackages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts (2)
1773-1797
: Consider using dynamic dates in test data for consistency.The mock data uses hardcoded dates like "2024-03-15" while the helper function
getTestDateRange
uses dynamic dates based on the current time. This inconsistency could cause issues when tests run at different times or in different time zones.Consider aligning the mock data with the dynamic date approach:
- const mockSingleCalendarEvents = [ - { - id: "event1", - status: "confirmed", - start: { dateTime: "2024-03-15T10:00:00Z" }, - end: { dateTime: "2024-03-15T11:00:00Z" }, - }, - { - id: "event2", - status: "confirmed", - start: { dateTime: "2024-03-15T14:00:00Z" }, - end: { dateTime: "2024-03-15T15:00:00Z" }, - }, - ]; + const getTestDateRange = () => { + const now = new Date(); + // Use current month boundaries for consistency + const timeMin = getTimeMin(now.toISOString()); + const timeMax = getTimeMax(now.toISOString()); + + // Use specific dates within the current month for event testing + const testStart = new Date(now.getFullYear(), now.getMonth(), 15, 10, 0, 0); + const testEnd = new Date(now.getFullYear(), now.getMonth(), 15, 23, 59, 59); + + return { + timeMin, + timeMax, + testDateFrom: testStart.toISOString(), + testDateTo: testEnd.toISOString(), + }; + }; + + const { timeMin } = getTestDateRange(); + const baseDate = timeMin.split("T")[0]; + + const mockSingleCalendarEvents = [ + { + id: "event1", + status: "confirmed", + start: { dateTime: `${baseDate}T10:00:00Z` }, + end: { dateTime: `${baseDate}T11:00:00Z` }, + }, + { + id: "event2", + status: "confirmed", + start: { dateTime: `${baseDate}T14:00:00Z` }, + end: { dateTime: `${baseDate}T15:00:00Z` }, + }, + ];
2395-2440
: Consider testing through public interface when possible.While testing the existence of
fetchAvailabilityAndSetCacheIncremental
is important for webhook integration, accessing private methods withas any
makes tests brittle to refactoring.Consider exposing this method through a public interface if it's meant to be used by webhook handlers, or test the behavior through public methods that use it internally.
packages/app-store/googlecalendar/lib/CalendarService.ts (1)
1229-1266
: Consider adding safeguards against cascading sibling refreshes.While the proactive sibling refresh is a clever optimization for ensuring multi-calendar cache availability, be mindful of potential performance impacts with many calendars or high-frequency updates.
Consider implementing:
- A refresh cooldown period to prevent rapid successive refreshes
- A maximum depth or breadth limit for sibling refreshes
- Metrics/logging to monitor refresh patterns in production
The current implementation with cache status checks should prevent infinite loops, but monitoring would help ensure this optimization doesn't become a bottleneck.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
packages/app-store/googlecalendar/api/webhook.ts
(1 hunks)packages/app-store/googlecalendar/lib/CalendarService.ts
(5 hunks)packages/app-store/googlecalendar/lib/__mocks__/googleapis.ts
(1 hunks)packages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts
(1 hunks)packages/app-store/googlecalendar/lib/__tests__/google-calendar-sync-tokens.integration-test.ts
(1 hunks)packages/app-store/googlecalendar/lib/__tests__/round-robin-individual-caches.integration-test.ts
(1 hunks)packages/app-store/googlecalendar/lib/__tests__/sibling-refresh.integration-test.ts
(1 hunks)packages/features/calendar-cache/calendar-cache.repository.interface.ts
(1 hunks)packages/features/calendar-cache/calendar-cache.repository.ts
(3 hunks)packages/prisma/migrations/20250711215639_add_next_sync_token_to_calendar_cache/migration.sql
(1 hunks)packages/prisma/schema.prisma
(1 hunks)packages/types/Calendar.d.ts
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/features/calendar-cache/calendar-cache.repository.ts (1)
packages/features/calendar-cache/calendar-cache.repository.interface.ts (1)
FreeBusyArgs
(5-5)
packages/app-store/googlecalendar/lib/__tests__/sibling-refresh.integration-test.ts (2)
packages/features/calendar-cache/calendar-cache.repository.ts (1)
CalendarCacheRepository
(51-176)packages/features/calendar-cache/lib/datesForCache.ts (2)
getTimeMin
(2-8)getTimeMax
(21-59)
packages/app-store/googlecalendar/lib/CalendarService.ts (3)
packages/types/Calendar.d.ts (1)
EventBusyDate
(56-60)packages/features/calendar-cache/lib/datesForCache.ts (2)
getTimeMin
(2-8)getTimeMax
(21-59)packages/features/calendar-cache/calendar-cache.ts (1)
CalendarCache
(14-30)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Security Check
🔇 Additional comments (16)
packages/app-store/googlecalendar/lib/__mocks__/googleapis.ts (1)
27-32
: LGTM! Clean mock implementation for testing incremental sync.The mock correctly returns the expected Google Calendar API response structure with
items
andnextSyncToken
, which supports testing of the new incremental synchronization functionality.packages/prisma/migrations/20250711215639_add_next_sync_token_to_calendar_cache/migration.sql (1)
1-2
: LGTM! Clean migration to support sync tokens.The migration correctly adds an optional
nextSyncToken
TEXT column to support incremental calendar synchronization. Making it nullable ensures backward compatibility with existing cache entries.packages/types/Calendar.d.ts (1)
297-297
: LGTM! Well-designed interface extension.The new optional method follows the existing interface patterns and maintains backward compatibility while enabling incremental calendar synchronization functionality.
packages/prisma/schema.prisma (1)
720-720
: LGTM! Schema correctly aligned with migration.The
nextSyncToken
field is properly defined as an optional String, matching the migration and supporting the incremental calendar synchronization feature.packages/features/calendar-cache/calendar-cache.repository.interface.ts (1)
15-15
: LGTM! Clean interface extension for sync token support.The optional
nextSyncToken
parameter is properly typed and aligns well with the incremental sync feature implementation.Also applies to: 21-21
packages/features/calendar-cache/calendar-cache.repository.ts (2)
15-16
: Verify the implications of extending cache duration to 3 months.The cache duration has been extended from 30 days to 90 days. While this reduces API calls and improves performance, it may lead to:
- Increased storage requirements
- Potentially stale calendar data for users who don't receive webhook updates
- Longer retention of deleted or modified events
Please ensure this aligns with your data freshness requirements and storage capacity.
137-175
: Well-implemented sync token storage!The
nextSyncToken
is correctly integrated into both update and create operations, maintaining consistency with the interface changes.packages/app-store/googlecalendar/lib/__tests__/sibling-refresh.integration-test.ts (1)
359-514
: Excellent test coverage for cache refresh coordination!The tests comprehensively cover:
- Cache coordination across sibling calendars
- Sync token persistence and retrieval
- Different time range scenarios
Well-structured integration tests that validate the sibling refresh feature.
packages/app-store/googlecalendar/lib/__tests__/CalendarService.test.ts (6)
1818-1995
: Comprehensive test coverage for fetchEventsIncremental.The test suite thoroughly covers sync token functionality including:
- Initial sync without token
- Incremental sync with existing token
- Pagination handling
- 410 error fallback to full sync
- Proper error propagation for non-410 errors
Well-structured and follows testing best practices.
1997-2044
: Good edge case coverage for event conversion.The tests properly validate:
- Standard event conversion
- Filtering of cancelled events
- Handling of all-day events (without dateTime)
This ensures robust event processing.
2046-2243
: Excellent test coverage for cache operations with sync tokens.The tests validate:
- Cache storage with sync tokens
- Incremental sync using cached tokens
- Full sync fallback when no token exists
- Error handling and recovery
The cache integration is well-tested.
2245-2393
: Well-designed tests for multi-calendar cache merging fix.The tests effectively validate that:
- Individual calendar caches created by incremental sync are properly merged
- Multi-calendar queries hit the merged cache
- No unnecessary API calls are made when cache is available
Great use of spies to verify the caching behavior.
2442-2525
: Excellent edge case and performance testing.The tests cover important scenarios:
- Empty event handling
- Large dataset performance (1000 events < 1 second)
- Graceful handling of malformed events
The performance assertion provides a concrete benchmark.
2527-2878
: Outstanding test coverage for sibling calendar refresh feature.These tests thoroughly validate:
- Proactive sibling calendar refresh during webhook processing
- Optimization to skip calendars with fresh sync token cache
- Selective refresh based on cache state (old-style, missing, or fresh)
The tests effectively demonstrate the performance benefits of the optimization.
packages/app-store/googlecalendar/lib/CalendarService.ts (2)
525-544
: LGTM!The
convertEventsToBusyTimes
method correctly filters out invalid events and converts valid events to the expected format.
705-761
: Excellent cache optimization!The enhanced cache retrieval logic that attempts to merge individual calendar caches when multi-calendar queries miss is a smart performance optimization. This will significantly improve cache hit rates for multi-calendar scenarios.
E2E results are ready! |
Introduced a private fetchEventsPaginated method to handle paginated event retrieval. Updated fetchEventsIncremental to use this helper for both incremental and full resync cases, reducing code duplication and improving maintainability.
…unit tests (#22264) * chore: remove unnecessary logs and fix documentation * refactor: extract GetSlotsInputWithRouting type and eliminate code duplication - Move GetSlotsInputWithRouting_2024_09_04 type to platform-types package for reuse - Refactor slots service to eliminate duplicate error handling logic - Fix TypeScript errors in slots service tests by adding missing type property - Update test expectations to match new implementation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: improve type safety in slots service - Export explicit types from slots-input.service for transformed queries - Replace 'any' type with proper TransformedSlotsQuery union type - Re-implement fetchAndFormatSlots abstraction to eliminate code duplication - Revert unrelated console.log in router.controller.ts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: simplify slots service implementation - Remove intermediate variable assignment in getAvailableSlotsWithRouting - Update test to match simplified routing parameters structure * test: add comprehensive error handling and edge case tests for slots service - Add error scenario tests for NotFoundException, invalid time range, and generic errors - Add edge case tests for null/undefined parameters and empty arrays - Improve test coverage for getAvailableSlotsWithRouting method - Mock SlotsInputService properly to enable isolated unit testing * 📝 CodeRabbit Chat: Rename TransformedGetSlotsQuery types to InternalGetSlotsQuery in slot services * fix: correct import path for AvailableSlotsService in slots service test - Fix import path from '@/lib/services/AvailableSlots' to '@/lib/services/available-slots.service' - Resolves unit test failure due to case sensitivity/naming mismatch - All API v2 tests now pass (9 test suites, 142 tests) Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fixed * chore * chore
Co-authored-by: Alex van Andel <me@alexvanandel.com>
* fix: update enterprise sales URL from i.cal.com to go.cal.com - Update EnterprisePage contact sales button URL - Update TeamList admin tools learn more URL - Update platform pricing enterprise redirect URL - Update documentation example URL - All URLs now point to go.cal.com/enterprise Co-Authored-By: peer@cal.com <peer@cal.com> * Apply suggestions from code review --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…oss (#22410) Co-authored-by: eunjae@cal.com <hey@eunjae.dev> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Keith Williams <keithwillcode@gmail.com> Co-authored-by: Omar López <zomars@me.com>
* feat: add 2FA status column to organization members table - Add twoFactorEnabled column to UserListTable with admin-only visibility - Modify backend handler to conditionally include 2FA data for org admins - Set column as hidden by default using initalColumnVisibility - Use Badge component to display enabled/disabled status - Implement proper permission checks using adminOrOwner variable Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: hide 2FA column from display options for non-admin users - Change enableHiding from true to adminOrOwner - Prevents non-admin users from seeing 2FA column in column visibility menu - Maintains existing cell-level permission checks for data access Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: resolve CI workflow dependency mismatch for integration-test job - Remove build job dependencies from integration-test job that were causing skipped job failures - integration-test now depends on [changes, check-label, deps] instead of build jobs - This fixes the 'required' check failure where skipped conditional jobs were treated as failures Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * revert: restore integration-test job dependencies as requested by keithwillcode - Restore integration-test dependencies to [changes, check-label, build, build-api-v1, build-api-v2] - Add conditional logic to only run integration-test when run-e2e == 'true' - This prevents the 'required' check from failing due to skipped conditional jobs - Addresses GitHub comment from keithwillcode requesting workflow revert Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * revert: remove conditional logic from integration-test job as requested - Remove run-e2e condition from integration-test job - Restore original workflow exactly as it was before any modifications - Addresses GitHub comment from keithwillcode requesting no CI changes Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…credit usage (#22567) * feat: add test to verify unpublished platform orgs are excluded from credit usage - Add filtering logic in _getTeamWithAvailableCredits to skip unpublished platform organizations - Add comprehensive test case that verifies user with memberships in both unpublished platform org and regular team - Ensure only regular team is selected for credit usage, not unpublished platform org - Test validates team.findUnique calls and credit balance checks for correct team filtering Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * Update credit-service.ts * Update credit-service.test.ts * fix: update test to work with repository-level filtering for unpublished platform orgs - Remove obsolete team.findUnique mocking since filtering moved to repository layer - Update test to mock findAllAcceptedPublishedTeamMemberships correctly - Test now validates integration with repository-level filtering - Maintains core validation that unpublished platform orgs are excluded from credit usage Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * docs: improve test comments to clarify repository-level filtering scenario - Add clearer comments explaining user has memberships in both teams - Clarify that repository method filters out unpublished platform orgs - Better document the architectural change from PR #22600 Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * docs: clarify test demonstrates user with memberships in both teams - Add detailed comments explaining user has memberships in TWO teams initially - Clarify that unpublished platform org (teamId: 1) and regular team (teamId: 2) scenario - Explain repository-level filtering removes unpublished platform orgs before credit service - Address user feedback about demonstrating two-team membership scenario Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * docs: add comprehensive comments explaining two-team filtering scenario - Clarify that user has memberships in BOTH teams initially in database - Explain that repository method filters out unpublished platform org (teamId: 1) - Document that only regular team (teamId: 2) is returned to credit service - Address user feedback about demonstrating the filtering behavior clearly - Test validates integration with repository-level filtering from PR #22600 Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * fix: update test to properly demonstrate filtering behavior - Mock repository to return only regular team (teamId: 2) as expected after filtering - Update credit balance mock and expectations to match teamId: 2 - Test now passes and validates that unpublished platform org is filtered out - Address user feedback about showing correct filtering behavior in test logic Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * feat: demonstrate two-team membership scenario in test logic - Mock repository to return both membership objects: teamId 1 and teamId 2 - Show user has memberships in both unpublished platform org and regular team - Mock different credit states: teamId 1 has no credits/limit reached, teamId 2 has available credits - Verify both teams are processed but only regular team (teamId 2) is selected - Test now demonstrates actual filtering behavior in test logic, not just comments - Addresses user feedback: 'create two membership with those two teams in that test' Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * feat: demonstrate two-team membership scenario in test logic - Mock repository to return both membership objects: teamId 1 and teamId 2 - Show user has memberships in both unpublished platform org and regular team - Mock different credit states: teamId 1 has no credits/limit reached, teamId 2 has available credits - Verify both teams are processed but only regular team (teamId 2) is selected - Test now demonstrates actual filtering behavior in test logic, not just comments - Addresses user feedback: 'create two membership with those two teams in that test' Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * Revert "feat: demonstrate two-team membership scenario in test logic" This reverts commit d7c4beb. * Update credit-service.test.ts * Update credit-service.test.ts * Update credit-service.test.ts --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add hourly booking charts on /insights * safe guard * rename * update styles * fix data * clean up * clean up * re-order charts * update style * apply feedback * rename * update query
) * feat: include record IDs in Salesforce assignment reason strings - Add recordId parameter to assignmentReasonHandler function - Include Contact ID, Lead ID, and Account ID in assignment reason strings - Update entire call chain to pass record IDs from CRM service - Maintain backward compatibility with optional recordId parameter Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: resolve lint warnings in assignment reason handler implementation - Change Record<string, any> to Record<string, unknown> in BookingHandlerInput type - Remove unused eventTypeId variable in getAttributeRoutingConfig function Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: revert to Record<string, any> with ESLint disable for BookingHandlerInput - Revert from Record<string, unknown> to Record<string, any> to maintain type compatibility - Add ESLint disable comment to suppress no-explicit-any warning - Maintains consistency with handleNewRecurringBooking.ts pattern Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: pass CRM record ID from booker state to handleNewBooking - Add crmRecordId field to booker store interface and initialization - Update mapBookingToMutationInput to include record ID from booker state - Modify handleNewBooking to extract record ID from bookingData parameter - Add crmRecordId to BookingCreateBody schema in Prisma layer - Follow existing pattern for CRM fields (teamMemberEmail, crmOwnerRecordType, crmAppSlug) - Ensures record ID flows: booker store → booking form → mapBookingToMutationInput → handleNewBooking This replaces the previous backend CRM service extraction approach with frontend booker state approach as requested by the user. Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Pass crmRecordId as prop --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>
Introduces test-gcal-webhooks.sh to start Tunnelmole, extract the public URL, and update GOOGLE_WEBHOOK_URL in the .env file. Handles process management, rate limits, and ensures environment configuration for Google Calendar webhooks.
Replaces 'ts-node' with 'npx tsx' in the dev:cron script for running cron-tester.ts, likely to improve compatibility or leverage tsx features.
* feat: add calendar cache status dropdown - Add updatedAt field to CalendarCache schema with migration - Create tRPC cacheStatus endpoint for fetching cache timestamps - Add action dropdown to CalendarSwitch for Google Calendar entries - Display formatted last updated timestamp in dropdown - Add placeholder for cache deletion functionality - Include translation strings for dropdown content The dropdown only appears for Google Calendar integrations that have active cache entries and provides cache management options for future extensibility. Co-Authored-By: zomars@cal.com <zomars@me.com> * fix: resolve Prisma type incompatibilities in repository files - Remove problematic satisfies clause in selectedCalendar.ts - Add missing cacheStatus parameter to ConnectedCalendarList component - Fixes type errors that were preventing CI from passing Co-Authored-By: zomars@cal.com <zomars@me.com> * refactor: integrate cache status into connectedCalendars handler - Remove separate cacheStatus tRPC endpoint as requested - Return cache status as separate field in connectedCalendars response - Update UI components to use cache data from connectedCalendars - Fix Prisma type incompatibilities in repository files Co-Authored-By: zomars@cal.com <zomars@me.com> * fix: resolve Prisma type incompatibilities and fix data flow for cache status - Fix Prisma.SortOrder usage in membership.ts orderBy clauses - Remove problematic satisfies clause in selectedCalendar.ts - Fix TeamSelect type reference in team.ts - Update SelectedCalendarsSettingsWebWrapper to properly pass cacheStatus data flow Co-Authored-By: zomars@cal.com <zomars@me.com> * Discard changes to packages/lib/server/repository/membership.ts * Discard changes to packages/lib/server/repository/team.ts * fix: improve calendar cache dropdown with proper formatting and subscription logic - Fix timestamp HTML entity encoding with interpolation escapeValue: false - Only show dropdown for subscribed Google calendars (googleChannelId exists) - Hide delete option when no cache data exists - Include updatedAt and googleChannelId fields upstream in user repository - Update data flow to pass subscription status through components Co-Authored-By: zomars@cal.com <zomars@me.com> * feat: update SelectedCalendar.updatedAt when Google webhooks trigger cache refresh - Add updateManyByCredentialId method to SelectedCalendarRepository - Update fetchAvailabilityAndSetCache to refresh SelectedCalendar timestamps - Ensure webhook flow updates both CalendarCache and SelectedCalendar records - Maintain proper timestamp tracking for calendar cache operations Co-Authored-By: zomars@cal.com <zomars@me.com> * Add script to automate Tunnelmole webhook setup Introduces test-gcal-webhooks.sh to start Tunnelmole, extract the public URL, and update GOOGLE_WEBHOOK_URL in the .env file. Handles process management, rate limits, and ensures environment configuration for Google Calendar webhooks. * Update dev:cron script to use npx tsx Replaces 'ts-node' with 'npx tsx' in the dev:cron script for running cron-tester.ts, likely to improve compatibility or leverage tsx features. * Update cache status string and improve CalendarSwitch UI Renamed 'last_updated' to 'cache_last_updated' in locale file for clarity and updated CalendarSwitch to use the new string. Also added dark mode text color support for cache status display. * refactor: move cache management to credential-level dropdown with Remove App - Create CredentialActionsDropdown component consolidating cache and app removal actions - Add deleteCache tRPC mutation for credential-level cache deletion - Update connectedCalendars handler to include cacheUpdatedAt at credential level - Move dropdown from individual CalendarSwitch to credential level in SelectedCalendarsSettingsWebWrapper - Remove cache-related props from CalendarSwitch component - Add translation strings for cache management actions - Consolidate all credential-level actions (cache management + Remove App) in one dropdown Co-Authored-By: zomars@cal.com <zomars@me.com> * fix: remove duplicate translation keys in common.json - Remove duplicate cache-related keys at lines 51-56 - Keep properly positioned keys later in file - Addresses GitHub comment from zomars about duplicate keys Co-Authored-By: zomars@cal.com <zomars@me.com> * fix: rename translation key to cache_last_updated - Address GitHub comment from zomars - Rename 'last_updated' to 'cache_last_updated' for specificity - Update usage in CredentialActionsDropdown component Co-Authored-By: zomars@cal.com <zomars@me.com> * fix: remove duplicate last_updated translation key Co-Authored-By: zomars@cal.com <zomars@me.com> * fix: add confirmation dialog for cache deletion and use repository pattern - Add confirmation dialog for destructive cache deletion action - Replace direct Prisma calls with CalendarCacheRepository pattern - Add getCacheStatusByCredentialIds method to repository interface - Fix import paths for UI components - Address GitHub review comments from zomars Co-Authored-By: zomars@cal.com <zomars@me.com> * Update CredentialActionsDropdown.tsx * Update common.json * Update common.json * fix: remove nested div wrapper to resolve HTML structure error - Remove wrapping div around DisconnectIntegration component - Fixes nested <p> tag validation error preventing Remove App functionality - Maintains existing confirmation dialog patterns Co-Authored-By: zomars@cal.com <zomars@me.com> * Fix API handler response termination logic Removed unnecessary return values after setting status in the integrations API handler. This clarifies response handling and prevents returning the response object when not needed. Resolves "API handler should not return a value, received object". * fix: 400 is correct error code for computing slot for past booking (#22574) * fix * add test * chore: release v5.5.1 * Refactor credential disconnect to use confirmation dialog Replaces the DisconnectIntegration component with an inline confirmation dialog for removing app credentials. Adds disconnect mutation logic and updates UI to improve user experience and consistency. * Set default value for CalendarCache.updatedAt Added a default value of NOW() for the updatedAt column in the CalendarCache table to ensure existing and future rows have a valid timestamp. Updated the Prisma schema to reflect this change and provide compatibility for legacy data and raw inserts. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Benny Joo <sldisek783@gmail.com> Co-authored-by: emrysal <me@alexvanandel.com>
- Add CalendarEvent and CalendarSyncToken models to Prisma schema - Implement CalendarCacheSqlRepository for SQL-based caching - Create CalendarCacheDualRepository for gradual migration - Add team-based feature flags: calendar-cache-sql-write and calendar-cache-sql-read - Maintain backward compatibility with existing JSON cache - Enable gradual SQL cache population without migrations - Update CalendarService to pass team context for feature flag checks - Fix linting issues: replace 'any' types with proper type definitions Co-Authored-By: zomars@cal.com <zomars@me.com>
…://git-manager.devin.ai/proxy/github.com/calcom/cal.com into zomars/1752095766-google-calendar-sync-tokens
- Add CalendarEvent and CalendarSyncToken tables to Prisma schema - Create CalendarCacheSqlRepository for SQL-based event storage - Implement CalendarCacheDualRepository for gradual migration - Add calendar-cache-sql-write and calendar-cache-sql-read feature flags - Support team-based feature flag control for opt-in rollout - Maintain backward compatibility with existing JSON cache - Enable gradual SQL cache population without migrations - Update CalendarService to pass team context for feature flags - Add integration test structure for SQL cache functionality Co-Authored-By: zomars@cal.com <zomars@me.com>
…errors - Fix duplicate getCacheStatusByCredentialIds method in CalendarCacheDualRepository - Ensure proper interface implementation for ICalendarCacheRepository - Update CalendarService.test.ts to handle optional EventBusyDate fields - Maintain backward compatibility with existing JSON cache functionality Co-Authored-By: zomars@cal.com <zomars@me.com>
Closing in favor of #22708 |
fix: implement proper cache merging for Google Calendar sync tokens
Summary
This PR fixes a critical bug where Google Calendar incremental sync was completely replacing cached events instead of merging them with existing data. This caused availability gaps where users appeared free when they were actually busy.
Root Cause: The
upsertCachedAvailability()
function was performing complete cache replacement instead of merging incremental changes from Google's sync tokens with existing cached events.Solution:
mergeBusyTimesWithCache()
method inCalendarService.ts
to merge incremental events with existing cachemergeCacheValues()
function incalendar-cache.repository.ts
to handle cache merging at the repository levelsetAvailabilityInCacheWithSyncToken()
to retrieve existing cache before mergingImpact: Prevents booking conflicts and availability gaps caused by lost calendar events during incremental sync.
Review & Testing Checklist for Human
Recommended Test Plan:
Diagram
Notes