Files
cal.diy/packages/features/calendar-subscription
a62eb2bdac refactor: replace shouldServeCache with mode parameter for calendar cache control (#26539)
* refactor: replace shouldServeCache with mode parameter for calendar cache control

Replace the boolean shouldServeCache parameter with a new CalendarFetchMode type
that can have values 'slots', 'overlay', and 'booking'. This provides better
control over when to serve cache vs relay on calendar providers.

- 'slots' mode: Check feature flags and use cache when available (for getting
  actual calendar availability)
- 'overlay' mode: Don't use cache (for overlay calendar availability)
- 'booking' mode: Don't use cache (for booking confirmation)
- undefined: Same as 'slots' for backwards compatibility

The cache decision logic is now centralized in getCalendar.ts based on the mode
parameter.

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: update CalendarService.test.ts to use mode parameter

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: use shared GetAvailabilityParams type across all calendar services

- Import GetAvailabilityParams and GetAvailabilityWithTimeZonesParams from @calcom/types/Calendar
- Replace inline type definitions with shared types in all calendar service implementations
- Update BaseCalendarService, CalendarCacheWrapper, and CalendarTelemetryWrapper
- Ensures consistent typing and follows DRY principles

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add missing IntegrationCalendar import and update mock getAvailability signature

- Add IntegrationCalendar back to sendgrid CalendarService imports
- Update bookingScenario mock getAvailability to use typed params object
- Add listCalendars method to mock Calendar object

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: update test files to use typed params object for getAvailability methods

- Update CalendarCacheWrapper.test.ts to call getAvailability/getAvailabilityWithTimeZones with params object
- Update getCalendarsEvents.test.ts toHaveBeenCalledWith assertions to expect params object
- All 32 tests now pass

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: consolidate to single GetAvailabilityParams type for both getAvailability methods

- Remove GetAvailabilityWithTimeZonesParams, use GetAvailabilityParams for both methods
- Add mode parameter to getAvailabilityWithTimeZones calls
- Update wrapper classes to pass mode through to underlying calendar
- Update test files to include mode in getAvailabilityWithTimeZones calls and assertions

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: use EventBusyDate with optional timeZone for getAvailabilityWithTimeZones

- Add optional timeZone field to EventBusyDate type
- Update getAvailabilityWithTimeZones return type to use EventBusyDate[]
- Update Google Calendar service and wrapper classes to use the new type

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: type errors and remove unused calendar watching methods

- Fix type errors in CalendarCacheWrapper.ts (convert null to undefined for timeZone)
- Fix type errors in getCalendarsEvents.ts (ensure timeZone is always present)
- Remove unused watchCalendar/unwatchCalendar from Calendar interface
- Remove unused startWatchingCalendarsInGoogle/stopWatchingCalendarsInGoogle from GoogleCalendarService
- Remove unused imports (uuid, uniqueBy, GOOGLE_WEBHOOK_URL, ONE_MONTH_IN_MS)

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: remove watchCalendar/unwatchCalendar from CalendarTelemetryWrapper

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: remove verbose JSDoc param comments from wrapper classes

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: make mode parameter required in getCalendar

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add required mode parameter to all getCalendar callers

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: provide default mode value in getBusyCalendarTimes

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add mode parameter to remaining getCalendar callers

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add mode parameter to vital and wipemycalother reschedule

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix: add mode parameter to credential-sync API endpoint

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* refactor: add 'none' mode to CalendarFetchMode and use as default

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* test: add mode parameter to getCalendarsEvents test calls

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* Update packages/app-store/delegationCredential.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-08 09:07:41 -03:00
..

Calendar Cache and Sync

The Calendar Cache and Sync feature provides efficient calendar synchronization with intelligent caching to reduce API calls and ensure real-time updates across your Cal.com instance.

Feature Overview

This feature introduces two complementary capabilities:

  • Calendar Cache: Stores calendar availability data locally to reduce external API calls and improve performance
  • Calendar Sync: Uses webhooks to automatically listen for calendar updates and apply changes in real-time

Key Benefits:

  • Efficiency: Reduces API calls with optimized caching strategies
  • Reliability: Guarantees updates through webhook event delivery
  • Real-Time Sync: Ensures calendars are always up-to-date with minimal latency
  • Scalability: Supports multiple calendars and handles high-volume updates seamlessly

Motivation: By subscribing to calendars via webhooks and implementing intelligent caching, you gain a smarter, faster, and more resource-friendly way to keep your data in sync. This eliminates the need for constant polling and reduces the load on external calendar APIs while ensuring data consistency.

Environment Variables

  • GOOGLE_WEBHOOK_URL: Optional, only used for local tests. Default points to application url.
  • GOOGLE_WEBHOOK_TOKEN: Required, token to validate Google Webhook incoming.
  • MICROSOFT_WEBHOOK_URL: Optional, only used for local tests. Default points to application url.
  • MICROSOFT_WEBHOOK_TOKEN: Required, token to validate Microsoft Webhook incoming.

Feature Flags

This feature is controlled by three feature flags that can be enabled independently:

1. calendar-subscription-cache

Enables calendar cache recording and usage through calendars. This flag should be managed individually by teams.

INSERT INTO "Feature" ("slug", "enabled", "description", "type", "stale", "lastUsedAt", "createdAt", "updatedAt", "updatedBy") 
VALUES ('calendar-subscription-cache', false, 'Allow calendar cache to be recorded and used through calendars.', 'OPERATIONAL', false, NULL, NOW(), NOW(), NULL) 
ON CONFLICT (slug) DO NOTHING;

2. calendar-subscription-sync

Enables calendar sync globally for all users regardless of team or organization.

INSERT INTO "Feature" ("slug", "enabled", "description", "type", "stale", "lastUsedAt", "createdAt", "updatedAt", "updatedBy") 
VALUES ('calendar-subscription-sync', false, 'Enable calendar sync for all calendars globally.', 'OPERATIONAL', false, NULL, NOW(), NOW(), NULL) 
ON CONFLICT (slug) DO NOTHING;

Enabling Features for Specific Users

To enable calendar cache features for specific users, add entries to the UserFeatures table:

-- Enable calendar-subscription-cache for user ID 123  
INSERT INTO "UserFeatures" ("userId", "featureId", "assignedAt", "assignedBy", "updatedAt") 
VALUES (123, 'calendar-subscription-cache', NOW(), 'admin', NOW()) 
ON CONFLICT ("userId", "featureId") DO NOTHING;

-- Enable calendar-subscription-sync for user ID 123
INSERT INTO "UserFeatures" ("userId", "featureId", "assignedAt", "assignedBy", "updatedAt") 
VALUES (123, 'calendar-subscription-sync', NOW(), 'admin', NOW()) 
ON CONFLICT ("userId", "featureId") DO NOTHING;

Enabling Features for Specific Teams

To enable calendar cache features for specific teams, add entries to the TeamFeatures table:

-- Enable calendar-subscription-cache for team ID 456
INSERT INTO "TeamFeatures" ("teamId", "featureId", "assignedAt", "assignedBy", "updatedAt") 
VALUES (456, 'calendar-subscription-cache', NOW(), 'admin', NOW()) 
ON CONFLICT ("teamId", "featureId") DO NOTHING;

-- Enable calendar-subscription-sync for team ID 456
INSERT INTO "TeamFeatures" ("teamId", "featureId", "assignedAt", "assignedBy", "updatedAt") 
VALUES (456, 'calendar-subscription-sync', NOW(), 'admin', NOW()) 
ON CONFLICT ("teamId", "featureId") DO NOTHING;

Architecture

The calendar cache and sync system consists of several key components:

Database Schema

  • CalendarCacheEvent Table: Stores cached calendar events with status tracking
  • SelectedCalendar Extensions: Additional fields for sync state and webhook management including:
    • channelId: Webhook channel identifier
    • channelResourceId: Resource ID for webhook subscriptions
    • channelResourceUri: URI for webhook notifications
    • channelKind: Type of webhook channel
    • channelExpiration: Webhook subscription expiration time
    • syncToken: Token for incremental sync
    • syncedAt: Last successful sync timestamp
    • syncErrorAt: Last sync error timestamp
    • syncErrorCount: Number of consecutive sync errors
    • syncSubscribedAt: Webhook subscription timestamp

Core Services

  • CalendarCacheEventRepository: Manages cached event storage and retrieval
  • CalendarSubscriptionService: Orchestrates webhook subscriptions and event processing
  • Provider-specific Adapters: Handle calendar-specific sync logic (Google, Office365)

Background Processes

  • Cron Jobs: Automated processes for cache cleanup and calendar watching
  • Webhook Handlers: Real-time event processing for calendar updates

Integration Points

  • Calendar Providers: Google Calendar, Office365, and other supported integrations
  • Webhook Endpoints: Receive real-time notifications from calendar providers
  • Cache Layer: Optimized storage for frequently accessed calendar data

For detailed technical implementation, see:

  • Database migrations in packages/prisma/migrations/