Compare commits

...
376 Commits
Author SHA1 Message Date
Alex van Andel 4c336fba92 chore: release v6.0.9
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2026-01-09 00:21:26 +00:00
cal-com-ci[bot]andLingo.dev 4cd664315d feat: update translations via @LingoDotDev (#26511)
Co-authored-by: Lingo.dev <support@lingo.dev>
2026-01-08 22:27:14 +00:00
Pedro Castro d9aef5b6a6 fix: add URL validation for logo fields (#26522)
* fix(auth): add URL validation for organization logo fields

- Add URL validation utility for server-side fetched URLs
- Validate logo URLs in tRPC organization schema
- Validate logo URLs in API v2 team DTOs
- Add graceful fallback in logo route for invalid URLs
- Only allow HTTPS and image data URLs
- Add unit tests for URL validation

* fix: add missing IP range and type validation

- Add RFC 6598 CGNAT range (100.64.0.0/10) to blocked IPs
- Add @IsString() decorator before custom URL validators
- Add boundary tests for new IP range

* fix: address review feedback

   - Export validateUrlForSSRFSync via @calcom/platform-libraries
   - Fix nullable/optional order in Zod schema

* fix: block localhost hostname and explicit null check

- Add localhost to BLOCKED_HOSTNAMES for sync validation
- Use explicit null check (url == null) instead of falsy check

* fix: allow empty string in URL validation

* refactor: extract shared validation logic

- Extract validateUrlCore() to eliminate duplication between sync/async versions
- Add JSDoc to all exported functions for better discoverability
- Remove redundant comments that repeated function names
- Simplify existing comments to be more concise

* fix: reject empty strings in URL validator

Previously if (!url) allowed empty strings to bypass validation.
Now explicitly checks for null/undefined only
2026-01-08 22:03:54 +00:00
Volnei Munhoz a5387bbffe update yarn lock (#26596) 2026-01-08 18:59:03 +00:00
Keith WilliamsandDevin AI 53833f15ea fix: add waitFor calls to prevent flaky time slot selection tests (#26592)
* fix: add waitFor calls to prevent flaky time slot selection tests

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: use locator variables to avoid repeating selectors

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 15:25:03 -03:00
Dhairyashil ShindeandVolnei Munhoz 84d1ce5bff feat(companion): availability detail page for android and extension (#26560)
* Availability Detail Page Header and fix event type payment amount badge, and index ui bug bottom navbar

* feat(companion): implement read-only availability detail page for Android/Extension

- Convert AvailabilityDetailScreen.tsx to read-only display with expandable sections
- Add header dropdown menu with edit options in availability-detail.tsx
- Update edit-availability-name.tsx with modal presentation pattern
- Update edit-availability-hours.tsx with modal presentation pattern
- Update edit-availability-override.tsx with modal presentation pattern
- Match iOS flow: read-only detail page with edit actions via header menu

* fix header on Availability Detail screen for android

* make dialoges center on extension

* update padding

* AvailabilityDetailScreen for android and extension

* added click to modal feat

* fix Date Overrides Card was always shown

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-08 23:31:59 +05:30
Keith Williams a748a75b08 chore: Update CODEOWNERS for GitHub actions/workflows (#26591) 2026-01-08 17:52:44 +00:00
Abhay MishraandVolnei Munhoz dc308a9538 fix: prevent seed-app-store startup crash by removing undefined seedAppData call (#26400)
Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-08 17:19:00 +00:00
ccff0045fc fix: Add email verification requirement for API v1 and v2 email updates (#24988)
* fix: Add email verification requirement for API v1 and v2 email updates

- API v2 (/v2/me): Implement email verification check when updating primary email
  - Store new email in metadata as emailChangeWaitingForVerification when verification is required
  - Send verification email using sendChangeOfEmailVerification
  - Allow immediate email change if new email is already a verified secondary email
  - Add hasEmailBeenChanged and sendEmailVerification flags to response
  - Add tests to verify email verification behavior
  - Add findVerifiedSecondaryEmail method to UsersRepository
  - Add PrismaFeaturesRepository to MeModule providers

- API v1 (/v1/users/{userId}): Implement same email verification logic
  - Check if email-verification feature flag is enabled
  - Store new email in metadata when verification is required
  - Send verification email for unverified email changes
  - Allow immediate change for verified secondary emails
  - Preserve existing API v1 response format

- Test fixtures: Add createSecondaryEmail method to UserRepositoryFixture

This fixes the vulnerability where users could update their primary email
without verification via API endpoints.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* update

* update

* refactor: Extract business logic to MeService and add platform-managed bypass

- Create MeService with all business logic extracted from MeController
- Update MeController to delegate to MeService (thin controller pattern)
- Add PrismaWorkerModule to MeModule imports to provide PrismaWriteService
- Add isPlatformManaged bypass: platform-managed users can update email without verification
- Fix test cleanup to use delete by ID instead of email to avoid failures when email changes
- Remove hasEmailBeenChanged and sendEmailVerification response flags per reviewer feedback
- Add comprehensive documentation to @ApiOperation describing email verification behavior
- Update tests to remove flag assertions

Addresses PR comments:
- supalarry: Extract logic to service layer
- supalarry: Allow platform-managed users to update email without verification
- supalarry: Remove response flags and document behavior in @ApiOperation instead
- cubic-dev-ai: Fix module dependency for PrismaFeaturesRepository
- cubic-dev-ai: Fix test cleanup issue

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* docs: Simplify API operation description

Remove internal implementation details about metadata staging and shorten the description to focus on API consumer behavior.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* fix

* update

* update

* update

* remove comment

* addressed commit

* review addressed

* use repository

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 15:51:11 +00:00
Eunjae LeeandDevin AI 03bb9481a2 fix: update E2E test to match German translation without '+' prefix (#26589)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 15:37:50 +00:00
Alex van Andel 23ecd1c906 refactor: First high level changes to getUsersAvailability (#26566)
* refactor: First high level changes to getUsersAvailability

* Fix usage of getUserAvailability where getUsersAvailability is unused

* Fix user.schema.ts in APIv2

* User handler did not provide initial data

* Small ts fixes

* Set user non-nullable in getTimezoneFromDelegatedCredential

* Small ts fixes, ensure consumers are aware its nonnullable

* Mode is defaulted to none

* Mode is defaulted to none, fix ts when directly using fn (temp)
2026-01-08 14:45:26 +00:00
Pedro CastroandKeith Williams f8dcc6b13d fix: filter Google Workspace credentials by current user (#26216)
* fix: filter Google Workspace credentials by current user

Add userId filter to getUsersFromGWorkspace credential query and add
unit tests for all googleWorkspace handler functions. Also fix OAuth2Client
import to use google-auth-library for proper type compatibility

* refactor(tests): improve googleWorkspace handler test structure

Move dynamic imports to beforeEach block to reduce repetition
and improve test readability

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-08 14:44:50 +00:00
f629b61be7 fix: capitalize German 'Uhr' in 24-hour time format (#25403)
* fix: capitalize German 'Uhr' in 24-hour time format

- Conditionally apply toLowerCase() only for 12-hour format (AM/PM)
- Preserve proper capitalization for 24-hour format in German and other locales
- German 'Uhr' now displays correctly as 'Uhr' instead of 'uhr'

Fixes #24455

* refactor: remove code comments for clarity

* use ternary in return instead of mutable variable

* refactor: remove toLowerCase from time formatting

* addressed cubic suggestion

---------

Co-authored-by: Pallav <90088723+Pallava-Joshi@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <adhabal2002@gmail.com>
2026-01-08 14:25:50 +00:00
Kartik 2f932f617c fix: remove "+" from Add Guests translations (#26582) 2026-01-08 14:19:26 +00:00
Mehmet SungurandPallav 9c4754dfcc fix(ui): prevent nested <p> hydration errors in confirmation dialogs (#25643)
Co-authored-by: Pallav <90088723+Pallava-Joshi@users.noreply.github.com>
2026-01-08 10:27:11 -03:00
dbc6b15ffc fix: time and timeUnit partial update workflows api v2 (#26503)
* test: add e2e test for workflow partial update time/timeUnit preservation

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: time and timeUnit partial update workflows api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 09:26:55 -03:00
ac3699dcb4 fix: set attendeeSeatId in evt for seated booking reschedule emails (#26498)
* fix: set attendeeSeatId in evt for seated booking reschedule emails

When an attendee reschedules a seated booking, the reschedule/cancel links
in emails were using bookingUid instead of seatUid after the first reschedule.
This was because evt.attendeeSeatId was not being set before sending the email.

This fix ensures that evt.attendeeSeatId is set to bookingSeat.referenceUid
so that the email links consistently use seatUid for seated bookings.

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* test: add E2E test for seatUid preservation across multiple reschedules

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: use valid time slots within availability window for E2E test

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: make E2E test self-contained to avoid shared state issues

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update E2E test to validate seatUid usability across reschedules

Co-Authored-By: morgan@cal.com <morgan@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 14:15:40 +02:00
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
Kartik 64828abad2 fix: added seed credentials for signin (#26559) 2026-01-08 11:32:13 +00:00
Syed Ali Shahbazandcubic-dev-ai[bot] 59fca85d92 fix: use graceful filtering for previously hard failing blocked users in team events (#26446)
* init

* typefix

* --

* fix test

* update index

* cleanup

* rm unnecessary comments

* improvements

* add tests

* test fixes

* fixes

* fixes

* fixes

* add try catch to make booking fail-open

* Update packages/features/watchlist/operations/check-user-blocking.ts

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

* fix type

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-08 08:30:54 -03:00
27623926fc test: improve flaky E2E tests (#26473)
* fix flakes

* revert

* fix

* update

* more update

* fix

* revert

---------

Co-authored-by: Anik Dhabal Babu <adhabal2002@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2026-01-08 15:52:53 +05:30
Carina WollendorferandCarinaWolli a68fcf8840 fix refresh token endpoint (#26577)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2026-01-08 15:40:59 +05:30
Amin Jaoui ea7e5b3f19 docs: fix missing log level number in README (#26574)
The first example in the logger level documentation was missing
the number 6 before 'fatal', making it inconsistent with the
second example and the level definitions above.
2026-01-08 09:55:13 +00:00
Volnei Munhoz 2b8a0a4d80 chore: biome ternary rules changes (#26576) 2026-01-08 09:15:34 +00:00
Hariom BalharaandDevin AI 2f92563606 refactor: Use confirmHandler directly in link and verify-booking-token routes (#26567)
Refactors the link and verify-booking-token API routes to call confirmHandler directly instead of using the tRPC caller pattern. This simplifies the code by removing the need for session getter, legacy request building, and context creation.

Changes:
- apps/web/app/api/link/route.ts: Use confirmHandler directly with ctx and input
- apps/web/app/api/verify-booking-token/route.ts: Use confirmHandler directly with ctx and input
- Updated tests to mock confirmHandler instead of tRPC caller

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 08:23:48 +00:00
Benny JooandDevin AI f5d345b133 refactor: remove @calcom/web imports from @calcom/features and add @calcom/testing package (#26480)
* fix: remove @calcom/web imports from packages/features to eliminate circular dependency

- Migrate UserTableUser and MemberPermissions types to packages/features/users/types/user-table.ts
- Migrate useGeo hook to packages/features/geo/GeoContext.tsx
- Migrate buildLegacyRequest to packages/lib/buildLegacyCtx.ts
- Migrate Calendar component to packages/features/calendars/weeklyview/components/
- Move test utilities (bookingScenario, fixtures) to packages/features/test/
- Update all imports in packages/features to use new locations
- Add re-exports in apps/web for backward compatibility

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: delete original implementation files and fix type issues

- Delete original calendar component files in apps/web (keep only re-export stubs)
- Migrate OutOfOfficeInSlots to packages/features/bookings/components
- Convert apps/web OutOfOfficeInSlots to re-export stub
- Fix className vs class issue in Calendar.tsx
- Fix @calcom/trpc import violation in user-table.ts by using structural type

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing isGroup and contains fields to UserTableUser attributes type

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update customRole type to match actual Prisma Role model

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix build

* fix

* fix

* cleanup weeklyview

* fix

* refactor to mv MemberPermissions to types package

* add types dependency to features

* fix

* fix

* fix

* fix

* fix

* fix

* rename

* rename

* migrate

* migrate

* migrate

* fix

* fix

* fix

* refactor: move test utilities from packages/features/test to tests/libs

- Move bookingScenario utilities to tests/libs/bookingScenario
- Move fixtures to tests/libs/fixtures
- Update all imports in packages/features test files to use new location
- Update all imports in apps/web test files to use new location
- Eliminates duplication of test utilities between packages/features and apps/web

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: correct relative import paths for tests/libs in test files

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: replace test utility implementations with re-exports to tests/libs

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: fix test import paths and move signup handler tests to apps/web

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: move buildLegacyCtx to packages/lib and restore handlers to packages/features

- Move buildLegacyCtx from apps/web/lib to packages/lib to break circular dependency
- Update apps/web/lib/buildLegacyCtx.ts to re-export from @calcom/lib
- Restore signup handlers and tests to packages/features/auth/signup/handlers
- Update handler imports to use @calcom/lib/buildLegacyCtx instead of @calcom/web/lib/buildLegacyCtx

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update recurring-event.test.ts imports to use tests/libs path

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: delete test re-export files and update imports to use tests/libs directly

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update remaining test imports to use tests/libs directly

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update handleRecurringEventBooking calls to match function signature (1 arg)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* remove

* migrate tests

* migrate tests

* refactor: update test mock imports by removing  and using async  for mock creators.

* fix type errors

* fix: add type assertion for MockUser in p2002.test-suite.ts

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: restore locale import in compareReminderBodyToTemplate.test.ts using relative path

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* feat: create @calcom/testing package and migrate tests from /tests directory

- Created new @calcom/testing package in /packages/testing
- Moved all files from /tests to /packages/testing
- Updated all imports across the codebase to use @calcom/testing alias
- Removed /tests directory at root level

This allows other packages like @calcom/features and @calcom/web to import
testing utilities using the @calcom/testing alias instead of relative paths.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix

* fix: add missing useBookings export to @calcom/atoms package

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing useCalendarsBusyTimes and useConnectedCalendars exports to @calcom/atoms

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* chore: add @calcom/testing as explicit devDependency to packages that use it

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: move setupVitest.ts into @calcom/testing package

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* chore: add biome rules to restrict @calcom/testing imports

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* rename libs to lib

* rename libs to lib

* add rule

* add rule

* refactor: remove @calcom/features imports from @calcom/testing

- Move mockPaymentSuccessWebhookFromStripe to fresh-booking.test.ts
- Replace ProfileRepository.generateProfileUid() with uuidv4()
- Clone Tracking type into @calcom/testing/src/lib/types.ts
- Update imports in expects.ts and getMockRequestDataForBooking.ts
- Move source files into src/ folder
- Move CalendarManager mock to @calcom/features

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add explicit exports for nested paths in @calcom/testing

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* improve

* improve

* fix

* fix

* fix type checks

* fix type checks

* fix type checks

* fix tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-08 16:59:11 +09:00
Joe Au-Yeung 04e447058c fix: Add copy-app-store-static to docker file (#26565)
* Add `copy-app-store-static` step

* Biome formatting
2026-01-08 04:30:02 -03:00
Joe Au-YeungandDevin AI 0cf5de5ef8 fix: log Zoom token refresh errors at ERROR level (#26547)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 21:49:11 +00:00
Pedro Castro 2aed9908b7 fix: replace gray-matter with direct yaml.load for js-yaml 4.x compatibility (#26555)
gray-matter uses yaml.safeLoad() which was removed in js-yaml 4.x, causing 500
errors on app store pages after the js-yaml 4.1.1 update (CWE-1321 fix)

- Add parseFrontmatter function using yaml.load with JSON_SCHEMA
- Add type guard for safe type narrowing
- Add unit tests for frontmatter parsing and security
- Remove gray-matter dependency
2026-01-07 15:16:26 -03:00
Anik Dhabal Babu f54a3d1d0c test: all flaky unit tests (#26558) 2026-01-07 17:53:19 +00:00
2d19003e8a style: use Tailwind color tokens instead of hardcoded hex values (#26557)
Replace hardcoded hex colors with their exact Tailwind equivalents:
- text-[#111827] → text-gray-900
- text-[#6B7280] → text-gray-500
- text-[#374151] → text-gray-700
- border-[#D1D5DB] → border-gray-300

This improves consistency with the rest of the codebase which
already uses these tokens (e.g., text-gray-500 is used 107 times).

Files changed:
- apps/web/modules/videos/views/videos-single-view.tsx
- companion/app/(tabs)/(event-types)/index.tsx
- companion/components/booking-list-screen/BookingListScreen.tsx
- companion/components/event-type-detail/tabs/AdvancedTab.tsx
- companion/components/screens/AvailabilityListScreen.tsx
- companion/components/screens/BookingDetailScreen.android.tsx

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Dylan Tarre <timecreepsby@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 17:37:07 +00:00
Eunjae Lee ae6e0689f4 docs: update google calendar guide (#26549)
* docs: update google calendar doc

* update page name and include .env in seed-app-store.ts

* add onre more step

* update
2026-01-07 17:28:44 +00:00
Pallav cdd946cf39 refactor: single line app feature desc (#26553) 2026-01-07 17:27:52 +00:00
Anik Dhabal Babu cd6dbd53ff fix: prevent disabled apps from appearing in app store category pages (#26551) 2026-01-07 16:55:06 +00:00
Volnei Munhoz 444b7b7231 Add flex biome adoption (#26550) 2026-01-07 17:33:19 +01:00
4585d7402d fix: BOOKING_PAID webhook & workflow isn't triggering after payment successful (#26044)
* fix booking paid webhook

* Update handlePaymentSuccess to include updatedBooking status

* Fix videoCallUrl undefined error in BOOKING_PAID workflow trigger

- Import getVideoCallUrlFromCalEvent to properly compute meeting URL
- Use conditional metadata to avoid passing undefined videoCallUrl
- Matches original handleConfirmation.ts behavior

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Add missing schedulingType to calendarEventForWorkflow

- Added schedulingType field to match original handleConfirmation.ts behavior
- This field was present in the original implementation but missing in the refactor

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Fix paymentMetadata nullability to match original behavior

- Changed from ?? null to optional chaining (undefined) to match original handleConfirmation.ts
- This ensures webhook consumers using z.string().optional() schemas continue to work
- undefined values are omitted from JSON, while null values would be explicitly included

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Fix type errors: add schedulingType to getBooking and use null for metadata

- Added schedulingType to getBooking.ts eventType select to make it available
- Changed paymentMetadata to use ?? null instead of undefined for type compatibility
- The metadata type expects { [key: string]: string | number | boolean | null }

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* await

* add tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 15:00:54 +00:00
Eunjae Lee f9635df629 chore: load .env for seed-insights.ts (#26545) 2026-01-07 14:39:41 +00:00
2cadc0b1e9 fix: remove shouldServeCache in getCalendarEvent getAvailability call (#26541)
* fix: remove shouldServeCache in getCalendarEvent getAvailability call

* test: remove shouldServeCache parameter from getAvailability test expectations

Co-Authored-By: morgan@cal.com <morgan@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 19:55:47 +05:30
Udit Takkar 0d905a6c11 fix: add arrayLimit (#26542) 2026-01-07 14:23:38 +00:00
Dhairyashil Shinde dcf10935de feat: add missing event type fields for advanced settings in api v2 (#25739)
* feat: api v2 add missing event type fields for advanced settings

Add 9 event type fields to API v2 that were available in tRPC but missing from the platform API:

- disableCancelling: disable cancelling for guests/organizer
- disableRescheduling: disable rescheduling for guests/organizer
- canSendCalVideoTranscriptionEmails: send Cal Video transcription emails
- autoTranslateInstantMeetingTitleEnabled: auto-translate instant meeting titles
- interfaceLanguage: preferred booking interface language
- allowReschedulingPastBookings: allow rescheduling past events
- allowReschedulingCancelledBookings: allow booking via reschedule link
- customReplyToEmail: custom reply-to email for confirmations
- showOptimizedSlots: optimize time slot arrangement

Updated output/input schemas, transformation services, and E2E tests.

* fix(api-v2): add proper OpenAPI types for nullable event type fields

Add explicit type and nullable properties to @ApiPropertyOptional decorators
for fields with `boolean | null` or `string | null` types. Without these,
Swagger was generating incorrect "type": "object" instead of the correct types.

Fixed fields:
- disableCancelling: type: Boolean, nullable: true
- disableRescheduling: type: Boolean, nullable: true
- interfaceLanguage: type: String, nullable: true
- allowReschedulingCancelledBookings: type: Boolean, nullable: true
- customReplyToEmail: type: String, nullable: true
- showOptimizedSlots: type: Boolean, nullable: true

* refactor: customReplyToEmail was intentionally excluded from this PR. The web UI
restricts this field to only allow the user's own verified emails via a
dropdown, but implementing the same validation in the API requires additional
business logic. This will be addressed in a separate PR with proper email
ownership validation.

* feat(api-v2): add validation for interfaceLanguage field

Add @IsIn validation to interfaceLanguage field to only accept supported
locales. This ensures API v2 matches the web UI behavior where users can
only select from a predefined dropdown of supported languages.

Changes:
- Add SUPPORTED_LOCALES constant to @calcom/platform-constants
- Add @IsIn([...SUPPORTED_LOCALES]) validation to create/update DTOs
- Add E2E tests for invalid locale rejection (400 error)
- Add cross-reference comments in i18n.json and api.ts to keep in sync

* docs(api): add default values to event type input field documentation

Added default value documentation to @DocsPropertyOptional decorators
for the new event type fields in API v2 (2024_06_14):

- disableCancelling: false
- disableRescheduling: false
- canSendCalVideoTranscriptionEmails: true
- autoTranslateInstantMeetingTitleEnabled: false
- allowReschedulingPastBookings: false
- allowReschedulingCancelledBookings: false
- showOptimizedSlots: false

This improves API documentation by clearly communicating default
values to API consumers in the OpenAPI spec.

* feat(api-v2): refactor event type settings to object types for future extensibility

- Convert disableRescheduling from boolean to object with disabled and minutesBefore properties
- Convert disableCancelling from boolean to object with disabled property
- Move canSendCalVideoTranscriptionEmails into CalVideoSettings as sendTranscriptionEmails
- Remove autoTranslateInstantMeetingTitleEnabled (Enterprise-only feature)
- Add DisableRescheduling_2024_06_14 and DisableCancelling_2024_06_14 input/output types
- Add transformation methods for new object types in input and output services
- Update E2E tests for new API contract

BREAKING CHANGE: disableRescheduling and disableCancelling now accept objects instead of booleans

* fix(api-v2): prevent clearing calVideoSettings when only sendTranscriptionEmails is provided

Only include calVideoSettings in transformed output if it has properties,
avoiding unintentional reset of existing settings during updates.
2026-01-07 16:03:01 +02:00
4571215794 feat(calendar-subscription): add telemetry metrics for cache performance and webhook calls (#26501)
* feat(calendar-subscription): add telemetry metrics for cache performance and webhook calls

- Add Sentry span telemetry to CalendarCacheWrapper.getAvailability() and getAvailabilityWithTimeZones() to measure:
  - Cache fetch duration (cacheFetchDurationMs)
  - Original calendar fetch duration (originalFetchDurationMs)
  - Number of calendars from cache vs original source
  - Number of events from each source
  - Whether cache was used (cacheUsed)

- Add Sentry span telemetry to CalendarSubscriptionService.processWebhook() to track:
  - Provider (google_calendar, office365_calendar)
  - Success/failure status
  - Processing duration (durationMs)
  - Error messages on failure
  - Channel ID and selected calendar ID

- Create telemetry module with types, sentry-span, and no-op-span implementations

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

* refactor(calendar-subscription): move telemetry to @calcom/lib for reusability

- Add withSpan helper to @calcom/lib/sentryWrapper for reusable telemetry
- Update CalendarCacheWrapper to use withSpan from @calcom/lib
- Update CalendarTelemetryWrapper to use withSpan from @calcom/lib
- Update CalendarSubscriptionService to use withSpan from @calcom/lib
- Remove old telemetry module from calendar-subscription feature
- Add telemetry tracking when cache is disabled for performance comparison

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

* fix(calendar-subscription): only apply telemetry wrapper when Sentry is configured

- Fix unit test failures by checking if Sentry is configured before wrapping
- Remove ESLint inline rules from getCalendar.ts

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

* refactor(calendar-subscription): move CalendarTelemetryWrapper to telemetry directory

- Move CalendarTelemetryWrapper from cache/ to telemetry/ directory
- Update import path in getCalendar.ts

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

* feat(telemetry): add console fallback when Sentry is not configured

- Add console logging fallback in development mode when Sentry is not configured
- Create isTelemetryEnabled() helper to check if telemetry should be enabled
- Update getCalendar.ts to use isTelemetryEnabled() helper
- Logs span name, operation, duration, and attributes to console via @calcom/lib/logger

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

* refactor(calendar-subscription): wrap all calendars with CalendarTelemetryWrapper

- CalendarTelemetryWrapper now wraps ALL cache-supported calendars with cacheEnabled parameter
- CalendarCacheWrapper keeps cache-specific metrics with distinct op (calendar.cache.internal.*)
- CalendarTelemetryWrapper uses canonical op (calendar.getAvailability) for consistent querying
- Nested spans: outer telemetry wrapper measures end-to-end, inner cache wrapper measures cache internals

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 11:27:40 +00:00
Adarsh Tiwari c3668d3664 fix: added team badge in event types (#26536)
* added team badge in event types

* added icon into the badge
2026-01-07 16:38:57 +05:30
61a932f8f5 feat: OAuth2 controller api v2 + refactor oAuth Trpc handlers (#25989)
* feat(api-v2): add OAuth2 controller skeleton for auth module

- Add new OAuth2 module under /auth with controller, service, repository, and DTOs
- Implement skeleton endpoints:
  - GET /v2/auth/oauth2/clients/:clientId - Get OAuth client info
  - POST /v2/auth/oauth2/clients/:clientId/authorize - Generate authorization code
  - POST /v2/auth/oauth2/clients/:clientId/exchange - Exchange code for tokens
  - POST /v2/auth/oauth2/clients/:clientId/refresh - Refresh access token
- Create input DTOs for authorize, exchange, and refresh operations
- Create output DTOs for client info, authorization code, and tokens
- Register OAuth2Module in endpoints.module.ts

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore: add missing functions to platform libraries

* feat(api-v2): integrate OAuthService from platform-libraries into OAuth2 controller

- Add OAuthService export to platform-libraries
- Refactor OAuth2Service to use OAuthService.validateClient() and OAuthService.verifyPKCE()
- Remove duplicate local implementations of validateClient and verifyPKCE methods

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat(api-v2): use local validateClient and verifyPKCE implementations

- Remove OAuthService export from platform-libraries (will be deprecated)
- Reimplement validateClient and verifyPKCE methods locally in OAuth2Service
- Use verifyCodeChallenge and generateSecret from platform-libraries directly

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor(api-v2): separate repositories for OAuth2, access codes, and teams

- Create AccessCodeRepository for access code Prisma operations
- Add findTeamBySlugWithAdminRole method to TeamsRepository
- Move generateAuthorizationCode, createTokens, verifyRefreshToken to OAuth2Service
- Update OAuth2Repository to only contain OAuth client operations
- Update OAuth2Module to import TeamsModule and provide AccessCodeRepository

Addresses PR review comments to properly separate concerns

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat(api-v2): implement JWT token creation and verification for OAuth2

- Implement createTokens method using jsonwebtoken to sign access and refresh tokens
- Implement verifyRefreshToken method to verify JWT refresh tokens
- Add ConfigService injection for CALENDSO_ENCRYPTION_KEY access
- Import ConfigModule in OAuth2Module for dependency injection

Based on logic from apps/web/app/api/auth/oauth/token/route.ts and
apps/web/app/api/auth/oauth/refreshToken/route.ts

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: refactor and dayjs import fix

* feat(api-v2): add ApiAuthGuard to getClient endpoint and e2e tests for OAuth2

- Add @UseGuards(ApiAuthGuard) to getClient endpoint for authentication
- Add comprehensive e2e tests for all OAuth2 endpoints:
  - GET /v2/auth/oauth2/clients/:clientId
  - POST /v2/auth/oauth2/clients/:clientId/authorize
  - POST /v2/auth/oauth2/clients/:clientId/exchange
  - POST /v2/auth/oauth2/clients/:clientId/refresh
- Tests cover happy paths and error cases (invalid client, invalid code, etc.)

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore(api-v2): hide OAuth2 endpoints from Swagger documentation

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* hide endpoints from doc

* fix(api-v2): address PR feedback for OAuth2 controller

- Fix P0 critical bug: token_type field name mismatch in DecodedRefreshToken interface
- Add @Equals('authorization_code') validation to exchange.input.ts grantType
- Add @Equals('refresh_token') validation to refresh.input.ts grantType
- Add @IsNotEmpty() validation to get-client.input.ts clientId
- Add @Expose() decorators to all output DTOs for proper serialization
- Add security test assertion to verify clientSecret is not returned in response

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* feat(api-v2): implement redirect behavior for OAuth2 authorize endpoint

- Update authorize endpoint to return HTTP 303 redirect with authorization code
- Add exact match validation for redirect URI (security requirement)
- Implement error handling with redirect to redirect URI and error query params
- Add state parameter support for CSRF protection
- Update e2e tests to verify redirect behavior (303 status, Location header, error redirects)

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor(api-v2): address PR feedback for OAuth2 authorize endpoint

- Make redirectUri a required input parameter (remove optional fallback)
- Move buildRedirectUrl and mapErrorToOAuthError to oauth2Service
- Add return statements to res.redirect() calls
- Simplify controller by delegating redirect URL building to service

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* wip move code outside of api v2

* feat(oauth): wire up dependency injection for OAuthService and repositories

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* refactor: oAuthService used in routes

* fix imports

* fix(api-v2): return 404 for invalid client ID instead of redirect in authorize endpoint

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api-v2): fix E2E test URL paths and remove bootstrap() in authenticated section

- Remove bootstrap() call in authenticated section to match working test pattern
- Change URL paths from /api/v2/... to /v2/... in authenticated section
- Keep bootstrap() and /api/v2/... paths in unauthenticated section

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api-v2): mock getToken from next-auth/jwt for E2E tests

- Add jest.mock for next-auth/jwt getToken function
- Mock returns null for unauthenticated tests
- Mock returns { email: userEmail } for authenticated tests
- Remove withNextAuth helper since ApiAuthGuard uses ApiAuthStrategy
  which calls getToken directly, not NextAuthStrategy

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix tests and code review

* cleanup generate secrets

* cleanup controller

* chore: remove console.log from OAuthService.validateClient

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* Update apps/web/app/api/auth/oauth/refreshToken/route.ts

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

* fix(api-v2): add bootstrap() to authenticated E2E tests and update URL paths to /api/v2/

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* Merge remote-tracking branch 'origin/devin/oauth2-controller-skeleton-1765988792' and remove console.log from token route

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* chore: remove dead code

* refactor

* refactor: generateAuthCode trpc handler and getClient trpc handler

* remove pkce check for refreshToken endpoint

* Update packages/trpc/server/routers/viewer/oAuth/getClient.handler.ts

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

* refactor: error handling

* refactor: error handling

* refactor: error handling

* remove console log

* provide redirectUri in generateAuthCodeHandler

* provide redirectUri in authorize view

* refactor: replace HttpError with ErrorWithCode in OAuth files

- Update OAuthService to use ErrorWithCode instead of HttpError
- Update mapErrorToOAuthError to check ErrorCode instead of status codes
- Update token/route.ts and refreshToken/route.ts to use ErrorWithCode
- Add ErrorWithCode export to platform-libraries
- Use getHttpStatusCode to map ErrorCode to HTTP status codes

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update generateAuthCode handler to use ErrorWithCode instead of HttpError

The handler was still checking for HttpError in its catch block, but OAuthService
now throws ErrorWithCode. This caused the error messages to be lost and replaced
with 'server_error' instead of the specific error messages.

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: update OAuth2 controller to use ErrorWithCode instead of HttpError

The controller was still checking for HttpError in its catch blocks, but OAuthService
now throws ErrorWithCode. This caused all errors to return 500 Internal Server Error
instead of the correct HTTP status codes (400, 401, 404).

Also added getHttpStatusCode export to platform-libraries.

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: add explicit unknown type annotation to catch blocks in OAuth2 controller

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: change NotFoundException to HttpException in authorize endpoint

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: handle err with ErrorWithCode in authorize endpoint catch block

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: move errorWithCode

* fix: error code rfc

* fix: no need to handle errors there is a middleware

* refactor errors

* refactor errors

* refactor redirecturi and state from api

* refactor: address PR comments for OAuth2 controller

- Remove unused GetOAuth2ClientInput class
- Change API tag from 'Auth / OAuth2' to 'OAuth2'
- Move OAuthClientFixture to separate fixture file (oauth2-client.repository.fixture.ts)
- Add 'type' property to OAuth2ClientDto for confidential/public client type
- Rename 'clientId' to 'id' in OAuth2ClientDto (using @Expose mapping)
- Clean up duplicate provider declarations in oauth2.module.ts
- Update e2e tests to use new fixture and verify type property

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.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>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Volnei Munhoz <volnei.munhoz@gmail.com>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-07 08:05:21 -03:00
Hariom Balhara ca32f04cc1 chore: Integrate booking cancellation audit (#26458)
## What does this PR do?
> **⚠️ Note: This PR does not enable booking audit in production.** The `BookingAuditTaskerProducerService` has an [`IS_PRODUCTION` guard](https://github.com/calcom/cal.com/blob/integrate-booking-creation-reschedule-audit/packages/features/booking-audit/lib/service/BookingAuditTaskerProducerService.ts#L106-L108) that skips audit task queueing in production environments. This allows the integration to be tested in development before enabling it in production.

Integrates audit logging for booking cancellations, following the pattern established in PR #26046 for booking creation/rescheduling audit.

- Related to #25125 (Booking Audit Infrastructure)

### Changes:
- Add audit logging for single booking cancellation via `onBookingCancelled`
- Add audit logging for bulk recurring booking cancellation via `onBulkBookingsCancelled`
- Pass `userUuid` and `actionSource` from webapp cancel route (WEBAPP)
- Pass `userUuid` and `actionSource` from API-v2 bookings service (API_V2)
- Create `getAuditActor` helper to derive actor from userUuid or create synthetic guest actor
- Add `getUniqueIdentifier` helper for generating unique actor identifiers
- Add warning log when `actionSource` is "UNKNOWN" for observability
- Add integration tests for booking cancellation audit

### Audit Data Captured:
- `cancellationReason` (simple string value)
- `cancelledBy` (simple string value)  
- `status` (old → new, e.g., "ACCEPTED" → "CANCELLED")

### Updates since last revision:
- Simplified `CancelledAuditActionService` schema: `cancellationReason` and `cancelledBy` are now stored as simple nullable strings instead of change objects (old/new), since cancellation is a one-time event where tracking previous values doesn't apply
- Added integration tests for cancelled booking audit in `booking-audit-cancelled.integration-test.ts`
- Added `getUniqueIdentifier` helper function in actor.ts for generating unique identifiers with prefixes

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - no documentation changes needed.
- [ ] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

1. Cancel a single booking via the webapp - verify audit record is created with actor and actionSource="WEBAPP"
2. Cancel a single booking via API v2 - verify audit record is created with actionSource="API_V2"
3. Cancel all remaining bookings in a recurring series - verify bulk audit records are created with shared operationId
4. Cancel via unauthenticated cancel link - verify guest actor is created with synthetic email (prefixed with "param-" or "fallback-")
5. Run integration tests: `yarn test packages/features/booking-audit/lib/service/__tests__/booking-audit-cancelled.integration-test.ts`

## Human Review Checklist

- [ ] Verify `onBookingCancelled` and `onBulkBookingsCancelled` methods exist in `BookingEventHandlerService`
- [ ] Review the `getAuditActor` fallback logic - creates synthetic email with "fallback-" or "param-" prefix when no userUuid available
- [ ] Confirm the simplified schema for `cancellationReason`/`cancelledBy` (no longer tracking old→new) is intentional
- [ ] Note: Audit logging calls are awaited directly - if audit service fails, the cancellation will fail. Confirm this is the desired behavior.
- [ ] Verify `CancelledAuditDisplayData` type no longer includes `previousReason` and `previousCancelledBy` fields

---

Link to Devin run: https://app.devin.ai/sessions/42404e76a66946fe9e46fa07fb12e779
Requested by: @hariombalhara (hariom@cal.com)
2026-01-07 16:15:57 +05:30
Dhairyashil Shinde 9e84f59216 feat(companion): UI Enhancements for Android and Extension (#26434)
* feat: companion-android-ui-upgrade version 1

* recurrings and unconfirmed booking filter and page implementation

* add badge and links to event type list page

* address cubics comments

* feat(companion): unify dropdown menu for Android and extension (#26486)

* feat(companion): unify dropdown menu for Android and extension

- Merge Android-specific dropdown implementations into base component files
- EventTypeListItem: Add DropdownMenu with Preview, Copy link, Edit, Duplicate, Delete actions
- BookingListItem: Add DropdownMenu with booking actions (reschedule, edit location, add guests, etc.)
- RecurringBookingListItem: Add DropdownMenu with recurring booking actions
- AvailabilityListItem: Add DropdownMenu with Set as Default, Duplicate, Delete actions
- BookingDetailScreen: Add DropdownMenu in header for Android with AlertDialog for cancel confirmation
- Delete all .android.tsx files as implementations are now unified

* fix(companion): fix typecheck errors after dropdown unification

- Remove unused props from EventTypeListItem.ios.tsx (copiedEventTypeId, handleEventTypeLongPress)
- Remove unused onActionsPress prop from BookingListItem.ios.tsx
- Remove copiedEventTypeId and handleEventTypeLongPress props from index.ios.tsx and index.tsx
- Remove onLongPress and onActionsPress props from BookingListScreen.tsx
- Remove handleScheduleLongPress, setSelectedSchedule, setShowActionsModal props from AvailabilityListScreen.tsx
- Fix BookingDetailScreen.tsx to use correct action property names (reschedule.visible instead of canReschedule, etc.)

* fix(companion): remove unused code after dropdown unification

- Remove unused handleEventTypeLongPress function and ActionSheetIOS import from index.ios.tsx
- Remove unused copiedEventTypeId state, handleEventTypeLongPress function, and ActionSheetIOS import from index.tsx
- Prefix unused setSelectedBooking with underscore in BookingListScreen.tsx
- Remove unused handleScheduleLongPress function and ActionSheetIOS import from AvailabilityListScreen.tsx

* feat(companion): unify booking filter UI for Android and extension

- Remove SegmentedControl from web/extension booking list page
- Use Header dropdown for booking status filter on both Android and web
- Use unified event type filter dropdown for both platforms
- Remove unused showFilterModal state and related code
- Pass filterOptions, activeFilter, and onFilterChange to Header for all platforms

* fix(companion): add header padding for web/extension to prevent button clipping

- Add headerLeftContainerStyle and headerRightContainerStyle with 12px padding for web platform
- Applied to root Stack and all nested tab Stack layouts
- Fixes issue where header buttons were touching edges and getting chopped off on extension/web
- Android remains unaffected as the fix is web-only

* fix(companion): add HeaderButtonWrapper for web-only header padding

- Create HeaderButtonWrapper component that adds 12px margin on web only
- Wrap all header buttons with HeaderButtonWrapper to prevent clipping
- Revert invalid screenOptions changes that caused typecheck errors
- Apply fix to all screens with native header buttons:
  - reschedule.tsx, edit-location.tsx, add-guests.tsx
  - mark-no-show.tsx, view-recordings.tsx, meeting-session-details.tsx
  - event-type-detail.tsx, BookingDetailScreen.tsx, profile-sheet.tsx
  - edit-availability-day.tsx, edit-availability-name.tsx, edit-availability-override.tsx

* update more ui-ux

* address cubics comments

* address cubics comments & open event type list page first for inttial render of app
2026-01-07 07:19:07 -03:00
Benny Joo 6d2491b394 refactor: Clean up the /tests in the root (#26525)
* refactor: Delete mockTRPCContext and mockData, and relocate mockStripeSubscription to stripe mock.

* chore: Delete unused Stripe, video client, and reminder scheduler mock files.
2026-01-07 07:18:15 -03:00
110491ecb9 fix: generate compliant passwords using meeting_password_requirement (#26148)
* fix(zoomvideo): generate compliant passwords using meeting_password_requirement

- Add meetingPasswordRequirementSchema to parse Zoom's password policy settings
- Implement validatePasswordAgainstRequirements() to check if a password meets the policy
- Implement generateCompliantPassword() to create passwords that comply with the policy
- Update translateEvent() to use getCompliantPassword() which validates the default password
  or generates a new compliant one based on meeting_password_requirement
- Add meeting_password_requirement to the settings API filter
- Improve error handling for non-JSON responses in OAuthManager (XML validation errors)

This fixes the frequent 'Error in JSON parsing Zoom API response' errors caused by
Zoom returning XML validation errors when the password doesn't comply with the
account's password policy (e.g., numeric-only requirement).

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* refactor: use cleaner single-pass consecutive character check

- Replace nested-loop O(n*k) implementation with single-pass O(n) helper
- Add proper guard for consecutiveLength < 4 (Zoom allows 0, 4-8)
- Move consecutive check before only_allow_numeric to apply it for all cases
- Fix edge-case bug where consecutiveLength 1-3 could incorrectly reject passwords

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Optimize OAuth response handling

Refactor OAuth response validation to read body only once.

* Improve error handling in Zoom API response parsing

Refactor error handling for Zoom API response parsing to improve logging and clarity.

* Improve compliant password generation logic

Enhance password generation to avoid consecutive characters when numeric only is required.

* Remove password requirement handling from VideoApiAdapter

Removed meeting password requirement schema and related functions for password validation and generation.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 09:51:30 +00:00
Hariom Balhara 010ac9e8f2 Make booking-audit integration test utils reusable (#26526) 2026-01-07 14:22:09 +05:30
Pedro CastroandMorgan 701c4cdb76 perf: batch booking queries in output service (#25900)
Replace N sequential queries with single batch queries in:
- getOutputRecurringBookings
- getOutputRecurringSeatedBookings

Uses existing batch repository methods. Reduces database roundtrips
from O(n) to O(1) for recurring booking lookups

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2026-01-07 08:41:09 +00:00
Pedro Castro 01be9f1ef2 fix: validate owner email on platform org creation (#26286)
Remove isPlatform bypass from owner verification to ensure users can only create organizations where they are the designated owner. Add test coverage for create and intentToCreateOrg handlers:

- Regression tests for isPlatform bypass fix
- Happy path for admin creating org for another user
2026-01-06 22:46:44 -03:00
Pedro Castro 30ef38804c refactor: use structured logger in video adapters (#26285)
- Remove debug console.log/console.error statements
- Add logger.debug for observability (meeting lifecycle events)
- Add logger.error with safe error pattern (message + name only)
- Fix error messages to avoid exposing response details
- Remove redundant try/catch blocks (errors propagate naturally)
2026-01-06 22:29:17 -03:00
Pedro CastroandAlex van Andel 0df161ef26 fix(ci): use env vars for input interpolation in workflow run steps (#26520)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2026-01-06 22:56:59 +00:00
b8b9251f76 fix: Support 10-digit phone numbers for Ivory Coast (+225) (#26465)
* fix: update ivory coast mask to 10 digits

* update formating for Benin numbers

---------

Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
2026-01-06 22:31:21 +00:00
Alex van Andel 1ebe7aa8ab chore: release v6.0.8
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2026-01-06 22:23:31 +00:00
Pedro Castro 170203051f fix: handle existing users on invite token flow (#26217)
* fix(auth): validate user before signup with invite token

Validate if user already exists before creating account when
signing up with team or organization invite tokens. Existing users
are redirected to login to accept the invitation.

- Add user existence check in signup handlers
- Return 409 for existing users with redirect to login
- Extract signup fetch logic to dedicated module
- Add e2e test coverage

* fix(auth): address code review feedback

- Fix fetchSignup tests to use vi.spyOn for proper mock restoration
- Add content-type validation before parsing JSON response
- Guard against undefined error in Stripe callback
- Use t() for localized error message
- Fix race condition in handlers by catching P2002 on create

* fix(auth): address additional code review feedback

- Add INVALID_SERVER_RESPONSE constant to follow established pattern
- Check error.meta.target includes email before returning USER_ALREADY_EXISTS
to avoid false positives from other unique constraint violations
- Add select: { id: true } to user.create calls since downstream functions only
need the user id

* test: add unit tests for P2002 handling in signup handlers

- Add shared test suite covering all P2002 edge cases
- Ensure 409 only for email constraint violations
- Fix non-token paths to use atomic create + catch pattern

* fix: update error message copy per review feedback

* fix(auth): address code review feedback and prevent orphan Stripe customers

- Add user existence check before Stripe customer creation (token flow)
- Add select clause to user.create for consistency
- Fix showToast argument order (pre-existing bug)
- Use toHaveURL instead of waitForURL in E2E tests

* fix(auth): resolve 500 errors by fixing Prisma error detection across module boundaries

The instanceof check for PrismaClientKnownRequestError fails when different
Prisma client instances are loaded. Added fallback check by constructor name

* fix(auth): validate invitedTo before upsert on team invite signup

* test(auth): update P2002 tests for new invite flow

P2002 tests now use non-token flow since token flow uses upsert
Added tests for invitedTo validation on invite signup

* fix(auth): add guards and P2002 handling per review feedback

- Guard existingUser check with if (foundToken?.teamId)
- Guard username check with if (username) for premium flow
- Add `select` clause to findFirst/findUnique queries
- Add try-catch on upsert for race condition P2002 errors

* fix(auth): narrow P2002 handling to email/username targets
2026-01-06 22:10:36 +00:00
8b5d9202db refactor: convert PrismaAttributeToUserRepository to accept Prisma as dependency (#26515)
* refactor: convert PrismaAttributeToUserRepository to accept Prisma as dependency

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: use Prisma types from generated client instead of custom types

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 18:09:07 +00:00
Eunjae LeeandDevin AI 6fa525812c docs: add DTO location and naming conventions to knowledge base (#26478)
* docs: add DTO location and naming conventions to knowledge base

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* docs: clarify DTO location rules for new features vs refactored code

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* docs: simplify DTO location - all DTOs go in packages/lib/dto/

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 15:02:55 -03:00
eacfcd15a4 feat: Hubspot write to meeting object (#26039)
* feat: Hubspot write to meeting object

* fix: translate hardcoded strings and remove debug console.log

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* refactor

* fix: improve static value detection for placeholder replacement

- Changed condition from startsWith/endsWith to includes('{') to properly detect embedded placeholders
- Strings like 'Hello {name}!' are now correctly processed for placeholder replacement
- Pure placeholder tokens that can't be resolved return null
- Partially resolved values are returned as-is

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* refactor: split WriteToObjectSettings into types and utils files

- Extract interfaces, enums, and type definitions to WriteToObjectSettings.types.ts
- Extract constants and utility functions to WriteToObjectSettings.utils.ts
- Update main component to use the new utility functions
- Improves code organization and maintainability

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* revert: restore original static value detection logic

Per user request - the startsWith/endsWith check was intentional

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* test: add unit tests for HubSpot CRM service

Tests cover:
- ensureFieldsExistOnMeeting: field validation against HubSpot properties
- getTextValueFromBookingTracking: UTM parameter extraction
- getTextValueFromBookingResponse: placeholder replacement
- getDateFieldValue: date field resolution for different date types
- getFieldValue: main field value resolution for all field types
- generateWriteToMeetingBody: write-to-meeting body generation
- getContacts: contact search functionality

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: correct type errors in HubSpot CRM service tests

- Import WhenToWrite enum from crm-enums
- Replace string literals with WhenToWrite.EVERY_BOOKING enum values
- Add missing whenToWrite property to field config objects

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: use type casting for intentional type errors in tests

- Cast numeric fieldValue to string for testing non-string handling
- Cast invalid field type string to CrmFieldType for testing unsupported types

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: prevent unhandled promise rejections in HubSpot CRM tests

- Re-apply mockGetAppKeysFromSlug implementation in beforeEach to ensure
  mock is always set correctly after clearAllMocks
- Change vi.resetAllMocks() to vi.clearAllMocks() to preserve mock
  implementations between tests
- Add explicit types to satisfy biome lint rules
- This fixes the 'Cannot read properties of undefined (reading client_id)'
  errors that were causing CI to fail with exit code 1

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* refactor: convert HubSpot tests to black-box testing through public methods

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: properly type mock CalendarEvent in HubSpot tests

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: properly type TFunction in mock CalendarEvent

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* chore: graceful owner fail test

* refactor

* fix: type check

* fix: remove null fields

* Update packages/app-store/hubspot/lib/CrmService.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-06 14:58:46 -03:00
Peer RichelsenandDevin AI 8ad5f7bf55 feat: add organization banner to user profile page (#26514)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 17:26:49 +00:00
Eunjae LeeandDevin AI f4248bf20d feat: implement FeatureOptInService (#25805)
* feat: implement FeatureOptInService WIP

* clean up

* feat: consolidate feature repositories and add updateFeatureForUser

- Implement updateFeatureForUser in FeaturesRepository (similar to updateFeatureForTeam)
- Move getUserFeatureState and getTeamFeatureState from PrismaFeatureOptInRepository to FeaturesRepository
- Update FeatureOptInService to use only FeaturesRepository
- Add setUserFeatureState and setTeamFeatureState methods to FeatureOptInService
- Update _router.ts to remove PrismaFeatureOptInRepository usage
- Remove PrismaFeatureOptInRepository.ts and FeatureOptInRepositoryInterface.ts
- Update features.repository.interface.ts and features.repository.mock.ts
- Add integration tests for updateFeatureForUser, getUserFeatureState, getTeamFeatureState
- Update service.integration-test.ts to use FeaturesRepository

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: rename updateFeatureForUser to setUserFeatureState

Rename to match the convention used for setTeamFeatureState

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: return FeatureState type from getUserFeatureState and getTeamFeatureState

* fix integration tests

* clean up logics

* update services and router

* refactor: change getUserFeatureState and getTeamFeatureState to accept featureIds array

- Renamed getUserFeatureState to getUserFeatureStates
- Renamed getTeamFeatureState to getTeamFeatureStates
- Changed parameter from featureId: string to featureIds: string[]
- Changed return type from FeatureState to Record<string, FeatureState>
- Updated FeatureOptInService to use the new batch methods
- Added tests for querying multiple features in a single call
- Optimized listFeaturesForTeam to fetch all feature states in one query

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* feat: add getFeatureStateForTeams for batch querying multiple teams

- Added getFeatureStateForTeams method to query a single feature across multiple teams in one call
- Updated FeatureOptInService.resolveFeatureStateAcrossTeams to use the new batch method
- Replaces N+1 queries with a single database query for team states
- Added comprehensive integration tests for the new method

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: combine org and team state queries into single call

- Include orgId in the teamIds array passed to getFeatureStateForTeams
- Extract org state and team states from the combined result
- Reduces database queries from 3 to 2 in resolveFeatureStateAcrossTeams

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: use team.isOrganization and clarify computeEffectiveState comment

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: use MembershipRepository.findAllByUserId with isOrganization

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* feat: add featureId validation using isOptInFeature type guard

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* less queries

* add fallback value

* fix type error

* move files

* add autoOptInFeatures column

* use autoOptInFeatures flag within FeatureOptInService

* add setUserAutoOptIn and setTeamAutoOptIn

* fix computeEffectiveState logic

* rewrite computeEffectiveState

* clean up integration tests

* clean up in afterEach

* fix type error

* refactor: use FeaturesRepository methods instead of direct Prisma calls

Replace all manual userFeatures and teamFeatures Prisma operations with
the new setUserFeatureState and setTeamFeatureState repository methods.

Changes include:
- Admin handlers (assignFeatureToTeam, unassignFeatureFromTeam)
- Test fixtures and integration tests
- Playwright fixtures
- Development scripts

This ensures consistent feature flag management through the repository
pattern and supports the new tri-state semantics (enabled/disabled/inherit).

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* clean up

* fix the logic

* extract some logic into applyAutoOptIn()

* remove wrong code

* refactor: convert setUserFeatureState and setTeamFeatureState to object params with discriminated union

- Convert multiple positional parameters to single object parameter
- Use discriminated union types: assignedBy required for enabled/disabled, omitted for inherit
- Update all callers across repository, service, handlers, fixtures, and tests

* fix type error

* use Promise.all

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 16:55:53 +01:00
cal-com-ci[bot]andLingo.dev 750408ec21 feat: update translations via @LingoDotDev (#26497)
Co-authored-by: Lingo.dev <support@lingo.dev>
2026-01-06 15:01:45 +00:00
5794584624 chore: remove Mintlify AI chat from CMD+K widget (#26485)
* chore: remove Mintlify AI chat from CMD+K widget

- Remove MintlifyChat component and related state from Kbar.tsx
- Delete packages/features/mintlify-chat directory (MintlifyChat.tsx, util.ts)
- Delete apps/web/app/api/mintlify-chat API routes and tests
- Delete packages/lib/server/mintlifyChatValidation.ts
- Remove Mintlify-related env vars from .env.example and turbo.json
- Refactor Kbar.tsx to fix lint issues (explicit types, exports at end)

Co-Authored-By: peer@cal.com <peer@cal.com>

* fix: use ReactNode import instead of JSX from react

The JSX type is not exported from 'react' module. Use the global
JSX.Element type (available in React projects) and import ReactNode
for the children prop type.

Co-Authored-By: peer@cal.com <peer@cal.com>

* feat: add all event-types and upcoming bookings to KBar

- Increase event types limit from 10 to 100 to show more event types
- Add useUpcomingBookingsAction hook to fetch and display upcoming bookings
- Bookings show title, date, and time in KBar search results
- Navigate to booking details page when selecting a booking

Co-Authored-By: peer@cal.com <peer@cal.com>

* Revert "feat: add all event-types and upcoming bookings to KBar"

This reverts commit 69d03397e3820e45e7207eb55b38117d269eae5e.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 14:37:33 +00:00
81b5d62f07 feat(api): add team event-types webhooks controller (#26449)
* feat(api): add team event-types webhooks controller

- Add TeamsEventTypesWebhooksController for managing webhooks on team event types
- Add IsTeamEventTypeWebhookGuard for authorization
- Add TeamEventTypeWebhooksService for business logic
- Register new controller in TeamsEventTypesModule
- Enable unsafeParameterDecoratorsEnabled in biome.json for NestJS support

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* test(api): add e2e tests for team event-types webhooks controller

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api): restrict team event-type webhooks to admins/owners only

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api): use regular imports instead of type imports for DI and DTOs

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix(api): use regular imports for DI in guard file

Co-Authored-By: morgan@cal.com <morgan@cal.com>

* fix: circular depndency in modules

* delete teams in test

* fix roles guard

* fix biome

* fix guard

* resolve type import

* resolve review feedback

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 11:23:18 -03:00
Pedro Castro 208a9eaa80 chore(auth): add error logging for saml-idp silent failures (#26484)
* chore(auth): add error logging for saml-idp silent failures

* chore(auth): add warn-level logging for saml-idp silent failures

* chore(auth): change 'No user found' log to warn level

* chore(auth): add warn-level logging for silent auth failures

- saml-idp authorize: credentials, code, token, userInfo, user lookup
- callbacks:signIn: account type, email, name, catch-all
- callbacks:jwt: unknown account type (info → warn)
- saml:profile: missing email from IdP
- getServerSession: user not found for valid token
2026-01-06 13:27:12 +00:00
Keith Williams 9e0ba5045e chore: change API codeowner to Foundation (#26504) 2026-01-06 12:55:18 +00:00
Udit Takkar 437d7d9e40 perf: improve cal video webhook (#26495)
* perf: improve cal video webhook

* save format

* refactor: use errorMs
2026-01-06 15:52:18 +04:00
Hariom Balhara a056c3217e chore: Add impersonation context support to booking audit (#26014)
## What does this PR do?

Adds infrastructure to track impersonation context in booking audit records and displays it in the UI. When an admin impersonates another user and performs booking actions, the audit system now:
- Records the **admin** as the actor (who actually performed the action)
- Stores the **impersonated user's UUID** in a separate `context` field
- Displays **"Impersonated By"** in the booking logs UI when viewing audit details

This separation ensures audit trail integrity (the admin is accountable) while preserving full context about whose account was being used.

### Changes
- Added `uuid` to `impersonatedBy` session object for actor identification
- Added `uuid` to top-level `User` type in next-auth types for session enrichment
- Added `context Json?` field to `BookingAudit` Prisma model
- Added `BookingAuditContextSchema` for type-safe context handling with `actingAsUserUuid` field
- Updated producer service interface and implementation to pass context through all queue methods
- Updated consumer service to persist context to database
- Updated repository to store and fetch context in BookingAudit records
- Added `impersonatedBy` field to `EnrichedAuditLog` type in `BookingAuditViewerService`
- Added `enrichImpersonationContext` method to resolve impersonated user details
- Updated booking logs UI to display "Impersonated By" in expanded details
- Added `impersonated_by` translation key

Link to Devin run: https://app.devin.ai/sessions/3f1252527aef4ead9401bdf055c0817b
Requested by: hariom@cal.com (@hariombalhara)

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - internal infrastructure change
- [ ] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

1. Verify type checks pass: `yarn type-check:ci --force`
2. Verify existing audit tests still pass: `TZ=UTC yarn test`
3. To fully test impersonation context display:
   - Have an admin impersonate a user
   - Perform a booking action (create, cancel, reschedule)
   - Navigate to the booking's audit logs
   - Expand the details for the action
   - Verify "Impersonated By" row appears showing the impersonated user's name
   - Verify the BookingAudit record has:
     - `actorId` pointing to the admin's AuditActor
     - `context` containing `{ actingAsUserUuid: "<impersonated-user-uuid>" }`

## Human Review Checklist

- [ ] Verify the `context` field schema design is appropriate for future extensibility
- [ ] Confirm the `uuid` addition to User type in next-auth doesn't break existing auth flows
- [ ] Check that the optional `context` parameter doesn't break existing queue method callers
- [ ] Verify no migration file is needed (or if squashing is handled separately)
- [ ] Verify the UI displays "Impersonated By" correctly when impersonation context is present
- [ ] Confirm `enrichImpersonationContext` handles edge cases (null context, invalid context, deleted user)

## Checklist

- [x] My code follows the style guidelines of this project
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have checked if my changes generate no new warnings
2026-01-06 16:16:18 +05:30
fca818a275 test: fix unit test flake (#25557)
* fix: revalidate teams cache after accepting invite via token

When a user accepts a team invite via token on the /teams page, the
teams cache was not being invalidated. This caused the page to show
stale data (empty list) while the sidebar correctly showed the teams.

This fix adds a call to revalidateTeamsList() after processing an
invite token, ensuring the cache is invalidated and fresh data is
fetched immediately.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* fix: revalidate teams cache after creating team in onboarding flow

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* Remove comments on teams cache revalidation

Removed comments about revalidating teams cache after invite processing.

* fix unit test flake

* Remove unused import in useCreateTeam hook

Removed unused import for revalidateTeamsList.

* Remove unused import for revalidateTeamsList

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 11:14:28 +05:30
Anshumancanrock 6672fd4c3d fix: "New" button sizing inconsistent between Workflows and Event Types pages (#26066)
* fix: consistent button sizing between fab and button variants on desktop

* fix: consistent button sizing between fab and button variants on desktop

* fix(ui): align New button sizing across pages

* fix: New button sizing inconsistent between Workflows and Event Types pages

* Update Button.tsx
2026-01-06 03:08:20 +00:00
Benny Joo 6ed18bba53 fix: atoms build by updating import paths (#26489)
* fix build

* fix build
2026-01-06 02:55:42 +00:00
Pedro Castro 920320d49b fix(auth): fix SAML tenant extraction and validation (#26482)
- Extract tenant from userInfo in saml-idp (IdP-initiated)
- Add profile.requested?.tenant fallback for OAuth (SP-initiated)
- Block invalid tenant format in hosted (security)
2026-01-05 18:52:48 +00:00
Volnei Munhoz 66b398b4ed Disable noReactSpecificProps as we use react (#26479) 2026-01-05 18:02:56 +00:00
e0fd01e377 feat: add lightweight E2E session warmup page (#26451)
* feat: add lightweight E2E session warmup endpoint

- Add /api/__e2e__/session-warmup endpoint that triggers NextAuth session loading
- Update apiLogin fixture to use the new endpoint instead of navigating to /settings/my-account/profile
- The endpoint is gated by NEXT_PUBLIC_IS_E2E=1 (already set in playwright.config.ts)
- This reduces overhead in E2E tests by avoiding loading a full UI page just to warm up the session

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: move session warmup endpoint to App Router

- Move /api/__e2e__/session-warmup from pages/api to app/api
- Use App Router patterns (NextResponse, buildLegacyRequest)
- Maintains same functionality for E2E session warming

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* rename path

* refactor: switch from API route to minimal SSR page (Option 2)

- Replace /api/e2e/session-warmup API route with /e2e/session-warmup page
- Use App Router page pattern with getServerSession for session warmup
- Update apiLogin fixture to navigate to the page instead of API request

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* revert users fixture but with a new url

* render nothing on success

* clean up

* trying something

* Revert "trying something"

This reverts commit 2ae2f7dcb42612e54eb072a9f09857272020889a.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-05 16:22:52 +00:00
Pedro Castro 23848e7503 chore(deps): update dependencies and add version constraints (#26390)
- Update sanitize-html to 2.17.0
- Remove unused Storybook dependencies from @calcom/ui
- Add resolutions for consistent dependency versions
- Clean up packageExtensions
2026-01-05 13:00:55 -03:00
Benny JooandDevin AI 404d46c991 refactor: Move trpc-dependent components from features to web [2] (#26420)
* fix

* move event types components to web

* update import paths

* mv apps components

* migrate form builder

* fix

* mv sso

* fix

* mv

* update import paths

* update import paths

* mv

* mv

* mv

* fix

* update Booker

* fix

* fix

* fix

* fix

* mv video

* mv embed components to web

* update import paths

* mv calendar weekly view components

* update import paths

* fix

* fixp

* fix

* fix

* fix

* fix: update FormBuilder imports to use @calcom/features/form-builder

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update broken import paths after file migrations

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: correct import paths for platform atoms and moved components

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: apply CSS type fixes and add missing atoms exports

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: resolve type errors in test files after component migrations

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: resolve remaining type errors in test files

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* migrate

* fix: resolve type errors in test and mock files

- Add missing bookingForm, bookerFormErrorRef, instantConnectCooldownMs to Booker.test.tsx bookings prop
- Add all required BookerEvent properties to event.mock.ts
- Add vi import from vitest to all mock files
- Fix date parameter types in packages/dayjs/__mocks__/index.ts
- Add verificationCode and setVerificationCode to test-utils.tsx mock store
- Remove children.type access in Section.tsx mock to fix type error
- Fix lint issues: remove unused React imports, use import type where needed, add return types
- Add biome-ignore comments for pre-existing lint warnings in test files

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* migrate

* migrate

* migrate

* update import paths

* update import paths

* update import paths

* fix

* migrate data table

* migrate data table

* fix

* fix

* fix

* migrate insights components

* migrate insights components

* fix

* mv

* update import paths

* fix

* fix

* fix

* fix

* fix

* fix: resolve type errors in test mocks

- Booker.test.tsx: Add all required UseFormReturn methods to bookingForm mock
- event.mock.ts: Fix entity, subsetOfHosts, instantMeetingParameters, fieldTranslations, image types
- dayjs/__mocks__/index.ts: Use Object.assign for proper typing of mock properties
- Section.tsx: Change 'class' to 'className' in JSX with biome-ignore comment

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing hasDataErrors and dataErrors to bookings.errors mock

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing loadingStates properties to bookings mock

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing slots properties (setTentativeSelectedTimeslots, tentativeSelectedTimeslots, slotReservationId)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update quickAvailabilityChecks to include utcEndIso and use valid status type

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing bookerForm properties (formName, beforeVerifyEmail, formErrors)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing UseFormReturn properties to bookerForm.bookingForm mock

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add hasFormErrors and formErrors to bookerForm.formErrors mock

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add hasFormErrors and formErrors to bookerForm.errors mock

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing isError property to mockEvent

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: use complete BookerEvent mock in Booker.test.tsx

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: use branded bookingFields type in event mock

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing schedule mock properties (isError, isSuccess, isLoading, dataUpdatedAt)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* revert

* fix

* fix

* fix

* fix build

* fix

* fix

* fix

* fix: correct AddMembersWithSwitch test wrapper to use initial assignAllTeamMembers value

- Fixed test wrapper to initialize useState with componentProps.assignAllTeamMembers
  instead of hardcoded false, allowing tests to properly test different states
- Updated test expectations for ALL_TEAM_MEMBERS_ENABLED_AND_SEGMENT_NOT_APPLICABLE
  state to match actual component behavior (toggle should be present and checked)
- Fixed 'should show Segment when toggled on' test to start with assignAllTeamMembers: false
  to properly test the flow of enabling it
- Added explicit types to satisfy biome lint requirements

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: use JSX.Element instead of React.JSX.Element for type compatibility

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 12:53:51 -03:00
Keith WilliamsandDevin AI 3d73238c00 fix: remove installation requirement from trusted bot check (#26466)
* fix: remove installation requirement from trusted bot check

The installation object is not present in the webhook payload when
GitHub Apps add labels via pull_request_target events. This caused
graphite-app[bot] to fail the authorization check and fall through
to the human permission check, which doesn't work for bots.

The fix removes the installation requirement and relies on:
- sender.type === 'Bot'
- sender.login matching the trusted bot list

This is secure because the sender fields come from GitHub's webhook
payload and cannot be forged by contributors.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: add extra logging about sender type

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: remove senderId from logging

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Update run-ci.yml

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 15:19:39 +00:00
bbfb17ae5c feat: update translations via @LingoDotDev (#26445)
Co-authored-by: Lingo.dev <support@lingo.dev>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-05 15:18:03 +00:00
Keith WilliamsandDevin AI 3ab6d9096e fix: cancel running CI workflow before re-triggering and allow trusted GitHub Apps (#26461)
* fix: cancel running CI workflow before re-triggering and allow trusted bots

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove hardcoded bot allowlist, keep only cancel-and-rerun improvement

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add app_id verification for trusted GitHub Apps (Graphite)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: simplify trusted bot check to use sender type, login, and installation context

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: remove unnecessary comments

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 11:58:20 -03:00
Pedro Castro 0109427d04 fix(auth): make identityProviderId lookup case-insensitive (#26405)
SAML IdPs may send NameIDs with different casing than stored, causing login failures.
Aligns with the existing case-insensitive email lookup pattern
2026-01-05 14:00:11 +00:00
sean-brydonandDevin AI f8e70517d1 fix: add @calcom/trpc#build dependency to @calcom/web#dev task (#26460)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 13:43:53 +00:00
Hariom Balhara e61e66ec34 chore: Ensure that uuid is available in server session[Booking Audit Prerequisite] (#25963)
## What does this PR do?

Similar to #25721, adds uuid in session so that BookingAudit has it readily available

Adds the user's UUID to the booking metadata by:
1. Extending the NextAuth `User` interface to include an optional `uuid` property from PrismaUser
2. Making `uuid` required on `Session.user` via intersection type (`User & { uuid: PrismaUser["uuid"] }`)
3. Adding `uuid` to the session user object in `getServerSession.ts`
4. Adding `uuid` to the `AdapterUser` transformation in `next-auth-custom-adapter.ts`
5. Passing `userUuid` from the session to the booking creation flow
6. Updating the API key verification flow to include `uuid` in the user data (repository, service, and type definitions)
7. Adding `req.userUuid` as a required field on the request object (like `req.userId`)
8. Adding `uuid` to mock session objects in web app routes and test context
9. Adding `uuid` to the `findByEmailAndIncludeProfilesAndPassword` query in UserRepository

Also removes commented-out code that was placeholder for future work and fixes lint warnings for unused variables.

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - no documentation changes needed.
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

1. Verify that the NextAuth session callback is already populating the `uuid` field on the user object
2. Create a booking and confirm `userUuid` is included in the booking metadata
3. Test API v1 endpoints (`/api/invites` POST and `/api/teams/[teamId]/publish`) to verify they receive the uuid from the authenticated user
4. Check that the booking flow works correctly with the new parameter
5. Test SAML login flow to verify session still works correctly (uuid is resolved from database after authentication)

## Human Review Checklist

- [ ] Verify the NextAuth session callback populates `uuid` - if not, this change will pass `undefined` at runtime
- [ ] Confirm `userUuid` is consumed downstream in the booking service
- [ ] Verify that `PrismaApiKeyRepository.findByHashedKey()` correctly fetches the user's uuid from the database
- [ ] Verify the discriminated union type in `ApiKeyService.ts` ensures `result.user` is always defined when `result.valid` is true
- [ ] Confirm all API v1 endpoints using `req.userUuid` go through the `verifyApiKey` middleware
- [ ] Verify `UserRepository.findByEmailAndIncludeProfilesAndPassword()` includes `uuid` in the select clause
- [ ] Verify SAML login still works correctly - uuid is now optional on User interface so SAML providers don't need to supply it at profile stage

## Updates since last revision

- **Made uuid optional on User, required on Session**: Changed the type strategy so `uuid` is optional on the NextAuth `User` interface but required on `Session.user` via intersection type. This allows SAML providers to not supply uuid at the profile stage while ensuring uuid is always present on the session after the user is resolved from the database.
- **Removed uuid from SAML functions**: Since uuid is now optional on User, the SAML profile and authorize functions no longer need to include it.

---

Link to Devin run: https://app.devin.ai/sessions/97e5603b719a420b9b35041252c9db26
Requested by: hariom@cal.com (@hariombalhara)
2026-01-05 17:24:30 +05:30
Hariom BalharaandDevin AI 9d39590510 feat: create BookingHistoryViewerService to combine audit logs with routing form submissions (#26045)
* feat: create BookingHistoryViewerService to combine audit logs with routing form submissions

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* refactor(booking): rename audit log query and enhance type safety

- Updated the booking logs view to use the new getBookingHistory query instead of getAuditLogs.
- Introduced DisplayBookingAuditLog type for improved clarity in BookingAuditViewerService.
- Refactored BookingHistoryViewerService to utilize the new DisplayBookingAuditLog type and added sorting functionality for history logs.
- Adjusted related types and methods to ensure consistency across services.

* refactor(routing-forms): streamline imports and enhance type definitions

- Consolidated type exports and imports from the features library for better organization.
- Removed redundant type definitions and functions in zod.ts, findFieldValueByIdentifier.ts, getFieldIdentifier.ts, and parseRoutingFormResponse.ts.
- Introduced new utility functions for handling field responses and parsing routing form responses.
- Improved type safety and clarity across routing form response handling.

* fix: remove double prefix from uniqueId in form submission entry

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* 1c97f9cc5d50416788c01876fe539bcc9750e9b2 (#26453)

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 11:11:05 +00:00
a7fd7890a7 feat: integrate BookingHistory with Bookings V3 design (#26301)
* Integrate BookingHistory with Bookings V3 design

* Enhance booking features by integrating booking audit functionality

- Updated the booking page to retrieve user feature statuses for "bookings-v3" and "booking-audit".
- Modified BookingDetailsSheet and BookingListContainer components to accept and utilize the new bookingAuditEnabled prop.
- Adjusted the BookingHistory display logic to conditionally render based on the bookingAuditEnabled state.
- Refactored SegmentedControl to support generic types for better type safety.

This change improves the user experience by allowing conditional access to booking audit features based on user permissions.

* Refactor BookingDetailsSheet to manage active segment state with Zustand store

- Removed local state management for active segment in BookingDetailsSheet and integrated Zustand store for better state synchronization.
- Introduced useActiveSegmentFromUrl hook to sync active segment with URL query parameters.
- Updated BookingDetailsSheet to handle derived active segment logic based on bookingAuditEnabled state.
- Adjusted SegmentedControl to ensure it defaults to "info" when activeSegment is null.

This refactor enhances the maintainability and responsiveness of the booking details component.

* refactor: rename useBiDirectionalSyncBetweenZustandAndNuqs to useBiDirectionalSyncBetweenStoreAndUrl

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-05 16:21:35 +05:30
87cf3210dc feat: queue or cancel payment reminder flow (#24889)
Co-authored-by: Pallav <90088723+Pallava-Joshi@users.noreply.github.com>
Co-authored-by: Ryukemeister <sahalrajiv6900@gmail.com>
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2026-01-05 08:10:55 +00:00
Anik Dhabal Babu acee514c42 fix: show empty screen from event type availability tab (#26396)
* fix

* update

* fix

* Remove copying of App Store static files step

Removed step to copy App Store static files from the workflow.
2026-01-05 10:40:14 +05:30
Keith WilliamsandDevin AI 64b2cf0577 fix(ci): add yarn prisma generate before cache key generation (#26439)
This ensures consistent cache keys between the Build Web App job and E2E
shards by running yarn prisma generate before generating the cache key.

The issue was that packages/prisma/enums/index.ts is:
1. Generated by yarn prisma generate
2. In .gitignore (not committed to git)
3. Included in the SOURCE_HASH (matches packages/**/**.[jt]s)
4. NOT excluded from the hash

E2E jobs already run yarn prisma generate before cache-build, but the
Build Web App job did not, causing different cache keys in the same
workflow run.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-04 21:38:22 -03:00
Keith WilliamsandDevin AI aca3b1ecdb fix(ci): delete old prod build caches on cache miss (#26437)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-04 18:26:01 -03:00
Hariom Balhara 897c9d65f0 fix(auth): enhance SAML login handling by introducing userId field and updating JWT token structure (#26428) 2026-01-04 19:44:54 +00:00
Dhairyashil Shinde c1e5e0ae66 feat(companion): new availability detail and actions pages for ios (#26424)
* version 1

* version 1.1

* better code

* covered all edge cases

* address cubics comments

* address cubics comments
2026-01-04 12:48:37 -03:00
Abhay Mishra f9dc3f2f9c fix(seed): add missing Host entries for seeded round‑robin team events (#26426) 2026-01-04 10:00:37 +00:00
Kartik Labhshetwar c6e74e6e25 fix: add vertical spacing when hovered (#26419) 2026-01-03 21:30:31 +00:00
Beto 285f161e68 refactor(companion): event type details screen improvements (#26415)
* refactor(companion): move EventTypeDetail component to a new file and update routing

* refactor(companion): format code for better readability in TabLayout and EventTypeDetail components

* refactor(companion): improve code formatting and readability in EventTypeDetail component

* refactor(companion): enhance code readability and formatting in EventTypeDetail component

* refactor(companion): improve code formatting and readability in EventTypeDetail component

* refactor(companion): enhance code formatting and readability in EventTypeDetail component

* refactor(companion): improve code formatting and readability in TabLayout component
2026-01-03 17:54:37 +00:00
shashank-100 9c08c5fed1 fix: patch React 19 vulnerabilities by upgrading to 19.2.3 (#26411)
* security: patch React 19 vulnerabilities by upgrading to 19.2.3

* chore: revert lingo.dev upgrade
2026-01-03 14:20:08 +00:00
Beto 0c724dd229 fix: update bundle identifier (#26402) 2026-01-03 18:40:28 +05:30
Eesh Midha 78826a37a1 fix: Make incomplete booking form mobile-responsive (#26413) 2026-01-03 13:02:14 +00:00
Joe Au-Yeung 048a9b04fa chore: add logging in next-auth (#26404)
* Add logging in next-auth
* Add logging at other return
2026-01-02 20:30:09 -03:00
Dhairyashil Shinde 60a4d3f2b4 feat(companion): Add DropdownMenu and Alert Dialog for Android (#26385)
* feat(companion): add DropdownMenu for Android event types list

Replace Alert.alert with react-native-reusables DropdownMenu component
for Android event type list items, providing a native-feeling menu
experience that matches iOS functionality.

Changes:
- Install react-native-reusables dropdown-menu component and dependencies
  (lucide-react-native, tailwindcss-animate, class-variance-authority,
  clsx, tailwind-merge)
- Create EventTypeListItem.android.tsx with DropdownMenu implementation
  - Single ellipsis button triggers dropdown menu
  - Menu includes: Preview, Copy link, Edit, Duplicate, Delete
  - Delete action marked as destructive variant
  - Proper safe area insets handling
- Add PortalHost to app/_layout.tsx for portal rendering support
- Create lib/utils.ts with cn() helper for className merging
- Update global.css with theme CSS variables (popover, border, accent,
  destructive, etc.) for dropdown menu styling
- Update tailwind.config.js with theme colors and tailwindcss-animate plugin
- Update metro.config.js with inlineRem: 16 for proper rem unit handling
- Remove Android Alert.alert fallback from event types index.tsx
- Fix lint issues in generated dropdown-menu.tsx (remove unnecessary fragments)

The Android experience now matches iOS with a single menu button that
opens a dropdown containing all event type actions, replacing the
previous Alert.alert dialog and separate action buttons.

Refs: https://reactnativereusables.com/docs/components/dropdown-menu

* adjust with of menu

* feat(companion): add DropdownMenu for Android booking and availability list items

- Add BookingListItem.android.tsx with DropdownMenu for booking actions
- Add BookingDetailScreen.android.tsx with DropdownMenu in header
- Add AvailabilityListItem.android.tsx with DropdownMenu for schedule actions

Actions include: Reschedule, Edit Location, Add Guests, View Recordings,
Meeting Session Details, Mark as No-Show, Report Booking, Cancel Event
for bookings; Set as Default, Duplicate, Delete for availability schedules.

* fix lint issues

* feat(android): replace native alerts with AlertDialog and Toast in event types

- Install AlertDialog and Alert components from react-native-reusables
- Create Android-specific event types screen (index.android.tsx)
- Replace native Alert.alert() with AlertDialog for delete confirmation
- Add inline validation errors (red border + error text) in create modal
- Implement Toast snackbar for success/error notifications (no layout shift)
- Auto-dismiss toast after 2.5 seconds
- Fix React Compiler compatibility by removing animated refs

This provides a more consistent and polished UI experience on Android,
matching the design system used in other parts of the app.

* feat(android): add AlertDialog for availability delete and booking cancel

- Add index.android.tsx for availability with AlertDialog for delete confirmation
- Add index.android.tsx for bookings with AlertDialog for cancel (with reason input)
- Both screens include Toast snackbar for success/error notifications
- Follows the same pattern as event types Android implementation

* feat(companion): add DropdownMenu and AlertDialog for Android

- Replace native Alert.alert context menus with DropdownMenu component
  for event types, bookings, and availability lists
- Replace FullScreenModal with AlertDialog for create/delete/cancel flows
- Add toast notifications for success/error feedback on Android
- Set consistent 380px max-width for all AlertDialogs
- Fix layout headers showing "index" text on event-types and availability
- Create Android-specific More screen with AlertDialog logout confirmation

Uses react-native-reusables components for polished Android UI

* better code

* fix cubics comments

* refactor(android): revert delete confirmations to native Alert.alert()

- Logout: reverted to native Alert.alert() (simple yes/no)
- Event Types Delete: reverted to native Alert.alert() (simple yes/no)
- Availability Delete: reverted to native Alert.alert() (simple yes/no)

Keep AlertDialog only where user input is needed:
- Event Types Create (has TextInput for title)
- Availability Create (has TextInput for name)
- Bookings Cancel (has TextInput for cancellation reason)

* refactor(android): remove redundant index.android.tsx files

The main index.tsx files already handle Android via Platform.OS checks.
Android-specific behavior for actions is in the list item components:
- EventTypeListItem.android.tsx
- BookingListItem.android.tsx
- AvailabilityListItem.android.tsx

This consolidates the code and reduces duplication.

* corrected the implementation both native and alert dialog

* address cubics comments

* fix lint issue and address cubic comments
2026-01-02 19:05:26 -03:00
Manas Kenge c58e0ca783 fix: Custom time input for availability (#26373)
* add custom time input

* add unit test

* add validation logic
2026-01-02 18:06:01 +00:00
Alex van Andel 0099c72f53 chore: release v6.0.7
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2026-01-02 16:32:27 +00:00
Pedro Castro 421936dc14 fix(auth): resolve session user by token subject ID (#26399)
* fix(auth): align session user resolution with token subject

* test(auth): add unit tests for getServerSession user resolution
2026-01-02 16:31:08 +00:00
Ram Shukla 6a6b98388a matched colour of icons across website (#26394) 2026-01-02 14:52:14 +00:00
Anik Dhabal Babu e9fac51f99 feat(ci): skip API v2 breaking changes check when unrelated files change (#26393) 2026-01-02 10:47:12 -03:00
Volnei Munhoz a1e5384859 Prefix node protocol (#26391) 2026-01-02 12:47:00 +00:00
Volnei Munhoz fed6899c36 disable noExcessiveLinesPerFunction-off-for-tests for tests (#26388) 2026-01-02 10:56:24 +00:00
Manas Kenge 8bc710eb6e fix: make delete confirmation consistent across schedules (#26300)
* add delete dialog

* add types
2026-01-02 10:54:40 +00:00
Anik Dhabal Babu 9d5983d32d test: flaky e2e tests (#26386) 2026-01-02 07:08:11 -03:00
18b041514f refactor(ui): remove unused components and exports (#26222)
Co-authored-by: Volnei Munhoz <volnei@cal.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-02 04:11:14 +00:00
Keith Williams c7a80abcba chore: Make atoms cache-key more reusable (#26384) 2026-01-02 02:48:04 +00:00
Keith WilliamsandDevin AI 20c67ef101 fix: handle non-deterministic AES-256-CBC decryption in crypto test (#26383)
AES-256-CBC doesn't guarantee throwing on wrong key decryption - it depends
on whether the decrypted bytes happen to have valid PKCS#7 padding. The test
now verifies that decryption either throws OR returns a value different from
the original plaintext.

This fixes flaky test failures that started appearing after the Vitest 4.0
upgrade, where the 'Closing rpc while fetch was pending' error was a secondary
symptom of the test failure causing worker teardown during module loading.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 23:18:35 -03:00
Keith WilliamsandDevin AI 966d4b5cc6 fix: address flaky E2E tests (#26374)
* fix: address flaky E2E tests

- booking-pages.e2e.ts: Use selectFirstAvailableTimeSlotNextMonth helper instead of brittle nth(1) selector to avoid race condition where time slots become unavailable
- fixtures/users.ts: Add retryOnNetworkError helper to handle transient ECONNRESET errors during apiLogin
- lib/testUtils.ts: Add waitForLoadState('networkidle') to goToUrlWithErrorHandling to ensure page is fully loaded before checking URL
- teams.e2e.ts: Add explicit wait for publish button visibility before clicking to avoid timeout
- unpublished.e2e.ts: Change from parallel to serial mode to avoid database deadlocks from concurrent writes

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: consolidate unpublished.e2e.ts tests to reduce concurrent DB writes

Instead of using serial mode, consolidate related tests into single test
functions that share setup data. This reduces concurrent users.create()
and users.deleteAll() calls from 7 to 3, significantly reducing the
chance of database deadlocks while maintaining parallel execution.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: only fail goToUrlWithErrorHandling on main navigation requests

The previous fix was incorrectly resolving the promise when any request
failed (like images, RSC requests, etc.), causing the URL check to fail.

Now we only consider it a navigation failure if:
- request.isNavigationRequest() is true
- request.frame() === page.mainFrame()

Also added a resolved flag to prevent multiple resolutions and removed
the networkidle wait which was causing issues.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 23:17:01 -03:00
Keith WilliamsandDevin AI af110633c1 refactor: detach yarn prisma generate from yarn-install action (#26382)
* refactor: detach yarn prisma generate from yarn-install action

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add run-prisma-generate input for backward compatibility

The yarn-install action now has a run-prisma-generate input that defaults
to true for backward compatibility. This ensures CI works correctly since
workflow files are pulled from the base branch (main) while actions are
pulled from the PR branch.

Workflows that have explicit yarn prisma generate steps now set
run-prisma-generate: false to avoid running it twice after merge.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: completely remove prisma generate from yarn-install action

Remove all prisma-related code from the yarn-install action:
- Remove the run-prisma-generate input parameter
- Remove the Generate Prisma client step

Remove explicit yarn prisma generate steps from all workflow files.

Prisma generation is now handled by the postinstall script in package.json
which runs 'turbo run post-install' after yarn install. This triggers
@calcom/prisma#post-install which runs 'prisma generate && prisma format'.

This makes the yarn-install action have no knowledge of Prisma at all,
as requested.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add generic post-install step to ensure generated files are up-to-date

When all caches are hit, yarn install completes quickly without running
the postinstall script. This means generated files (like Prisma types)
may not be created.

Add a generic 'turbo run post-install' step that runs after yarn install
to ensure all post-install tasks complete regardless of cache state.
This keeps the action from having Prisma-specific knowledge while
ensuring the post-install pipeline runs.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: remove post-install step from yarn-install action

Remove the turbo run post-install step as requested. The yarn-install
action now only handles yarn install with caching, with no knowledge
of post-install tasks or Prisma generation.

Let CI show what fails without explicit post-install handling.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Add back Prisma schema loaded from schema.prisma

✔ Generated Prisma Client (6.16.1) to ./generated/prisma in 442ms

✔ Generated Zod Prisma Types to ./zod in 1.43s

✔ Generated Kysely types (2.2.0) to ./../kysely in 271ms

✔ Generated Prisma Enum Generator to ./enums/index.ts in 176ms where needed

* Adding Prisma schema loaded from schema.prisma

✔ Generated Prisma Client (6.16.1) to ./generated/prisma in 451ms

✔ Generated Zod Prisma Types to ./zod in 1.40s

✔ Generated Kysely types (2.2.0) to ./../kysely in 271ms

✔ Generated Prisma Enum Generator to ./enums/index.ts in 205ms where needed for E2E

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 23:00:56 -03:00
Beto 919827707f feat: add .easignore file to manage EAS build uploads for the companion app (#26375)
- Introduced a new .easignore file to specify which files and directories to ignore during EAS builds.
- Configured to only upload the companion app folder while excluding unnecessary build artifacts and dependencies.
2026-01-02 00:40:17 +00:00
Keith WilliamsandDevin AI b66797a3af fix: remove PR/commit-specific keys from docs-build cache (#26379)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-02 00:21:04 +00:00
Volnei Munhoz 94f18f6f9c chore: disable lint staged from merge main (#26380) 2026-01-01 21:13:12 -03:00
Keith WilliamsandDevin AI 64dcf5d3f6 fix: add cleanup and mock embed-iframe to prevent test teardown leak (#26377)
* fix: add cleanup and mock embed-iframe to prevent test teardown leak

The CancelBooking.cancellationFee.test.tsx was causing an unhandled jsdom
exception during test teardown due to the @calcom/embed-core/embed-iframe
module scheduling timers that would fire after the jsdom environment was
destroyed.

Changes:
- Mock @calcom/embed-core/embed-iframe to prevent sdkActionManager from
  scheduling timers during tests
- Add afterEach cleanup to ensure React Testing Library properly cleans up
  between tests
- Remove unused React import

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add afterAll cleanup to restore scrollIntoView and unmock embed-iframe

Add proper cleanup in afterAll to:
- Restore Element.prototype.scrollIntoView to its original value
- Call vi.unmock for embed-iframe to avoid polluting other tests in the same worker

This prevents cross-test pollution that was causing flaky 'Closing rpc while fetch was pending' errors in other test files running in the same Vitest worker.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add cleanup to TestFormDialog and defer imports in editLocation.handler tests

- TestFormDialog.test.tsx: Add fake timers and flush pending timers before cleanup
  to prevent Radix FocusScope setTimeout from firing after jsdom teardown
- editLocation.handler.test.ts: Remove top-level imports to prevent watchlist
  module loading during test collection (tests are already skipped)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: defer imports in confirm.handler.test.ts to prevent Salesforce GraphQL module loading

Tests are already skipped, so imports are not needed during collection phase.
This prevents 'Closing rpc while fetch was pending' errors from Salesforce GraphQL module imports.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-02 00:10:55 +00:00
Keith WilliamsandDevin AI 8ef7b56b37 feat: re-trigger pr.yml when ready-for-e2e label is added (#26376)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 20:42:12 -03:00
Pedro Castro 40dd546429 chore(deps): update dependencies and add version constraints (#26328)
* chore(deps): update dependencies and add version constraints

 - Update direct dependencies: body-parser, @nestjs/swagger, react-use, trigger.dev
 - Add resolutions for consistent dependency versions across the monorepo
 - Add packageExtensions to ensure compatible transitive dependency versions

* fix: upgrade rollup resolution from 3.29.5 to 4.22.4

 Rollup 3.x is incompatible with vite 5.x which requires rollup ^4.20.0.
 The previous resolution caused CI failures due to missing ./parseAst
 export

* fix: update axios resolution to 1.13.2

Align resolution with direct dependency in apps/api/v2.
Both versions include the fix, but 1.13.2 is newer and
avoids an unnecessary downgrade
2026-01-01 23:18:53 +00:00
Beto 6bdb08317d feat(companion): update app logo and splash screen (#26372)
* feat(companion): add ios logo

* update app.json to use new icon for iOS

* refactor: update app.json and icon.json for improved formatting and naming consistency

* feat: add expo-splash-screen plugin and update app.json configuration

* chore: update adaptive icon

* chore: update adaptive icon
2026-01-01 18:49:52 -03:00
Dhairyashil ShindeandVolnei Munhoz 6339f77efc feat(companion): booking actions ios ui update (#26307)
* feat(companion): add native iOS UI components for modals and pickers

- Add LogoutConfirmModal.ios.tsx using native Alert.alert()
- Add BookingModals.ios.tsx using native Alert.prompt() for reject modal
- Add RescheduleScreen.ios.tsx using @expo/ui/swift-ui DateTimePicker

These iOS-specific implementations provide native glass UI experience
instead of custom React Native modals.

* fix(companion): use correct DatePicker API from @expo/ui/swift-ui

- Change import from DateTimePicker to DatePicker
- Use onDateChange instead of onDateSelected
- Use displayedComponents as array instead of string
- Use selection instead of initialDate

* feat(companion): add native Android DateTimePicker for RescheduleScreen

- Use @expo/ui/jetpack-compose DateTimePicker for native Android date/time selection
- Use variant='picker' with showVariantToggle=false for consistent UI
- Use displayedComponents='date' for date picker and 'hourAndMinute' for time picker
- Use is24Hour=true for 24-hour time format

* Revert "feat(companion): add native Android DateTimePicker for RescheduleScreen"

This reverts commit 95677679c2e86889b935e658fac011ae9669fa10.

* adjust date and time picker for ios, and use native ios ui for delete event type

* feat(companion): add native Android DateTimePicker and web HTML inputs for RescheduleScreen

- Add RescheduleScreen.android.tsx using @react-native-community/datetimepicker for native Android date/time pickers
- Update RescheduleScreen.tsx to use native HTML date/time inputs on web/extension
- Install @react-native-community/datetimepicker package

* fix lint errors

* use expos date and time picker for android

* address cubics comments

* remove dependancy causing android build fail

* fix versions

* custom date and time picker for android

* fix react compiler memo issue

* address cubics commments

* feat(companion): convert booking action pages to native iOS bottom sheets (#26366)

* feat(companion): add native iOS bottom sheet for meeting session details

* move file to correct location, remove bg and use glass ui bg

* feat(companion): convert booking action pages to iOS bottom sheets

- Add iOS-specific bottom sheet implementations for:
  - edit-location (detents: 0.5, 0.7)
  - mark-no-show (detents: 0.4, 0.6)
  - view-recordings (detents: 0.7, 0.9)
  - add-guests (detents: 0.6, 0.8)
  - reschedule (detents: 0.8, 0.95)
- Move route files from (tabs)/(bookings)/ to root app/ level
- Register screens in root _layout.tsx with platform-specific options
- Update navigation paths from nested to root level
- Remove migrated screens from bookings _layout.tsx

* updated booking actions pages to use glass ui bottom sheet

* new ui for booking actions ready

* add biome file

* fix event type detail react compiler issue

* update button style

* fix black flash ui

* use glass ui buttons for Availability and event type detail page

* fix lint issue

* address cubics comments

* make booking actions ui transparent

* remove black flash and keep transparent ui

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-01 18:48:30 -03:00
bbf9274d37 chore: upgrade Vitest to 4.0.16 and Vite to 6.4.1 (#26351)
* chore: upgrade Vitest to 4.0.16 and Vite to 6.4.1

- Update vitest from 2.1.9 to 4.0.16
- Update @vitest/ui from 2.1.9 to 4.0.16
- Update vitest-fetch-mock from 0.3.0 to 0.4.5
- Update vitest-mock-extended from 2.0.2 to 3.1.0
- Update vite from 4.5.14/5.4.21 to 6.4.1 across all packages
- Update @vitejs/plugin-react to 5.1.2
- Update @vitejs/plugin-react-swc to 4.2.2
- Update @vitejs/plugin-basic-ssl to 2.1.0
- Update vite-plugin-dts to 4.5.4
- Rename vitest.config.ts to vitest.config.mts for ESM compatibility
- Add globals: true to vitest config

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

* fix: address Vitest 4.0 and Vite 6 breaking changes

- Convert arrow function mockImplementation patterns to regular functions
  (Vitest 4.0 breaking change: arrow functions can't be constructor mocks)
- Fix CSS imports with ?inline suffix for Vite 6 compatibility
- Add biome override to disable useArrowFunction rule for test files
- Fix syntax errors in test files introduced by regex replacements

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

* fix: fix remaining Vitest 4.0 constructor mock patterns

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

* fix: fix more Vitest 4.0 constructor mock patterns and exclude API v2 spec files

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

* fix: convert more arrow function mocks to regular functions for Vitest 4.0

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

* fix: convert more arrow function mocks to regular functions for Vitest 4.0

- Fix CrmService.integration.test.ts jsforce.Connection mock
- Fix RetellSDKClient.test.ts Retell mock
- Fix RetellAIService.test.ts CreditService mocks
- Fix GoogleCalendarSubscriptionAdapter.test.ts CalendarAuth mock

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

* fix: convert Google Calendar and OAuthManager arrow function mocks for Vitest 4.0

- Fix googleapis.ts Calendar, OAuth2Client, and JWT mocks
- Fix utils.ts JWT mock
- Fix OAuthManager.ts defaultMockOAuthManager mock

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

* fix: add React plugin, jsdom environment, and fix more constructor mocks for Vitest 4.0

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

* fix: convert HostRepository PrismaClient mock to regular function for Vitest 4.0

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

* fix: add useOrgBranding mock to React component tests for Vitest 4.0

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

* fix: update TestFunction type for Vitest 4.0 compatibility

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

* fix: convert listBookingReports constructor mocks to regular functions for Vitest 4.0

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

* fix: convert UserRepository constructor mock to regular function for Vitest 4.0

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

* fix: convert OrganizationPaymentService constructor mock to regular function for Vitest 4.0

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

* fix: convert more constructor mocks to regular functions for Vitest 4.0

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

* fix: add apps/web path aliases to vitest config

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

* fix: fix test issues for Vitest 4.0 compatibility

- Fix Response constructor 204 status code issue in testUtils.ts
- Fix FeaturesRepository mock persistence in handleNotificationWhenNoSlots.test.ts
- Add @vitest-environment node directive to formSubmissionUtils.test.ts
- Fix document.querySelector mock in embed.test.ts

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

* fix: clear EventManager spy between tests for Vitest 4.0 compatibility

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

* fix: update TeamRepository mock pattern for Vitest 4.0 compatibility

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

* fix: convert RoutingFormResponseRepository mock to regular function for Vitest 4.0

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

* fix: convert more constructor mocks to regular functions for Vitest 4.0

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

* fix: fix mock reset and spy clear issues for Vitest 4.0

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

* fix: fix remaining test failures for Vitest 4.0 upgrade

- Fix booking-validations.test.ts: convert UserRepository mock to regular function
- Fix route.test.ts: update 500 error test to mock ImageResponse instead of fetch
- Fix users-public-view.test.tsx: add missing mocks for getOrgFullOrigin and useRouterQuery
- Add @calcom/web path alias to vitest config

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

* fix: add vitest-mocks for generated files that don't exist in CI

- Add svg-hashes.json mock for route.test.ts
- Add tailwind.generated.css mock for embed.test.ts
- Update vitest config to use mock files

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

* fix: update vitest config aliases for CI compatibility

- Use array format for aliases to ensure proper ordering
- Add @calcom/platform-constants alias to resolve from source
- Add @calcom/embed-react alias to resolve from source
- Ensure svg-hashes.json mock alias is matched before @calcom/web

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

* fix: add @calcom/embed-snippet alias for CI compatibility

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

* Fix wrong test

* fix: migrate from CLI flags to VITEST_MODE env var for Vitest 4.0

Vitest 4.0 no longer allows custom CLI flags like --packaged-embed-tests-only.
This change migrates to using VITEST_MODE environment variable instead:
- VITEST_MODE=packaged-embed for packaged embed tests
- VITEST_MODE=integration for integration tests
- VITEST_MODE=timezone for timezone-dependent tests

Updated vitest.config.mts to handle mode-based include/exclude patterns.
Updated CI workflows and package scripts to use the new env var approach.

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

* fix: return default include pattern instead of undefined in vitest config

The getTestInclude() function was returning undefined for the default case,
but Vitest 4.0 expects an array. This caused 'resolved.include is not iterable'
error in CI.

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

* fix: always set INTEGRATION_TEST_MODE for jsdom environment

The getBookingFields.ts file checks for INTEGRATION_TEST_MODE to allow
server-side imports in the jsdom environment. Without this, tests fail
with 'getBookingFields must not be imported on the client side' error.

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

* fix: support legacy CLI flags for backwards compatibility with main workflow

The CI runs workflows from main branch, which uses the old CLI flag approach
(yarn test -- --integrationTestsOnly). This commit adds backwards compatibility
by checking both VITEST_MODE env var and process.argv for the legacy flags.

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 18:16:10 -03:00
Beto b8e9b9eb3f refactor(companion): remove react-native-context-menu-view dependency and enhance profile button with user avatar support (#26357)
- Removed `react-native-context-menu-view` from `package.json` and `bun.lock`.
- Updated profile button in `Availability`, `EventTypesIOS`, and `More` components to display user avatar if available, enhancing user experience.
- Cleaned up code formatting for better readability.
2026-01-02 01:48:34 +05:30
Mohit Balwani 02a86f1db0 fix: replace title with aria-label to avoid multiple tooltips (#26370) 2026-01-01 20:02:30 +00:00
Benny Joo d97a55ed6d chore: Bump biome rule level from warn to error for rules that prevent circular dependency between packages (#26364) 2026-01-01 16:48:16 +00:00
Keith WilliamsandDevin AI 50675593fa refactor: simplify api-v1-production-build cache key for durability (#26365)
* feat: add cache-api-v1-build-key action for durable caching

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: simplify cache key inline instead of separate action

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-01 14:22:03 +00:00
128d15ea8f fix: ensure proper async handling in delegation credentials (#25898)
* fix: ensure proper async handling in ensureDefaultCalendars

Replace forEach(async...) with Promise.allSettled to ensure:
- Caller properly awaits completion
- Errors are captured and logged
- All users are processed even if some fail

Adds unit tests for ensureDefaultCalendars

* fix: use correct Jest assertion pattern for async test

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 19:30:26 +00:00
Pedro CastroandKeith Williams b08997b553 fix: remove debug logs and clean up verbose logging (#25896)
- Remove debug console.log statements in calendar and video adapter services
- Clean up verbose request/response logging in OAuth controllers
- Remove leftover debug prefixes

Ensure only necessary data is captured in observability systems

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-31 19:12:28 +00:00
Keith WilliamsandDevin AI 486817a688 fix: add timeout: 0 to E2E assertions that check for absence of elements (#26353)
This fixes hanging E2E tests where assertions like toHaveCount(0) and
not.toBeVisible() would wait for the full timeout (10s in CI, 120s locally)
before failing, instead of failing immediately.

These assertions are 'state check' assertions that verify an element is
already absent or hidden, rather than waiting for it to become so.
Adding { timeout: 0 } makes them fail immediately if the condition is not met.

Files updated:
- locale.e2e.ts: 16 instances of toHaveCount(0)
- booking-seats.e2e.ts: 8 instances of toHaveCount(0)
- organization-redirection.e2e.ts: 3 instances of toHaveCount(0)
- organization-creation-flows.e2e.ts: 5 instances of not.toBeVisible()
- insights-charts.e2e.ts: 1 instance of toHaveCount(0)
- bookings-list.e2e.ts: 1 instance of toHaveCount(0)
- availability.e2e.ts: 1 instance of toHaveCount(0)
- managed-event-types.e2e.ts: 1 instance of toHaveCount(0)
- team-invitation.e2e.ts: 1 instance of toHaveCount(0)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 14:58:20 -03:00
BetoandVolnei Munhoz 4563194fcf feat(companion): update deps to sdk 55 canary (#26348)
* update deps

* chore: remove companion biome configuration and update main biome.json ignore patterns

* chore: update expo and react dependencies in bun.lock

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2025-12-31 16:38:15 +00:00
Keith WilliamsandDevin AI c959fffb12 fix: reduce default Playwright test timeout from 60s to 30s in CI (#26345)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 13:33:13 -03:00
Volnei Munhoz ed14219e44 upgrade typescript (#26347) 2025-12-31 13:32:55 -03:00
Keith WilliamsandDevin AI 59ba1754fe fix: use stable test dates in duplicate API calls E2E tests (#26349)
The tests were failing on December 31 because they used new Date() which
caused month boundary issues with the prefetch logic. This change uses
a fixed future date (July 2030) to ensure consistent test behavior
regardless of when the tests are run.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 13:05:11 -03:00
Keith WilliamsandDevin AI 16f6099e46 ci: simplify DB cache key and skip yarn-install on cache hit (#26344)
* ci: skip yarn-install in setup-db when DB cache exists

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: skip entire setup-db job when DB cache exists

This saves ~35-40s per workflow run by:
1. Adding DB cache lookup to prepare job (lookup-only mode)
2. Skipping the entire setup-db job when cache exists (avoids postgres container startup)
3. Keeping the yarn-install skip in setup-db.yml as a fallback

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: simplify DB cache key and skip yarn-install on cache hit

- Remove commit SHA and PR number from cache key for better reuse
- Cache key now only depends on prisma schema/migrations hash
- Skip yarn-install in setup-db when DB cache exists (saves ~17s)
- Revert changes to pr.yml required job logic

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: move DB cache lookup to prepare step and skip cache-db on hit

- Move cache lookup to pr.yml prepare step for early detection
- Pass db-cache-hit output to setup-db.yml as input
- Skip yarn-install and cache-db action when cache exists
- setup-db job still runs and reports success (no required job changes)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: skip container initialization when DB cache exists

- Rename setup-db to setup-db-seed (only runs on cache miss)
- Add lightweight setup-db wrapper job that always returns success
- When cache exists: setup-db-seed is skipped, setup-db returns success
- When cache miss: setup-db-seed runs with postgres, setup-db checks result
- This avoids postgres container startup (~17-20s) when cache exists

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: add cache-db-key action for consistent cache key generation

- Create cache-db-key action to generate DB cache key in one place
- Update cache-db action to use cache-db-key for consistency
- Update pr.yml prepare step to use cache-db-key for lookup
- This ensures the lookup key always matches the actual cache key

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: remove runner.os from cache-db-key

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: simplify setup-db by removing wrapper job

- Remove setup-db wrapper job and rename setup-db-seed back to setup-db
- setup-db is now skipped when cache exists (no container startup)
- Update required check to allow skipped for setup-db when cache hit

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: revert to two-job pattern for setup-db

- setup-db-seed: only runs on cache miss (has postgres container)
- setup-db: wrapper that always runs and reports success
- This ensures downstream jobs (Tests, Production builds) are not skipped
- Reverts required check to simple setup-db.result != 'success'

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: single setup-db job with conditional steps on cache hit

- Removed two-job pattern (setup-db-seed + wrapper)
- Single setup-db job calls setup-db.yml reusable workflow
- Pass DB_CACHE_HIT input from prepare job's db-cache-hit output
- Skip yarn-install and cache-db steps when cache hit (~17s savings)
- Container still starts (will optimize in follow-up)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 19:47:31 +05:30
Tamal ChakrabortyandAnik Dhabal Babu 6451b7e013 fix: removed weird scrollbar from apps/intalled/ navigation (#26336)
* fix: removed weird scrollbar from apps/intalled navigation

* revert accidental changes to ./yarn.lock

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-31 13:57:39 +00:00
3704324474 feat: update translations via @LingoDotDev (#26340)
Co-authored-by: Lingo.dev <support@lingo.dev>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-31 13:31:47 +00:00
17224d9df3 ci: reduce e2e-api-v2 test overhead with caching and Jest optimizations (#26331)
* perf: increase E2E test shards from 4 to 6 for faster CI

Increase the number of parallel E2E test shards from 4 to 6 to reduce
overall CI wall-clock time. Each shard runs on a separate 4-vCPU runner
with 4 workers, so adding more shards increases total parallelism.

This should reduce E2E test time from ~3 minutes per shard to ~2 minutes
per shard by distributing tests across more parallel jobs.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* update

* fix

* update

* readd

* final update

* fix flake

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 10:19:09 -03:00
Keith WilliamsandDevin AI c47c6f2909 perf: optimize postgres health check in all CI workflows (#26343)
* perf: optimize postgres health check in e2e workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* perf: optimize postgres health check in all e2e workflows

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-31 09:54:56 -03:00
Keith Williams 38890de7f1 chore: Use 8 shards for main E2E tests (#26342)
* chore: Use 6 shards for main E2E tests

* Update .github/workflows/e2e.yml
2025-12-31 09:44:52 -03:00
Kartik LabhshetwarandDhairyashil Shinde fdb4cc5f70 fix: replace scroll-bar with no-scrollbar in AvailableTimeSlots component (#26339)
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-31 10:25:37 +00:00
spandev 11150309d4 fix: added message in schedule bulk update (#26334) 2025-12-31 10:02:40 +00:00
Tamal Chakraborty 582e547bea Fix: Changed Delete My Account button from primary to Destructive (#26326) 2025-12-31 04:02:27 +00:00
Anik Dhabal Babu fee19654b0 fix: meetin url (#26321) 2025-12-31 03:53:38 +00:00
Pedro Castro 4226dfb05f fix(ci): improve security for external contributions (#26327)
- Remove pull_request_review trigger
- Add trust-check job to validate PR authors before running CI
- Create run-ci.yml workflow for maintainer approval via label
- Use workflow run timestamp to prevent backdating attacks
- Add per_page and in-progress checks for robustness
2025-12-31 00:16:52 -03:00
Volnei Munhoz 8bed6b0899 Spread biome errors (#26329) 2025-12-30 23:38:43 +00:00
Keith WilliamsandDevin AI b4790dd2aa refactor: move deps job to prepare job step to save ~20s per workflow (#26320)
* refactor: move deps job to prepare job step to save ~10s per workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: remove unused yarn-install.yml workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-30 14:44:23 -03:00
Anik Dhabal Babu 77ff8607d1 test: flaky unit test (#26310)
* fix: wip

* test

* Change pull_request to pull_request_target in workflow

* test

* update

* fix unit test flakes

* Update cache path to exclude node_modules

Remove node_modules from cache path in action.yml
2025-12-30 14:20:29 -03:00
Keith WilliamsandDevin AI bc6ff386a4 refactor: move eventTypeSlug and eventTypeLocations to @calcom/lib/zod (#26115)
* refactor: move eventTypeSlug and eventTypeLocations to @calcom/lib/zod

Move shared Zod schemas from @calcom/prisma/zod-utils to @calcom/lib/zod
to avoid prisma imports in non-repository code.

Changes:
- Create packages/lib/zod/eventType.ts with eventTypeSlug, eventTypeLocations,
  and EventTypeLocation type
- Re-export from @calcom/prisma/zod-utils for backwards compatibility
- Update packages/features/eventtypes/lib/schemas.ts to import from @calcom/lib/zod
- Remove unused slugify function from zod-utils.ts

This allows files like schemas.ts to avoid importing from @calcom/prisma,
which helps maintain the architectural boundary that prisma should only
be imported in repository code.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: remove barrel file and use explicit imports

Address PR feedback:
- Delete packages/lib/zod/index.ts barrel file
- Update imports to use explicit path @calcom/lib/zod/eventType
- Simplify EventTypeLocation type to use z.infer

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: use explicit type definition with z.ZodType for eventTypeLocations

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-30 13:03:10 -03:00
319d9858d4 fix: improve Insights empty state responsive design at 320px (#26203)
* fix: improve Insights empty state responsive design at 320px

* Update apps/web/modules/shell/UpgradeTip.tsx

Co-authored-by: Keith Williams <keithwillcode@gmail.com>

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-30 12:37:46 -03:00
Keith WilliamsandDevin AI 1dbbc934cc chore: use lookup-only cache check to skip deps job downloads (#26314)
* fix(ci): skip yarn install in deps job when cache is hit

The Install Dependencies / Yarn install & cache step in pr.yml is primarily
for populating the cache when nothing is cached. When cache keys are found,
we can skip the actual yarn install and let the workflow carry on quickly.

This adds a skip-install-if-cache-hit parameter to the yarn-install action
that allows skipping the install when node_modules cache is hit. This is
enabled for the deps job in yarn-install.yml but not for other jobs that
actually need node_modules for their work.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix(ci): also skip playwright install in deps job when cache is hit

Extends the skip-install-if-cache-hit parameter to the yarn-playwright-install
action as well, so both yarn install and playwright install are skipped in the
deps job when their respective caches are hit.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix(ci): use lookup-only cache check to avoid downloading 1.2GB

When skip-install-if-cache-hit is true, use actions/cache/restore@v4 with
lookup-only: true to check if caches exist without downloading them. This
avoids downloading ~1.2GB of cache data when we just want to verify caches
exist in the deps job.

The flow is now:
1. If skip-install-if-cache-hit is true, run lookup-only checks for all caches
2. If all caches hit, skip the entire restore + install flow (no downloads)
3. If any cache misses, fall back to normal restore + install + save behavior

This optimization only applies when skip-install-if-cache-hit is set to true,
so other jobs that need node_modules continue to work normally.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Apply suggestion from @keithwillcode

* Apply suggestion from @keithwillcode

* Apply suggestion from @keithwillcode

* Apply suggestion from @keithwillcode

* fix(ci): address @cubic-dev-ai feedback on cache conditions

1. yarn-install: Add 'all-caches-check' step to compute whether all three
   caches hit (not just node_modules). This ensures we only bail out when
   everything is cached, matching the PR description.

2. yarn-playwright-install: Fix backward compatibility for install step.
   In default mode, check playwright-cache.outputs.cache-hit (the restore step).
   In skip mode, check playwright-cache-check.outputs.cache-hit (lookup-only).

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-30 12:29:33 -03:00
cal-com-ci[bot]andLingo.dev 3410ae6795 feat: update translations via @LingoDotDev (#26315)
Co-authored-by: Lingo.dev <support@lingo.dev>
2025-12-30 15:28:55 +00:00
cal-com-ci[bot]andLingo.dev d3e5cfb311 feat: update translations via @LingoDotDev (#26313)
Co-authored-by: Lingo.dev <support@lingo.dev>
2025-12-30 14:29:47 +00:00
Keith WilliamsandDevin AI 7985732683 chore: Delete cache-build cache entries on PR close (#26312)
* chore: Delete cache-build cache entries on PR close

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: Extract cache-build key generation into reusable action

- Create .github/actions/cache-build-key to generate cache keys
- Update cache-build action to use the shared key action
- Update delete workflow to use the shared key action
- Checkout PR head SHA in delete workflow for correct hash computation

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: Remove PR head SHA checkout per review feedback

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: Use prefix-based cache deletion for simpler cleanup

- Use useblacksmith/cache-delete prefix mode to delete all caches matching branch
- Remove dependency on cache-build-key action for deletion
- No checkout needed since we're just using the branch name as prefix

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: Simplify cache key by removing Linux and node version segments

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-30 11:24:33 -03:00
2b61bddf7b feat: add completed onboarding column to organization members table (#25582)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
2025-12-30 10:57:49 -03:00
Anik Dhabal BabuandKeith Williams cc8da034c0 test: flaky e2e tests (#26308)
* fix another

* fix flakes

* Update apps/web/playwright/fixtures/apps.ts

Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* fix

* fix

* test fix

* fix test

* tweak

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-30 13:45:01 +00:00
Udit TakkarandSyed Ali Shahbaz 2c7cb530a1 fix: add eventTypeId and eventTypeSlug guard (#25773)
* fix: add eventTypeId and eventTypeSlug guard

* chore: update test

* refactor: improvemnt

* revert:

---------

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
2025-12-30 10:33:38 -03:00
Volnei Munhoz c52eff65a2 chore: fix biome warnings/errors (#26295)
* Fix icon-names

* make all errors into warns

* Minimal fix to mock
2025-12-30 11:46:26 +00:00
Keith WilliamsandDevin AI e4753778fe fix(ci): use getCollaboratorPermissionLevel for trust check (#26306)
* fix(ci): use GitHub App token for team membership check

The default GITHUB_TOKEN doesn't have org-level permissions to query
team membership via the teams.getMembershipForUserInOrg API. This causes
the API to return 404 even for valid team members, making the trust check
incorrectly fail for core team members.

This change generates a short-lived GitHub App token with org-level access
to properly verify team membership.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix(ci): use getCollaboratorPermissionLevel for trust check

Replace the team membership check (teams.getMembershipForUserInOrg) with
getCollaboratorPermissionLevel which works with the default GITHUB_TOKEN.

This approach:
- Checks if users have write/maintain/admin access to the repo
- Works without requiring a GitHub App token with org-level permissions
- Is semantically correct: if someone can push to the repo, they're trusted

The previous approach using teams.getMembershipForUserInOrg required
org-level permissions that the default GITHUB_TOKEN doesn't have,
causing 404 errors even for valid team members.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Apply suggestion from @keithwillcode

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-30 08:04:09 -03:00
Pedro Castro ae14e10b24 fix(ci): verify org membership when author_association fails (#26296)
* fix(ci): verify org membership via API when author_association fails

* refactor: use core team membership check instead of
    org membership
2025-12-30 10:23:02 +00:00
Manas Kenge 7c1a3b0c15 fix dialog (#26298) 2025-12-30 07:49:46 +00:00
Peer RichelsenandDevin AI ec90c1ae24 fix: display full URLs in workflow links (#26292)
- Exclude 'link' toolbar item from Editor for all workflow actions (not just SMS)
- Add replaceCloakedLinksInHtml utility to sanitize HTML and replace cloaked links with visible URLs
- Apply sanitization to email content before sending in all workflow email paths

This ensures recipients can see the actual destination of URLs, helping them identify potentially malicious links.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-30 01:53:04 -03:00
ccc8c2b566 fix: add security gate for external contributor PRs (#26293)
This change adds a trust-check job that gates CI for external contributors:

- Trusted contributors (OWNER, MEMBER, COLLABORATOR) can run CI immediately
- External contributors require approval from a core team member (write access or higher)
- Approval must be for the current commit SHA (stale approvals are ignored)
- Added pull_request_review trigger so CI runs when approval is given
- The required job now fails with a clear message for untrusted PRs

Co-authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
Co-authored-by: Pedro Castro <pedro@cal.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-29 22:31:11 -03:00
e4b0a1b941 chore: restore production build cache with stable key using actions/cache (#26276)
* fix: align env vars between Production Builds and E2E workflows for turbo cache sharing

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: move E2E-specific env vars to step-level for turbo cache alignment

Instead of adding env vars to production-build-without-database.yml (which
caused DB calls during build), move the E2E-specific env vars from workflow-level
to step-level in e2e.yml. This ensures the cache-build step has the same env
context in both workflows, enabling turbo remote cache sharing.

Env vars moved to step-level:
- DATABASE_DIRECT_URL (to cache-db and Run Tests steps)
- E2E_TEST_MAILHOG_ENABLED (to Run Tests step)
- EMAIL_SERVER_* (to Run Tests step)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: restore production build cache with stable key using actions/cache

- Restore artifact caching for .next, dist, and .turbo directories
- Use actions/cache@v4 (accelerated by Blacksmith on their runners)
- Design stable cache key scoped to branch:
  - Includes branch name (head_ref for PRs, ref_name for pushes)
  - Hashes yarn.lock for dependency changes
  - Hashes source files in apps/web and packages/*/src
  - Excludes generated directories (prisma/zod, kysely) that caused instability
- Add restore-keys for partial cache hits
- Only run yarn build on cache miss
- Revert e2e.yml env var changes (no longer needed with artifact caching)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: simplify restore-keys to single fallback

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove restore-keys entirely for exact cache matching only

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use broader package pattern with exclusions for generated prisma files

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add exclusions for prisma/generated and prisma/client directories

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Apply suggestion from @cubic-dev-ai[bot]

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

* fix: add .json and .css patterns to cache hash for config and style changes

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: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2025-12-29 21:59:00 -03:00
spandev 23c4e7edef fix: no result for oo headline (#26289) 2025-12-30 00:51:28 +00:00
Benny JooandDevin AI 00e5770273 refactor: Move attribute and routing-forms code from app-store/lib to features (#26025)
* mv

* wip

* wip

* wip

* wip

* plural

* fix: resolve TypeScript type errors for attribute refactoring

- Add TransformedAttributeOption type to handle transformed contains field
- Update imports to use routing-forms Attribute type where needed
- Fix getValueOfAttributeOption to use TransformedAttributeOption type
- Update AttributeOptionValueWithType to use TransformedAttributeOption
- Fix pre-existing lint warnings (any -> unknown, proper type casting)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* cleanup

* cleanup

* fix

* fix

* fix

* fix

* fix

* fix: add explicit type annotation to reduce callback in getAttributes.ts

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: use RouterOutputs from @calcom/trpc/react for consistent type inference

- Update AppPage.tsx to use RouterOutputs from @calcom/trpc/react instead of inferRouterOutputs<AppRouter>
- Update MultiDisconnectIntegration.tsx to use the same RouterOutputs type source
- Add eslint-disable comments for pre-existing warnings (useEffect deps, img elements)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: explicitly type attribute property in AttributeOptionAssignment

The attribute property from Pick<AttributeOption, 'attribute'> was typed as
'unknown' because Prisma relations don't have explicit types when picked.
This explicitly defines the attribute shape with id, type, and isLocked
properties that are used in assignValueToUser.ts.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: remove unused assignedUsers from AttributeOptionAssignment Pick

The assignedUsers property was not being used in the code but was required
by the Pick type, causing a type mismatch when the actual data from the
database query didn't include it.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update import path for AttributeOptionAssignment and BulkAttributeAssigner types

The types.d.ts file was moved from packages/lib/service/attribute/ to
packages/app-store/routing-forms/types/. Updated the import path in utils.ts
to point to the new location.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 21:51:06 -03:00
Anik Dhabal Babu 5f0e408d2f fix: hide expected webServer errors in E2E tests to reduce noise (#26251)
* fix: e2e failure in CI

* fix
2025-12-29 21:47:02 -03:00
Anik Dhabal Babu ff9d88479c test: few more e2e flakes (#26278)
* test: few more e2e flakes

* fix another
2025-12-29 19:58:15 -03:00
7c373ddad6 feat: Introduce biome (#25664)
* Configure biome

* Fix companion build

* fix: remove generated files from formatter ignore list to enable proper formatting

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

* fix: add explicit stripe dependency to @calcom/features to fix type resolution

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

* fix: rename const require to nodeRequire in generate-swagger.ts to avoid TypeScript reserved identifier conflict

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

* fix: add guard for document in makeBodyVisible to prevent test environment teardown errors

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

* fix: replace ESLint with Biome CLI in embed-code-generator.e2e.ts

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

* fix: address cubic review comments

- Fix invalid --reporter-path Biome CLI option by using shell redirection
- Fix packages/lib lint report filename (app-store.json -> lib.json)
- Add typescript-eslint and eslint back to companion for lint:react-compiler
- Add missing restricted import rules to biome.json:
  - packages/lib: add ../trpc/** and @trpc/server restrictions
  - packages/trpc: add ../apps/web/** restriction

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

* chore: regenerate companion bun.lock after adding eslint dependencies

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

* Remove remaining eslint things

* add tailwind directives

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 19:41:41 -03:00
Anik Dhabal BabuandDevin AI 96dc3b5cc6 fix: improve test isolation for managed event type e2e tests (#26283)
- Move managedEventTypeSlug generation inside beforeAll to ensure uniqueness across test runs
- Add deleteAllTeamEventTypes method to EventTypesRepositoryFixture
- Explicitly delete all team event types in afterAll before deleting teams

This fixes flaky tests in organizations-member-team-admin-event-types.e2e-spec.ts
where the managed event type creation was intermittently failing with 400 Bad Request.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 16:12:01 -03:00
Keith WilliamsandDevin AI ed53b4dbe3 chore: reduce release-docker workflow permissions to minimum required (#26277)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 16:20:08 +00:00
Kartik Labhshetwar aae93cd268 fix: add destructive color and rounded-t-none to user dropdown button (#26275) 2025-12-29 16:03:54 +00:00
Kartik Labhshetwar 07108c4139 fix: update NewApiKeyButton with size and variant props (#26272) 2025-12-29 15:36:56 +00:00
Keith Williams 7dd9e7f23a chore: Give Unit Tests job more vCPUs (#26273) 2025-12-29 15:20:21 +00:00
Keith WilliamsandDevin AI c36165bcfd fix: remove nested turbo run for copy-app-store-static to fix remote caching (#26270)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 15:04:11 +00:00
Keith Williams 108e7381d0 perf: Use Blacksmith Docker caching (#26252) 2025-12-29 11:40:58 -03:00
Anik Dhabal Babu 25345aba3c test: falky e2e tests (#26269) 2025-12-29 14:27:21 +00:00
Adarsh Tiwari 7eef3d33c5 responsive button (#26259) 2025-12-29 11:12:51 -03:00
Keith WilliamsandDevin AI e94ea4d4b8 fix: exclude .next/node_modules from yarn cache to prevent corruption (#26268)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 11:10:00 -03:00
Dhairyashil Shinde b8e34bdc06 feat(companion): new booking details page and long press feature for ios (#26264)
* longpress ios - event type, booking, availability

* new booking details page for ios

* remove comments

* address cubics comments

* use lowercase type same as api v2
2025-12-29 18:57:48 +05:30
Keith WilliamsandDevin AI 3f003bafe5 feat: add PUSH_IMAGE input for docker builds (#26254)
* feat: add PUSH_IMAGE boolean input to release-docker workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: simplify push-image expression to always return string

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: make RELEASE_TAG input work for manual workflow triggers

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add postMessage listener to capture __iframeReady events early

This fixes a race condition in the embed E2E tests where the __iframeReady
event could fire before the Cal.ns[namespace] API was ready to receive it.

The fix adds a window.message listener immediately in the addInitScript that
captures __iframeReady events directly from postMessage, which doesn't depend
on the namespace API being ready. This ensures window.iframeReady is set
even if the event fires before the Cal API listener is attached.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Revert "fix: add postMessage listener to capture __iframeReady events early"

This reverts commit fdd02fcf1e5286f2b3b36a9f4c9889b269720845.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 10:25:33 -03:00
Keith Williams e38ef5edef chore: Reduce actions cost (#26260) 2025-12-29 13:20:01 +00:00
Keith WilliamsandDevin AI 4226d2262d fix: add postMessage listener to capture __iframeReady events early (#26258)
This fixes a race condition in the embed E2E tests where the __iframeReady
event could fire before the Cal.ns[namespace] API was ready to receive it.

The fix adds a window.message listener immediately in the addInitScript that
captures __iframeReady events directly from postMessage, which doesn't depend
on the namespace API being ready. This ensures window.iframeReady is set
even if the event fires before the Cal API listener is attached.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 18:35:50 +05:30
Volnei Munhoz 00c7415e28 chore: companion package versions fixed (#26261)
* companion versions fixed

* lock it right way

* Fix bun.lock
2025-12-29 09:07:24 -03:00
Keith WilliamsandDevin AI 4128a9b4fb refactor: use explicit type annotations for TUpdateInputSchema to reduce type inference complexity (#26133)
* refactor: use explicit type annotations for TUpdateInputSchema to reduce type inference complexity

This change significantly reduces TypeScript type-checking time by:
1. Defining explicit TypeScript types instead of using z.infer<> on complex schema chains
2. Using z.ZodType<T> annotations on schemas to prevent TypeScript from inferring through .extend(), .partial(), .merge() chains
3. Removing the dependency on EventTypeSchema from @calcom/prisma/zod/modelSchema which pulls in many dependencies

The schema still validates all fields at runtime - only the compile-time type inference is optimized.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: update BookingFieldInput and users types to fix type errors

- BookingFieldInput now includes name, hidden, required properties with index signature
- users type changed from (string | number)[] to number[]
- Zod schema updated to use z.array(z.number()) for users field
- Removed unused stringOrNumber import

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: handle bookingFields null case with Prisma.DbNull for JSON field compatibility

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove index signature from BookingFieldInput for API v2 DTO compatibility

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: remove useless JSDoc comments per PR feedback

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* test: add unit tests for aiPhoneCallConfig transformation in ZUpdateInputSchema

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* test: add unit tests for bookingFields null to Prisma.DbNull transformation

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: remove comments from update.handler.test.ts

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: scope test describe block to update.handler per PR feedback

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 07:40:49 -03:00
Keith WilliamsandDevin AI 55805f081d fix: add artifact handling for API v2 E2E tests (#26249)
* fix: add artifact handling for API v2 E2E tests

- Add jest-junit reporter to generate JUnit XML test results
- Update workflow to upload from correct path (apps/api/v2/test-results)
- Add if-no-files-found: ignore and retention-days: 30 for consistency

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Apply suggestion from @keithwillcode

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 02:22:38 -03:00
Keith WilliamsandDevin AI 2a6a8e635c chore: migrate GitHub workflows from Buildjet to Blacksmith (#26247)
* chore: migrate GitHub workflows from Buildjet to Blacksmith

- Replace buildjet-*vcpu-ubuntu-2204 runners with blacksmith-*vcpu-ubuntu-2204
- Replace buildjet/cache@v4 with actions/cache@v4
- Replace buildjet/setup-node@v4 with actions/setup-node@v4
- Replace buildjet/cache-delete@v1 with useblacksmith/cache-delete@v1
- Rename delete-buildjet-cache.yml to delete-blacksmith-cache.yml

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: bump Blacksmith runners to Ubuntu 24.04

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Reduce 16vcpu to 4vcpu for the API v2 E2E

* Remove 8vcpu usage

* chore: switch Blacksmith runners to ARM architecture

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: switch Blacksmith runners back to AMD (remove -arm suffix)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: improve test cleanup to cover all bookings including reassignment-created ones

- Changed afterEach cleanup to find all bookings by eventTypeId instead of tracking bookingIds
- This ensures bookings created indirectly by managedEventManualReassignment are also cleaned up
- Removed problematic prefix-based deleteMany calls that could affect parallel tests
- Fixes idempotencyKey collision errors on high-parallelism CI runners

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: improve icons screenshot test stability with deviceScaleFactor and increased threshold

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: cap Playwright workers to 4 to match vCPU allocation on Blacksmith runners

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-29 05:12:31 +00:00
Keith Williams b6e0182002 chore: Fix peer dependencies in yarn.lock (#26250) 2025-12-29 05:05:34 +00:00
spandev b372477aa0 fix: save button in availibility disabled when no changes (#26174)
* fix: save button in availibility disabled when no changes

* fix: updated comparison logic

* fix: changed logic from and to or
2025-12-29 04:15:51 +00:00
Eesh Midha 77f99b636c fix: add proper disabled-state styling to Select component (#25697)
* fix: add proper disabled-state styling to Select component using state.isDisabled

* chore: apply hover:border-subtle since disabled items are not clickable and only hover state should change the border
2025-12-29 01:07:01 -03:00
Keith Williams 716e66b0c3 chore: Use relative imports for @calcom/prisma inside of @calcom/prisma (#26245)
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Switch @calcom/prisma to use relative imports for client and enums. This removes self-references, stabilizes builds, and improves type resolution.

- **Refactors**
  - Replaced imports from "@calcom/prisma/*" with local "./client" and "./enums" across extensions, selects, mocks, and availability check.
  - Updated safeJSONStringify parameter type from any to unknown.
  - Minor formatting cleanup in zod-utils.

<sup>Written for commit 85c0a7b75fb1291be5b848a73d1ccb5543283f49. Summary will update automatically on new commits.</sup>

<!-- End of auto-generated description by cubic. -->
2025-12-29 00:52:12 -03:00
Keith Williams 83dcb71947 perf: Improve apps/web tsconfig.json (#26246) 2025-12-29 00:31:25 -03:00
Pedro CastroandKeith Williams 5fe54fd3f2 fix(schedules): add missing await on async permission check (#26218)
The hasReadPermissionsForUserId function is async but was being
   called without await in two locations.

   This aligns with the existing correct usage in
   ScheduleRepository.findManyDetailedScheduleByUserId

   - Add await to getAllSchedulesByUserId.handler.ts
   - Add await to ScheduleRepository.findDetailedScheduleById
   - Refactor ScheduleRepository tests to use shared prismaMock
   - Add new handler test with authorization coverage

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-28 23:47:08 -03:00
cal-com-ci[bot]andLingo.dev 1c6f5d9ec0 feat: update translations via @LingoDotDev (#26219)
Co-authored-by: Lingo.dev <support@lingo.dev>
2025-12-29 02:18:32 +00:00
309340d3f3 fix: add missing peer dependencies and fix inconsistent peer dependency declarations (#26244)
* fix: add missing peer dependencies and fix inconsistent peer dependency declarations

- @calcom/ui: Move react from dependencies to peerDependencies (was inconsistent with react-dom being a peer)
- @calcom/emails: Move react and react-dom to peerDependencies
- @coss/ui: Add react and react-dom as peerDependencies (uses lucide-react and @base-ui/react)
- @calcom/app-store: Add react, react-dom, zod as peerDependencies (depends on @calcom/features which has these peers)
- @calcom/platform-libraries: Add react, react-dom, stripe, zod as peerDependencies (depends on @calcom/features)
- @calcom/features: Add next as peerDependency (depends on @calcom/trpc which has next as peer), update react/react-dom to flexible version ranges
- @calcom/features/ee: Add react, react-dom, react-hook-form as peerDependencies (uses @calcom/ui and @hookform packages)

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

* fix: add more peer dependencies for PnP compatibility

Additional changes:
- @calcom/app-store: Move stripe from dependencies to peerDependencies
- @calcom/ui: Move @tanstack/react-query to peerDependencies (singleton pattern)
- @calcom/trpc: Move @tanstack/react-query to peerDependencies (singleton pattern)
- @calcom/atoms: Move @tanstack/react-query to peerDependencies (singleton pattern)
- @calcom/stripepayment: Add react, react-dom, stripe as peerDependencies
- @calcom/caldavcalendar: Add react, react-dom, react-hook-form as peerDependencies
- @calcom/exchange2013calendar: Add react, react-dom, react-hook-form as peerDependencies
- @calcom/exchange2016calendar: Add react, react-dom, react-hook-form as peerDependencies
- @calcom/ics-feed: Add react, react-dom, react-hook-form as peerDependencies

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

* fix: revert dependency moves for packages with own builds

Packages with their own build step should not have dependencies
moved to peerDependencies as they need those deps at build time.

Reverted:
- @calcom/trpc: Keep @tanstack/react-query out of peerDependencies
- @calcom/atoms: Restore @tanstack/react-query to dependencies
- @calcom/stripepayment: Restore stripe to dependencies

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-28 21:29:44 -03:00
Dhairyashil Shinde 49ae10149f feat(companion): iOS native UI components and simplified event type creation (#26240)
ios:


https://github.com/user-attachments/assets/efdfd3e3-239f-4cbf-be1a-7784d1df1851


android:



https://github.com/user-attachments/assets/a8e22a5c-60f3-4fb6-8923-b8a786bceb0c




## Overview

This PR introduces native iOS UI components, refactors the profile menu, and simplifies the event type creation flow for a more native iOS experience.

## Key Changes

### iOS Native UI Components
- **iOS-specific Event Types Page**: Added native Stack.Header, glass UI, and context menus for iOS
- **Platform-specific Profile Sheet**: Created separate implementations for iOS (formSheet) and Android/Web (modal)
- **Bottom Glass UI Navbar**: Updated bottom navigation bar with glass UI styling for iOS
- **Native iOS Alerts**: Replaced custom modals with native `Alert.prompt` for event types and availability pages

### Profile Menu Refactor
- Restructured More page with folder layout and native iOS header support
- Added profile button to More page header on iOS with glass UI
- Added "Copy public page link" and "Roadmap" options to profile sheet
- Refactored Header component: removed inline profile modal, now uses route-based navigation
- Updated Availability page with New menu and profile button in header
- Fixed "My Settings" URL to use `/general` endpoint
- Removed "Profile" item from More section menu
- Updated tab layout to support `(more)` folder structure

### Simplified Event Type Creation
- Reduced event type creation to only require title input
- Auto-generate slug from title using slugify utility
- Set default duration to 15 minutes
- Leave description empty (users can edit later)
- Applied to both iOS and Android/Web platforms

### UI Improvements
- Updated login button styling: changed background color to pure black (#000000) with white text for better contrast
2025-12-28 18:48:48 -03:00
Tamal Chakraborty 3fc847c9f7 fix insight routing ui mergin bug (#26237) 2025-12-28 20:34:44 +00:00
Tamal Chakraborty 0be0928e66 add ui fix for availability page (#26235) 2025-12-28 20:32:28 +00:00
Dhairyashil Shinde 9203cb262c feat(companion): component improvements, migrate to path aliases, expo-haptics, expo-image (#26226)
* react compiler

* remove compilation mode 'all', it will use infer by default

* feat(companion): add theme tokens, path aliases, and component improvements

- Extend tailwind.config.js with Cal.com brand color tokens (cal.text, cal.bg, cal.border, cal.accent, cal.brand)
- Create theme/colors.ts for JS usage where Tailwind classes can't be used
- Configure path aliases in tsconfig.json (@/components, @/hooks, @/utils, etc.)
- Add expo-image and expo-haptics dependencies
- Enhance AppPressable with Reanimated animations (opacity + scale) and haptic feedback
- Extract shared logic from BookingListItem into useBookingListItemData hook and BookingListItemParts
- Extract shared logic from EventTypeListItem into useEventTypeListItemData hook and EventTypeListItemParts
- Extract shared logic from AvailabilityListItem into AvailabilityListItemParts
- Update all list item components to use new theme tokens instead of hardcoded hex values

* fix react compiler non memo issue

* feat(companion): migrate to path aliases and expo-image

- Remove theme/colors.ts and theme/index.ts (defer dark mode to future PR)
- Replace colors import with hardcoded hex values in components
- Migrate all files to use path aliases (@/components/*, @/hooks/*, etc.)
- Migrate SvgImage to use expo-image for better performance
- Update tsconfig.json to remove @/theme/* alias

* fix(companion): add path aliases to extension tsconfig

Add baseUrl and paths configuration to tsconfig.extension.json to support
path aliases in shared types used by the extension build.
2025-12-28 08:08:33 -03:00
Abhishek b6b0492362 fix:gap at webhook form actions (#26233) 2025-12-28 09:41:48 +00:00
Abhishek 95f98eb58e fix: gap between giphy gif setup buttons (#26232) 2025-12-28 09:01:00 +00:00
Dhairyashil Shinde 4036fb6d08 feat(companion): react compiler (#26221)
* react compiler

* remove compilation mode 'all', it will use infer by default
2025-12-27 16:06:00 -03:00
samaRandDhairyashil Shinde 7fdfd0d6a0 fix: prevented overflow in WelcomeToCalcomModal by adjusting dialog content styles (#26202)
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-27 17:52:07 +00:00
Dhairyashil Shinde 2a84d46fe9 feat(companion): add Biome for linting and formatting (#26214)
* feat(companion): add ESLint with Prettier integration

- Add ESLint with eslint-config-expo/flat for SDK 55
- Integrate Prettier via eslint-plugin-prettier
- Configure environment-specific settings for Node.js config files and browser extension
- Add lint script to package.json
- Fix Prettier formatting issues in AvailabilityTab.tsx and types/index.ts

* fix(companion): use bun lockfile instead of npm

- Remove package-lock.json that was accidentally committed
- Update bun.lock with ESLint dependencies

* fix(companion): fix all ESLint errors (16 total)

- Fix unescaped entities in JSX (react/no-unescaped-entities):
  - app/(tabs)/(event-types)/index.tsx: escape quotes in delete confirmation
  - components/LoginScreen.tsx: escape apostrophe in "Don't have an account"
  - components/NetworkStatusBanner.tsx: escape apostrophes in offline message
  - components/booking-modals/BookingModals.tsx: escape apostrophe in rejection message
  - components/event-type-detail/tabs/AdvancedTab.tsx: escape quotes and apostrophes
  - components/screens/AvailabilityListScreen.tsx: escape quotes in delete confirmation

- Fix react-hooks/rules-of-hooks in RescheduleScreen.tsx:
  - Move useMemo calls before conditional early return to ensure hooks
    are called in the same order on every render

* fix(companion): fix all ESLint warnings (68 total)

- Fix import/no-named-as-default warnings by using named imports
- Fix @typescript-eslint/no-unused-vars warnings by removing unused imports/variables
- Fix react-hooks/exhaustive-deps warnings with eslint-disable comments
- Convert unused error variables in catch blocks to bare catch
- Remove unused imports (useRouter, Alert, useSafeAreaInsets, etc.)
- All ESLint checks now pass with 0 errors and 0 warnings

* feat(companion): add pre-commit lint check with --max-warnings=0

- Add companion lint check to root lint-staged.config.mjs
- Runs 'bun run lint -- --fix --max-warnings=0' for companion files
- Follows same pattern as apps/packages lint check
- Supports SKIP_WARNINGS=1 env var to bypass warning check if needed
- Commit will fail if any ESLint errors or warnings are present

* fix(companion): restore state variables and imports removed during ESLint fixes

- Restore locationAddress, locationLink, locationPhone state variables in event-type-detail.tsx (still used in fetchEventTypeData)
- Restore Alert import in BookingListScreen.tsx (still used for report booking)
- Add eslint-disable comments for the restored state variables since they're only used by setters

* test

* test

* fix eslint pre commit check

* fix: In React Native, HTML entities like &apos; are rendered literally as text, not decoded like in web browsers

* refactor(companion): remove ESLint and Prettier config in preparation for Biome

* feat(companion): add Biome for linting and formatting

- Install @biomejs/biome with exact version pinning (2.3.10)
- Add biome.json with formatting settings matching previous Prettier config
- Add lint, format, check, and check:ci scripts to package.json
- Update lint-staged to use Biome instead of Prettier
- Remove Prettier and prettier-plugin-tailwindcss dependencies
- Delete .prettierrc.js configuration file

* style(companion): apply Biome formatting and fix lint-staged config

- Update lint-staged to use 'biome format' instead of 'biome check'
  (pre-commit should only format, not lint)
- Apply Biome formatting to all companion files

* feat(companion): configure Biome for strict linting with pre-commit enforcement

- Apply Biome unsafe fixes (unused imports, optional chaining, etc.)
- Configure biome.json rules to disable overly strict rules for existing code:
  - noExplicitAny, noArrayIndexKey, useIterableCallbackReturn (suspicious)
  - useExhaustiveDependencies, noUnusedFunctionParameters (correctness)
  - noStaticOnlyClass (complexity)
  - noNonNullAssertion (style)
  - noStaticElementInteractions (a11y)
- Update lint-staged to use 'biome check --write --error-on-warnings'
  (pre-commit now runs both formatting AND linting, fails on warnings)

* fix(companion): enable noNonNullAssertion rule and fix all violations

- Enable noNonNullAssertion rule in biome.json (set to 'error')
- Fix 7 violations across the codebase:
  - hooks/useBookings.ts: Add runtime check before API call
  - hooks/useEventTypes.ts: Add runtime check before API call
  - hooks/useSchedules.ts: Add runtime check before API call
  - extension/entrypoints/content.ts: Add null checks for cache and getAttribute

* fix(companion): enable noStaticOnlyClass and noStaticElementInteractions rules

- Enable noStaticOnlyClass rule in biome.json
- Enable noStaticElementInteractions rule in biome.json
- Convert CalComAPIService from static class to object literal pattern
- Convert WebAuthService from static class to object literal pattern
- Add role="tooltip" to Tooltip.web.tsx for accessibility

* fix(companion): resolve TypeScript type errors in useEffect dependencies and remove unused state property

* fix(companion): enable noUnusedFunctionParameters rule and fix 9 violations

* fix(companion): enable noUnusedVariables rule and fix 4 violations

* fix(companion): enable useIterableCallbackReturn rule and fix 11 violations

* fix(companion): enable useExhaustiveDependencies rule and fix 7 violations

* fix(companion): enable noArrayIndexKey rule and fix 10 violations

* fix(companion): enable noExplicitAny rule and fix all violations

- Enable noExplicitAny rule in biome.json
- Replace any types with proper specific types across all files:
  - calcom.ts: Add proper type definitions for API responses and inputs
  - event-types.types.ts: Add BookingLimitsCount, BookingLimitsDuration, ConfirmationPolicy types
  - buildPartialUpdatePayload.ts: Fix type mismatches for booking limits functions
  - booking-actions.ts: Add proper types for booking action handlers
  - BookingDetailScreen.tsx, MarkNoShowScreen.tsx: Add types for attendee data
  - AvailabilityListItem.ios.tsx, BookingListItem.ios.tsx: Import SFSymbols7_0 type
  - extension/content.ts: Fix slot types and __cleanup invocation issues
- Remove unused imports and interfaces

* address cubics comments

* add useHookAtTopLevel rule
2025-12-27 08:19:53 -03:00
38e4c568b8 fix: add undeclared dependencies and remove unused/misplaced dependencies (#26205)
* chore: lock all package versions to match yarn.lock

This commit pins all dependency versions in package.json files to exact
versions matching the yarn.lock file, removing ^ and ~ prefixes.

Changes:
- Locked 427 dependencies across 47 package.json files
- Versions now match exactly what is resolved in yarn.lock
- Ensures reproducible builds and prevents unexpected version drift

This change improves build reproducibility by ensuring that the versions
specified in package.json files match exactly what yarn.lock resolves to.

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

* fix: add undeclared dependencies to trpc, ui, and platform-types packages

- @calcom/trpc: add cookie, uuid and their type definitions
- @calcom/ui: add Lexical packages, Radix UI components, classnames, sonner, react-easy-crop, zod
- @calcom/platform-types: add @nestjs/common, @nestjs/swagger, libphonenumber-js, luxon, zod

These dependencies were being used in the code but not declared in package.json,
relying on hoisting from other packages.

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

* chore: update yarn.lock after adding undeclared dependencies

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

* fix: upgrade Prisma versions in example apps and pin remaining @types/node

- Upgraded @prisma/client to 6.16.1 in example apps to match main app
- Pinned @types/node to 20.17.23 in atoms, libraries, and example apps
- Pinned @types/react to 18.0.26 and @types/react-dom to 18.2.6 in example apps

Addresses PR review comments about Prisma version mismatch and unpinned @types/node

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

* chore: remove unused and misplaced dependencies

Removed unused dependencies:
- @calcom/web: mime-types, posthog-node, react-date-picker, react-multi-email, react-phone-number-input, recoil, @vercel/edge-functions-ui, lottie-react, jotai
- @calcom/features: @lexical/react, lexical, akismet-api, stripe-event-types

Removed misplaced dependencies from @calcom/web (already in @calcom/ui):
- @radix-ui/react-avatar, @radix-ui/react-dialog, @radix-ui/react-dropdown-menu
- @radix-ui/react-hover-card, @radix-ui/react-id, @radix-ui/react-popover
- @radix-ui/react-slider, @radix-ui/react-switch, @radix-ui/react-toggle-group
- react-colorful

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

* fix: add back jotai and react-phone-number-input dependencies

These dependencies were incorrectly removed in the previous commit:
- jotai: Required as peer dependency by @daily-co/daily-react
- react-phone-number-input: CSS imported in WorkflowStepContainer.tsx

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

* chore: update yarn.lock after Prisma version upgrade

Updates yarn.lock to reflect:
- @prisma/client upgraded from 6.7.0 to 6.16.1 in example apps
- Removed unused @prisma/client@6.7.0 resolution

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

* fix: align dependency versions per PR review feedback

- @nestjs/common: 10.0.0 -> 10.3.3 in platform-types (match api-v2)
- cookie: ^0.7.0 -> 0.7.0 in trpc (pin exact version)
- uuid: ^8.3.2 -> 8.3.2 in trpc (pin exact version)
- @types/cookie: ^0.6.0 -> 0.6.0 in trpc (pin exact version)
- @types/uuid: ^8.3.4 -> 8.3.4 in trpc (pin exact version)

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

* refactor: move root dependencies to proper packages

- Remove all dependencies from root package.json (they were misplaced)
- Add @evyweb/ioctopus, city-timezones, date-fns-tz, p-limit to @calcom/features
- @daily-co/daily-js already exists in @calcom/web
- @vercel/functions already exists in @calcom/features
- date-fns already exists in @calcom/ui

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-26 23:02:24 -03:00
Alex van Andel ab64019e27 chore: release v6.0.6
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2025-12-27 00:34:40 +00:00
Syed Ali Shahbaz 8b7497b8cd chore: Return webhook version in the header (#26139)
* init

* add tests

* fix type

* type fix

* fix

* fix tests

* fix test
2025-12-27 00:31:20 +00:00
Dhairyashil Shinde 18017b5320 feat(companion): TypeScript best practices improvements (#26206)
* feat(companion): TypeScript best practices improvements

- Add separate tsconfig.extension.json for extension code typechecking
- Add typecheck scripts: typecheck, typecheck:extension, typecheck:all
- Create ambient declarations for browser extension APIs (browser.d.ts)
- Create type definitions for attendee and google-calendar types
- Replace all @ts-ignore with @ts-expect-error or remove where ambient declarations cover them
- Replace any types with proper types in AuthContext, webAuth, buildPartialUpdatePayload
- Fix implicit any errors in extension content.ts
- Update deepEqual function to use unknown instead of any for better type safety

All typechecks now pass for both app and extension code.

* feat(companion): enable full TypeScript strict mode (#26208)

* feat(companion): enable strictNullChecks and strictFunctionTypes

Phase 1 of strict mode enablement for the companion app.

Changes:
- Enable strictNullChecks and strictFunctionTypes in tsconfig.json
- Fix null check for scheduleDetails in fetchScheduleDetails
- Add explicit type annotations to limits arrays in event-type-detail.tsx
- Filter conferencing options with null appId before passing to buildLocationOptions
- Update LimitsTab interface to use union type for field parameter
- Add optional chaining for onEdit, onDuplicate, onDelete in EventTypeListItem.ios.tsx
- Add explicit type annotations to options arrays in AvailabilityListScreen.tsx
- Add explicit type annotations to dateOptions and timeOptions in RescheduleScreen.tsx
- Fix type guard return types in calcom.ts to explicitly return boolean

All typechecks pass for both app and extension code.

* feat(companion): enable full strict mode and fix any types (Phase 2 + Step 7)

Phase 2: Enable full strict mode
- Replace strictNullChecks + strictFunctionTypes with strict: true
- Fix implicit any errors in Alert.prompt callbacks (BookingDetailScreen, useBookingActions)

Step 7: Fix metadata any types in type definition files
- Update UserProfile.metadata to Record<string, unknown>
- Update CreateEventTypeInput.metadata to Record<string, unknown>
- Update Booking.responses to Record<string, unknown>

All typechecks pass for both app and extension code with full strict mode enabled.

* use JSON.stringify()

* fix restores the recursive key comparison with sorted keys

* prevents false positives when objects have different keys

* feat(companion): add tree shaking optimization scripts (#26212)

* feat(companion): add tree shaking optimization scripts

Add npm scripts to enable Expo's experimental tree shaking for production builds:
- export: Basic expo export command
- export:ios / export:android: Platform-specific exports
- export:optimized: Export with tree shaking enabled (all platforms)
- export:optimized:ios / export:optimized:android: Platform-specific with tree shaking

Bundle size improvement measured:
- Baseline: 5.48 MB (1804 modules)
- With tree shaking: 5.25 MB (1831 modules)
- Reduction: ~230 KB (4.2% smaller)

Also documented tree shaking configuration options in .env.example for:
- npm scripts (recommended)
- Manual env var setting
- EAS build profile configuration

* revert .env.example file

* revert .env.example file
2025-12-26 17:13:50 +00:00
Pedro Castro ab512ea263 chore: bump package versions (#26211)
* chore: bump package versions

- @nestjs/common 10.4.20
- @nestjs/platform-express 10.4.20
- @jsforce/jsforce-node 3.10.10
- dompurify 3.3.1
- @dub/embed-react 0.0.18
- @dub/embed-core 0.0.18
- http-proxy-middleware 2.0.9
- action-download-artifact v6

* fix: align NestJS core packages to same version

Update @nestjs/core and @nestjs/testing to 10.4.20 to match
@nestjs/common and @nestjs/platform-express versions
2025-12-26 13:38:25 -03:00
Volnei MunhozandDevin AI 44586c7dec chore: lock all package versions to match yarn.lock (#26204)
This commit pins all dependency versions in package.json files to exact
versions matching the yarn.lock file, removing ^ and ~ prefixes.

Changes:
- Locked 427 dependencies across 47 package.json files
- Versions now match exactly what is resolved in yarn.lock
- Ensures reproducible builds and prevents unexpected version drift

This change improves build reproducibility by ensuring that the versions
specified in package.json files match exactly what yarn.lock resolves to.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-26 11:54:30 -03:00
Anik Dhabal Babu 38efed4f56 ci: create new workflow for API v2 unit tests (#26189)
* playwright

* Remove copy-app-store-static from web server command

* check

* test

* api v2 unit test
2025-12-26 14:08:32 +00:00
Dhairyashil Shinde 91af737a7c feat(companion): linkedin plugin (#26193)
* feat/companion-extension-linkedin-plugin

* better alignment

* better code
2025-12-26 17:33:00 +05:30
Alex van Andel 6daac15bea fix: GH based cronjobs in EU (#25992)
* fix: GH based cronjobs in EU

* Some fixups

* Some further fixes
2025-12-26 11:43:28 +00:00
Kartik LabhshetwarandDhairyashil Shinde 3f093ef625 fix: add hover transparency and rounded top to ApiKeyListItem actions (#26150)
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-25 16:28:52 +00:00
Kartik Labhshetwarandcubic-dev-ai[bot] 21958dd511 fix: improve mobile responsiveness for workflows page (#24257)
* refactor: update WorkflowPage layout, add tooltip to name, adjust badge styling

* Update packages/features/ee/workflows/pages/workflow.tsx

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

* chore: removing tooltip

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2025-12-25 18:58:01 +05:30
Dhairyashil Shinde d51237844c feat(companion): implement comprehensive booking actions system (#26185) 2025-12-25 04:50:14 +01:00
Yash Gupta b002d7d797 fix: prevent WelcomeToCalcomModal footer overflow (#26186)
* fix: prevent WelcomeToCalcomModal footer overflow

* fix: removes extra space
2025-12-25 04:27:53 +05:30
8befcced39 ci: shard API v2 E2E tests into 4 parallel jobs (#26183)
* ci: shard API v2 E2E tests into 4 parallel jobs

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* check

* Fix typo in workflow name from 'Update' to 'Updatee'

* Rename workflow from 'PR Updatee' to 'PR Update'

* update

* test

* update

* fix

* update

* check

* remove

* revert

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-24 10:46:49 -03:00
Hariom Balhara 49d5f204f0 Add use client at the top and ignore warnings (#26184) 2025-12-24 10:42:57 +00:00
Anik Dhabal Babu c2b7dcb900 fix: flaky E2E tests on filter segment (#26182)
* fix: flaky e2e tests on filter segment e2e

* check

* Click first event type in advanced page test
2025-12-24 07:24:13 -03:00
Keith WilliamsandDevin AI b773b23ebb refactor: Remove buildjet cache from cache-build action (#26181)
* refactor: Remove buildjet cache from cache-build action

The buildjet cache was causing cache misses due to unstable hashFiles()
keys that included generated Prisma files. Since we now use Turbo Remote
Caching, the buildjet cache is redundant and was causing more problems
than it solved.

This simplifies the cache-build action to just run yarn build, relying
on Turbo Remote Caching for build artifact caching.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: Preserve original name and description in cache-build action

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-24 09:19:28 +05:30
Pedro Castro 99b82c55d5 chore: update direct dependencies (#26172)
Updates:
- vite: 4.5.3→4.5.14, 5.4.6→5.4.21
- nodemailer: 6.7.8→7.0.11
- @playwright/test: 1.45.3→1.55.1
- next-auth: 4.22.1→4.24.13
- class-validator: 0.14.0→0.14.3
- dompurify: 3.2.3→3.3.1

Includes type fixes for next-auth adapter compatibility
2025-12-23 23:42:55 -03:00
Keith WilliamsandDevin AI 054a0fa7db refactor: Add dedicated setup-db job to eliminate cache race condition (#26171)
* refactor: Add dedicated setup-db job to eliminate cache race condition

- Create new setup-db.yml workflow that runs cache-db action
- Update pr.yml to add setup-db job that runs before all E2E jobs
- Update integration-test, e2e, e2e-api-v2, e2e-app-store, e2e-embed,
  and e2e-embed-react jobs to depend on setup-db instead of build-api-v1
- Add setup-db to required job needs list and result check

This eliminates the race condition where multiple jobs could try to
write to the same database cache simultaneously.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: Remove DB parts from api-v1-production-build.yml

The database setup is now handled by the dedicated setup-db job,
so the postgres service and cache-db action are no longer needed
in the API v1 build workflow.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Apply suggestion from @keithwillcode

* Made integration tests dependency consistent

* refactor: Remove unnecessary env vars from setup-db.yml

Only keep the env vars needed for database setup:
- CALENDSO_ENCRYPTION_KEY (for db-seed)
- DATABASE_URL / DATABASE_DIRECT_URL (for database connection)
- TURBO_TOKEN / TURBO_TEAM (for turbo caching)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: Add back E2E_TEST_CALCOM_QA_* env vars needed by db-seed

These env vars are used by scripts/seed.ts to create the QA user
with Google Calendar credentials during database seeding.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: Restore postgres service and cache-db to api-v1-production-build.yml

The API v1 build still needs a database to run properly. Restored the
postgres service and cache-db action, and added dependency on setup-db
so it waits for the database cache to be created first.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* E2E for API v2 no longer waiting on API v2 build

* Reordering the jobs by dependencies

* add GOOGLE_API_CREDENTIALS env var to setup db

* Added back all env vars to setup-db

* fix: Include commit SHA in cache-db key to invalidate cache on new commits

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: Strip back setup-db.yml env vars to minimal set needed for db-seed

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 22:39:26 -03:00
Pedro CastroandKeith Williams cd6c5fe6df chore: remove unused dependencies (#26169)
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
* chore: remove unused dependencies

- Remove msw from apps/web (test was disabled with test.fixme)
- Remove integrations.e2e.ts (unused test file depending on msw)
- Remove jsforce from apps/api/v2 (never imported, salesforce uses @jsforce/jsforce-node)
- Remove rollup-plugin-node-builtins and vite-plugin-node-polyfills from atoms (never used)
- Remove fs/path/os aliases from atoms vite.config.ts

Resolves: #76, #118, #354 (partial), #356, #347, #266

* fix(companion): remove unused glob dependency

Glob was declared as devDependency but never imported in companion code
Resolves dependabot alerts #465, #460

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-23 21:38:38 -03:00
Alex van Andel 83aadf0213 chore: release v6.0.5 2025-12-24 00:37:16 +00:00
Alex van Andel 7f59a1f058 Revert "perf: (googlecalendar): batch freebusy calls by delegation credential (#24331)"
This reverts commit 253c33df33.
2025-12-24 00:35:18 +00:00
Keith Williams 5322d9640b chore: Change API v2 depends on for CI (#26170) 2025-12-23 23:19:51 +00:00
8ac3d423cb fix: When checking email domains to block replace includes with endsWith (#26166)
* Lint fixes

* Replace `includes` with `endsWith`

* Fix typo

* test: add tests for email domain blocking fix

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 19:56:43 -03:00
Alex van Andel 14edd6c42f chore: release v6.0.4
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2025-12-23 20:55:12 +00:00
Keith WilliamsandDevin AI 1c5f05638f fix: search by branch instead of SHA in E2E report workflow_dispatch (#26168)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 20:51:14 +00:00
fe4017f302 docs: clarify tRPC architecture - packages/features vs apps/web/modules (#26155)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-23 19:38:09 +00:00
BetoandDhairyashil Shinde 2abfae7f13 feat(companion): Booking details screen navigation header improvements (#26163)
* feat(companion): restructure booking detail components and enhance type safety

- Migrate BookingDetail component to a new file structure under (tabs)/(bookings) for better organization.
- Introduce a new BookingDetailScreen with improved header and menu options.
- Update app.json to enable typed routes and enhance TypeScript configuration in tsconfig.json.
- Remove the old booking-detail.tsx file to clean up the codebase.
- Adjust imports and routing to reflect the new structure, ensuring all components are properly linked.

This refactor aims to improve maintainability and clarity in the booking detail flow.

* add header options

* refactor(booking-detail): rename "Standalone Actions" menu to "Danger Zone" for clarity

---------

Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-23 19:35:55 +00:00
Dhairyashil Shinde 75d8300635 fix/companion-consider-all-profile-links (#26158) 2025-12-23 19:24:26 +00:00
Volnei Munhoz 67f20f4503 fix: Change matcher params for CI changes matcher (#26162)
* Change matcher params

* upgrade dorny

* Fix predicated-quantifier

* Fix predicated-quantifier
2025-12-23 19:20:06 +00:00
Keith Williams d6376c6d70 chore: CODEOWNERS Change Platform -> Consumer (#26160) 2025-12-23 19:18:42 +00:00
Keith WilliamsandDevin AI 9256d306b9 ci: make E2E report jobs non-blocking by moving to separate workflow (#26157)
* ci: make E2E report jobs non-blocking by moving to separate workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: minimize permissions in e2e-report workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: refactor to reuse existing workflow files via workflow_call

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: add workflow_dispatch trigger for manual testing of E2E report workflow

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: simplify workflow_dispatch to only require pr_number input

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* ci: remove secrets inheritance from merge-reports for fork PR security

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 19:16:36 +00:00
Anik Dhabal Babu b62493235c fix: all the e2e flakes visible (#26161)
* fix: all th e2e flakes

* check

* fix
2025-12-23 18:55:37 +00:00
Anik Dhabal Babu f35b36fafa add appId fallback for appName in event results (#26146) 2025-12-23 17:20:28 +00:00
Anik Dhabal Babu 2689cdfdff perf: pass app data to OmniInstallAppButton to avoid redundant API calls (#26156)
* perf: pass app data to OmniInstallAppButton to avoid redundant API calls

* Clean up comments in OmniInstallAppButton component

Removed comment about pre-fetched app data and fetching logic.
2025-12-23 16:49:34 +00:00
Dhairyashil ShindeandPallav efcf68869d fix: Routing page horizontal scroll for small mobile devices (#24663)
* fix: horizontal scroll for small mobile devices

* address cubics comments

* fix disable form toggle

---------

Co-authored-by: Pallav <90088723+Pallava-Joshi@users.noreply.github.com>
2025-12-23 16:23:50 +00:00
Benny JooandDevin AI 8afe87ff75 refactor: Move trpc-dependent components from features to web [1] (#25859)
* refactor: migrate UnconfirmedBookingBadge from features to apps/web

Move UnconfirmedBookingBadge.tsx from packages/features/bookings/ to
apps/web/modules/bookings/components/ as part of the architectural
refactor to remove trpc client imports from the features layer.

Also removes unused preserveBookingsQueryParams function from Navigation.tsx.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: move shell navigation and badges to apps/web

Move shell navigation components and trpc-using badges from
packages/features to apps/web/modules to fix circular dependency:

- Move navigation folder to apps/web/modules/shell/navigation/
- Move TeamInviteBadge.tsx to apps/web/modules/shell/
- Create Shell wrapper in apps/web that provides MobileNavigationContainer
- Update all Shell imports in apps/web to use the new wrapper
- Remove MobileNavigationContainer default from features Shell.tsx
- Fix pre-existing lint warnings in touched files

This establishes the pattern for migrating React components that use
trpc hooks from the features layer to the web app layer, ensuring
proper dependency direction: apps/web imports from packages/features,
never the reverse.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: move SideBar.tsx to apps/web to fix build error

SideBar.tsx was importing Navigation from the moved navigation folder,
causing a build error. Moving SideBar.tsx to apps/web and updating the
features Shell to not have a default SidebarContainer fixes this.

The web Shell wrapper now provides both the default SidebarContainer
and MobileNavigationContainer, maintaining the injection pattern.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* revert

* revert

* revert

* wip

* wip

* wip

* wip

* wip

* wip

* not used anywhere

* wip

* wip

* wip

* wip

* fix

* fix

* wip

* wip

* wip

* wip

* wip

* fix

* fix

* fix

* fix

* migrate

* migrate admin-adpi

* wip

* feat: migrate organization settings components from packages/features to apps/web/modules

- Migrate profile.tsx, appearance.tsx, general.tsx, privacy.tsx, guest-notifications.tsx, delegationCredential.tsx, other-team-members-view.tsx, other-team-profile-view.tsx
- Migrate attributes directory (AttributesForm.tsx, DeleteAttributeModal.tsx, ListSkeleton.tsx, attributes-create-view.tsx, attributes-edit-view.tsx, attributes-list-view.tsx)
- Migrate admin directory (AdminOrgEditPage.tsx, AdminOrgPage.tsx, WorkspacePlatformPage.tsx)
- Update all page imports to use new paths from ~/settings/organizations/
- Update relative imports in migrated files to use @calcom/features paths
- Fix lint warnings in migrated files

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update test import path after migration

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: remove unnecessary test-setup import (already in vitest config)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* wip

* refactor: delete original files after migration to apps/web/modules

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix

* fix

* fix

* fix

* wip

* refactor more

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* mv

* update import paths

* wip

* wip

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* mv

* mv

* mv

* fix

* wip

* wip

* fix

* fix

* fix

* fix: make test mocks resilient to vi.resetAllMocks()

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: fix AttributeForm test failures

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix

* refactor: move ee files to apps/web/modules/ee/ folder

- Move teams, workflows, and organizations folders to apps/web/modules/ee/
- Add LICENSE file to apps/web/modules/ee/
- Update all import paths from ~/teams/ to ~/ee/teams/
- Update all import paths from ~/settings/organizations/ to ~/ee/organizations/
- Remove duplicate MemberInvitationModal copy.tsx file

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: move useHasPaidPlan and dependent files to apps/web/modules

- Move useHasPaidPlan.ts from packages/features/billing/hooks to apps/web/modules/billing/hooks
- Move intercom files from packages/features/ee/support to apps/web/modules/ee/support
- Move ContactMenuItem.tsx and dependencies (freshchat, helpscout, zendesk) to apps/web/modules/ee/support
- Move ViewRecordingsDialog.tsx and RecordingListSkeleton to apps/web/modules/ee/video
- Move CalVideoSettings.tsx to apps/web/modules/eventtypes/components/locations
- Move CreateOrEditOutOfOfficeModal.tsx to apps/web/modules/settings/outOfOffice
- Refactor UpgradeTeamsBadge to accept props and create wrapper in apps/web/modules/billing
- Update all callers to use new file locations
- Add eslint-disable comments for pre-existing lint warnings

This fixes the tRPC server build failure caused by circular dependency where
the server build was traversing into packages/features and pulling in React
hooks that depend on @calcom/trpc/react types.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: correct UpgradeTeamsBadge import path to use package export

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix: pass plan state through SelectProps to UpgradeTeamsBadge

- Add upgradeTeamsBadgeProps field to ExtendedOption type in Select component
- Update OptionComponent to spread upgradeTeamsBadgeProps to UpgradeTeamsBadge
- Update getOptions.ts to accept PlanState object and include upgradeTeamsBadgeProps
- Update WorkflowStepContainer.tsx to pass planState to getWorkflowTriggerOptions/getWorkflowTemplateOptions
- Update WorkflowDetailsPage.tsx to pass upgradeTeamsBadgeProps in transformed action options
- Update AddActionDialog.tsx interface and mapping to include upgradeTeamsBadgeProps
- Add eslint-disable comments for pre-existing React Hook dependency warnings

This fixes the UpgradeTeamsBadge refactoring issue where the badge was always showing
'upgrade' text instead of the correct text based on plan state (trial_mode, inactive_team_plan, etc.)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update import paths to use /ee/ folder for workflows and organizations

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update workflow component imports to use /ee/ folder

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: add missing types.ts for LocationInput.tsx

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: extract BookingRedirectForm type to shared location

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* wip

* wip

* fix: update BookingRedirectForm import to use local types file

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* wip

* fix

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 12:22:26 -03:00
Pedro CastroandKeith Williams 7847177e8b fix(api): accept avatar URLs and use email for user creation (#25629)
* fix(api): fix user creation with avatarUrl and username

- avatarValidator: accept URLs in addition to base64 images
- organizations-users-service: use email for user creation instead of username

The avatarValidator was incorrectly rejecting valid URLs even though the API documentation shows URL examples and all e2e tests use URLs.

The user creation was failing when username was provided because createNewUsersConnectToOrgIfExists requires a valid email, not username. The username is correctly applied via updateOrganizationUser after creation.

Fixes user creation endpoint POST /v2/organizations/{orgId}/users

* test(api): add tests for avatar validator fixes

  Add comprehensive test coverage for avatarValidator changes:

  - Unit tests: 18 scenarios covering valid/invalid URLs and base64 images
  - E2E tests: user creation with username + avatarUrl (URL and base64)
  - Security validation: reject unsafe protocols and malformed data
  - Error message verification for validation failures

  Addresses testing requirements from code review

* fix(api): enhance avatar validator security per code review

  - Reject HTTP URLs, accept only HTTPS for security and browser compatibility
  - Reject empty strings and whitespace (use null to reset avatar)
  - Update validation message to clarify HTTPS requirement
  - Add test coverage for new security restrictions

 Addresses security feedback from code review regarding mixed content vulnerabilities and clearer API semantics for avatar reset

* refactor(api): simplify avatarValidator null check

Remove redundant null/undefined check since @IsOptional decorator already skips validation for undefined values. Updated test mock to include @IsOptional to match real DTO usage

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-23 15:07:14 +00:00
Hariom BalharaandDevin AI 866c8c046d fix: create host records when team membership transitions to accepted via PATCH (#26138)
The PATCH endpoint for /v2/teams/:teamId/memberships/:membershipId had a bug
where host records for assignAllTeamMembers event types were not created when
a membership transitioned from accepted=false to accepted=true.

The bug was caused by incorrect operation ordering:
1. Update membership (first update)
2. Get current membership (gets already-updated state)
3. Update membership again (second update)
4. Check if transition happened (condition never fires)

Fixed by reordering to match the org-scoped controller pattern:
1. Get current membership BEFORE any updates
2. Update membership
3. Compare and call updateNewTeamMemberEventTypes if transition occurred

Also added an e2e test to verify host records are created when membership
transitions from accepted=false to accepted=true via PATCH.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 10:46:14 +00:00
Kartik LabhshetwarandDhairyashil Shinde 96f8a89efa fix: replace console logging with logger across services and features (#26127)
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-23 08:24:23 +00:00
Kartik Labhshetwar a2cb529d62 fix: update CommandInput styling for focus and transition (#26055) 2025-12-23 13:16:55 +05:30
9c680838b6 fix(companion): improve code clarity and type safety in components (#26062)
- Remove 'as any' type assertion in LoginScreen.tsx, use Platform.OS check
- Fix malformed className string in LogoutButton.tsx (extra quotes)
- Remove @ts-ignore comments in Tooltip.tsx with proper web-specific types
- Replace 'any' type with Schedule type in AvailabilityTab.tsx
- Replace 'any' type with 'string' for SF Symbol icons in EventTypeListItem.ios.tsx
- Remove console.log error handling in SvgImage.tsx
- Extract duplicated formatDuration function to use shared utility from formatters.ts
- Extract repeated inline styles to sectionDividerStyle constant in AvailabilityTab.tsx

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
2025-12-23 00:26:16 +00:00
Dhairyashil ShindeandPeer Richelsen 6650fdb9ef refactor(companion): extract AvailabilityDetailScreen with AppPressable migration (#26106)
* refactor(companion): extract AvailabilityDetailScreen with AppPressable migration

Apply Phases 2, 3, 4 to availability-detail.tsx:
- Phase 2: Extract screen logic (~995 lines) to components/screens/AvailabilityDetailScreen.tsx
- Route file is now a minimal ~35 line wrapper with Stack.Screen config
- Phase 3: ScrollView+map pattern kept (7 days is a fixed small list, FlatList not needed)
- Phase 4: Migrate all TouchableOpacity to AppPressable (63 instances)

Follows the same pattern as EventTypeDetailScreen extraction.

* fix(companion): add GlassView header with Save button to AvailabilityDetailScreen (#26107)

* refactor(companion): extract BookingDetailScreen with AppPressable migration (#26108)

* refactor(companion): extract AvailabilityListScreen with AppPressable migration (#26109)

* fix(companion): add GlassView header with Save button to AvailabilityDetailScreen

* refactor(companion): extract BookingDetailScreen with AppPressable migration

* refactor(companion): extract AvailabilityListScreen with AppPressable migration

* refactor(companion): Standardized error handling with dev-only debug logs (#26110)

* address cubics comments

* address cubics comments

* addressed typecheck erros

* removed localhost from wxt.config for chrome extension

* declare FullScreenModal  FullScreenModalProps

---------

Co-authored-by: Peer Richelsen <peer@cal.com>

* add loggers for dev env

---------

Co-authored-by: Peer Richelsen <peer@cal.com>

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
2025-12-22 22:47:55 +00:00
Dhairyashil Shinde 9909ac53fc fix: use app name instead of app slug in email (#25285)
* fix: google calender name in email

* fix: google calender name in email

* cleaner code

* test: add test for human-readable app name in appsStatus
2025-12-23 03:41:08 +05:30
Anik Dhabal Babu f598a8ebdd ci: skip merge & report publishing when all E2E tests pass (#23552)
* fix

* Refactor PR workflow to use pull_request_target

Updated the GitHub Actions workflow

* update

* Update PR workflow trigger and permissions

Changed event trigger from 'pull_request_target' to 'pull_request' and removed branch restrictions.

* test

* revert
2025-12-22 19:31:43 +00:00
23920fe9ce fix: Org/team admin or owner should be marked as ‘no show’ in a member’s booking (#26009)
* fix: update tempOrgRediret on updating s
lug

* Update packages/trpc/server/routers/viewer/organizations/adminUpdate.handler.ts

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

* refactor

* fix

* fix

* revert

* fix handle no show

* revert

* Remove metadata from organization query selection

Removed metadata selection from organization query.

* use repo

* update

* Update packages/features/bookings/lib/checkIfUserIsAuthorizedToManageBooking.ts

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>

* update

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
2025-12-22 15:42:20 -03:00
Anik Dhabal Babu 33eee8dfc3 fix: Email reminder issue with seated event (#26136)
* fix emailworkflow reminder attendee

* update
2025-12-22 18:26:40 +00:00
Amit Sharma f5b9b6b0f9 feat: store ads clickid when creating an account (#25763)
* feat: store ads clickid when creating an account

* fix: type check

* fix: google campaignId not being added to stripe

* remove tracking in stripe app
2025-12-22 23:29:51 +05:30
b664857809 feat: set HubSpot meeting owner from cal's organizer (#25998)
* feat: add HubSpot owner(organizer in cal)

* refactor: improve logging and token handling in HubSpot integration

* Update packages/app-store/hubspot/lib/CrmService.ts

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

* feat: enhance error handling for missing scopes

* refactor

* remove unused

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
2025-12-22 22:52:04 +05:30
Anik Dhabal Babu c746fdcdfe ix disable cancelling persistence and rescheduling toggle (#26131) 2025-12-22 15:31:16 +00:00
76b53eb3d4 chore: remove webpack config and convert next.config to TypeScript (#26126)
* chore: remove webpack experimental flags from apps/web

- Remove webpackMemoryOptimizations and webpackBuildWorker from experimental config
- Remove unused DefinePlugin for process.env.BUILD_ID (not used anywhere in codebase)
- Remove unused buildId parameter from webpack function signature

These webpack-specific experimental flags were showing up during dev mode
even though Turbopack is used for development. The flags only apply to
production webpack builds and their presence in the config was confusing.

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

* chore: remove webpack function for full Turbopack build

- Remove entire webpack function (IgnorePlugin, PrismaPlugin, resolve.fallback, sideEffects)
- Remove unused PrismaPlugin import
- Turbopack handles all bundling without webpack configuration

Benchmark shows no performance regression:
- Main (with webpack): 67s compile
- Full webpack removal: 69s compile

Both fail at same pre-existing TypeScript error on main branch.

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

* chore: convert next.config.js to TypeScript

- Convert CommonJS require() to ES6 imports
- Add proper TypeScript types for config and plugins
- Remove /* eslint-disable */ comment
- Keep all existing functionality intact

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

* conditional load axiom

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-22 12:23:00 -03:00
Amit Sharma 090247a058 fix: event type not installed apps list empty (#26128) 2025-12-22 13:37:52 +00:00
Hariom BalharaandDevin AI e23354b48b fix: ESC key handler only works once in embed modal (#25615)
* fix: ESC key handler only works once in embed modal

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* Fix bug found by cubic and add tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-22 10:06:09 -03:00
Syed Ali Shahbaz 0b7f51410a chore: Add webhook version documentation link to webapp (#26121)
* init

* further improvement
2025-12-22 10:22:41 +00:00
Anik Dhabal Babu 31da9eaa8f fix: e2e flakes on analytics apps tests (#26119)
* test

* test

* fix flakes
2025-12-22 15:30:01 +05:30
192d927232 fix: align page headers by removing py-2 padding from ShellMain (#26084)
* fix: align insights header with other pages by using ShellMainAppDir

Co-Authored-By: peer@cal.com <peer@cal.com>

* fix: remove py-2 padding from ShellMain to align with ShellMainAppDir

Co-Authored-By: peer@cal.com <peer@cal.com>

* address cubics comment - keep sticky bg, only remove padding

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
2025-12-22 09:31:56 +00:00
Rajiv Sahal f9ff3248e5 feat: endpoint to update location for existing booking (#25367)
* feat: init endpoint to update booking location

* chore: update controller

* chore: DTOs for update location endpoint

* chore: add update booking method

* fix: refactor

* feat: service update booking location

* chore: update platform libraries

* chore: update exports

* chore: e2e tests for updating booking location endpoint

* chore: update e2e tests for updating booking location endpoint

* chore: update bookings module

* fixup

* chore: update configs

* fixup: revert changes

* chore: remove unused handlers

* fix: update inputs

* refactor: booking location service

* fixup

* revert: unnecessary changes

* chore: cleanup

* fix: e2e tests

* chore: implement cubic feedback

* chore: implement feedback

* fixup

* chore: more PR feedback
2025-12-22 09:25:00 +00:00
mintlify[bot] 6ebd401953 Update docs/developing/guides/automation/webhooks.mdx (#26118)
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
2025-12-22 09:20:07 +00:00
mintlify[bot]andSyed Ali Shahbaz d69ba02851 Add versioned webhook payload reference with interactive selection (#26008)
* Update docs/developing/guides/automation/webhooks.mdx

Co-Authored-By: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* Update docs/developing/guides/automation/webhooks.mdx

Co-Authored-By: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* Update docs/developing/guides/automation/webhooks.mdx

Co-Authored-By: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* Update docs/developing/guides/automation/webhooks.mdx

Co-Authored-By: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* Update docs/developing/guides/automation/webhooks.mdx

Co-Authored-By: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* Update docs/developing/guides/automation/webhooks.mdx

Co-Authored-By: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>

* Documentation edits made through Mintlify web editor

* Documentation edits made through Mintlify web editor

---------

Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
2025-12-22 06:19:02 +00:00
Keith WilliamsandDevin AI 851cca25aa perf: add z.ZodType annotations to high-impact schemas (#26114)
* perf: add z.ZodType annotations to high-impact schemas

Add explicit type annotations to reduce TypeScript type inference overhead
and .d.ts file bloat in the tRPC package.

Changes:
- packages/prisma/zod-utils.ts: Add EventTypeLocation type and annotate eventTypeLocations schema
- packages/features/eventtypes/lib/schemas.ts: Add TEventTypeDuplicateInput and TCreateEventTypeInput types with annotations
- packages/app-store/routing-forms/zod.ts: Add FieldOption, TNonRouterField, TRouterField, TField, TFields types with annotations for zodField and zodFields

These schemas feed into multiple tRPC routers and were identified as high-impact
targets for reducing type checking time and declaration file sizes.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: replace z.infer with explicit types and define EventTypeLocation locally

Address PR feedback:
- Replace z.infer<typeof calVideoSettingsSchema> with explicit CalVideoSettings type
- Define EventTypeLocation type locally instead of importing from prisma
- Add z.ZodType annotation to calVideoSettingsSchema

Note: Still importing Zod schemas from @calcom/prisma/zod-utils for validation.
Awaiting guidance on whether to move those to @calcom/lib.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 23:15:04 -03:00
ee6989a575 refactor: split raqbUtils into server and client modules to fix RAQB import in server context (#26112)
* refactor: add server and client raqbUtils modules

Add two new modules to split RAQB utilities:
- raqbUtils.server.ts: Server-safe utilities without RAQB runtime
- raqbUtils.client.ts: Client-only utilities requiring RAQB runtime

This enables server-side code to import RAQB utilities without
pulling in the react-awesome-query-builder runtime library.

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

* refactor: update imports to use server/client raqbUtils modules and fix lint warnings

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

* fix: fix type errors in getLuckyUser.ts and remove dead code in RouteBuilder.tsx

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-22 02:00:19 +00:00
Keith WilliamsandDevin AI 545eed9b0d fix: always fetch fresh PR labels to avoid stale event payload data (#26113)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-22 01:06:05 +00:00
Volnei MunhozandDevin AI 40883386f0 fix: address peer dependency issues across the monorepo (#26105)
MOVE:
- Move @next/third-parties from root to apps/web (only used there)
- Remove date-fns-tz from root, add date-fns and date-fns-tz to root deps

REMOVE:
- Remove sonner from packages/lib (not used there, already in apps/web)
- Remove next-seo from packages/ui (not used there, already in apps/web)
- Remove next-auth from apps/api/v2 (only used for User type in tests)

ADD peerDependencies:
- packages/ui: add react-dom
- packages/features: add react, react-dom, react-is, date-fns-tz, stripe, zod
- packages/platform/atoms: add react-dom
- packages/trpc: add next, react, react-dom

ADD dependencies:
- apps/web: add @next/third-parties, i18next, react-i18next
- apps/api/v2: add axios (required by @nestjs/axios)

FIX:
- apps/api/v2: replace next-auth User type with @calcom/prisma/client User

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 23:20:49 +00:00
0673d667f8 feat: upgrade api/v1 and example apps to Next.js 16.1.0 (#26104)
* feat: upgrade api/v1 and example apps to Next.js 16.1.0

- Update apps/api/v1 to Next.js 16.1.0
- Rename middleware.ts to proxy.ts per Next.js 16 migration
- Add turbopack config to next.config.js
- Update packages/platform/examples/base to Next.js 16.1.0
- Add eslint-disable to config files (following apps/web pattern)

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

* chore: update yarn.lock for Next.js 16.1.0 upgrade

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 18:19:18 -03:00
a2e2b7ff97 chore: upgrade yarn from 3.4.1 to 4.12.0 (#26102)
* chore: upgrade yarn from 3.4.1 to 4.12.0

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

* fix: update engines.yarn to match upgraded version

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 17:20:56 -03:00
Keith WilliamsandDevin AI 127b7d5532 ci: consolidate changes and check-label jobs into prepare (#26101)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 19:51:37 +00:00
a9a3389039 feat: upgrade apps/web to Next.js 16.1.0 (#26093)
* feat: upgrade apps/web to Next.js 16.1.0

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: enable Turbopack for Next.js 16.1 production builds

- Add turbopack: {} config to next.config.js to enable Turbopack for builds
- Fix re-exported config errors in webhook API routes by defining config locally
  - alby/webhook.ts
  - btcpayserver/webhook.ts
  - paypal/webhook.ts
  - stripepayment/webhook.ts

Turbopack requires route segment configs to be statically analyzable,
so they cannot be re-exported from other modules.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: update revalidateTag calls for Next.js 16.1 API changes

Next.js 16.1 changed the revalidateTag signature to require a second
argument (profile). Using 'max' profile as recommended by Next.js docs
for stale-while-revalidate semantics.

Updated files:
- app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts
- app/(use-page-wrapper)/(main-nav)/teams/actions.ts
- app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions.ts
- app/(use-page-wrapper)/settings/(settings-layout)/organizations/roles/actions.ts
- app/(use-page-wrapper)/settings/organizations/(org-user-only)/members/actions.ts
- app/cache/travelSchedule.ts

Also cleaned up next.config.js turbopack config formatting.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add profile parameter to revalidateTag in membership.ts for Next.js 16.1

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix routing form

* refactor: rename middleware.ts to proxy.ts per Next.js 16 migration

Next.js 16 has deprecated the 'middleware' file convention and renamed it to 'proxy'.
This change follows the official migration guide:
https://nextjs.org/docs/messages/middleware-to-proxy

Changes:
- Renamed apps/web/middleware.ts to apps/web/proxy.ts
- Renamed the middleware function to proxy
- Updated CODEOWNERS reference
- Updated comment reference in logout page

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: Anik Dhabal Babu <adhabal2002@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-21 16:31:48 -03:00
Eesh MidhaandDhairyashil Shinde 4b4565b19d fix: constrain AddActionDialog overflow and footer behavior (#26087)
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-21 17:08:37 +00:00
Keith WilliamsandDevin AI 2da6f5b3b1 fix: remove labeled trigger to prevent workflow reruns on non-E2E labels (#26099)
When any label is added to a PR, the workflow was re-running and causing issues
because the E2E check would fail for non-ready-for-e2e labels.

This change removes 'labeled' from the trigger types entirely. Users can now:
1. Add the ready-for-e2e label to a PR
2. Click 'Re-run all jobs' in GitHub Actions UI to trigger E2E tests

This is simpler and avoids the complexity of trying to maintain previous check
status when non-E2E labels are added.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 15:54:35 +00:00
Volnei Munhoz d61a613911 fix: use idiomatic dorny/paths-filter exclusion pattern (#26097) 2025-12-21 14:49:43 +00:00
Keith WilliamsandDevin AI 09f2aa113b fix: resolve lint warnings in web app (#26017)
* fix: resolve lint warnings in web app

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove unused isReadPermission variable

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove unused loading state entirely

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 14:38:27 +00:00
f7bb2683cb ci: skip Playwright install on cache hit (#26060)
* update

* Add cache-db action to e2e workflow

* fix: remove cache-db from prepare job (requires Postgres service)

The prepare job doesn't have a Postgres service container, so cache-db
was failing with 'connection refused' when trying to run psql.

cache-db should only run in the e2e shards which have the Postgres service.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* update

* Update e2e.yml

* Add newline at end of e2e.yml file

* fix

* Fix indentation in e2e.yml for retention-days

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 10:58:41 -03:00
83ee986bbd fix: lock package versions and organize devDependencies (#26095)
* fix: lock package versions to exact versions from yarn.lock

Replace version ranges (^, ~) with exact resolved versions from yarn.lock
to ensure consistent dependency resolution across all environments.

This change affects 26 package.json files with 89 version updates including:
- TypeScript: ^5.9.0-beta -> 5.9.2
- Zod: ^3.22.4 -> 3.25.76
- React: ^18 -> 18.2.0
- Various Radix UI, Vite, PostCSS, and other dependencies

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

* fix: preserve npm alias format for @radix-ui packages

The previous commit incorrectly converted npm aliases like
'npm:@radix-ui/react-dialog@^1.0.4' to just '1.0.4', which broke
yarn install as it tried to find non-existent packages.

This fix restores the npm alias format while keeping the pinned versions:
- @radix-ui/react-dialog-atoms: npm:@radix-ui/react-dialog@1.0.4
- @radix-ui/react-tooltip-atoms: npm:@radix-ui/react-tooltip@1.0.6

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

* refactor: move dev dependencies to devDependencies section

Move 26 dependencies that are clearly development-only to the
devDependencies section across 10 packages:

- Testing: @types/jest, jest, ts-jest, @golevelup/ts-jest
- Build tools: typescript, ts-node, concurrently, dotenv-cli
- Linting: eslint-*, eslint-config-*, eslint-plugin-*
- Types: @types/express, @types/turndown, @types/uuid

This improves dependency organization and ensures production builds
don't include unnecessary development dependencies.

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-12-21 10:18:07 -03:00
Dhairyashil Shinde c8af45537a fix: three dots icon missing for ios availability (#26094) 2025-12-21 12:54:13 +00:00
19ac0139c1 fix: Remove all links legacyBehavior (#25585)
* Remove all links legacyBehavior

* fix: resolve type errors in Button and Dropdown when using Link without legacyBehavior

- Button.tsx: Only pass ref to button element, not to Link (Link manages its own anchor)
- Dropdown.tsx: Strip ref from props when using Link to avoid type incompatibility

This fixes the type errors that were causing API V1 and V2 builds to fail.

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

* fix: only pass disabled and type props to button element, not to Link

Link component doesn't accept disabled or type props, so these should only be passed when rendering a button element.

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

* fix: strip ref from passThroughProps when rendering Link

The passThroughProps spread was including a ref property that's incompatible with Link's expected ref type. This strips the ref when rendering a Link component.

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

* fix: use type assertion for React.createElement props to handle union types

The Button component uses a union type for props that can be either Link or button props. TypeScript can't narrow the union type properly when using React.createElement with a dynamic element type, so we use a type assertion to cast the props to the correct type.

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

* fix: render Link and button separately to avoid type conflicts

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

* fix: preserve data-testid when rendering Button as Link

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

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 12:40:27 +00:00
Dhairyashil Shinde 067fa7e137 feat(companion): Add Google Calendar mark no-show functionality (#26085) 2025-12-21 13:30:31 +01:00
Beto aa127b2c2b refactor: (companion) (iOS) create an ios screen for specific native logic (#26081)
* create an ios screen for specific native logic

* feat: update bookings layout to conditionally show header on iOS

* feat: add useActiveBookingFilter hook for managing booking filter state

- Introduced a new hook, useActiveBookingFilter, to manage the active booking filter state and provide related utilities.
- Added filter options for "upcoming", "unconfirmed", "past", and "cancelled" bookings.
- Updated index.ts to export the new hook and its types for UI state management.

* refactor: streamline booking filter management and remove unused code

- Integrated the useActiveBookingFilter hook to manage booking filter state, simplifying the filter logic.
- Removed redundant state variables and functions related to booking filters.
- Cleaned up the code by eliminating unused imports and commented-out code sections.
- Updated the booking fetching logic to utilize the new filter parameters directly.

* refactor: move meeting URL extraction and info retrieval to utility module

- Extracted meeting URL extraction and meeting info retrieval logic into a new utility module, meetings-utils.ts.
- Updated index.ios.tsx and index.tsx to utilize the new getMeetingInfo function from the utility module, simplifying the component code.
- Removed redundant helper functions from the component files to enhance maintainability.

* refactor: extract empty state content logic into utility module

- Moved the getEmptyStateContent function from the Bookings component files to a new utility module, bookings-utils.ts, to enhance code reusability and maintainability.
- Updated index.ios.tsx and index.tsx to utilize the new utility function, simplifying the component code and improving clarity.
- Removed redundant empty state logic from the component files.

* refactor: enhance booking filtering and utility functions

- Updated the Bookings component to utilize new utility functions for filtering bookings by event type and search queries, improving code clarity and maintainability.
- Moved formatting functions (formatTime, formatDate, formatMonthYear, getMonthYearKey) and grouping logic (groupBookingsByMonth) to the bookings-utils module, centralizing related functionality.
- Removed redundant code from the Bookings component files, streamlining the overall structure.

* refactor: implement booking actions hook for improved management

- Introduced a new `useBookingActions` hook to centralize booking-related actions such as rescheduling, confirming, and rejecting bookings, enhancing code organization and reusability.
- Updated the `Bookings` component to utilize the new hook, simplifying the component logic and reducing redundancy.
- Removed outdated state management and functions related to booking actions, streamlining the overall code structure.

* refactor: consolidate booking components and enhance structure

- Refactored the Bookings component to utilize a new BookingListScreen component, improving code organization and readability.
- Introduced BookingListItem for individual booking rendering, streamlining the rendering logic and enhancing maintainability.
- Removed redundant state management and functions from the Bookings component, simplifying the overall structure.
- Updated modal handling for booking actions, rescheduling, and rejection to improve user experience and code clarity.

* feat: add BookingListItem component for enhanced booking display

- Introduced a new BookingListItem component for rendering individual booking details, improving modularity and reusability.
- Implemented context menu actions for booking management, including rescheduling, editing location, and adding guests.
- Updated type definitions for BookingListItemProps to include additional action handlers for better functionality.
- Refactored existing BookingListItem component to utilize the new props structure, enhancing clarity and maintainability.

* refactor: simplify layout and styling in BookingListItem and BookingListScreen components

- Updated the BookingListItem component to streamline the layout by reducing padding and adjusting the gap between elements.
- Modified the BookingListScreen component to remove unnecessary horizontal padding in the content container style, enhancing the overall layout consistency.
2025-12-21 11:38:42 +00:00
51bce6763f refactor: split tRPC build into server and react phases (#26082)
* refactor: import AppRouter from generated types instead of server source

This change improves tRPC build performance by having the client-side code
import AppRouter from pre-generated type declarations instead of traversing
the entire server router tree.

Changes:
- Create type bridge file at packages/trpc/types/app-router.ts
- Update packages/trpc/react/trpc.ts to import from the bridge
- Update .gitignore to only ignore types/server (generated files)
- Update eslint.config.mjs to only ignore types/server (generated files)

The type bridge provides:
1. Faster typechecking - avoids parsing 458 server files
2. Stable import location that's easy to lint against
3. Single place to adjust if generated path changes

Build order is already enforced in turbo.json (type-check depends on @calcom/trpc#build).

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: move bridge file to react/ to avoid TS5055 error

Move the AppRouter type bridge file from types/app-router.ts to react/app-router.ts
to avoid the TS5055 'Cannot write file because it would overwrite input file' error.

The issue was that placing the bridge file in types/ caused TypeScript to treat
the generated .d.ts files as input files during the tRPC build, then fail when
trying to emit to the same location.

By placing the bridge in react/ (which is excluded from the tRPC server build),
the bridge file is only used by client code and doesn't interfere with the
server type generation.

Changes:
- Move bridge file from types/app-router.ts to react/app-router.ts
- Update import in react/trpc.ts to use ./app-router
- Revert .gitignore to ignore all of types/ (generated files)
- Revert eslint.config.mjs to ignore all of types/**

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: split tRPC build into server and react phases

- Create tsconfig.server.json for server-only type generation
- Create tsconfig.react.json for react/client type generation
- Update build script to run server build first, then react build
- Remove || true so build properly fails on errors
- This allows react code to import from generated server types

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* refactor: split @calcom/trpc exports to separate server and react entrypoints

- Remove react exports from @calcom/trpc root (index.ts)
- Update 89 files to import from @calcom/trpc/react instead of @calcom/trpc
- This fixes the boundary leak where server builds were pulling in react code
- Server build no longer compiles react/app-router.ts, fixing the chicken-and-egg
  issue where react code needed generated server types that didn't exist yet

This improves TypeScript build performance by preventing the server type
generation from traversing the entire react/client type graph.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: import WorkflowType from lib/types instead of React component

This fixes a boundary leak where the server build was pulling in React
components through the WorkflowRepository import chain. By importing
WorkflowListType from lib/types instead of WorkflowListPage.tsx, the
server build no longer traverses React component files.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: extract server-safe types to prevent boundary leaks in tRPC build

- Extract ChildrenEventType to lib/childrenEventType.ts (server-safe)
- Extract Slots type to calendars/lib/slots.ts (server-safe)
- Create types.server.ts files for eventtypes and bookings
- Update server code to import from server-safe type files
- Update DatePicker.tsx to use extracted Slots type
- Update app-store utils to use BookerEventForAppData type

This prevents the server build from pulling in React files through
transitive imports from @calcom/features barrel exports.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: update Segment.test.tsx mock path to @calcom/trpc/react

The test was mocking @calcom/trpc but importing from @calcom/trpc/react.
After the entrypoint separation, the mock path needs to match the import path.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: temporarily restore || true to unblock PR merge

The pre-existing Prisma type errors (~345 errors) will be addressed in a follow-up PR.
This allows the two-phase build architecture changes to be merged first.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Run trpc build as part of API v2 build

* Removed the bridge file

* refactor: extract event type schemas to server-safe file

- Create packages/features/eventtypes/lib/schemas.ts with createEventTypeInput and EventTypeDuplicateInput
- Update types.ts to re-export schemas from the new server-safe location
- Update tRPC schema files to import from schemas.ts instead of types.server.ts
- Delete types.server.ts (was duplicating ~200 lines unnecessarily)

This keeps the server build graph clean while avoiding code duplication.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Removed the optionality of the tRPC builds

* Removed the extra command for API v2

* refactor: rename calendars/lib/slots.ts to types.ts

Per Keith's feedback, renamed the file to types.ts since it contains type definitions.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* Added back tRPC build:server for API v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-20 23:43:04 -03:00
Keith WilliamsandDevin AI 0e3696f20c chore: dedupe yarn.lock to remove duplicate package versions (#26068)
* chore: dedupe yarn.lock to remove duplicate package versions

- Consolidated 762 duplicate package versions
- Reduced yarn.lock from 51,211 lines (1.7MB) to 44,471 lines (1.5MB)
- Removed 7,071 lines (~200KB) of redundant dependency entries
- Major packages deduplicated include: resolve, semver, type-fest, commander, glob, lru-cache, dotenv, @babel/* packages, typescript, tslib, postcss, and many more

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: resolve type errors in managed event types and react-select components

- Add Zod-compatible versions of allManagedEventTypeProps and unlockedManagedEventTypeProps
  that only include scalar fields (excludes Prisma relation fields)
- Update handleChildrenEventTypes.ts and queries.ts to use the new Zod-compatible props
- Fix react-select CSS type errors in Select.tsx files by using Object.assign
  instead of spread operator to avoid TypeScript type inference issues
- Fix lint warning in updateNewTeamMemberEventTypes by using if statement

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: derive eventType parameter type from actual query result

Use Awaited<ReturnType<typeof getEventTypesToAddNewMembers>>[number] to ensure
type safety at call sites, avoiding Prisma type namespace mismatches.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: disable turbo cache for @calcom/trpc#build to prevent stale type errors

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: correct field names in API v1 validation schemas

- Remove timeZone from booking schema (field doesn't exist on Booking model)
- Remove bookingId from destination-calendar schema (field doesn't exist, only booking relation)
- Change avatar to avatarUrl in user schema (correct field name)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use Object.assign for react-select styles to fix TypeScript spread type errors

The spread operator causes TypeScript to compute an incompatible type with
CSSObjectWithLabel due to the accentColor property. Using Object.assign
preserves the correct type inference.

Fixed files:
- FormEdit.tsx
- DestinationCalendarSelector.tsx (features and platform)
- TimezoneSelect.tsx
- ApiKeyDialogForm.tsx
- Select.tsx (features/form)
- WebhookForm.tsx

Also fixed pre-existing lint warnings:
- Constant truthiness in label assignment
- Unused variant parameter

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove extra fields from allManagedEventTypePropsForZod to match original behavior

The Zod-compatible version should only include scalar fields that were in the
original allManagedEventTypeProps. Removed instantMeetingScheduleId, profileId,
rrSegmentQueryValue, and assignRRMembersUsingSegment which were incorrectly
added and caused test failures by including extra fields in Prisma update payloads.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove access to fields not in Zod schema

- Remove unnecessary destructuring of profileId and instantMeetingScheduleId
  from managedEventTypeValues in handleChildrenEventTypes.ts (these fields
  are already sourced from other variables)
- Set rrSegmentQueryValue to undefined directly in queries.ts instead of
  accessing it from managedEventTypeValues (not applicable for managed children)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add name property to mock credentials and revert turbo cache change

- Add name property to MockCredential type and factory function in
  InstallAppButtonChild.test.tsx to match expected credentials type
- Revert turbo cache disable for @calcom/trpc#build (per review comment)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: revert API v1 validation changes and restore eslint comment

- Revert API v1 validation changes (booking.ts, destination-calendar.ts,
  user.ts) since API v1 is deprecated and these could be breaking changes
- Restore eslint-disable comment for @typescript-eslint/no-empty-function
  in Select.tsx that was accidentally removed

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add inputs to @calcom/trpc#build to properly invalidate cache

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: properly fix API v1 validation schemas for stricter zod 3.25.76

The yarn dedupe upgraded zod from 3.22.4 to 3.25.76, which has stricter
.pick() typing that now properly rejects picking non-existent fields.

Changes:
- user.ts: Pick avatarUrl (actual Prisma field) and extend with avatar
  for API v1 backward compatibility
- booking.ts: Remove timeZone from pick (not a field on Booking model,
  only exists in nested attendees/user objects)
- destination-calendar.ts: Remove bookingId from pick (not a field on
  DestinationCalendar model)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: remove turbo.json inputs for @calcom/trpc#build to use cached artifacts

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use robust selector for react-select option in routing forms E2E test

The previous selector used .nth(1) which assumed the email text appeared
exactly twice in the DOM in a specific order. This broke when react-select
was upgraded from 5.7.2 to 5.8.0 via yarn dedupe.

The new approach waits for the react-select listbox to appear and clicks
the option within it, which is more robust against DOM structure changes.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-20 23:30:03 -03:00
github-actions[bot] f846126a2d chore: version packages (#25833)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-20 22:05:28 +00:00
Keith WilliamsandDevin AI 825f55c0a1 fix: extract shared types to non-React modules to fix circular dependencies (#26083)
- Move InvalidAppCredentialBannerProps to packages/features/users/types/invalidAppCredentials.ts
- Add WorkflowListType to packages/features/ee/workflows/lib/types.ts
- Update server file imports to use new type locations
- Update React component imports to re-export from new locations

This fixes circular dependencies where server files were importing from React
component modules that import from @calcom/trpc, creating:
server -> component -> @calcom/trpc -> react -> server (circular)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-21 01:43:49 +05:30
Pedro Castro 9ae2381755 fix(auth): validate IdP authority before SAML account linking (#26005)
* fix(auth): validate IdP authority before SAML account linking

Adds verification that SAML IdP is authoritative for the email domain
before allowing account conversion

* fix(auth): deny by default on missing SAML tenant + optimize membership query

 - Block account conversion when tenant is missing (deny by default)
 - Replace JOIN + ILIKE with two indexed lookups for O(1) performance

* refactor(auth): apply data minimization to security logs
2025-12-20 17:45:18 +00:00
Anik Dhabal Babu a37805439b fix: fix credential type mismatch in AppPage component (#25802)
* test

* update

* Refactor create-event-type.input.ts for slug handling

Removed unused import and transformation for slug.

* Remove slugify transformation from slug field

Removed slugify transformation from slug property.

* Remove slugify transformation from slug field

Removed slugify transformation from slug property.
2025-12-20 17:11:35 +00:00
253c33df33 perf: (googlecalendar): batch freebusy calls by delegation credential (#24332)
* perf(googlecalendar): batch freebusy calls by delegation credential

- Group selectedCalendars by delegationCredentialId before making API calls
- Make one batched freebusy query per delegation credential group
- Reduces total API calls while respecting credential boundaries
- Maintains existing caching behavior per group
- Updated both getAvailability and getAvailabilityWithTimeZones methods
- Added groupCalendarsByDelegationCredential helper method
- Handles edge case when no calendars provided but fallbackToPrimary is true
- Fixed linting issue: replaced hasOwnProperty with 'in' operator

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

* test(googlecalendar): add test for delegation credential batching

- Verify calendars are grouped by delegationCredentialId
- Ensure exactly 3 API calls made for 3 delegation credential groups
- Confirm all busy times from different groups are properly returned
- Fix type-safety issues by replacing 'as any' with proper type constraints
- Fix ESLint warnings: unused variables and any types in mock functions

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

* fix(googlecalendar): ensure fallback logic works with empty calendar groups

- Handle empty calendar groups by ensuring at least one iteration
- Add test for chunking groups larger than 50 calendars
- Verify all delegation credential batching logic works correctly

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

* fix: fix remaining type errors from merge conflict resolution

- Changed getCacheOrFetchAvailability to getFreeBusyData in getAvailabilityWithTimeZones
- Removed orphaned merge conflict marker in test file

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

* fix: reset test file to original PR version and update method name

- Reset CalendarService.test.ts to original PR version (0e9eb9e97a)
- Updated getCacheOrFetchAvailability to getFreeBusyData to match main branch

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

* fix: reset test file to main branch version

The original PR's test file had tests for caching features that have been
removed from main. Reset to main's version to fix type errors.

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

* test(googlecalendar): add tests for delegation credential batching logic

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

* Revamp devin's implementation

* Remove comsoles.log

* fix(tests): update delegation credential batching tests to match reimplementation

- Remove tests for private methods that no longer exist (groupCalendarsByDelegationCredential, chunkArray)
- Update getAvailability test to verify calendar fetching without expecting multiple API calls per delegation credential
- Keep existing tests for fallback to primary calendar and non-google calendar handling

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

* Remove dead code

* improve documentation

* docs: add README explaining Google Calendar availability batching feature

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

* docs: translate README to English

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

* docs: move README to calendar-batch package with comprehensive documentation

- Remove README from googlecalendar lib (wrong location)
- Add comprehensive README to packages/features/calendar-batch/
- Document CalendarBatchService and CalendarBatchWrapper
- Explain how getCalendar() integrates with batching
- Include architecture, data model, and performance considerations

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

* fix: address cubic-dev-ai review comments

- Remove misleading comment from getCalendar.ts cache block
- Fix typo 'optmization' -> 'optimization' in comment
- Add comprehensive tests for CalendarBatchWrapper batching behavior
  - Test separate calls for calendars without delegationCredentialId
  - Test batching calendars with same delegationCredentialId
  - Test chunking into groups of 50 for API limits
  - Test mixed calendars handling
  - Test fallbackToPrimary with empty array
  - Test result flattening from batched calls
  - Test pass-through methods delegation

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

* fix: add shouldServeCache param to CalendarBatchWrapper and verify batching call count

- Fix CalendarBatchWrapper.getAvailability signature to match Calendar interface (add shouldServeCache param)
- Update CalendarBatchWrapper tests to pass shouldServeCache parameter
- Add integration test in CalendarService.test.ts that verifies CalendarBatchWrapper makes separate API calls for different delegationCredentialIds (call count assertion)
- This fixes the getCalendarsEvents test failures caused by signature mismatch

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

* Improve CalendarBatchImplementation

* test: add shouldServeCache forwarding and order-independent batching verification tests

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

* test: make CalendarBatchWrapper tests order-independent

Refactored tests to avoid relying on Promise.all execution order:
- 'should make separate calls for calendars without delegationCredentialId'
  now uses set comparison instead of toHaveBeenNthCalledWith
- 'should batch calendars with the same delegationCredentialId together'
  now finds calls by delegation credential instead of call order

This addresses Sean's review comment about potential flakiness due to
Promise.all not guaranteeing execution order of parallel promises.

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

* Remove hardcoded ID

* test: add comprehensive tests for resolveCalendarServeStrategy

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* feat: use Promise.allSettled for partial failure handling in CalendarBatchWrapper

- Changed Promise.all to Promise.allSettled in getAvailability and getAvailabilityWithTimeZones
- Returns partial results when some batches fail instead of failing entirely
- Logs warnings for failed batches with error details
- Added tests for partial failure scenarios

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* test: add comprehensive tests for getAvailabilityWithTimeZones

- Added batching behavior tests (separate calls, batching by delegationCredentialId, chunking)
- Added partial failure handling tests (partial results, all fail, no throw)
- Added edge case test for underlying calendar not implementing the method
- Total: 24 tests now covering both getAvailability and getAvailabilityWithTimeZones

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add required serviceAccountKey fields to delegatedTo mock objects

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add missing client_id and private_key to serviceAccountKey mock

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: keith@cal.com <keithwillcode@gmail.com>
2025-12-20 13:45:44 -03:00
ed0c9392a9 fix: E2E flakes after splitting the tests (#26059)
* fix: split confirm-emails e2e test to authenticate as booking owner

The test was flaky because it authenticated as an admin user (authEmail)
but created bookings for different users (emailsEnabledSetup.user and
emailsDisabledSetup.user). When confirming/declining bookings, the
ApiAuthGuard + BookingUidGuard rejected requests with 401 because the
authenticated user wasn't the booking owner.

The fix splits the test into two separate describe blocks, each with its
own app instance that authenticates as the actual booking owner. This
ensures the authenticated user always matches the booking owner.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* fix: add unauthenticated app for attendee reschedule test

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* fix: use real API key authentication instead of withApiAuth mock

- Replace withApiAuth mock with real API key authentication using ApiKeysRepositoryFixture
- This avoids Passport strategy registration conflicts between test suites
- For attendee reschedule test, use unauthenticated request (no auth header) since endpoint uses OptionalApiAuthGuard
- Remove separate unauthenticatedApp instance as it's no longer needed

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

* fix flakes

* update

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-20 13:04:21 -03:00
Anik Dhabal Babu 0098b076a1 fix: cache build error on CI (#25958)
* fix(slots): hide out-of-office slots across timezones

* update

* fix build error
2025-12-20 15:24:56 +00:00
sean-brydon 95a4567f35 perf: use compound key (#25970) 2025-12-20 14:57:55 +00:00
spandevandDhairyashil Shinde d8ddb466b0 fix: slots in email embed sorted (#25676)
* fix: slots in email embed sorted

* fix: removed mutating of original array

* fix: incorrect access of sortedTimes

---------

Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-20 13:12:50 +00:00
Benny Joo 6e5b812286 fix: add missing Korean translation (#26075) 2025-12-20 15:02:03 +05:30
Alex van Andelandcubic-dev-ai[bot] 8568cab283 fix: Handle error when no default calendar exists for a o365 account (#26074)
* fix: Handle error when no default calendar exists for a o365 account

* Update packages/app-store/office365calendar/api/callback.ts

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

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2025-12-20 06:33:46 +00:00
Alex van Andel 8d04a23bce chore: release v6.0.3
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2025-12-20 01:00:01 +00:00
dd8477c0bf fix(typo): correct spelling of organization in error message (#26035)
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
2025-12-20 00:16:18 +00:00
BetoandDhairyashil aebfd4919b feat(companion): Update availability screen to use liquid glass (#26041)
* Use previous header for android

* use activity instead of ternary statements

* update layout to use header buttons in availability screen

* fix styles and add context menu

* add set as default action

---------

Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
2025-12-19 19:05:26 +00:00
Dhairyashil Shinde 69a857ad98 feat(companion): Multi-browser extension support (Chrome, Firefox, Safari, Edge, Brave) and fix text node errors (#26063)
* feat(companion): add multi-browser OAuth support for extension

- Add browser-specific OAuth client ID and redirect URI configuration
- Support Chrome, Firefox, Safari, Edge, and Brave browsers
- Add build scripts for each browser target (ext:build-{browser})
- Fix Brave Shields compatibility for production builds
- Add EXTENSION_SETUP.md documentation

BREAKING CHANGE: None - backward compatible with existing Chrome config

* fix(companion): replace && conditional rendering with ternary operators

Replace all `{condition && (<Component />)}` patterns with explicit
`{condition ? (<Component />) : null}` syntax across the companion app.

This fixes "Unexpected text node: . A text node cannot be a child of
a <View>" errors that occur with react-native-css-interop when using
&& conditional rendering in React Native web builds.

Files updated:
- app/event-type-detail.tsx (16)
- app/booking-detail.tsx (10)
- app/(tabs)/bookings.tsx (8)
- app/(tabs)/availability.tsx (6)
- app/availability-detail.tsx (5)
- app/(tabs)/(event-types)/index.tsx (4)
- components/event-type-detail/tabs/LimitsTab.tsx (9)
- components/event-type-detail/tabs/BasicsTab.tsx (3)
- components/event-type-detail/tabs/AdvancedTab.tsx (3)
- components/event-type-detail/tabs/RecurringTab.tsx (1)
- components/event-type-detail/tabs/AvailabilityTab.tsx (1)
- components/event-type-list-item/EventTypeListItem.ios.tsx (3)
- components/BookingActionsModal.tsx (2)
- components/Tooltip.tsx (1)
- components/LocationsList.tsx (1)
- components/Header.tsx (1)
- components/EmptyScreen.tsx (1)

* correct command for edge

* dont break ci

* deslop ai
2025-12-19 23:50:20 +05:30
Pedro Castro af4a10c008 fix(seo): prevent booking confirmation pages from being indexed (#26058)
Booking confirmation pages contain PII (names, emails, phone numbers)
and should not be indexed by search engines

- Add robots noindex to /booking/[uid]/page.tsx
- Add robots noindex to /booking/[uid]/embed/page.tsx

Follows same pattern as not-found.tsx
2025-12-19 13:34:49 -03:00
Pedro Castro 90a83a611c docs: add ListEventTypes atom documentation (#25775)
- Add list-event-types.mdx with Quick start, Props, Demo video, and Combining with EventTypeSettings sections
- Add list_event_types_light.png screenshot
- Update mint.json navigation to include new page
2025-12-19 13:23:07 -03:00
sean-brydon b33d8c64df add turbo repo (#26051) 2025-12-19 14:27:19 +00:00
Carina WollendorferandCarinaWolli 73b276015c fix: remove pkce check for refreshToken endpoint (#26050)
* remove pkce check for refreshToken endpoint

* adjust e2e tests

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2025-12-19 15:18:49 +01:00
Abhishek 9c223fc718 fix: settings icon at app setup - event types (#26048)
* fix/setting-icon-app-card

* fix: settings icon app card
2025-12-19 14:13:58 +00:00
Eesh MidhaandRajiv Sahal 6910b85301 refactor(dialog): standardize icon container styling (#26036)
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
2025-12-19 19:22:04 +05:30
125ed4f6f7 feat: update favicons with new Cal design (#25392)
* feat: add environment-based favicons (prod vs dev)

- Add cal-prod.png (dark/gray) favicon for production environments
- Add cal-dev.png (red) favicon for development/localhost environments
- Update FAVICON_16 and FAVICON_32 constants to switch based on IS_PRODUCTION

Co-Authored-By: peer@cal.com <peer@cal.com>

* feat: add higher resolution icons for all icon types (apple-touch, android-chrome, mstile)

- Add 180x180 apple-touch-icon for prod and dev
- Add 150x150 mstile icons for prod and dev
- Add 192x192 and 256x256 android-chrome icons for prod and dev
- Update all icon constants to use IS_PRODUCTION switching

Co-Authored-By: peer@cal.com <peer@cal.com>

* refactor: simplify favicon to single new design

- Remove environment-based favicon switching
- Update all icon files with new Cal favicon design
- Remove dev/prod icon variants
- Update constants to use static icon paths

Co-Authored-By: peer@cal.com <peer@cal.com>

* feat: add favicon.ico with new Cal favicon design

Co-Authored-By: peer@cal.com <peer@cal.com>

* chore: update favicon icons with final design

Co-Authored-By: peer@cal.com <peer@cal.com>

* chore: update favicon icons with final design v3

Co-Authored-By: peer@cal.com <peer@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-19 13:12:14 +00:00
Kartik Labhshetwar 2cab5475ce fix: improve CustomEmailTextField styling and focus behavior (#26024) 2025-12-19 13:08:28 +00:00
Syed Ali Shahbaz 5032d2716d fix: Add email to user select in credential to ensure consistent type (#26020)
* Add email to user select

* type fix
2025-12-19 13:03:04 +00:00
3ccf001e1d fix: add name property to delegation credentials for type compatibility (#26022)
* fix: add name property to delegation credentials for type compatibility

The MultiDisconnectIntegration component expects credentials with user.name property,
but delegation credentials only had user.email. This caused a type mismatch when
spreading both credential types together in appCredentialsByType handler.

Added name: null to the delegation credentials user object to ensure type compatibility.

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

* fix: update getUserDisplayName to check value instead of just property existence

The narrowing logic was causing TypeScript to infer 'never' type because
after adding name property to delegation credentials, the 'name in user'
check always passes. Now we check if name has a truthy value before using it.

Also fixed lint warning by using optional chaining for onSuccess callback.

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

* fix: add explicit return type and typeof checks to getUserDisplayName

The function now has an explicit return type of string | null and uses
typeof checks to ensure proper type narrowing. This prevents TypeScript
from inferring a wider return type that includes {} when the user object
has properties with non-string types.

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

* test: update delegation credential test to include name property

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-19 12:21:48 +00:00
4c282ea9ca feat: add promotion codes support to SMS credit purchases (#23774)
Co-authored-by: peer@cal.com <peer@cal.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-19 08:57:13 -03:00
Anik Dhabal Babu 1135e47338 fix: render markdown in custom page redirect messages (#25987)
Before:-
<img width="1986" height="762" alt="image (26)" src="https://github.com/user-attachments/assets/90e16a5c-a8f1-4269-8873-8854a82c012e" />
<img width="3456" height="2068" alt="image (27)" src="https://github.com/user-attachments/assets/6714a1d5-454d-4fe7-b6ce-84120353a10a" />
After:-
<img width="977" height="456" alt="Screenshot 2025-12-17 at 9 09 22 PM" src="https://github.com/user-attachments/assets/449611ab-8d84-41e2-a342-0e334562cec5" />
2025-12-19 16:44:06 +05:30
Udit TakkarandAnik Dhabal Babu 68e670ae06 fix: hide OOO slots across timezones (#25966)
* fix: use organizer timezone

* fix: use organizer timezone

* fix: use organizer timezone

* fix type error

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-19 08:12:39 -03:00
sean-brydon 8b13979a41 chore: implement posthog tracking company email upgrade point (#25977)
* implement posthog tracking

* track dismiss
2025-12-19 10:39:30 +00:00
4beebd227b fix: flaky E2E tests and refactor (#25974)
* fix: flaky E2E tests and refactor

* fix

* fix: week limit tests to use same week for pre-booking and UI booking

The week limit tests were failing because the pre-booking was created in
week 1 but the UI booking was done in week 2. Since weekly limits are
per-week, the pre-booking didn't count toward the limit in week 2.

Fixed by keeping both bookings in the same week:
- Pre-booking on Monday (satisfies daily limit, counts toward weekly)
- UI booking on Tuesday (same week, hits weekly limit of 2)

This ensures the weekly limit is properly tested and all remaining
weekdays in the week get blocked after hitting the limit.

Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-19 07:35:47 -03:00
Prateek Dwivedi 853358d9c4 fix(logging): replace console.log with logger.error in editLocation handler (#26037) 2025-12-19 08:15:44 +00:00
PallavandAnik Dhabal Babu 7dcf4ee5c8 fix: prevent custom calendar for team event (#26033)
* fix: prevent custom calendar for team event

* Remove commented-out disableRescheduling code

Removed commented-out code for disabling rescheduling.

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-19 07:22:27 +00:00
42f2c170aa feat: add coss-ui core package (#25984)
* Install/add components in base coss-ui package

* fix components imports

* add yarn script to pull

* Update packagejson

* remove skeleton duplicates

* feat: allow importing components with the cli

* fix: update exports in package.json to reference styles.css instead of globals.css

* add lucide dep

* refactor: re-pull components

* refactor: remove unused registries section from components.json

* refactor: implement changes suggested by Volnei

* refactor(wip): implemet coss ui components on the profile page

* fix src/src problem

* update command to overwrite existing components

* pulled from registry

* restore globals.css

* feat: add pull script

* feat: enhance pull script with validation and error handling

* remove duplicate components

* refactor: reimport coss component and fix ts errors

* fix: components pulling

* chore: regenerate yarn.lock

* chore: remove tailwindcss/forms

* trying different moduleResolution

* TypeScript requires module to also be "NodeNext".

* remove unnecessary changes

* type fixes plus resolve @coss/ui

* use bundler tsconfig

* add missing deps to features and ui

* Add bundler to other packages

* fix module enext resolution with bundler

* remove reduant files

* remove package json from features

* revert unrelated change to the PR

---------

Co-authored-by: pasqualevitiello <pasqualevitiello@gmail.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
2025-12-18 19:57:21 +00:00
Peer RichelsenandDhairyashil 3423777ee3 feat: gmail, outlook, yahoo links during email verification (#26038)
* added gmail, outlook, yahoo links during email verification

* added proton

* enable for self-hosters too

* undo i18n

* Discard changes to companion/bun.lock

* nit

* refactor: code quality improvments

---------

Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
2025-12-18 19:56:38 +00:00
Dhairyashil ShindeandVolnei Munhoz c8a8c37b45 fix(companion): prevent localhost URL from being baked into production extension builds (#26032)
* fix(companion): separate dev and prod build scripts to prevent localhost in production

- Add ext:build-dev and ext:build-prod scripts with clear separation
- Add BUILD_FOR_STORE flag to force production URL in store builds
- Add visual build indicators (store / dev) for clarity
- Prevent EXPO_PUBLIC_COMPANION_DEV_URL from leaking into production builds

* update commands to work for ci

* update version

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2025-12-18 19:19:04 +00:00
Benny JooandAnik Dhabal Babu f291c1c4e7 fix: add mergeWithEnglishFallback for i18n translations (#26016)
* fix

* fix

* fix

* fix

* Improve translation cache handling in i18n.ts

Refactor translation cache retrieval and fallback logic.

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-18 16:47:54 +00:00
Hariom BalharaandDevin AI 71792bdeaa fix: ensure linkFailed event fires for 404, 500, and 403 errors in embeds (#25261)
- Add CalComPageStatus handling in NotFound and ErrorPage components using useLayoutEffect
- Remove redundant pageStatus logic from PageWrapperAppDir.tsx since App Router error/notFound pages set status themselves
- Refactor embed-iframe.ts: split checkPageStatusAndHandleError into hasPageError() and handlePageError()
- Add page status checks before firing linkReady to catch errors set after initialization
- Ensures linkFailed event fires correctly for all error status codes in embed scenarios

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-18 16:30:32 +00:00
Eunjae Lee 945ded951f fix: integration test of booking audit service (#26027) 2025-12-18 15:26:03 +00:00
Pedro CastroandMorgan 975fb21d86 feat(atoms): add ListEventTypes atom to enable event type management (#25047) (#25113)
* feat: add ListEventTypes atom (#25047)

* feat: add ListEventTypes atom for Platform (#25047)

- Add EventTypeListItem component in @calcom/features
- Add ListEventTypesPlatformWrapper with delete functionality
- Implement useAtomGetAllEventTypes hook
- Update backend to include slug, description, length
- Add 11 unit tests (65% coverage)
- Add 3 i18n keys

No breaking changes. Backward compatible.

* refactor(eventtypes): improve EventTypeListItem readability

- Extract EventTypeContent and EventTypeActions sub-components
- Add formatEventTypeDuration helper (90min → '1h 30m')
- Use Badge for duration display (consistency with EventTypeDescription)
- Use polymorphic Wrapper component (DRY)
- Add comprehensive tests
- Reduce main component size

Addresses @volnei feedback

* refactor: replace window.confirm with ConfirmationDialog

- Replace native window.confirm with ConfirmationDialogContent

- Update test mocks for Dialog components

- Fix HTML nesting (div instead of p for Badge container)

- Follows Cal.com pattern from AvailabilitySettings

Addresses @ThyMinimalDev feedback

* fix: add aria-label to options button for accessibility

* test: update getBulkEventTypes test to include new fields (description, slug, length)

* refactor: move EventTypeListItem to atoms package

---------

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2025-12-18 12:24:41 -03:00
Anik Dhabal Babuandcubic-dev-ai[bot] b20b52a1f8 fix: update tempOrgRediret on updating org slug (#25838)
* fix: update tempOrgRediret on updating s
lug

* Update packages/trpc/server/routers/viewer/organizations/adminUpdate.handler.ts

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

* refactor

* fix

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2025-12-18 13:18:56 +00:00
Benny Joo 176aeaafd8 refactor: trpc test file is importing @calcom/web (#25979)
* add eslint config

* refactor test
2025-12-18 10:10:46 -03:00
Anik Dhabal Babu 9ba867922a fix type error (#26021) 2025-12-18 12:55:54 +00:00
Hariom BalharaandDevin AI f1011ddd08 chore: Improves the core booking audit architecture by adding new capabilities and simplifying the existing interfaces. (#25872)
* feat(booking-audit): extract core audit system changes from PR 25125

This PR extracts core audit infrastructure changes without integration changes:

1. New action services introduced:
   - SeatBookedAuditActionService
   - SeatRescheduledAuditActionService

2. Simplification of ActionService interface:
   - Streamlined IAuditActionService interface
   - Reduced TypeScript burden with cleaner type definitions

3. ActionSource support:
   - Added BookingAuditSource enum (API_V1, API_V2, WEBAPP, WEBHOOK, UNKNOWN)
   - Added source and operationId fields to BookingAudit model

4. New AuditAction types:
   - SEAT_BOOKED
   - SEAT_RESCHEDULED
   - APP actor type

5. New BookingAuditAccessService:
   - Permission-based access control for audit logs
   - Added readTeamAuditLogs and readOrgAuditLogs permissions

6. Fixes in the logs viewer flow:
   - Enhanced BookingAuditViewerService with improved filtering
   - Local AttendeeRepository for actor enrichment

Changes are contained within packages/features/booking-audit with minimal
outside changes (permission registry only).

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* refactor(booking-audit): streamline action handling and enhance localization

- Replaced action icon retrieval with a mapping object for improved clarity and performance.
- Introduced constants for actor role labels to simplify role retrieval.
- Added new localization strings for audit log permission errors and organization requirements.
- Updated various service and repository interfaces to enhance type safety and clarity.
- Removed deprecated architecture documentation and adjusted related imports for consistency.

These changes aim to improve code maintainability and user experience in the booking audit system.

* fix(booking-audit): enhance actor role localization and operation ID tracking

- Updated actor role labels in the booking logs view to use lowercase for consistency.
- Improved localization by wrapping actor role display in a translation function.
- Added operationId field to audit logs for better correlation of actions across multiple bookings.
- Enhanced BookingAuditViewerService to include operationId in enriched audit logs.
- Updated integration tests to verify consistent operationId across related audit logs.

These changes aim to improve localization accuracy and facilitate better tracking of user actions in the booking audit system.

* feat: integrate credential repository and enhance app actor handling

- Added CredentialRepository to manage app credentials, including a method to find credentials by ID.
- Updated BookingAudit system to support app actors identified by credential ID, improving actor attribution and audit clarity.
- Introduced a new utility function to map app slugs to display names, enhancing the user experience in audit logs.
- Modified relevant interfaces and types to accommodate the new credential handling and app actor structure.
- Enhanced BookingAuditViewerService to display app names based on credentials, ensuring accurate representation in audit logs.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-18 12:46:24 +00:00
9019be58ed fix: allow required check to pass when E2E tests are skipped due to missing label (#26006)
* fix: allow required check to pass when E2E tests are skipped due to missing label

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

* revert: remove unnecessary integration-test condition change

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

* chore: trigger fresh CI run

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

* all should pass to allow merge

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-18 08:49:12 -03:00
Eunjae LeeandDevin AI cef8610925 feat: add enabled column to UserFeatures and TeamFeatures for tri-state semantics (#25765)
* feat: add enabled column to UserFeatures and TeamFeatures for tri-state semantics

- Add enabled Boolean column to UserFeatures model with default true
- Add enabled Boolean column to TeamFeatures model with default true
- Update FeaturesRepository to use tri-state semantics:
  - enabled=true: feature is explicitly enabled
  - enabled=false: feature is explicitly disabled (blocks inheritance)
  - No row: inherit from team/org level
- Update SQL queries to check enabled=true for feature access
- Add enableFeatureForTeam method to interface and implementation

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* update comments

* add integration tests

* add more test

* select enabled only

* no @default(true)

* fix types and tests

* add missing enabled

* add missing enabled

* rename enableFeatureForTeam to updateFeatureForTeam and support FeatureState

* refactor: rename updateFeatureForTeam to setTeamFeatureState

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix integration test

* fix tests

* add more tests

* add missing enabled

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-18 07:16:20 -03:00
Syed Ali Shahbaz 056922b6ee feat: add webhook versioning (#23861)
* add webhook version schema

* version the code

* update version from numeric to date val

* migration

* update schema and build factory

* update string

* move version picker

* tooltip instead of infobadge

* --

* fix type

* --

* fix type

* fix type

* --

* fix messed up merge

* improvements to payloadfactory

* extract version off of DB and instead keep it in IWebhookRepository

* fix webhookform

* fix type safety and routing ambiguity

* scalable with easier factory extensions and base definition

* fix types

* --

* --

* clean up prisma/client type imports

* fix

* type fix

* type fix

* cleanup

* add tests and registry changes

* unintended file inclusion

* type-fix

* select in repo

* --

* explicit return type

* --

* fix type

* fixes

* feedback 1

* feedback 2

* use enum instead of string

* fixes
2025-12-18 09:36:22 +02:00
Dhairyashil Shinde 42bd4b4057 fix: make isReschedule required in checkIfBookerEmailIsBlocked (#26002) 2025-12-17 19:52:10 -03:00
sean-brydonandcubic-dev-ai[bot] 64767cec4f chore: add onboarding events in posthog (#25981)
* add onboarding events in posthog

* Update apps/web/modules/onboarding/organization/teams/organization-teams-view.tsx

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

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2025-12-17 22:43:54 +00:00
Volnei MunhozandPeer Richelsen e84550ba76 chore: Isolate companion build (#25985)
* Isolate companion build

* Fix typo

* Update .github/workflows/pr.yml

* Improve branch protection

* integration tests missing

* fix typo

* fix to only have required

* fix to only have required

* fix to only have required

* adjust to keep as before

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2025-12-17 22:42:10 +00:00
Keith Williams e6d0253950 chore: Change atoms build command to build-npm (#25996)
* chore: Change atoms build command to build-npm to avoid turbo compilations

* Updated turbo.json atoms#build reference

* Updated atoms production build for CI
2025-12-17 16:30:54 -03:00
Dhairyashil ShindeandPeer Richelsen 471d1caac9 fix(companion): Fix Gmail OAuth integration (#25978)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2025-12-17 15:13:54 -03:00
Keith WilliamsandDevin AI 15b1675db1 perf: reduce TypeScript type bloat in tRPC package via z.ZodType annotations (#25845)
* fix: prevent Prisma conditional types from leaking into .d.ts files

This PR addresses TypeScript performance issues caused by Prisma's conditional types leaking through the type graph:

1. Replace Prisma.UserGetPayload with explicit UpdatedUserResult type in updateProfile.handler.ts
2. Replace Prisma.EventTypeGetPayload with explicit UpdatedEventTypeResult type in update.handler.ts
3. Replace Prisma.OutOfOfficeEntryGetPayload with explicit OOOEntryResult type in outOfOfficeCreateOrUpdate.handler.ts
4. Replace Prisma.CredentialGetPayload with explicit Credential type in getUserConnectedApps.handler.ts
5. Fix inconsistent DI usage in EventTypeRepository - use this.prismaClient instead of global prisma singleton

These changes prevent massive recursive Prisma types from propagating through the type graph and being emitted in .d.ts files, which improves TypeScript performance.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: correct reasonId type to number | null in OOOEntryResult

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* perf: add z.ZodType annotations to reduce .d.ts file sizes

- Annotate exported Zod schemas with z.ZodType<T> to prevent full Zod generic tree from being emitted in declaration files
- eventTypes/types.d.ts reduced from 231KB to 115KB (50% reduction)
- _app.d.ts reduced from 782KB to 753KB (3.7% reduction)
- viewer/_router.d.ts reduced from 722KB to 695KB (3.7% reduction)
- workflows/getAllActiveWorkflows.schema.d.ts significantly reduced
- routing-forms/formMutation.schema.d.ts significantly reduced

Files modified:
- packages/trpc/server/routers/viewer/eventTypes/types.ts
- packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.schema.ts
- packages/trpc/server/routers/apps/routing-forms/formMutation.schema.ts
- packages/features/eventtypes/lib/types.ts

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* perf: comprehensive z.ZodType annotations to reduce .d.ts file sizes

Applied z.ZodType<T> annotations to 89 schema files across the tRPC package.
This prevents TypeScript from emitting the full Zod generic tree in .d.ts files,
reducing declaration file sizes for downstream consumers.

Files modified include schemas in:
- viewer/teams (round-robin, managed events, invitations, etc.)
- viewer/bookings (get, find, confirm, etc.)
- viewer/eventTypes (get, delete, getByViewer, etc.)
- viewer/workflows (list, delete, verify, etc.)
- viewer/auth (changePassword, verifyPassword, etc.)
- viewer/apiKeys (create, delete, edit, etc.)
- viewer/sso (get, update, delete, updateOIDC)
- viewer/oAuth (addClient, generateAuthCode)
- viewer/calendars (setDestinationCalendar)
- viewer/deploymentSetup (update, validateLicense)
- apps/routing-forms (formQuery, deleteForm, etc.)
- publicViewer (submitRating, markHostAsNoShow, etc.)
- loggedInViewer (eventTypeOrder, routingFormOrder, etc.)

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: revert slots/types.ts z.ZodType annotation that caused type mismatch

The slots/types.ts schema has a transform that converts duration from
string to number, which makes the z.ZodType<T> annotation incompatible.
Reverting to original to fix Unit test failure.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use 3-generic z.ZodType pattern for schemas with .default() modifiers

For schemas with .default() modifiers, the input and output types differ:
- Input type: field is optional (what callers send)
- Output type: field is required (what handlers receive after parsing)

This commit:
1. Fixes get.schema.ts (offset has .default(0))
2. Fixes removeMember.schema.ts (isOrg has .default(false))
3. Fixes resendInvitation.schema.ts (isOrg has .default(false))
4. Fixes listMembers.schema.ts (limit has .default(10))
5. Fixes getByViewer.schema.ts (limit has .default(10))
6. Reverts eventTypes/types.ts (complex transforms hard to model)
7. Reverts features/eventtypes/lib/types.ts (complex transforms hard to model)

The 3-generic pattern z.ZodType<Output, z.ZodTypeDef, Input> properly models
the difference between input and output types while still preventing the full
Zod generic tree from being emitted in .d.ts files.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use 3-generic z.ZodType pattern for schemas with transforms/defaults

- organizations/update.schema.ts: orgId has .transform() that converts string to number, so input type is string | number but output type is number
- publicViewer/event.schema.ts: fromRedirectOfNonOrgLink has .default(false), so input has it optional but output has it required

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use 3-generic z.ZodType pattern for updateProfile.schema.ts

Address reviewer feedback: isDeleted field in secondaryEmails has .default(false),
so input type has it optional but output type has it required.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* chore: remove explanatory comments from schema files

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: use 3-generic z.ZodType pattern for addClient.schema.ts enablePkce field

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: address Hariom's PR feedback

- Rename TGetInputSchemaInput to TGetInputRawSchema in get.schema.ts
- Use Prisma-free JsonValue type from @calcom/types/Json in updateProfile.handler.ts
- Fix publish.schema.ts with 3-generic pattern for z.coerce.number()

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix: add sort field to TGetInputSchema types

Added sort field to both TGetInputRawSchema and TGetInputSchema types
to match the Zod schema that was updated in main branch.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-17 15:06:57 -03:00
Calcom Bot c20f6cbdd6 feat: update translations via @LingoDotDev (#24385)
Hey team,

[**Lingo.dev**](https://lingo.dev) here with fresh translations!

### In this update

- Added missing translations
- Performed brand voice, context and glossary checks
- Enhanced translations using Lingo.dev Localization Engine

### Next Steps

- [x] Review the changes
- [x] Merge when ready
2025-12-17 13:30:35 -03:00
Benny Joo 03dd0c1501 refactor: Move SelectedCalendarRepository and WorkflowRelationsRepository from /lib to /features (#25982)
* wip

* wip
2025-12-17 16:05:03 +00:00
Beto 84ecb0e568 chore(companion): update dependencies to latest expo canary version (#25948)
* chore: update dependencies and update event types screen header

* refactor: simplify EventTypeListItem component by removing unused imports and code

- Removed unnecessary imports such as Tooltip and Svg.
- Cleaned up the component by eliminating commented-out code and unused props.
- Streamlined the button rendering in the context menu for better readability.

* feat: enhance EventTypes header with blur effect and clean up code

- Added blurEffect property to Stack.Header for improved visual aesthetics.
- Removed commented-out code to streamline the EventTypes component.
- Updated search bar properties for better user experience.

* refactor: update TabLayout and EventTypes for improved platform handling

- Simplified TabLayout by removing the liquid glass effect check and adding a WebTabs fallback for web support.
- Updated EventTypes header to conditionally apply blur effect based on liquid glass availability, enhancing visual consistency across platforms.

* feat: enhance TabLayout with MaterialCommunityIcons for improved UI

- Updated TabLayout to use MaterialCommunityIcons for tab icons, enhancing visual consistency.
- Added softwareKeyboardLayoutMode to app.json for better keyboard handling on mobile devices.

* feat: update TabLayout to prevent transparent background on iOS 18

- Added disableTransparentOnScrollEdge prop to NativeTabs to ensure a solid background on iOS 18 and older versions.
2025-12-17 15:37:52 +00:00
Anik Dhabal BabuandDevin AI 27775e5d03 fix: preserve newlines and links in calendar event descriptions (#25868)
The event type description is stored as HTML from the rich text editor.
When converting to plain text for calendar events, the HTML tags were
being stripped without preserving the formatting, causing:
- Newlines to be lost (text runs together)
- Links to be broken

This fix:
- Converts <br>, </p>, </div>, </li>, </h1-6> tags to newlines
- Preserves links in readable format: 'text (url)' or just 'url'
- Normalizes multiple newlines to max 2 for cleaner output

Affects all calendar integrations (Google, Outlook, etc.)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-17 15:02:12 +00:00
Benny Joo 0986864835 refactor: Move PrismaRoutingFormRepository from lib to /features/routing-forms (#25975)
* wip

* update import paths
2025-12-17 14:26:17 +00:00
Benny Joo cb7844fd22 refactor: Migrate repositories/services from /lib to /features (#25925)
* deployment

* update imports

* booking report

* update import paths

* watch list

* watch list

* api key

* api key

* selected slots

* wip

* event type translation

* work flow step

* booking reference

* fix tests

* fix

* fix

* migrate

* wip

* address

* fix
2025-12-17 14:14:50 +00:00
Eunjae LeeandDevin AI aaaff0705b fix(bookings): enable past date selection for cancelled bookings (#25644)
* refactor(data-table): clean up DateRangeFilter range options

- Replace 'past' | 'custom' with 'past' | 'future' | 'any' | 'customOnly'
- Add direction field to PresetOption for preset compatibility filtering
- Derive presets visibility automatically based on compatible presets
- Update bookings list to use new range values:
  - past -> 'past'
  - upcoming -> 'future'
  - unconfirmed/recurring/cancelled -> 'any'

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* feat(playground): add DateRangeFilter playground page with E2E tests

- Add playground page at /settings/admin/playground/date-range-filter
- Demonstrate all 4 range options: past, future, any, customOnly
- Add link to playground index page
- Add E2E tests for presets visibility and date restrictions

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix(playground): use correct meta.filter pattern for column filter config

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* clean up the playground esign

* add unit tests instead of e2e

* fix the implementation

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-17 13:47:51 +00:00
Benny Joo dd27d077ca refactor: Create TravelScheduleRepository and PrismaOrgMembershipRepository in /features (#25853)
* move repo to travelSchedule

* update imports

* mv

* update imports
2025-12-17 10:24:44 -03:00
Carina WollendorferandCarinaWolli 5fe3714edd feat: auto skip consent screen for trusted oauth clients (#25640)
* auto constent for trusted clients

* add loading state

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2025-12-17 13:00:12 +00:00
Eunjae LeeandDevin AI e0a28af46e feat(bookings): conditionally show heading/subtitle based on view (#25889)
* feat(bookings): conditionally show heading/subtitle based on view

- Add heading and subtitle props back to ShellMainAppDir in page.tsx
- Use headerClassName marker to identify the heading element
- Add useLayoutEffect in BookingCalendarContainer to hide heading when calendar view is mounted
- Restore heading visibility when switching back to list view

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor(bookings): extract shell heading visibility into reusable hook

- Create useBookingsShellHeadingVisibility hook with explicit visible parameter
- Move visibility logic from BookingCalendarContainer to BookingsContent
- Use data attribute to track if we hid the header (idempotent/Strict-Mode-safe)
- Explicit show/hide based on view state instead of relying on unmount

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor(bookings): simplify shell heading visibility hook

Remove HIDDEN_DATA_ATTR tracking since the header wrapper won't have
a hidden class from any other source

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-17 12:46:12 +00:00
Kartik Labhshetwar 970af8bd6a fix: change button color to destructive in WorkflowListPage (#25965) 2025-12-17 12:42:00 +00:00
Dhairyashil Shinde 2f1dd92677 feat(companion): open cal.com/app on new tab and fix extension/mobile UX issues (#25962)
* feat(companion): improve extension UX for new tab and fix mobile app issues

- Open cal.com/app when extension clicked on restricted pages (chrome://newtab, etc.)
- Auto-open sidebar when redirected to cal.com/app with ?openExtension=true
- Fix duplicate search bar in event types on web/extension
- Fix tab order mismatch on extension (Event Types, Bookings, Availability, More)
- Add logout confirmation modal for web since Alert.alert doesn't work
- Default COMPANION_DEV_URL to empty string for production builds

* fix(companion): use URL API for query parameter cleanup

Replace regex-based URL cleanup with URL API to properly handle
all query parameter positions. The previous regex produced invalid
URLs when openExtension=true was the first of multiple parameters
(e.g., ?openExtension=true&foo=bar became &foo=bar instead of ?foo=bar). fix(companion): wait for page load before auto-opening sidebar

Fix race condition where sidebar wouldn't auto-open on first visit
to cal.com/app. On uncached pages, now waits for the load event
before opening, while cached pages use a shorter delay.
2025-12-17 17:14:37 +05:30
Udit Takkar 61c8c9d970 chore: pass guests (#25961) 2025-12-17 11:43:42 +00:00
Abhishek 0604c960a4 fix: popover ios issue (#25696)
* fix: popover ios issue

* add comments

* more comments
2025-12-17 10:14:56 +00:00
Eunjae Lee c361b9bbc5 chore: enable booking redesign for e2e (#25642)
* enable bookings-v3 feature flag for e2e tests WIP

* fix e2e

* update comments
2025-12-17 10:09:09 +00:00
Volnei Munhoz c2d275551a Remove next build eslint and ts checks disabled for CI (#25950) 2025-12-17 03:43:00 +00:00
Volnei Munhoz 0ea7f1944f fix types (#25952)
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2025-12-17 02:56:15 +00:00
Alex van Andel 1af7bfa20e chore: release v6.0.2 2025-12-17 02:38:43 +00:00
Volnei Munhoz 641b249e92 chore: release amd as latest (#25949)
* release amd as latest

* remove dockerfile change

* Apply suggestions from code review

changed from linux/amd64 to amd64

* Revert removed comment

* introduce latest as parameter

* introduce latest as parameter
2025-12-17 02:35:55 +00:00
Volnei Munhoz f3f5725563 chore/fix onboarding types (#25951) 2025-12-17 02:09:26 +00:00
Dhairyashil Shinde a2a77376b3 fix: companion extension oauth (#25939)
* fix: companion extension oauth

* fix: ios build

* address cubics comments
2025-12-16 22:22:44 +00:00
Hariom Balhara ee298af4eb fix: update email validation to include pm.me and other email provider domain (#25879)
* fix: update email validation to include pm.me domain and improve error handling in extractDomainFromEmail function

* feat(organizations): add pm.me and additional personal email domains

- Add pm.me (ProtonMail short domain) to personal email providers list
- Add googlemail.com, ymail.com, msn.com, mac.com, and other common personal email domains
- Add Mail.com variants (email.com, post.com, consultant.com, etc.)
- Add protonmail.ch, gmx.de, naver.com, and other regional providers
- Update all three locations: utils.ts, orgCreationUtils.ts, and test file
- Fix ESLint warnings for unnecessary escape characters in regex
2025-12-16 18:45:35 +00:00
Rakshit Sisodiya 47a5fc7bf7 fix: allow organizations to sign up with existing usernames (#25941)
* fix: allow organizations to sign up with existing usernames

- Update usernameCheck to check organization context when currentOrgDomain is provided
- Organizations can now use usernames that exist in other orgs or global namespace
- Only checks username availability within the specific organization
- Fixes issue where org signups were blocked by global username conflicts

Refs #25800

* Update username.ts
2025-12-16 17:47:59 +00:00
Volnei Munhoz a1a5f2477d fix check types (#25907) 2025-12-16 17:07:32 +00:00
sean-brydon 94e0d476d9 fix: skip plan on invite to team (#25924)
* fix: skip plan on invite to team

* address cubic
2025-12-16 14:44:35 +00:00
45fcabef8c chore: replace GH_ACCESS_TOKEN with GitHub App token (#25518)
* chore: replace GH_ACCESS_TOKEN with GitHub App token

Replace personal access token (GH_ACCESS_TOKEN) with GitHub App token
generation using actions/create-github-app-token@v1 for improved security.

Updated workflows:
- draft-release.yml
- post-release.yml
- cleanup.yml
- cleanup-report.yml
- publish-report.yml
- i18n.yml

Benefits:
- Short-lived tokens (1 hour) vs long-lived PATs
- Fine-grained, scoped permissions
- Not tied to individual user accounts
- Better audit trail

Required setup:
- Create a GitHub App with contents:write permission
- Install the app on calcom/cal.com and calcom/test-results-2
- Add RELEASE_APP_ID and RELEASE_APP_PRIVATE_KEY secrets

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* chore: rename secrets to CI_CAL_APP_ID and CI_CAL_APP_PRIVATE_KEY

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* chore: use reusable workflow from calcom-ci-secrets for token generation

This isolates the GitHub App private key in a separate repository,
ensuring that compromised actions in cal.com can only access short-lived
tokens, not the key itself.

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* chore: use explicit secret passing instead of secrets: inherit

Only pass the two required secrets (CI_CAL_APP_ID, CI_CAL_APP_PRIVATE_KEY)
to the reusable workflow instead of inheriting all secrets.

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* chore: remove secrets block - using environment secrets from calcom-ci-secrets

Secrets are now loaded from the ci-github-app environment in
calcom-ci-secrets, so cal.com workflows no longer need to pass them.

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* chore: revert to explicit secret passing

Environment secrets in cross-repo reusable workflows don't work as expected.
Secrets must be passed explicitly from the caller repository.

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* chore: generate GitHub App token directly in workflows

Remove dependency on calcom-ci-secrets reusable workflow.
Token generation is now inline using actions/create-github-app-token
pinned to SHA 7e473efe3cb98aa54f8d4bac15400b15fad77d94 (v2.2.0).

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-12-16 14:12:56 +00:00
Anik Dhabal Babu 593ed461c8 slugify lenient (#25923) 2025-12-16 14:01:54 +00:00
Morgan b8827aca52 fix: atoms css scoping (#25921)
* fix: atoms css scoping

* fixup! fix: atoms css scoping
2025-12-16 19:20:46 +05:30
Benny JooandVolnei Munhoz c3bcd623f6 refactor: create CreditsRepository in /features/credits (#25843)
* mv test

* mv repo

* update imports

* Update packages/features/ee/billing/api/webhook/_checkout.session.completed.ts

Co-authored-by: Volnei Munhoz <volnei@cal.com>

* fix test

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2025-12-16 10:42:27 -03:00
Kartik Labhshetwar 272cf43322 fix: add dark mode support to emptypage skeleton and layout (#25913)
* fix: add dark mode support to emptypage skeleton and layout

* style: remove dark blur effect from EmptyPage component

* style: add dark mode divide subtle to EmptyPage component
2025-12-16 12:45:23 +00:00
Anik Dhabal Babu a8e2ba4663 Revert "fix: improve E2E test stability and reduce flakiness (#25897)" (#25919)
This reverts commit b83f8dd6b8.
2025-12-16 12:30:50 +00:00
3082d6c2f3 feat: export all booking question fields in csv for non seated events in insights (#25837)
* feat(insights): include all booking question fields in CSV export for non-seated events

- For non-seated events: export all custom booking question fields (phone, text, number, select, multiselect, url, checkbox, textarea) excluding system fields
- For seated events: preserve existing behavior (only phone-type fields)
- Add extractFieldValue helper to handle all field value types
- Fix phone fallback logic to only use actual phone field values
- Optimize cache lookup with single get() instead of has() + get()

* refactor(insights): extract CSV data transformation logic into separate module

- Extract manipulation logic from getCsvData into csvDataTransformer.ts
- Add extractFieldValue, isSystemField, and other helper functions
- Add processBookingsForCsv and transformBookingsForCsv functions
- Add comprehensive snapshot tests with dummy data
- Tests demonstrate how input becomes output for various scenarios

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix(insights): update BookingWithAttendees type to match Prisma query result

- Change noShow field type from boolean to boolean | null
- Fixes type error TS2345 in InsightsBookingBaseService.ts

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: eunjae@cal.com <hey@eunjae.dev>
2025-12-16 10:35:21 +00:00
Benny JooandDevin AI f98acb7301 refactor: migrate workflows utilities from trpc to features layer (#25534)
* refactor: migrate workflows utilities from trpc to features layer

Move workflow utility functions from packages/trpc/server/routers/viewer/workflows/util.ts
to packages/features/ee/workflows/lib/workflowUtils.ts to break circular dependencies.

Functions migrated:
- isAuthorized
- getAllWorkflowsFromEventType
- scheduleWorkflowNotifications
- scheduleBookingReminders

Changes:
- Created new workflowUtils.ts in features layer with migrated functions
- Added getBookingsForWorkflowReminders to WorkflowRepository (no prisma outside repositories)
- Updated all imports in features layer to use new location
- Updated trpc util.ts to re-export from features for backward compatibility
- Fixed pre-existing lint warning (any -> unknown) in handleMarkNoShow.ts

This is part of the effort to remove circular dependencies between
packages/features and packages/trpc.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove re-exports from trpc util.ts, update imports to use features layer

Per user request, removed the backward compatibility re-exports from
packages/trpc/server/routers/viewer/workflows/util.ts and updated all
imports in the trpc package to import directly from the features layer.

Files updated to import from @calcom/features/ee/workflows/lib/workflowUtils:
- confirm.handler.ts (getAllWorkflowsFromEventType)
- delete.handler.ts (isAuthorized)
- update.handler.ts (isAuthorized, scheduleWorkflowNotifications)
- getAllActiveWorkflows.handler.ts (getAllWorkflowsFromEventType)
- get.handler.ts (isAuthorized)
- util.test.ts (isAuthorized)
- delete.handler.test.ts (isAuthorized)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update test imports to use features layer for workflow utilities

Updated test files to import scheduleBookingReminders and
scheduleWorkflowNotifications from @calcom/features/ee/workflows/lib/workflowUtils
instead of @calcom/trpc/server/routers/viewer/workflows/util.

Files updated:
- packages/features/ee/workflows/lib/test/workflows.test.ts
- packages/features/tasker/tasks/scanWorkflowBody.test.ts

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: split workflowUtils.ts into individual files

Split the monolithic workflowUtils.ts into separate files for each function:
- isAuthorized.ts - Authorization check for workflow access
- getAllWorkflowsFromEventType.ts - Get workflows for an event type
- scheduleWorkflowNotifications.ts - Schedule workflow notifications
- scheduleBookingReminders.ts - Schedule booking reminders

The workflowUtils.ts now re-exports from these individual files for
backward compatibility.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix import

* fix more

* wip

* wip

* remove workflowUtils

* wip

* refactor deleteRemindersOfActiveOnIds

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-16 10:17:46 +00:00
Anik Dhabal Babu 4e3ce77de4 fix: custom replyTo is not set (#25867) 2025-12-16 04:20:03 +00:00
InD3v 0b5b76d594 fix: adjust padding in timezone select, event advanced edit icon, and sidebar bottom nav (#25877) 2025-12-16 01:11:10 +00:00
Pallav b6935666e5 fix: disable button routing (#25894) 2025-12-16 01:10:37 +00:00
Alex van Andel b25a2bf202 chore: release v6.0.1
Post release / release (push) Canceled after 0s
Release Docker / Release AMD64 (push) Canceled after 0s
Release Docker / Release ARM (push) Canceled after 0s
2025-12-16 01:09:06 +00:00
Abhishek 06d4c7d102 fix lint (#25870) 2025-12-16 01:08:05 +00:00
Dhairyashil Shinde 5b9dd09f0d feat(holidays): improve UI/UX and add contextual emojis (#25895)
* refactor(holidays): improve code quality and address PR review feedback

- Move HolidaysView.tsx from /features to /apps/web/modules following
  the pattern of keeping trpc-using components in /apps/web/modules
- Fix prisma import to use named import: `import { prisma }`
- Fix timezone bug in checkConflicts: use dayjs.utc() for consistent
  date boundaries regardless of server timezone
- Fix toggleHoliday validation to include both current and next year
  holidays, matching the holidays displayed to users
- Implement dependency injection pattern for holiday repository:
  - Create PrismaHolidayRepository with instance methods
  - Add HOLIDAY_REPOSITORY DI token and module
  - Update containers to load holiday repository module
  - Update calculateHolidayBlockedDates to use injected repository
- Remove stale HOLIDAY_CACHE_DAYS env declaration (now a constant)
- Update tests to mock repository instead of prisma directly

* feat(holidays): improve UI responsiveness and add country flags

- Add country flag emojis to holidays dropdown using Unicode regional
  indicator symbols
- Handle edge cases for religious holidays (Hindu, Christian, etc.)
  which dont have 2-letter country codes
- Increase country dropdown width to 180px for better readability
- Make OOO/Holidays tabs responsive: use Select dropdown on mobile,
  ToggleGroup on desktop
- Make + Add button responsive: show only + icon on mobile,
  full text on desktop
- Fix PrismaHolidayRepository import to use @calcom/prisma for
  consistency with other repositories

* feat(holidays): add contextual emojis for holidays

- Add keyword-based emoji mapping for 80+ holidays
- Display holiday emojis in styled containers on settings page
- Add country flag emojis to dropdown using Unicode regional indicators
- Use dynamic emojis on booking page unavailable dates

* fix(holidays): address PR review feedback

- Fix emoji ordering: move Chinese/Lunar New Year before generic new year to prevent incorrect match
- Fix i18n: use t() instead of hardcoded text more in conflict warning
- Fix a11y: use sr-only pattern for mobile button to maintain screen reader accessibility

* fix failing test: packages/features/availability/lib/calculateHolidayBlockedDates.test.ts

* fix failing test: packages/features/availability/lib/calculateHolidayBlockedDates.test.ts

* fix failing tests and builds
2025-12-16 00:40:04 +00:00
Alex van Andel db2caa17ce fix: Allow single-label domains and missing dots (#25899) 2025-12-16 05:10:22 +05:30
b83f8dd6b8 fix: improve E2E test stability and reduce flakiness (#25897)
* fix: improve E2E test stability and reduce flakiness

- Replace hardcoded waits with proper Playwright waitFor assertions in slot selection
- Add explicit waits for calendar and time slot elements to be visible before clicking
- Replace fixed 2s wait in gotoRoutingLink with networkidle wait
- Replace fixed 5s email wait with retry logic (10 retries, 500ms intervals)
- Use unique usernames with timestamps to avoid parallel test collisions
- Use features fixture instead of direct prisma calls for feature flag mutations
- Fix login.e2e.ts to use unique username instead of hardcoded 'pro'
- Fix signup.e2e.ts to use unique usernames and proper feature flag handling
- Remove unused 'users' parameter from tests that don't need it

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

* perf: replace waitForTimeout with smart waits for faster E2E tests

- Replace 30 waitForTimeout calls with proper Playwright waits
- Use waitFor({ state: 'visible' }) for element visibility
- Use waitForLoadState('networkidle') for page load completion
- Use waitForFunction for localStorage state changes

Performance improvements:
- limit-tab.e2e.ts: 10s fixed wait -> element visibility wait
- booking-duplicate-api-calls.e2e.ts: 5s fixed wait -> networkidle
- change-theme.e2e.ts: 3s fixed wait -> localStorage state check
- team-invitation.e2e.ts: multiple 500ms-3s waits -> element waits
- booking-seats.e2e.ts: 2s waits -> dropdown visibility waits
- embed-code-generator.e2e.ts: 1s waits -> iframe visibility waits
- organization-privacy.e2e.ts: 500ms waits -> element/networkidle waits
- organization-invitation.e2e.ts: 500ms-1s waits -> element waits
- analyticsApps.e2e.ts: 1s wait -> networkidle
- integrations.e2e.ts: 1s wait -> calendar element wait
- fixtures/apps.ts: 1s waits -> element visibility waits

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-15 20:19:47 -03:00
Beto 883ac103f8 fix: android redirect (#25888)
* fix android redirect

* remove logs
2025-12-15 18:14:42 +00:00
Volnei Munhoz d13adc8ffd Fix user parameter (#25884) 2025-12-15 18:07:28 +00:00
Kartik Labhshetwar d64255be47 fix: change sidebar hover background to subtle when locale ready (#25876) 2025-12-15 17:50:03 +00:00
2480 changed files with 123865 additions and 56605 deletions
-5
View File
@@ -1,5 +0,0 @@
---
"@calcom/atoms": minor
---
feat: Booker accepts rrHostSubsetIds to specify round robin hosts
+57
View File
@@ -0,0 +1,57 @@
# EAS Build ignore file for monorepo
# Only upload the companion app folder
# ===========================================
# IGNORE EVERYTHING AT ROOT LEVEL
# ===========================================
/*
# ===========================================
# EXCEPT THE COMPANION APP
# ===========================================
!companion
# ===========================================
# BUT IGNORE THESE INSIDE COMPANION
# ===========================================
# Native folders - EAS generates these during builds (~2.1 GB)
companion/ios
companion/android
# Dependencies - EAS installs these during builds (~1.6 GB)
companion/node_modules
# Expo build cache
companion/.expo
companion/dist
companion/web-build
# Metro
companion/.metro-health-check*
# WXT Chrome Extension outputs (not needed for mobile builds)
companion/.output
companion/.wxt
companion/dev
# Kotlin cache
companion/.kotlin
# Build artifacts
companion/*.jks
companion/*.p8
companion/*.p12
companion/*.key
companion/*.mobileprovision
# Debug logs
companion/*.log
# TypeScript build info
companion/*.tsbuildinfo
# Environment files
companion/.env
companion/.env.*
!companion/.env.example
+8 -9
View File
@@ -261,6 +261,9 @@ EMAIL_SERVER_PORT=1025
## @see https://support.google.com/accounts/answer/185833
# EMAIL_SERVER_PASSWORD='<gmail_app_password>'
# queue or cancel payment reminder email/flow
AWAITING_PAYMENT_EMAIL_DELAY_MINUTES=
# Used for E2E for email testing
# Set it to "1" if you need to email checks in E2E tests locally
# Make sure to run mailhog container manually or with `yarn dx`
@@ -431,14 +434,7 @@ BLACKLISTED_GUEST_EMAILS=
NEXT_PUBLIC_VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
# Mintlify chat api
# Power AI chat in for docs
MINTLIFY_CHAT_API_KEY=
NEXT_PUBLIC_ENABLE_MINTLIFY_CHAT=
NEXT_PUBLIC_CHAT_API_URL=
NEXT_PUBLIC_DOCS_URL=
# Custom privacy policy / terms URLs (for self-hosters: change to your privacy policy / terms URLs)
# Custom privacy policy/ terms URLs (for self-hosters: change to your privacy policy / terms URLs)
NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL=
NEXT_PUBLIC_WEBSITE_TERMS_URL=
@@ -509,4 +505,7 @@ SEED_PLATFORM_OAUTH_CLIENT_SECRET=
ENABLE_ASYNC_TASKER="false" # set to "true" to enable
TRIGGER_SECRET_KEY=
TRIGGER_API_URL=https://api.trigger.dev
TRIGGER_DEV_PROJECT_REF=
TRIGGER_DEV_PROJECT_REF=
GOOGLE_ADS_ENABLED=1 # To enable Google Ads tracking (gclid)
LINKEDIN_ADS_ENABLED=1 # To enable LinkedIn Ads tracking (li_fat_id)
+5 -3
View File
@@ -1,5 +1,7 @@
.github/actions/**/* @calcom/Foundation
.github/workflows/**/* @calcom/Foundation
/**/package.json @calcom/Foundation
/apps/api/**/* @calcom/API
/apps/api/**/* @calcom/Foundation
/apps/web/**/layout.tsx @calcom/Consumer @calcom/Foundation
/apps/web/lib/csp.ts @calcom/Foundation
/apps/web/lib/buildNonce.ts @calcom/Foundation
@@ -7,7 +9,7 @@
/apps/web/lib/core/**/* @calcom/Foundation
/apps/web/lib/booking.ts @calcom/Foundation
/apps/web/lib/handleOrgRedirect.ts @calcom/Foundation
/apps/web/middleware.ts @calcom/Foundation
/apps/web/proxy.ts @calcom/Foundation
/deploy/**/* @calcom/Foundation
/packages/app-store/applecalendar/**/* @calcom/Foundation
/packages/app-store/caldavcalendar/**/* @calcom/Foundation
@@ -28,7 +30,7 @@
/packages/features/bookings/lib/getLuckyUser.ts @calcom/Foundation
/packages/features/schedules/lib/slots.ts @calcom/Foundation
/packages/platform/atoms/**/*WebWrapper.tsx @calcom/Consumer
/packages/platform/**/* @calcom/Platform @calcom/Foundation
/packages/platform/**/* @calcom/Consumer @calcom/Foundation
/packages/prisma/**/* @calcom/Foundation
/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts @calcom/Foundation
/packages/trpc/server/routers/viewer/bookings/get.handler.ts @calcom/Foundation
@@ -0,0 +1,23 @@
name: Generate cache-build key
description: "Generate the cache key for production build caching"
inputs:
branch_key:
required: true
description: "Branch key for cache scoping (e.g., github.head_ref for PRs)"
outputs:
key:
description: "The generated cache key"
value: ${{ steps.generate-key.outputs.key }}
runs:
using: "composite"
steps:
- name: Generate cache key
id: generate-key
shell: bash
env:
CACHE_NAME: prod-build
BRANCH_KEY: ${{ inputs.branch_key }}
LOCKFILE_HASH: ${{ hashFiles('yarn.lock') }}
SOURCE_HASH: ${{ hashFiles('apps/**/**.[jt]s', 'apps/**/**.[jt]sx', 'apps/**/*.json', 'apps/**/*.css', 'packages/**/**.[jt]s', 'packages/**/**.[jt]sx', 'packages/prisma/schema.prisma', 'packages/prisma/migrations/**/*.sql', '!**/node_modules/**', '!packages/prisma/generated/**', '!packages/prisma/client/**', '!packages/prisma/zod/**', '!packages/kysely/**') }}
run: |
echo "key=${CACHE_NAME}-${BRANCH_KEY}-${LOCKFILE_HASH}-${SOURCE_HASH}" >> $GITHUB_OUTPUT
+7 -17
View File
@@ -1,33 +1,23 @@
name: Cache production build binaries
description: "Cache or restore if necessary"
inputs:
node_version:
required: false
default: v18.x
runs:
using: "composite"
steps:
- name: Generate cache key
id: cache-key
uses: ./.github/actions/cache-build-key
with:
branch_key: ${{ github.head_ref || github.ref_name }}
- name: Cache production build
uses: buildjet/cache@v4
uses: actions/cache@v4
id: cache-build
env:
# WARN: Don't touch this cache key. Currently github.sha refers to the latest commit in main
# and not the branch that's attempting to merge to main, which causes CI errors when merged
# to main.
# TODO: Fix this problem if intending to modify this cache key.
cache-name: prod-build
key-1: ${{ inputs.node_version }}-${{ hashFiles('yarn.lock') }}
key-2: ${{ hashFiles('apps/**/**.[jt]s', 'apps/**/**.[jt]sx', 'packages/**/**.[jt]s', 'packages/**/**.[jt]sx', '!**/node_modules') }}
key-3: ${{ github.event.pull_request.number || github.ref }}
key-4: ${{ github.sha }}
key-5: ${{ github.event.pull_request.head.sha }}
with:
path: |
${{ github.workspace }}/apps/web/.next
${{ github.workspace }}/apps/web/public/embed
**/.turbo/**
**/dist/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}-${{ env.key-5 }}
key: ${{ steps.cache-key.outputs.key }}
- run: |
export NODE_OPTIONS="--max_old_space_size=8192"
yarn build
+23
View File
@@ -0,0 +1,23 @@
name: Generate cache-db key
description: "Generate the cache key for database caching"
inputs:
path:
required: false
default: "backups/backup.sql"
description: "Path to the backup file"
outputs:
key:
description: "The generated cache key"
value: ${{ steps.generate-key.outputs.key }}
runs:
using: "composite"
steps:
- name: Generate cache key
id: generate-key
shell: bash
env:
CACHE_NAME: cache-db
PATH_KEY: ${{ inputs.path }}
PRISMA_HASH: ${{ hashFiles('packages/prisma/schema.prisma', 'packages/prisma/migrations/**/**.sql', 'packages/prisma/*.ts') }}
run: |
echo "key=${CACHE_NAME}-${PATH_KEY}-${PRISMA_HASH}" >> $GITHUB_OUTPUT
+7 -6
View File
@@ -10,14 +10,15 @@ inputs:
runs:
using: "composite"
steps:
- name: Generate cache key
id: cache-key
uses: ./.github/actions/cache-db-key
with:
path: ${{ inputs.path }}
- name: Cache database
id: cache-db
uses: buildjet/cache@v4
uses: actions/cache@v4
env:
cache-name: cache-db
key-1: ${{ hashFiles('packages/prisma/schema.prisma', 'packages/prisma/migrations/**/**.sql', 'packages/prisma/*.ts') }}
key-2: ${{ github.event.pull_request.number || github.ref }}
key-3: ${{ github.event.pull_request.head.sha }}
DATABASE_URL: ${{ inputs.DATABASE_URL }}
DATABASE_DIRECT_URL: ${{ inputs.DATABASE_URL }}
E2E_TEST_CALCOM_QA_EMAIL: ${{ inputs.E2E_TEST_CALCOM_QA_EMAIL }}
@@ -25,7 +26,7 @@ runs:
E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS: ${{ inputs.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }}
with:
path: ${{ inputs.path }}
key: ${{ runner.os }}-${{ env.cache-name }}-${{ inputs.path }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}
key: ${{ steps.cache-key.outputs.key }}
- run: yarn db-seed
if: steps.cache-db.outputs.cache-hit != 'true'
shell: bash
@@ -34,6 +34,10 @@ inputs:
description: "Whether to push the built image"
required: false
default: "false"
use-as-latest:
description: "Publish as latest"
required: false
default: "false"
runs:
using: "composite"
@@ -61,7 +65,7 @@ runs:
docker.io/calcom/cal.com
ghcr.io/calcom/cal.com
flavor: |
latest=${{ !github.event.release.prerelease }}
latest=${{ !github.event.release.prerelease && inputs.use-as-latest == 'true' }}
suffix=${{ inputs.platform-suffix }}
- name: Copy env
@@ -87,7 +91,7 @@ runs:
docker compose logs database
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: useblacksmith/setup-docker-builder@v1
with:
driver-opts: |
network=container:database
@@ -96,7 +100,7 @@ runs:
- name: Build image
id: docker_build
uses: docker/build-push-action@v6
uses: useblacksmith/build-push-action@v2
with:
context: ./
file: ./Dockerfile
@@ -155,7 +159,7 @@ runs:
- name: Push image
id: docker_push
uses: docker/build-push-action@v6
uses: useblacksmith/build-push-action@v2
if: ${{ inputs.push-image == 'true' && !github.event.release.prerelease }}
with:
context: ./
+62 -8
View File
@@ -15,12 +15,16 @@ inputs:
node_version:
required: false
default: v20.x
skip-install-if-cache-hit:
description: "Skip yarn install if node_modules cache is hit. Use this for jobs that only need to check that cache exists."
required: false
default: "false"
runs:
using: "composite"
steps:
- name: Use Node ${{ inputs.node_version }}
uses: buildjet/setup-node@v4
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node_version }}
- name: Expose yarn config as "$GITHUB_OUTPUT"
@@ -29,10 +33,57 @@ runs:
run: |
echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
# When skip-install-if-cache-hit is true, first check if all caches exist without downloading (lookup-only mode)
# This avoids downloading ~1.2GB of cache data when we just want to verify caches exist
- name: Check yarn cache (lookup-only)
if: ${{ inputs.skip-install-if-cache-hit == 'true' }}
uses: actions/cache/restore@v4
id: yarn-download-cache-check
with:
path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}
key: yarn-download-cache-${{ hashFiles('yarn.lock') }}
lookup-only: true
- name: Check node_modules cache (lookup-only)
if: ${{ inputs.skip-install-if-cache-hit == 'true' }}
uses: actions/cache/restore@v4
id: yarn-nm-cache-check
with:
path: |
**/node_modules/
!**/.next/node_modules/
key: ${{ runner.os }}-yarn-nm-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
lookup-only: true
- name: Check yarn install state cache (lookup-only)
if: ${{ inputs.skip-install-if-cache-hit == 'true' }}
uses: actions/cache/restore@v4
id: yarn-install-state-cache-check
with:
path: .yarn/ci-cache/
key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
lookup-only: true
# Compute whether all caches hit (only in skip mode)
- name: Check if all caches hit
if: ${{ inputs.skip-install-if-cache-hit == 'true' }}
id: all-caches-check
shell: bash
run: |
if [[ "${{ steps.yarn-download-cache-check.outputs.cache-hit }}" == "true" && \
"${{ steps.yarn-nm-cache-check.outputs.cache-hit }}" == "true" && \
"${{ steps.yarn-install-state-cache-check.outputs.cache-hit }}" == "true" ]]; then
echo "all-hit=true" >> $GITHUB_OUTPUT
else
echo "all-hit=false" >> $GITHUB_OUTPUT
fi
# Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325
# Yarn cache is also reusable between arch and os.
# Only restore if not in skip mode, or if skip mode but any cache check missed
- name: Restore yarn cache
uses: buildjet/cache@v4
if: ${{ inputs.skip-install-if-cache-hit != 'true' || steps.all-caches-check.outputs.all-hit != 'true' }}
uses: actions/cache@v4
id: yarn-download-cache
with:
path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}
@@ -40,25 +91,28 @@ runs:
# Invalidated on yarn.lock changes
- name: Restore node_modules
if: ${{ inputs.skip-install-if-cache-hit != 'true' || steps.all-caches-check.outputs.all-hit != 'true' }}
id: yarn-nm-cache
uses: buildjet/cache@v4
uses: actions/cache@v4
with:
path: "**/node_modules/"
path: |
**/node_modules/
!**/.next/node_modules/
key: ${{ runner.os }}-yarn-nm-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
# Invalidated on yarn.lock changes
- name: Restore yarn install state
if: ${{ inputs.skip-install-if-cache-hit != 'true' || steps.all-caches-check.outputs.all-hit != 'true' }}
id: yarn-install-state-cache
uses: buildjet/cache@v4
uses: actions/cache@v4
with:
path: .yarn/ci-cache/
key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
- name: Install dependencies
if: ${{ inputs.skip-install-if-cache-hit != 'true' || steps.all-caches-check.outputs.all-hit != 'true' }}
shell: bash
run: |
yarn install --inline-builds
yarn prisma generate
run: yarn install --inline-builds
env:
# CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action.
YARN_ENABLE_IMMUTABLE_INSTALLS: "false" # So it doesn't try to remove our private submodule deps
@@ -1,5 +1,10 @@
name: Install playwright binaries
description: "Install playwright, cache and restore if necessary"
inputs:
skip-install-if-cache-hit:
description: "Skip playwright install if cache is hit. Use this for jobs that only need to check that cache exists."
required: false
default: "false"
runs:
using: "composite"
steps:
@@ -7,15 +12,35 @@ runs:
shell: bash
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package.json').devDependencies['@playwright/test'])")" >> $GITHUB_ENV
- name: Cache playwright binaries
id: playwright-cache
uses: buildjet/cache@v4
# When skip-install-if-cache-hit is true, first check if cache exists without downloading (lookup-only mode)
- name: Check playwright cache (lookup-only)
if: ${{ inputs.skip-install-if-cache-hit == 'true' }}
id: playwright-cache-check
uses: actions/cache/restore@v4
with:
path: |
~/Library/Caches/ms-playwright
~/.cache/ms-playwright
${{ github.workspace }}/node_modules/playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
lookup-only: true
# Only restore cache if not in skip mode, or if skip mode but cache check missed
- name: Cache playwright binaries
if: ${{ inputs.skip-install-if-cache-hit != 'true' || steps.playwright-cache-check.outputs.cache-hit != 'true' }}
id: playwright-cache
uses: actions/cache@v4
with:
path: |
~/Library/Caches/ms-playwright
~/.cache/ms-playwright
${{ github.workspace }}/node_modules/playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
# In default mode: run if playwright-cache missed
# In skip mode: run if playwright-cache-check missed (but cache restore step was also skipped)
- name: Yarn playwright install
if: ${{ (inputs.skip-install-if-cache-hit != 'true' && steps.playwright-cache.outputs.cache-hit != 'true') || (inputs.skip-install-if-cache-hit == 'true' && steps.playwright-cache-check.outputs.cache-hit != 'true') }}
shell: bash
run: yarn playwright install --with-deps
+7 -2
View File
@@ -24,6 +24,11 @@ jobs:
uses: ./.github/workflows/unit-tests.yml
secrets: inherit
api-v2-unit-test:
name: Tests
uses: ./.github/workflows/api-v2-unit-tests.yml
secrets: inherit
build-api-v1:
name: Production builds
uses: ./.github/workflows/api-v1-production-build.yml
@@ -75,9 +80,9 @@ jobs:
secrets: inherit
required:
needs: [lint, type-check, unit-test, integration-test, build, build-api-v1, build-api-v2, e2e, e2e-embed, e2e-embed-react, e2e-app-store]
needs: [lint, type-check, unit-test, api-v2-unit-test, integration-test, build, build-api-v1, build-api-v2, e2e, e2e-embed, e2e-embed-react, e2e-app-store]
if: always()
runs-on: buildjet-2vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: fail if conditional jobs failed
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') || contains(needs.*.result, 'cancelled')
+8 -10
View File
@@ -43,7 +43,7 @@ env:
jobs:
build:
name: Build API v1
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
services:
postgres:
@@ -56,10 +56,11 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-cmd "pg_isready -h 127.0.0.1 -U postgres"
--health-interval 2s
--health-timeout 3s
--health-retries 15
--health-start-period 2s
ports:
- 5432:5432
steps:
@@ -68,21 +69,18 @@ jobs:
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/cache-db
- name: Cache API v1 production build
uses: buildjet/cache@v4
uses: actions/cache@v4
id: cache-api-v1-build
env:
cache-name: api-v1-build
key-1: ${{ hashFiles('yarn.lock') }}
key-2: ${{ hashFiles('apps/api/v1/**.[jt]s', 'apps/api/v1/**.[jt]sx', '!**/node_modules') }}
key-3: ${{ github.event.pull_request.number || github.ref }}
# Ensures production-build.yml will always be fresh
key-4: ${{ github.sha }}
with:
path: |
${{ github.workspace }}/apps/api/v1/.next
**/.turbo/**
**/dist/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
key: ${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
- name: Log Cache Hit
if: steps.cache-api-v1-build.outputs.cache-hit == 'true'
run: echo "Cache hit for API v1 build. Skipping build."
+8 -24
View File
@@ -6,13 +6,15 @@ on:
env:
DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
DATABASE_DIRECT_URL: ${{ secrets.CI_DATABASE_URL }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
jobs:
build:
name: Build API v2
permissions:
contents: read
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
services:
postgres:
@@ -35,29 +37,11 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- name: Cache API v2 production build
uses: buildjet/cache@v4
id: cache-api-v2-build
env:
cache-name: api-v2-build
key-1: ${{ hashFiles('yarn.lock') }}
key-2: ${{ hashFiles('apps/api/v2/**.[jt]s', 'apps/api/v2/**.[jt]sx', '!**/node_modules') }}
key-3: ${{ github.event.pull_request.number || github.ref }}
# Ensures production-build.yml will always be fresh
key-4: ${{ github.sha }}
with:
path: |
**/dist/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
- name: Log Cache Hit
if: steps.cache-api-v2-build.outputs.cache-hit == 'true'
run: echo "Cache hit for API v2 build. Skipping build."
- name: Run build
if: steps.cache-api-v2-build.outputs.cache-hit != 'true'
- name: Generate Prisma schemas
working-directory: apps/api/v2
run: yarn workspace @calcom/api-v2 run generate-schemas
- name: Build API v2 with Turbo
run: |
export NODE_OPTIONS="--max_old_space_size=8192"
yarn workspace @calcom/api-v2 run generate-schemas &&
rm -rf apps/api/v2/node_modules &&
yarn install &&
yarn workspace @calcom/api-v2 run build
yarn turbo run build --filter=@calcom/api-v2
shell: bash
+22
View File
@@ -0,0 +1,22 @@
name: API v2 Unit
on:
workflow_call:
env:
LINGO_DOT_DEV_API_KEY: ${{ secrets.CI_LINGO_DOT_DEV_API_KEY }}
permissions:
contents: read
jobs:
test:
name: API v2 Unit
timeout-minutes: 20
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- run: yarn prisma generate
- name: Run API v2 unit tests
working-directory: apps/api/v2
run: |
export NODE_OPTIONS="--max_old_space_size=8192"
yarn workspace @calcom/platform-libraries build && yarn test
+5 -11
View File
@@ -8,34 +8,28 @@ jobs:
name: Build Atoms
permissions:
contents: read
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- name: Cache atoms production build
uses: buildjet/cache@v4
uses: actions/cache@v4
id: cache-atoms-build
env:
cache-name: atoms-build
key-1: ${{ hashFiles('yarn.lock') }}
key-2: ${{ hashFiles('packages/platform/atoms/**.[jt]s', 'packages/platform/atoms/**.[jt]sx', '!**/node_modules') }}
key-3: ${{ github.event.pull_request.number || github.ref }}
# Ensures production-build.yml will always be fresh
key-4: ${{ github.sha }}
key-2: ${{ hashFiles('packages/platform/atoms/**.[jt]s', 'packages/platform/atoms/**.[jt]sx', 'packages/platform/atoms/package.json', '!**/node_modules') }}
with:
path: |
**/dist/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
- name: Log Cache Hit
if: steps.cache-atoms-build.outputs.cache-hit == 'true'
run: echo "Cache hit for Atoms build. Skipping build."
key: ${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
- name: Run build
if: steps.cache-atoms-build.outputs.cache-hit != 'true'
run: |
export NODE_OPTIONS="--max_old_space_size=8192"
rm -rf packages/platform/atoms/node_modules
yarn install
yarn workspace @calcom/atoms run build
yarn workspace @calcom/atoms run build-npm
shell: bash
+1 -1
View File
@@ -6,7 +6,7 @@ on:
jobs:
cleanup:
runs-on: buildjet-2vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: Check out code
uses: actions/checkout@v4
@@ -0,0 +1,55 @@
name: Check API v2 breaking changes
on:
workflow_call:
permissions:
contents: read
env:
API_KEY_PREFIX: ${{ secrets.CI_API_KEY_PREFIX }}
API_PORT: ${{ vars.CI_API_V2_PORT }}
API_URL: "http://localhost"
CALCOM_LICENSE_KEY: ${{ secrets.CI_CALCOM_LICENSE_KEY }}
DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
DATABASE_READ_URL: ${{ secrets.CI_DATABASE_URL }}
DATABASE_WRITE_URL: ${{ secrets.CI_DATABASE_URL }}
JWT_SECRET: ${{ secrets.CI_JWT_SECRET }}
NEXTAUTH_SECRET: ${{ secrets.CI_NEXTAUTH_SECRET }}
NODE_ENV: ${{ vars.CI_NODE_ENV }}
NODE_OPTIONS: --max-old-space-size=4096
REDIS_URL: "redis://localhost:6379"
STRIPE_API_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
WEB_APP_URL: "https://app.cal.com"
jobs:
check-api-v2-breaking-changes:
name: Check API v2 breaking changes
timeout-minutes: 10
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- name: Generate Swagger
working-directory: apps/api/v2
run: |
yarn prisma generate
yarn generate-swagger
- name: Check API v2 breaking changes
run: |
docker run --rm \
-v "$PWD:/work" -w /work \
tufin/oasdiff:latest \
breaking \
https://raw.githubusercontent.com/calcom/cal.com/refs/heads/main/docs/api-reference/v2/openapi.json \
docs/api-reference/v2/openapi.json \
--fail-on ERR \
--err-ignore .github/oasdiff-err-ignore.txt
+3 -1
View File
@@ -3,11 +3,13 @@ on:
workflow_call:
env:
NODE_OPTIONS: --max-old-space-size=4096
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
permissions:
contents: read
jobs:
check-types:
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
+12 -3
View File
@@ -11,12 +11,20 @@ jobs:
cleanup-report:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94
with:
app-id: ${{ secrets.CI_CAL_APP_ID }}
private-key: ${{ secrets.CI_CAL_APP_PRIVATE_KEY }}
repositories: 'test-results-2'
- name: Checkout GitHub Pages Branch
uses: actions/checkout@v4
with:
repository: calcom/test-results-2
ref: gh-pages
token: ${{ secrets.GH_ACCESS_TOKEN }}
token: ${{ steps.generate-token.outputs.token }}
- name: Set Git User
run: |
@@ -26,12 +34,13 @@ jobs:
- name: Cleanup HTML reports on PR close/merge
env:
BRANCH_REPORTS_DIR: reports/${{ github.event.pull_request.head.ref }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
run: |
if [ -d "$BRANCH_REPORTS_DIR" ]; then
rm -rf "$BRANCH_REPORTS_DIR"
git add .
git commit -m "workflow: remove all reports for branch ${{ github.event.pull_request.head.ref }} (PR closed/merged)"
git commit -m "workflow: remove all reports for branch $HEAD_REF (PR closed/merged)"
git push
else
echo "No reports found for branch ${{ github.event.pull_request.head.ref }}. Nothing to clean up."
echo "No reports found for branch $HEAD_REF. Nothing to clean up."
fi
+10 -2
View File
@@ -22,12 +22,20 @@ jobs:
# Contains all reports for deleted branch
BRANCH_REPORTS_DIR: reports/${{ github.event.ref }}
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94
with:
app-id: ${{ secrets.CI_CAL_APP_ID }}
private-key: ${{ secrets.CI_CAL_APP_PRIVATE_KEY }}
repositories: 'test-results-2'
- name: Checkout GitHub Pages Branch
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
repository: calcom/test-results-2
ref: gh-pages
token: ${{ secrets.GH_ACCESS_TOKEN }}
token: ${{ steps.generate-token.outputs.token }}
- name: Set Git User
# see: https://github.com/actions/checkout/issues/13#issuecomment-724415212
run: |
+1 -1
View File
@@ -12,7 +12,7 @@ env:
jobs:
build:
name: Build Companion App & Extension
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
steps:
@@ -9,15 +9,25 @@ on:
jobs:
cron-scheduleSMSReminders:
env:
APP_URL: ${{ secrets.APP_URL }}
CRON_API_KEY: ${{ secrets.CRON_API_KEY }}
APP_URL_US: ${{ vars.APP_URL_US }}
APP_URL_EU: ${{ vars.APP_URL_EU }}
CRON_API_KEY_US: ${{ secrets.CRON_API_KEY }}
CRON_API_KEY_EU: ${{ secrets.CRON_API_KEY_EU }}
runs-on: ubuntu-latest
steps:
- name: cURL request
if: ${{ env.APP_URL && env.CRON_API_KEY }}
- name: cURL request EU
if: ${{ env.APP_URL_EU && env.CRON_API_KEY_EU }}
run: |
curl ${{ secrets.APP_URL }}/api/cron/workflows/scheduleSMSReminders \
curl ${{ env.APP_URL_EU }}/api/cron/workflows/scheduleSMSReminders \
-X POST \
-H 'content-type: application/json' \
-H 'authorization: ${{ secrets.CRON_API_KEY }}' \
-H 'authorization: ${{ env.CRON_API_KEY_EU }}' \
-sSf
- name: cURL request US
if: ${{ env.APP_URL_US && env.CRON_API_KEY_US }}
run: |
curl ${{ env.APP_URL_US }}/api/cron/workflows/scheduleSMSReminders \
-X POST \
-H 'content-type: application/json' \
-H 'authorization: ${{ env.CRON_API_KEY_US }}' \
-sSf
@@ -9,15 +9,25 @@ on:
jobs:
cron-scheduleWhatsappReminders:
env:
APP_URL: ${{ secrets.APP_URL }}
CRON_API_KEY: ${{ secrets.CRON_API_KEY }}
APP_URL_EU: ${{ vars.APP_URL_EU }}
APP_URL_US: ${{ vars.APP_URL_US }}
CRON_API_KEY_EU: ${{ secrets.CRON_API_KEY_EU }}
CRON_API_KEY_US: ${{ secrets.CRON_API_KEY }}
runs-on: ubuntu-latest
steps:
- name: cURL request
if: ${{ env.APP_URL && env.CRON_API_KEY }}
- name: cURL request EU
if: ${{ env.APP_URL_EU && env.CRON_API_KEY_EU }}
run: |
curl ${{ secrets.APP_URL }}/api/cron/workflows/scheduleWhatsappReminders \
curl ${{ env.APP_URL_EU }}/api/cron/workflows/scheduleWhatsappReminders \
-X POST \
-H 'content-type: application/json' \
-H 'authorization: ${{ secrets.CRON_API_KEY }}' \
-H 'authorization: ${{ env.CRON_API_KEY_EU }}' \
-sSf
- name: cURL request US
if: ${{ env.APP_URL_US && env.CRON_API_KEY_US }}
run: |
curl ${{ env.APP_URL_US }}/api/cron/workflows/scheduleWhatsappReminders \
-X POST \
-H 'content-type: application/json' \
-H 'authorization: ${{ env.CRON_API_KEY_US }}' \
-sSf
+17 -7
View File
@@ -9,15 +9,25 @@ on:
jobs:
cron-webhookTriggers:
env:
APP_URL: ${{ secrets.APP_URL }}
CRON_API_KEY: ${{ secrets.CRON_API_KEY }}
APP_URL_US: ${{ vars.APP_URL_US }}
APP_URL_EU: ${{ vars.APP_URL_EU }}
CRON_API_KEY_US: ${{ secrets.CRON_API_KEY }}
CRON_API_KEY_EU: ${{ secrets.CRON_API_KEY_EU }}
runs-on: ubuntu-latest
steps:
- name: cURL request
if: ${{ env.APP_URL && env.CRON_API_KEY }}
- name: cURL request US
if: ${{ env.APP_URL_US && env.CRON_API_KEY_US }}
run: |
curl ${{ secrets.APP_URL }}/api/cron/webhookTriggers \
curl ${{ env.APP_URL_US }}/api/cron/webhookTriggers \
-X POST \
-H 'content-type: application/json' \
-H 'authorization: ${{ secrets.CRON_API_KEY }}' \
--fail
-H 'authorization: ${{ env.CRON_API_KEY_US }}' \
-sSf
- name: cURL request EU
if: ${{ env.APP_URL_EU && env.CRON_API_KEY_EU }}
run: |
curl ${{ env.APP_URL_EU }}/api/cron/webhookTriggers \
-X POST \
-H 'content-type: application/json' \
-H 'authorization: ${{ env.CRON_API_KEY_EU }}' \
-sSf
@@ -0,0 +1,33 @@
name: Delete Blacksmith Cache
on:
workflow_dispatch:
inputs:
cache_key:
description: "Blacksmith Cache Key to Delete"
required: true
type: string
pull_request:
types: [closed]
jobs:
manually-delete-blacksmith-cache:
if: github.event_name == 'workflow_dispatch'
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: useblacksmith/cache-delete@v1
with:
key: ${{ inputs.cache_key }}
delete-cache-build-on-pr-close:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: blacksmith-2vcpu-ubuntu-2404
env:
CACHE_NAME: prod-build
steps:
- name: Delete cache-build cache
uses: useblacksmith/cache-delete@v1
with:
key: ${{ env.CACHE_NAME }}-${{ github.event.pull_request.head.ref }}
prefix: "true"
@@ -1,17 +0,0 @@
name: Manually Delete BuildJet Cache
on:
workflow_dispatch:
inputs:
cache_key:
description: "BuildJet Cache Key to Delete"
required: true
type: string
jobs:
manually-delete-buildjet-cache:
runs-on: buildjet-2vcpu-ubuntu-2204
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: buildjet/cache-delete@v1
with:
cache_key: ${{ inputs.cache_key }}
+3 -9
View File
@@ -9,27 +9,21 @@ jobs:
name: Build Docs
permissions:
contents: read
runs-on: buildjet-2vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- name: Cache Docs build
uses: buildjet/cache@v4
uses: actions/cache@v4
id: cache-docs-build
env:
cache-name: docs-build
key-1: ${{ hashFiles('yarn.lock') }}
key-2: ${{ hashFiles('docs/**.*', '!**/node_modules') }}
key-3: ${{ github.event.pull_request.number || github.ref }}
key-4: ${{ github.sha }}
with:
path: |
**/docs/**
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
# Log cache hit
- name: Log Cache Hit
if: steps.cache-docs-build.outputs.cache-hit == 'true'
run: echo "Cache hit for Docs build. Skipping build."
key: ${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}
- name: Run build
if: steps.cache-docs-build.outputs.cache-hit != 'true'
working-directory: docs
+15 -4
View File
@@ -17,13 +17,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94
with:
app-id: ${{ secrets.CI_CAL_APP_ID }}
private-key: ${{ secrets.CI_CAL_APP_PRIVATE_KEY }}
repositories: 'cal.com'
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: 'main'
token: ${{ secrets.GH_ACCESS_TOKEN }}
token: ${{ steps.generate-token.outputs.token }}
- name: Configure git
run: |
@@ -49,14 +56,18 @@ jobs:
- uses: ./.github/actions/yarn-install
- name: Bump version
env:
VERSION: ${{ inputs.next_version }}
run: |
cd apps/web
yarn version ${{ inputs.next_version }}
yarn version "$VERSION"
- name: Commit changes
env:
VERSION: ${{ inputs.next_version }}
run: |
git add .
git commit -m "chore: release v${{ inputs.next_version }}"
git commit -m "chore: release v$VERSION"
git push
- name: Draft release
+25 -24
View File
@@ -27,11 +27,13 @@ env:
VAPID_PRIVATE_KEY: ${{ secrets.VAPID_PRIVATE_KEY }}
JWT_SECRET: ${{ secrets.CI_JWT_SECRET }}
NODE_ENV: ${{ vars.CI_NODE_ENV }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
jobs:
e2e:
timeout-minutes: 20
name: E2E API v2
runs-on: buildjet-16vcpu-ubuntu-2204
name: E2E API v2 (${{ matrix.shard }}/${{ strategy.job-total }})
runs-on: blacksmith-4vcpu-ubuntu-2404
services:
postgres:
image: postgres:13
@@ -43,10 +45,11 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-cmd "pg_isready -h 127.0.0.1 -U postgres"
--health-interval 2s
--health-timeout 3s
--health-retries 15
--health-start-period 2s
ports:
- 5432:5432
redis:
@@ -63,6 +66,8 @@ jobs:
--health-retries 5
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: docker/login-action@v3
with:
@@ -72,33 +77,29 @@ jobs:
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/cache-db
- name: Generate Swagger
working-directory: apps/api/v2
run: yarn generate-swagger
- name: Check breaking changes
- name: Build platform packages with Turbo
run: |
docker run --rm \
-v "$PWD:/work" -w /work \
tufin/oasdiff:latest \
breaking \
https://raw.githubusercontent.com/calcom/cal.com/refs/heads/main/docs/api-reference/v2/openapi.json \
docs/api-reference/v2/openapi.json \
--fail-on ERR \
--err-ignore .github/oasdiff-err-ignore.txt
yarn turbo run build \
--filter=@calcom/platform-constants \
--filter=@calcom/platform-enums \
--filter=@calcom/platform-utils \
--filter=@calcom/platform-types \
--filter=@calcom/platform-libraries \
--filter=@calcom/trpc
- name: Run Tests
working-directory: apps/api/v2
run: |
yarn workspace @calcom/platform-libraries build && yarn test:e2e
yarn test:e2e:ci --shard=${{ matrix.shard }}/${{ strategy.job-total }}
EXIT_CODE=$?
echo "yarn workspace @calcom/platform-libraries build && yarn test:e2e command exit code: $EXIT_CODE"
echo "yarn test:e2e:ci --shard=${{ matrix.shard }}/${{ strategy.job-total }} command exit code: $EXIT_CODE"
exit $EXIT_CODE
- name: Upload Test Results
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: test-results-api-v2
path: test-results
name: test-results-api-v2-shard-${{ matrix.shard }}
path: apps/api/v2/test-results
if-no-files-found: ignore
retention-days: 7
+8 -6
View File
@@ -45,7 +45,7 @@ jobs:
e2e-app-store:
timeout-minutes: 20
name: E2E App Store
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
services:
postgres:
image: postgres:13
@@ -57,10 +57,11 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-cmd "pg_isready -h 127.0.0.1 -U postgres"
--health-interval 2s
--health-timeout 3s
--health-retries 15
--health-start-period 2s
ports:
- 5432:5432
mailhog:
@@ -83,6 +84,7 @@ jobs:
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/yarn-playwright-install
- run: yarn prisma generate
- uses: ./.github/actions/cache-db
env:
DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
@@ -93,7 +95,7 @@ jobs:
E2E_TEST_CALCOM_GCAL_KEYS: ${{ secrets.E2E_TEST_CALCOM_GCAL_KEYS }}
- uses: ./.github/actions/cache-build
- name: Run Tests
run: yarn e2e:app-store
run: yarn e2e:app-store --workers=4
- name: Upload Test Results
if: ${{ always() }}
uses: actions/upload-artifact@v4
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
e2e-atoms:
timeout-minutes: 15
name: E2E Atoms
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: docker/login-action@v3
with:
+8 -6
View File
@@ -45,7 +45,7 @@ jobs:
e2e-embed:
timeout-minutes: 20
name: E2E Embed React
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
services:
postgres:
image: postgres:13
@@ -57,10 +57,11 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-cmd "pg_isready -h 127.0.0.1 -U postgres"
--health-interval 2s
--health-timeout 3s
--health-retries 15
--health-start-period 2s
ports:
- 5432:5432
strategy:
@@ -75,11 +76,12 @@ jobs:
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/yarn-playwright-install
- run: yarn prisma generate
- uses: ./.github/actions/cache-db
- uses: ./.github/actions/cache-build
- name: Run Tests
run: |
yarn e2e:embed-react
yarn e2e:embed-react --workers=4
yarn workspace @calcom/embed-react packaged:tests
- name: Upload Test Results
if: ${{ always() }}
+8 -6
View File
@@ -45,7 +45,7 @@ jobs:
e2e-embed:
timeout-minutes: 20
name: E2E Embed Core
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
services:
postgres:
image: postgres:13
@@ -57,10 +57,11 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-cmd "pg_isready -h 127.0.0.1 -U postgres"
--health-interval 2s
--health-timeout 3s
--health-retries 15
--health-start-period 2s
ports:
- 5432:5432
mailhog:
@@ -83,10 +84,11 @@ jobs:
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/yarn-playwright-install
- run: yarn prisma generate
- uses: ./.github/actions/cache-db
- uses: ./.github/actions/cache-build
- name: Run Tests
run: yarn e2e:embed
run: yarn e2e:embed --workers=4
- name: Upload Test Results
if: ${{ always() }}
uses: actions/upload-artifact@v4
+212
View File
@@ -0,0 +1,212 @@
name: E2E Report
on:
workflow_run:
workflows: ["PR Update"]
types:
- completed
workflow_dispatch:
inputs:
pr_number:
description: 'The PR number to generate report for'
required: true
type: string
jobs:
get-pr-info:
name: Get PR Info
runs-on: ubuntu-latest
# For workflow_run: only run if the triggering workflow failed
# For workflow_dispatch: always run (inputs are provided manually)
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'failure' }}
permissions:
actions: read
pull-requests: read
outputs:
pr-number: ${{ steps.get-info.outputs.pr-number }}
head-branch: ${{ steps.get-info.outputs.head-branch }}
has-blob-reports: ${{ steps.get-info.outputs.has-blob-reports }}
source-run-id: ${{ steps.get-info.outputs.source-run-id }}
source-run-number: ${{ steps.get-info.outputs.source-run-number }}
source-run-attempt: ${{ steps.get-info.outputs.source-run-attempt }}
source-head-sha: ${{ steps.get-info.outputs.source-head-sha }}
steps:
- name: Get PR and run info
id: get-info
uses: actions/github-script@v7
with:
script: |
const isDispatch = context.eventName === 'workflow_dispatch';
if (isDispatch) {
// For workflow_dispatch: look up everything from PR number
const prNumber = context.payload.inputs.pr_number;
console.log('Looking up PR:', prNumber);
// Get PR details
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: parseInt(prNumber)
});
const headSha = pr.head.sha;
const headBranch = pr.head.ref;
console.log('PR head SHA:', headSha);
console.log('PR head branch:', headBranch);
// Find the "PR Update" workflow
const { data: workflows } = await github.rest.actions.listRepoWorkflows({
owner: context.repo.owner,
repo: context.repo.repo
});
const prUpdateWorkflow = workflows.workflows.find(w => w.name === 'PR Update');
if (!prUpdateWorkflow) {
core.setFailed('Could not find "PR Update" workflow');
return;
}
console.log('Found PR Update workflow ID:', prUpdateWorkflow.id);
// Find the most recent completed run for this branch with blob-report artifacts
// We search by branch instead of SHA to handle cases where:
// 1. The PR was updated after E2E tests ran (artifacts exist for older SHA)
// 2. The current run for the SHA is still queued/in-progress
const { data: runs } = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: prUpdateWorkflow.id,
branch: headBranch,
status: 'completed',
per_page: 20
});
console.log('Found', runs.workflow_runs.length, 'completed runs for branch', headBranch);
// Find a run with blob-report artifacts
let selectedRun = null;
let hasBlobReports = false;
for (const run of runs.workflow_runs) {
console.log('Checking run', run.id, 'conclusion:', run.conclusion);
const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: run.id
});
const blobReports = artifacts.artifacts.filter(a => a.name.startsWith('blob-report-'));
if (blobReports.length > 0) {
console.log('Found run with blob reports:', run.id, 'artifacts:', blobReports.map(a => a.name));
selectedRun = run;
hasBlobReports = true;
break;
}
}
if (!selectedRun) {
console.log('No runs found with blob-report artifacts');
core.setOutput('pr-number', prNumber);
core.setOutput('head-branch', headBranch);
core.setOutput('source-head-sha', headSha);
core.setOutput('has-blob-reports', 'false');
core.setOutput('source-run-id', '');
core.setOutput('source-run-number', '');
core.setOutput('source-run-attempt', '');
return;
}
core.setOutput('pr-number', prNumber);
core.setOutput('head-branch', headBranch);
core.setOutput('source-head-sha', headSha);
core.setOutput('source-run-id', selectedRun.id.toString());
core.setOutput('source-run-number', selectedRun.run_number.toString());
core.setOutput('source-run-attempt', selectedRun.run_attempt.toString());
core.setOutput('has-blob-reports', 'true');
return;
}
// For workflow_run: extract from payload
const workflowRun = context.payload.workflow_run;
const headSha = workflowRun.head_sha;
const headBranch = workflowRun.head_branch;
console.log('Head SHA:', headSha);
console.log('Head Branch:', headBranch);
// Set source run info
core.setOutput('source-run-id', workflowRun.id.toString());
core.setOutput('source-run-number', workflowRun.run_number.toString());
core.setOutput('source-run-attempt', workflowRun.run_attempt.toString());
core.setOutput('source-head-sha', headSha);
// Check for blob report artifacts
const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: workflowRun.id
});
const blobReports = artifacts.artifacts.filter(a => a.name.startsWith('blob-report-'));
console.log('Found blob reports:', blobReports.map(a => a.name));
core.setOutput('has-blob-reports', blobReports.length > 0 ? 'true' : 'false');
// Try to get PR number from workflow_run payload first
if (workflowRun.pull_requests && workflowRun.pull_requests.length > 0) {
const prNumber = workflowRun.pull_requests[0].number;
console.log('PR number from payload:', prNumber);
core.setOutput('pr-number', prNumber.toString());
core.setOutput('head-branch', headBranch);
return;
}
// Fall back to API lookup
try {
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: headSha
});
if (prs.length === 0) {
console.log('No PRs found for commit');
core.setOutput('pr-number', '');
core.setOutput('head-branch', headBranch);
return;
}
// Find open PR or use first one
const openPr = prs.find(pr => pr.state === 'open') || prs[0];
console.log('PR number from API:', openPr.number);
core.setOutput('pr-number', openPr.number.toString());
core.setOutput('head-branch', openPr.head.ref);
} catch (e) {
console.log('Error fetching PR:', e);
core.setOutput('pr-number', '');
core.setOutput('head-branch', headBranch);
}
merge-reports:
name: Merge reports
needs: [get-pr-info]
if: ${{ needs.get-pr-info.outputs.has-blob-reports == 'true' && needs.get-pr-info.outputs.pr-number != '' }}
uses: ./.github/workflows/merge-reports.yml
with:
source_run_id: ${{ needs.get-pr-info.outputs.source-run-id }}
source_run_number: ${{ needs.get-pr-info.outputs.source-run-number }}
source_run_attempt: ${{ needs.get-pr-info.outputs.source-run-attempt }}
source_head_sha: ${{ needs.get-pr-info.outputs.source-head-sha }}
# No secrets: inherit - merge-reports only needs the default GITHUB_TOKEN for artifact download
publish-report:
name: Publish HTML report
needs: [get-pr-info, merge-reports]
if: ${{ needs.get-pr-info.outputs.pr-number != '' }}
uses: ./.github/workflows/publish-report.yml
with:
head_branch: ${{ needs.get-pr-info.outputs.head-branch }}
source_run_id: ${{ needs.get-pr-info.outputs.source-run-id }}
source_run_number: ${{ needs.get-pr-info.outputs.source-run-number }}
source_run_attempt: ${{ needs.get-pr-info.outputs.source-run-attempt }}
pr_number: ${{ needs.get-pr-info.outputs.pr-number }}
secrets: inherit
+11 -9
View File
@@ -5,7 +5,6 @@ permissions:
actions: write
contents: read
env:
NODE_OPTIONS: --max-old-space-size=4096
ALLOWED_HOSTNAMES: ${{ vars.CI_ALLOWED_HOSTNAMES }}
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
DAILY_API_KEY: ${{ secrets.CI_DAILY_API_KEY }}
@@ -15,11 +14,11 @@ env:
E2E_TEST_APPLE_CALENDAR_EMAIL: ${{ secrets.E2E_TEST_APPLE_CALENDAR_EMAIL }}
E2E_TEST_APPLE_CALENDAR_PASSWORD: ${{ secrets.E2E_TEST_APPLE_CALENDAR_PASSWORD }}
E2E_TEST_MAILHOG_ENABLED: ${{ vars.E2E_TEST_MAILHOG_ENABLED }}
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
EMAIL_SERVER_PORT: ${{ secrets.CI_EMAIL_SERVER_PORT }}
EMAIL_SERVER_USER: ${{ secrets.CI_EMAIL_SERVER_USER }}
EMAIL_SERVER_PASSWORD: ${{ secrets.CI_EMAIL_SERVER_PASSWORD}}
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
GOOGLE_LOGIN_ENABLED: ${{ vars.CI_GOOGLE_LOGIN_ENABLED }}
NEXTAUTH_SECRET: ${{ secrets.CI_NEXTAUTH_SECRET }}
NEXTAUTH_URL: ${{ secrets.CI_NEXTAUTH_URL }}
@@ -30,6 +29,7 @@ env:
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
NEXT_PUBLIC_WEBAPP_URL: ${{ vars.CI_NEXT_PUBLIC_WEBAPP_URL }}
NEXT_PUBLIC_WEBSITE_URL: ${{ vars.CI_NEXT_PUBLIC_WEBSITE_URL }}
NODE_OPTIONS: --max-old-space-size=4096
PAYMENT_FEE_FIXED: ${{ vars.CI_PAYMENT_FEE_FIXED }}
PAYMENT_FEE_PERCENTAGE: ${{ vars.CI_PAYMENT_FEE_PERCENTAGE }}
SAML_ADMINS: ${{ secrets.CI_SAML_ADMINS }}
@@ -45,7 +45,7 @@ jobs:
e2e:
timeout-minutes: 20
name: E2E (${{ matrix.shard }}/${{ strategy.job-total }})
runs-on: buildjet-8vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
services:
postgres:
image: postgres:13
@@ -57,10 +57,11 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-cmd "pg_isready -h 127.0.0.1 -U postgres"
--health-interval 2s
--health-timeout 3s
--health-retries 15
--health-start-period 2s
ports:
- 5432:5432
mailhog:
@@ -74,7 +75,7 @@ jobs:
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
shard: [1, 2, 3, 4, 5, 6, 7, 8]
steps:
- uses: docker/login-action@v3
with:
@@ -84,10 +85,11 @@ jobs:
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/yarn-playwright-install
- run: yarn prisma generate
- uses: ./.github/actions/cache-db
- uses: ./.github/actions/cache-build
- name: Run Tests
run: yarn e2e --shard=${{ matrix.shard }}/${{ strategy.job-total }}
run: yarn e2e --shard=${{ matrix.shard }}/${{ strategy.job-total }} --workers=4
- name: Upload Test Results
uses: actions/upload-artifact@v4
if: always()
+10 -2
View File
@@ -10,12 +10,20 @@ concurrency:
jobs:
i18n:
name: Run i18n
runs-on: buildjet-2vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
actions: write
contents: write
pull-requests: write
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94
with:
app-id: ${{ secrets.CI_CAL_APP_ID }}
private-key: ${{ secrets.CI_CAL_APP_PRIVATE_KEY }}
repositories: 'cal.com'
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
@@ -23,7 +31,7 @@ jobs:
cache: 'npm'
- uses: lingodotdev/lingo.dev@main
env:
GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
with:
api-key: ${{ secrets.CI_LINGO_DOT_DEV_API_KEY }}
pull-request: true
+3 -2
View File
@@ -45,7 +45,7 @@ jobs:
integration:
timeout-minutes: 20
name: Integration
runs-on: buildjet-8vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
services:
postgres:
image: postgres:13
@@ -81,9 +81,10 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- run: yarn prisma generate
- uses: ./.github/actions/cache-db
- name: Run Tests
run: yarn test -- --integrationTestsOnly
run: VITEST_MODE=integration yarn test
# TODO: Generate test results so we can upload them
# - name: Upload Test Results
# if: ${{ always() }}
+1 -1
View File
@@ -6,7 +6,7 @@ permissions:
contents: read
jobs:
lint:
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
+22 -2
View File
@@ -1,17 +1,37 @@
# https://playwright.dev/docs/test-sharding#merging-reports-from-multiple-shards
on:
workflow_call:
inputs:
source_run_id:
description: 'The run ID to download artifacts from (for workflow_run triggered calls)'
required: true
type: string
source_run_number:
description: 'The run number for artifact naming'
required: true
type: string
source_run_attempt:
description: 'The run attempt for artifact naming'
required: true
type: string
source_head_sha:
description: 'The head SHA to checkout for Playwright version consistency'
required: true
type: string
jobs:
merge-reports:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
with:
ref: ${{ inputs.source_head_sha }}
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/yarn-playwright-install
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
run-id: ${{ inputs.source_run_id }}
github-token: ${{ github.token }}
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
@@ -20,6 +40,6 @@ jobs:
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_number }}-${{ github.run_attempt }}
name: html-report--attempt-${{ inputs.source_run_number }}-${{ inputs.source_run_attempt }}
path: playwright-report
retention-days: 14
@@ -12,13 +12,13 @@ permissions:
jobs:
annotate:
if: always()
runs-on: buildjet-2vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/cache-build
- name: Download base branch bundle stats
uses: dawidd6/action-download-artifact@v2
uses: dawidd6/action-download-artifact@v6
if: success()
with:
workflow: nextjs-bundle-analysis.yml
+2 -1
View File
@@ -49,12 +49,13 @@ env:
jobs:
analyze:
if: always()
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- run: yarn prisma generate
- uses: ./.github/actions/cache-build
- name: Analyze bundle
run: |
+12 -1
View File
@@ -6,16 +6,27 @@ on:
tags:
- "*"
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94
with:
app-id: ${{ secrets.CI_CAL_APP_ID }}
private-key: ${{ secrets.CI_CAL_APP_PRIVATE_KEY }}
repositories: 'cal.com'
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: 'main'
token: ${{ secrets.GH_ACCESS_TOKEN }}
token: ${{ steps.generate-token.outputs.token }}
- name: Configure git
run: |
+308 -95
View File
@@ -1,11 +1,13 @@
# ⚠️ SECURITY: Do not add steps that checkout PR code or run local actions before trust-check job completes.
name: PR Update
on:
pull_request_target:
types: [opened, synchronize, reopened, labeled]
types: [opened, synchronize, reopened]
branches:
- main
- gh-actions-test-branch
workflow_dispatch:
permissions:
@@ -17,49 +19,207 @@ concurrency:
cancel-in-progress: true
jobs:
changes:
name: Detect changes
runs-on: buildjet-2vcpu-ubuntu-2204
# Security gate: Check if PR is from a trusted contributor or approved via run-ci label
# This MUST run before any job that checks out PR code and executes it with secrets
trust-check:
name: Trust Check
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
pull-requests: read
actions: read
issues: read
outputs:
is-trusted: ${{ steps.check-trust.outputs.is-trusted }}
steps:
- name: Check if PR is trusted
id: check-trust
uses: actions/github-script@v7
with:
script: |
const trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR'];
if (!context.payload.pull_request) {
if (context.eventName === 'workflow_dispatch') {
console.log('workflow_dispatch event - assuming trusted (manual trigger)');
core.setOutput('is-trusted', true);
return;
}
console.log('No pull request context found');
core.setOutput('is-trusted', false);
return;
}
const owner = context.repo.owner;
const repo = context.repo.repo;
// Fetch fresh PR data - payload labels may be stale on re-runs
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: context.payload.pull_request.number,
});
const prNumber = pr.number;
const headSha = pr.head.sha;
async function hasWriteAccess(username) {
try {
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner,
repo,
username,
});
return ['admin', 'maintain', 'write'].includes(permission.permission);
} catch (e) {
console.log(`Permission check failed for ${username}: ${e.message}`);
return false;
}
}
console.log(`PR #${prNumber} by ${pr.user.login} (${pr.author_association})`);
// Check 1: Is the author a trusted contributor?
if (trustedAssociations.includes(pr.author_association)) {
console.log(`Author has trusted association: ${pr.author_association}`);
core.setOutput('is-trusted', true);
return;
}
// Check 2: Verify write access via API (author_association can be unreliable)
if (await hasWriteAccess(pr.user.login)) {
console.log(`Author has write access`);
core.setOutput('is-trusted', true);
return;
}
// Check 3: Was 'run-ci' label added AFTER this SHA was pushed by someone with write access?
// This enables re-runs triggered by the run-ci.yml workflow
// NOTE: We use workflow run created_at instead of commit timestamp because
// git commit timestamps can be arbitrarily backdated by attackers
if (pr.labels?.some(l => l.name === 'run-ci')) {
const events = await github.paginate(github.rest.issues.listEvents, {
owner,
repo,
issue_number: prNumber,
per_page: 100,
});
const labelEvent = events
.filter(e => e.event === 'labeled' && e.label?.name === 'run-ci')
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0];
if (labelEvent) {
// Get workflow runs to find when this SHA was first pushed
const runs = await github.paginate(github.rest.actions.listWorkflowRuns, {
owner,
repo,
workflow_id: 'pr.yml',
head_sha: headSha,
per_page: 100,
});
// Filter runs to this PR (in case same SHA exists in multiple PRs)
const matchingRuns = runs.filter(run =>
!run.pull_requests?.length || run.pull_requests.some(p => p.number === prNumber)
);
if (matchingRuns.length > 0) {
const labelTime = new Date(labelEvent.created_at);
// Use the oldest run's created_at as the push time
const originalRun = matchingRuns[matchingRuns.length - 1];
const pushTime = new Date(originalRun.created_at);
if (labelTime > pushTime) {
const adder = labelEvent.actor.login;
if (await hasWriteAccess(adder)) {
console.log(`Approved via 'run-ci' label added by ${adder} after push (label: ${labelTime.toISOString()}, push: ${pushTime.toISOString()})`);
core.setOutput('is-trusted', true);
return;
}
console.log(`Label 'run-ci' added by ${adder} (no write access)`);
} else {
console.log(`Label 'run-ci' is stale (label: ${labelTime.toISOString()}, push: ${pushTime.toISOString()})`);
}
} else {
console.log('No workflow runs found for this SHA - cannot validate label timing');
}
}
}
console.log('External contribution requires "run-ci" label from a maintainer');
core.setOutput('is-trusted', false);
prepare:
name: Prepare
needs: [trust-check]
if: needs.trust-check.outputs.is-trusted == 'true'
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
pull-requests: read
outputs:
has-files-requiring-all-checks: ${{ steps.filter.outputs.has-files-requiring-all-checks }}
has_companion: ${{ steps.filter.outputs.has_companion }}
has-api-v2-changes: ${{ steps.filter.outputs.has-api-v2-changes }}
commit-sha: ${{ steps.get_sha.outputs.commit-sha }}
run-e2e: ${{ steps.check-if-pr-has-label.outputs.run-e2e == 'true' }}
db-cache-hit: ${{ steps.cache-db-check.outputs.cache-hit }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- name: Generate DB cache key
id: cache-db-key
uses: ./.github/actions/cache-db-key
- name: Check DB cache (lookup-only)
id: cache-db-check
uses: actions/cache/restore@v4
with:
path: backups/backup.sql
key: ${{ steps.cache-db-key.outputs.key }}
lookup-only: true
- uses: dorny/paths-filter@v3
id: filter
with:
predicate-quantifier: "every"
filters: |
has-files-requiring-all-checks:
- "!(**.md|**.mdx|.github/CODEOWNERS|docs/**|help/**|apps/web/public/static/locales/**/common.json|i18n.lock)"
- '**'
- '!companion/**'
- '!**/*.md'
- '!**/*.mdx'
- '!.github/CODEOWNERS'
- '!docs/**'
- '!help/**'
- '!apps/web/public/static/locales/**/common.json'
- '!i18n.lock'
has_companion:
- "companion/**"
has-api-v2-changes:
- "apps/api/v2/**"
- "packages/platform-constants/**"
- "packages/platform-enums/**"
- "packages/platform-utils/**"
- "packages/platform-types/**"
- "packages/platform-libraries/**"
- "packages/trpc/**"
- "packages/prisma/schema.prisma"
- "docs/api-reference/v2/**"
- name: Get Latest Commit SHA
id: get_sha
run: |
echo "commit-sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
check-label:
needs: [changes]
runs-on: buildjet-2vcpu-ubuntu-2204
name: Check for E2E label
permissions:
pull-requests: read
outputs:
run-e2e: ${{ steps.check-if-pr-has-label.outputs.run-e2e == 'true' && (github.event.action != 'labeled' || github.event.label.name == 'ready-for-e2e') }}
steps:
- name: Check if PR exists with ready-for-e2e label for this SHA
id: check-if-pr-has-label
uses: actions/github-script@v7
with:
script: |
let labels = [];
let prNumber = null;
if (context.payload.pull_request) {
labels = context.payload.pull_request.labels;
prNumber = context.payload.pull_request.number;
} else {
try {
const sha = '${{ needs.changes.outputs.commit-sha }}';
const sha = '${{ steps.get_sha.outputs.commit-sha }}';
console.log('sha', sha);
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
@@ -73,132 +233,174 @@ jobs:
return;
}
const pr = prs[0];
console.log(`PR number: ${pr.number}`);
console.log(`PR title: ${pr.title}`);
console.log(`PR state: ${pr.state}`);
console.log(`PR URL: ${pr.html_url}`);
labels = pr.labels;
prNumber = prs[0].number;
}
catch (e) {
core.setOutput('run-e2e', false);
console.log(e);
return;
}
}
// Always fetch fresh PR data to get current labels
// This avoids stale label data from event payloads
try {
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
console.log(`PR number: ${pr.number}`);
console.log(`PR title: ${pr.title}`);
console.log(`PR state: ${pr.state}`);
console.log(`PR URL: ${pr.html_url}`);
labels = pr.labels;
}
catch (e) {
core.setOutput('run-e2e', false);
console.log(e);
return;
}
const labelFound = labels.map(l => l.name).includes('ready-for-e2e');
console.log('Found the label?', labelFound);
core.setOutput('run-e2e', labelFound);
deps:
name: Install dependencies
needs: [changes, check-label]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/yarn-install.yml
- uses: ./.github/actions/yarn-install
if: ${{ steps.filter.outputs.has-files-requiring-all-checks == 'true' }}
with:
skip-install-if-cache-hit: "true"
- uses: ./.github/actions/yarn-playwright-install
if: ${{ steps.filter.outputs.has-files-requiring-all-checks == 'true' }}
with:
skip-install-if-cache-hit: "true"
type-check:
name: Type check
needs: [changes, check-label, deps]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/check-types.yml
secrets: inherit
lint:
name: Linters
needs: [changes, check-label, deps]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/lint.yml
secrets: inherit
unit-test:
name: Tests
needs: [changes, check-label, deps]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/unit-tests.yml
secrets: inherit
api-v2-unit-test:
name: Tests
needs: [prepare]
if: ${{ needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/api-v2-unit-tests.yml
secrets: inherit
setup-db:
name: Setup Database
needs: [prepare]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/setup-db.yml
with:
DB_CACHE_HIT: ${{ needs.prepare.outputs.db-cache-hit }}
secrets: inherit
build-api-v1:
name: Production builds
needs: [changes, check-label, deps]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/api-v1-production-build.yml
secrets: inherit
build-api-v2:
name: Production builds
needs: [changes, check-label, deps]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/api-v2-production-build.yml
secrets: inherit
build-atoms:
name: Production builds
needs: [changes, check-label, deps]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/atoms-production-build.yml
secrets: inherit
build-docs:
name: Production builds
needs: [changes, check-label, deps]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/docs-build.yml
secrets: inherit
build-companion:
name: Companion builds
needs: [changes, check-label, deps]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: needs.prepare.outputs.has_companion == 'true'
uses: ./.github/workflows/companion-build.yml
secrets: inherit
build:
name: Production builds
needs: [changes, check-label, deps]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/production-build-without-database.yml
secrets: inherit
integration-test:
name: Tests
needs: [changes, check-label, build, build-api-v1, build-api-v2]
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, build, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/integration-tests.yml
secrets: inherit
e2e:
name: Tests
needs: [changes, check-label, build, build-api-v1, build-api-v2]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, build, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/e2e.yml
secrets: inherit
check-api-v2-breaking-changes:
name: Check API v2 breaking changes
needs: [prepare]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-api-v2-changes == 'true' }}
uses: ./.github/workflows/check-api-v2-breaking-changes.yml
secrets: inherit
e2e-api-v2:
name: Tests
needs: [changes, check-label, build, build-api-v1, build-api-v2]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/e2e-api-v2.yml
secrets: inherit
e2e-app-store:
name: Tests
needs: [changes, check-label, build, build-api-v1, build-api-v2]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, build, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/e2e-app-store.yml
secrets: inherit
e2e-embed:
name: Tests
needs: [changes, check-label, build, build-api-v1, build-api-v2]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, build, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/e2e-embed.yml
secrets: inherit
e2e-embed-react:
name: Tests
needs: [changes, check-label, build, build-api-v1, build-api-v2]
if: ${{ needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [prepare, build, setup-db]
if: ${{ needs.prepare.outputs.run-e2e == 'true' && needs.prepare.outputs.has-files-requiring-all-checks == 'true' }}
uses: ./.github/workflows/e2e-embed-react.yml
secrets: inherit
@@ -208,59 +410,70 @@ jobs:
uses: ./.github/workflows/nextjs-bundle-analysis.yml
secrets: inherit
merge-reports:
name: Merge reports
if: ${{ !cancelled() && needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
needs: [changes, check-label, e2e, e2e-embed, e2e-embed-react, e2e-app-store]
uses: ./.github/workflows/merge-reports.yml
secrets: inherit
publish-report:
name: Publish HTML report
if: ${{ !cancelled() && needs.check-label.outputs.run-e2e == 'true' && needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
permissions:
contents: write
issues: write
pull-requests: write
needs: [changes, check-label, merge-reports]
uses: ./.github/workflows/publish-report.yml
secrets: inherit
cleanup-report:
name: Cleanup HTML report
if: ${{ !cancelled() && needs.check-label.outputs.run-e2e == 'true' && (github.event.pull_request.merged == true || github.event.pull_request.state == 'closed') }}
permissions:
contents: write
issues: write
pull-requests: write
needs: [changes, check-label, publish-report]
uses: ./.github/workflows/cleanup-report.yml
secrets: inherit
required:
needs:
[
changes,
trust-check,
prepare,
lint,
type-check,
unit-test,
api-v2-unit-test,
check-api-v2-breaking-changes,
integration-test,
check-label,
build,
build-api-v1,
build-api-v2,
build-atoms,
build-docs,
build-companion,
setup-db,
e2e,
e2e-api-v2,
e2e-embed,
e2e-embed-react,
e2e-app-store
e2e-app-store,
]
if: always()
runs-on: buildjet-2vcpu-ubuntu-2204
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: fail if conditional jobs failed
if: needs.changes.outputs.has-files-requiring-all-checks == 'true' && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') || contains(needs.*.result, 'cancelled'))
- name: Fail if trust-check did not succeed
run: |
echo "::error::Trust check did not complete successfully (result: ${{ needs.trust-check.result }}). Please re-run the workflow."
exit 1
if: needs.trust-check.result != 'success'
- name: Fail if PR is not trusted (external contributor without run-ci label)
run: |
echo "::error::This PR is from an external contributor and requires the 'run-ci' label before CI can run."
echo "A maintainer must review the code and add the 'run-ci' label to trigger CI checks."
exit 1
if: needs.trust-check.outputs.is-trusted != 'true' && needs.trust-check.result == 'success'
- name: Fail if conditional jobs failed
run: exit 1
if: |
(
needs.prepare.outputs.has-files-requiring-all-checks == 'true' &&
(
needs.lint.result != 'success' ||
needs.type-check.result != 'success' ||
needs.unit-test.result != 'success' ||
needs.api-v2-unit-test.result != 'success' ||
(needs.prepare.outputs.has-api-v2-changes == 'true' && needs.check-api-v2-breaking-changes.result != 'success') ||
needs.build.result != 'success' ||
needs.build-api-v1.result != 'success' ||
needs.build-api-v2.result != 'success' ||
needs.build-atoms.result != 'success' ||
needs.build-docs.result != 'success' ||
needs.setup-db.result != 'success' ||
needs.integration-test.result != 'success' ||
needs.e2e.result != 'success' ||
needs.e2e-api-v2.result != 'success' ||
needs.e2e-embed.result != 'success' ||
needs.e2e-embed-react.result != 'success' ||
needs.e2e-app-store.result != 'success'
)
) ||
(
needs.prepare.outputs.has_companion == 'true' &&
needs.build-companion.result != 'success'
)
@@ -4,6 +4,7 @@ on:
permissions:
contents: read
actions: write
env:
ALLOWED_HOSTNAMES: ${{ vars.CI_ALLOWED_HOSTNAMES }}
@@ -38,10 +39,33 @@ env:
jobs:
build:
name: Build Web App
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- run: yarn prisma generate
- name: Generate cache key
id: cache-key
uses: ./.github/actions/cache-build-key
with:
branch_key: ${{ github.head_ref || github.ref_name }}
- name: Check if production build cache exists
uses: actions/cache@v4
id: cache-check
with:
path: |
${{ github.workspace }}/apps/web/.next
${{ github.workspace }}/apps/web/public/embed
**/.turbo/**
**/dist/**
key: ${{ steps.cache-key.outputs.key }}
lookup-only: true
- name: Delete old production build caches for this branch
if: steps.cache-check.outputs.cache-hit != 'true'
uses: useblacksmith/cache-delete@v1
with:
key: prod-build-${{ github.head_ref || github.ref_name }}
prefix: "true"
- uses: ./.github/actions/cache-build
+45 -11
View File
@@ -1,5 +1,26 @@
on:
workflow_call:
inputs:
head_branch:
description: 'The head branch name for report path'
required: true
type: string
source_run_id:
description: 'The source run ID for report path'
required: true
type: string
source_run_number:
description: 'The source run number for artifact naming and comment'
required: true
type: string
source_run_attempt:
description: 'The source run attempt for artifact naming and comment'
required: true
type: string
pr_number:
description: 'The PR number to post comment on'
required: true
type: string
permissions:
contents: write
issues: write
@@ -10,15 +31,23 @@ jobs:
continue-on-error: true
env:
# Unique URL path for each workflow run attempt
HTML_REPORT_URL_PATH: reports/${{ github.head_ref }}/${{ github.run_id }}/${{ github.run_attempt }}
BRANCH_REPORTS_DIR: reports/${{ github.head_ref }}
HTML_REPORT_URL_PATH: reports/${{ inputs.head_branch }}/${{ inputs.source_run_id }}/${{ inputs.source_run_attempt }}
BRANCH_REPORTS_DIR: reports/${{ inputs.head_branch }}
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94
with:
app-id: ${{ secrets.CI_CAL_APP_ID }}
private-key: ${{ secrets.CI_CAL_APP_PRIVATE_KEY }}
repositories: 'test-results-2'
- name: Checkout GitHub Pages Branch
uses: actions/checkout@v4
with:
repository: calcom/test-results-2
ref: gh-pages
token: ${{ secrets.GH_ACCESS_TOKEN }}
token: ${{ steps.generate-token.outputs.token }}
- name: Set Git User
# see: https://github.com/actions/checkout/issues/13#issuecomment-724415212
run: |
@@ -34,22 +63,27 @@ jobs:
- name: Cleanup old HTML reports
if: ${{ env.BRANCH_REPORTS_EXIST == 'true' }}
timeout-minutes: 3
env:
HEAD_BRANCH: ${{ inputs.head_branch }}
run: |
rm -rf $BRANCH_REPORTS_DIR
rm -rf "$BRANCH_REPORTS_DIR"
git add .
git commit -m "workflow: remove all reports for branch ${{ github.head_ref }}"
git commit -m "workflow: remove all reports for branch $HEAD_BRANCH"
- name: Download zipped HTML report
uses: actions/download-artifact@v4
with:
name: html-report--attempt-${{ github.run_number }}-${{ github.run_attempt }}
name: html-report--attempt-${{ inputs.source_run_number }}-${{ inputs.source_run_attempt }}
path: ${{ env.HTML_REPORT_URL_PATH }}
- name: Push HTML Report
timeout-minutes: 3
# commit report, then try push-rebase-loop until it's able to merge the HTML report to the gh-pages branch
# this is necessary when this job running at least twice at the same time (e.g. through two pushes at the same time)
env:
RUN_ID: ${{ inputs.source_run_id }}
RUN_ATTEMPT: ${{ inputs.source_run_attempt }}
run: |
git add .
git commit -m "workflow: add HTML report for run-id ${{ github.run_id }} (attempt: ${{ github.run_attempt }})"
git commit -m "workflow: add HTML report for run-id $RUN_ID (attempt: $RUN_ATTEMPT)"
while true; do
git pull --rebase
@@ -74,18 +108,18 @@ jobs:
uses: peter-evans/find-comment@v2
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
issue-number: ${{ inputs.pr_number }}
comment-author: "github-actions[bot]"
body-includes: <!-- GENERATED-E2E-RESULTS -->
- name: Create comment
if: steps.fc.outputs.comment-id == ''
uses: peter-evans/create-or-update-comment@v3
with:
issue-number: ${{ github.event.pull_request.number }}
issue-number: ${{ inputs.pr_number }}
body: |
<!-- GENERATED-E2E-RESULTS -->
## E2E results are ready!
- [Workflow #${{ github.run_number }}.${{ github.run_attempt }} latest results](${{ steps.url.outputs.link }})
- [Workflow #${{ inputs.source_run_number }}.${{ inputs.source_run_attempt }} latest results](${{ steps.url.outputs.link }})
- name: Update comment
if: steps.fc.outputs.comment-id != ''
uses: peter-evans/create-or-update-comment@v3
@@ -95,4 +129,4 @@ jobs:
body: |
<!-- GENERATED-E2E-RESULTS -->
## E2E results are ready!
- [Workflow #${{ github.run_number }}.${{ github.run_attempt }} latest results](${{ steps.url.outputs.link }})
- [Workflow #${{ inputs.source_run_number }}.${{ inputs.source_run_attempt }} latest results](${{ steps.url.outputs.link }})
+30 -6
View File
@@ -1,5 +1,9 @@
name: "Release Docker"
permissions:
contents: read
packages: write
env:
POSTGRES_USER: "unicorn_user"
POSTGRES_PASSWORD: "magical_password"
@@ -14,18 +18,30 @@ on:
workflow_dispatch:
inputs:
RELEASE_TAG:
description: "v{Major}.{Minor}.{Patch}"
description: "Tag to build (e.g., v6.0.5)"
required: true
PUSH_IMAGE:
description: "Push the Docker image to DockerHub"
type: boolean
default: true
jobs:
release-amd64:
name: "Release AMD64"
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- name: checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.RELEASE_TAG || github.ref }}
- name: "Determine tag"
run: 'echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV'
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "RELEASE_TAG=${{ inputs.RELEASE_TAG }}" >> $GITHUB_ENV
else
echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
fi
- name: Build and test Docker image
uses: ./.github/actions/docker-build-and-test
@@ -39,7 +55,8 @@ jobs:
postgres-password: ${{ env.POSTGRES_PASSWORD }}
postgres-db: ${{ env.POSTGRES_DB }}
database-host: ${{ env.DATABASE_HOST }}
push-image: "true"
push-image: ${{ (github.event_name == 'push' || inputs.PUSH_IMAGE) && 'true' || 'false' }}
use-as-latest: "true"
- name: Notify Slack on Success
if: success()
@@ -69,9 +86,16 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.RELEASE_TAG || github.ref }}
- name: "Determine tag"
run: 'echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV'
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "RELEASE_TAG=${{ inputs.RELEASE_TAG }}" >> $GITHUB_ENV
else
echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
fi
- name: Build and test Docker image
uses: ./.github/actions/docker-build-and-test
@@ -85,7 +109,7 @@ jobs:
postgres-password: ${{ env.POSTGRES_PASSWORD }}
postgres-db: ${{ env.POSTGRES_DB }}
database-host: ${{ env.DATABASE_HOST }}
push-image: "true"
push-image: ${{ (github.event_name == 'push' || inputs.PUSH_IMAGE) && 'true' || 'false' }}
- name: Notify Slack on Success
if: success()
+125
View File
@@ -0,0 +1,125 @@
name: Run CI
on:
pull_request_target:
types: [labeled]
permissions:
actions: write
contents: read
jobs:
trigger:
name: Trigger CI
if: github.event.label.name == 'run-ci' || github.event.label.name == 'ready-for-e2e'
runs-on: ubuntu-latest
steps:
- name: Verify and trigger CI
uses: actions/github-script@v7
with:
script: |
const adder = context.payload.sender.login;
const senderType = context.payload.sender.type;
const pr = context.payload.pull_request;
console.log(`Sender: ${adder} (type: ${senderType})`);
const trustedBotLogins = ['graphite-app[bot]'];
let isAuthorized = false;
if (senderType === 'Bot' && trustedBotLogins.includes(adder)) {
console.log(`Authorized: trusted GitHub App`);
isAuthorized = true;
}
if (!isAuthorized) {
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: adder,
});
if (!['admin', 'maintain', 'write'].includes(perm.permission)) {
core.setFailed(`${adder} does not have write access`);
return;
}
console.log(`Label added by ${adder}`);
}
// Find the latest pr.yml run for this PR's head SHA
const { data: runs } = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'pr.yml',
head_sha: pr.head.sha,
per_page: 5,
});
// Filter runs to this PR (in case same SHA exists in multiple PRs)
const matchingRuns = runs.workflow_runs.filter(run =>
!run.pull_requests?.length || run.pull_requests.some(p => p.number === pr.number)
);
if (matchingRuns.length === 0) {
core.setFailed(`No PR workflow found for SHA ${pr.head.sha}`);
return;
}
const latestRun = matchingRuns[0];
// If workflow is still running, cancel it first then re-run
if (latestRun.status === 'in_progress' || latestRun.status === 'queued') {
console.log(`Workflow is running (status: ${latestRun.status}). Cancelling it first...`);
await github.rest.actions.cancelWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: latestRun.id,
});
// Wait for the workflow to be cancelled (poll with timeout)
const maxWaitTime = 60000; // 60 seconds
const pollInterval = 2000; // 2 seconds
const startTime = Date.now();
while (Date.now() - startTime < maxWaitTime) {
await new Promise(resolve => setTimeout(resolve, pollInterval));
const { data: updatedRun } = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: latestRun.id,
});
if (updatedRun.status === 'completed') {
console.log(`Workflow cancelled successfully (conclusion: ${updatedRun.conclusion})`);
break;
}
console.log(`Waiting for workflow to cancel... (status: ${updatedRun.status})`);
}
// Check final status
const { data: finalRun } = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: latestRun.id,
});
if (finalRun.status !== 'completed') {
core.setFailed(`Timed out waiting for workflow to cancel (status: ${finalRun.status})`);
return;
}
}
console.log(`Re-running workflow ${latestRun.id} (was: ${latestRun.conclusion || latestRun.status})`);
// Re-run preserves original context (PR, SHA, etc.)
await github.rest.actions.reRunWorkflow({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: latestRun.id,
});
console.log(`Triggered: ${latestRun.html_url}`);
+56
View File
@@ -0,0 +1,56 @@
name: Setup Database
on:
workflow_call:
inputs:
DB_CACHE_HIT:
required: false
type: string
default: "false"
description: "Whether the DB cache was hit (skip yarn-install and cache-db if true)"
permissions:
contents: read
env:
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
DATABASE_DIRECT_URL: ${{ secrets.CI_DATABASE_URL }}
E2E_TEST_CALCOM_QA_EMAIL: ${{ secrets.E2E_TEST_CALCOM_QA_EMAIL }}
E2E_TEST_CALCOM_QA_PASSWORD: ${{ secrets.E2E_TEST_CALCOM_QA_PASSWORD }}
E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS: ${{ secrets.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }}
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
jobs:
setup-db:
name: Setup Database
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 15
services:
postgres:
image: postgres:13
credentials:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: calendso
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
if: inputs.DB_CACHE_HIT != 'true'
- run: yarn prisma generate
if: inputs.DB_CACHE_HIT != 'true'
- uses: ./.github/actions/cache-db
if: inputs.DB_CACHE_HIT != 'true'
+3 -7
View File
@@ -9,16 +9,12 @@ jobs:
test:
name: Unit
timeout-minutes: 20
runs-on: buildjet-4vcpu-ubuntu-2204
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- run: yarn prisma generate
- run: yarn test -- --no-isolate
# We could add different timezones here that we need to run our tests in
- run: TZ=America/Los_Angeles yarn test -- --timeZoneDependentTestsOnly --no-isolate
- name: Run API v2 tests
working-directory: apps/api/v2
run: |
export NODE_OPTIONS="--max_old_space_size=8192"
yarn workspace @calcom/platform-libraries build && yarn test
- run: TZ=America/Los_Angeles VITEST_MODE=timezone yarn test -- --no-isolate
-18
View File
@@ -1,18 +0,0 @@
name: Yarn install
on:
workflow_call:
permissions:
contents: read
jobs:
setup:
name: Yarn install & cache
runs-on: buildjet-4vcpu-ubuntu-2204
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/dangerous-git-checkout
- uses: ./.github/actions/yarn-install
- uses: ./.github/actions/yarn-playwright-install
+5 -1
View File
@@ -1,3 +1,7 @@
yarn lint-staged
if [ -f .git/MERGE_HEAD ]; then
echo "Merge detected. Skipping lint-staged and generators."
exit 0
fi
yarn lint-staged
yarn app-store:build && git add packages/app-store/*.generated.*
-19
View File
@@ -1,19 +0,0 @@
node_modules
.next
public
**/**/node_modules
**/**/.next
**/**/public
*.lock
*.log
.gitignore
.npmignore
.prettierignore
.DS_Store
.eslintignore
packages/prisma/zod
packages/prisma/enums
apps/web/public/embed
packages/ui/components/icon/dynamicIconImports.tsx
-1
View File
@@ -1 +0,0 @@
module.exports = require("./packages/config/prettier-preset");
+8 -9
View File
@@ -1,13 +1,12 @@
{
"recommendations": [
"DavidAnson.vscode-markdownlint", // markdown linting
"yzhang.markdown-all-in-one", // nicer markdown support
"esbenp.prettier-vscode", // prettier plugin
"dbaeumer.vscode-eslint", // eslint plugin
"ban.spellright", // Spell check for docs
"stripe.vscode-stripe", // stripe VSCode extension
"Prisma.prisma", // syntax|format|completion for prisma
"rebornix.project-snippets", // Share useful snippets between collaborators
"inlang.vs-code-extension" // improved i18n DX
"biomejs.biome",
"DavidAnson.vscode-markdownlint",
"yzhang.markdown-all-in-one",
"ban.spellright",
"stripe.vscode-stripe",
"Prisma.prisma",
"rebornix.project-snippets",
"inlang.vs-code-extension"
]
}
+5 -2
View File
@@ -1,12 +1,15 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.preferences.importModuleSpecifier": "non-relative",
"spellright.language": ["en"],
"spellright.documentTypes": ["markdown", "typescript", "typescriptreact"],
"tailwindCSS.classFunctions": ["cva"]
"tailwindCSS.classFunctions": ["cva"],
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
+2 -2
View File
@@ -2,8 +2,8 @@ diff --git a/dist/commonjs/serverSideTranslations.js b/dist/commonjs/serverSideT
index bcad3d02fbdfab8dacb1d85efd79e98623a0c257..fff668f598154a13c4030d1b4a90d5d9c18214ad 100644
--- a/dist/commonjs/serverSideTranslations.js
+++ b/dist/commonjs/serverSideTranslations.js
@@ -36,7 +36,6 @@ var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
@@ -36,7 +36,6 @@ var _fs = _interopRequireDefault(require("node:fs"));
var _path = _interopRequireDefault(require("node:path"));
var _createConfig = require("./config/createConfig");
var _node = _interopRequireDefault(require("./createClient/node"));
-var _appWithTranslation = require("./appWithTranslation");
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-873
View File
File diff suppressed because one or more lines are too long
+942
View File
File diff suppressed because one or more lines are too long
+5 -9
View File
@@ -1,11 +1,7 @@
compressionLevel: mixed
enableGlobalCache: false
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"
yarnPath: .yarn/releases/yarn-3.4.1.cjs
yarnPath: .yarn/releases/yarn-4.12.0.cjs
+16 -8
View File
@@ -16,6 +16,8 @@ You are a senior Cal.com engineer working in a Yarn/Turbo monorepo. You prioriti
- Use `date-fns` or native `Date` instead of Day.js when timezone awareness isn't needed
- Put permission checks in `page.tsx`, never in `layout.tsx`
- Use `ast-grep` for searching if available; otherwise use `rg` (ripgrep), then fall back to `grep`
- Use Biome for formatting and linting
## Don't
@@ -36,11 +38,8 @@ You are a senior Cal.com engineer working in a Yarn/Turbo monorepo. You prioriti
# Type check - always run on changed files
yarn type-check:ci --force
# Lint single file
yarn eslint --fix path/to/file.tsx
# Format single file
yarn prettier --write path/to/file.tsx
# Lint and format single file
yarn biome check --write path/to/file.tsx
# Unit test specific file
yarn vitest run path/to/file.test.ts
@@ -69,9 +68,9 @@ yarn dev # Start dev server
yarn dx # Dev with database setup
# Build & check
yarn build # Build all packages
yarn lint:fix # Lint and fix all
yarn type-check # Type check all
yarn build # Build all packages
yarn biome check --write . # Lint and format all
yarn type-check # Type check all
# Tests (use TZ=UTC for consistency)
TZ=UTC yarn test # All unit tests
@@ -82,6 +81,14 @@ yarn prisma generate # Regenerate types after schema changes
yarn workspace @calcom/prisma db-migrate # Run migrations
```
### Biome focused workflow
+
```bash
yarn biome check --write .
yarn type-check:ci --force
```
## Boundaries
### Always do
@@ -89,6 +96,7 @@ yarn workspace @calcom/prisma db-migrate # Run migrations
- Run relevant tests before pushing
- Use `select` in Prisma queries
- Follow conventional commits for PR titles
- Run Biome before pushing
### Ask first
- Adding new dependencies
+18 -17
View File
@@ -19,20 +19,20 @@ ARG NEXT_PUBLIC_SINGLE_ORG_SLUG
ARG ORGANIZATIONS_ENABLED
ENV NEXT_PUBLIC_WEBAPP_URL=http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER \
NEXT_PUBLIC_API_V2_URL=$NEXT_PUBLIC_API_V2_URL \
NEXT_PUBLIC_LICENSE_CONSENT=$NEXT_PUBLIC_LICENSE_CONSENT \
NEXT_PUBLIC_WEBSITE_TERMS_URL=$NEXT_PUBLIC_WEBSITE_TERMS_URL \
NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL=$NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL \
CALCOM_TELEMETRY_DISABLED=$CALCOM_TELEMETRY_DISABLED \
DATABASE_URL=$DATABASE_URL \
DATABASE_DIRECT_URL=$DATABASE_URL \
NEXTAUTH_SECRET=${NEXTAUTH_SECRET} \
CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY} \
NEXT_PUBLIC_SINGLE_ORG_SLUG=$NEXT_PUBLIC_SINGLE_ORG_SLUG \
ORGANIZATIONS_ENABLED=$ORGANIZATIONS_ENABLED \
NODE_OPTIONS=--max-old-space-size=${MAX_OLD_SPACE_SIZE} \
BUILD_STANDALONE=true \
CSP_POLICY=$CSP_POLICY
NEXT_PUBLIC_API_V2_URL=$NEXT_PUBLIC_API_V2_URL \
NEXT_PUBLIC_LICENSE_CONSENT=$NEXT_PUBLIC_LICENSE_CONSENT \
NEXT_PUBLIC_WEBSITE_TERMS_URL=$NEXT_PUBLIC_WEBSITE_TERMS_URL \
NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL=$NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL \
CALCOM_TELEMETRY_DISABLED=$CALCOM_TELEMETRY_DISABLED \
DATABASE_URL=$DATABASE_URL \
DATABASE_DIRECT_URL=$DATABASE_URL \
NEXTAUTH_SECRET=${NEXTAUTH_SECRET} \
CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY} \
NEXT_PUBLIC_SINGLE_ORG_SLUG=$NEXT_PUBLIC_SINGLE_ORG_SLUG \
ORGANIZATIONS_ENABLED=$ORGANIZATIONS_ENABLED \
NODE_OPTIONS=--max-old-space-size=${MAX_OLD_SPACE_SIZE} \
BUILD_STANDALONE=true \
CSP_POLICY=$CSP_POLICY
COPY package.json yarn.lock .yarnrc.yml playwright.config.ts turbo.json i18n.json ./
COPY .yarn ./.yarn
@@ -47,6 +47,7 @@ RUN yarn install
# Build and make embed servable from web/public/embed folder
RUN yarn workspace @calcom/trpc run build
RUN yarn --cwd packages/embeds/embed-core workspace @calcom/embed-core run build
RUN yarn --cwd apps/web workspace @calcom/web run copy-app-store-static
RUN yarn --cwd apps/web workspace @calcom/web run build
RUN rm -rf node_modules/.cache .yarn/cache apps/web/.next/cache
@@ -70,7 +71,7 @@ RUN chmod +x scripts/*
# Save value used during this build stage. If NEXT_PUBLIC_WEBAPP_URL and BUILT_NEXT_PUBLIC_WEBAPP_URL differ at
# run-time, then start.sh will find/replace static values again.
ENV NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL \
BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL
BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL
RUN scripts/replace-placeholder.sh http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER ${NEXT_PUBLIC_WEBAPP_URL}
@@ -83,12 +84,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd
COPY --from=builder-two /calcom ./
ARG NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000
ENV NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL \
BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL
BUILT_NEXT_PUBLIC_WEBAPP_URL=$NEXT_PUBLIC_WEBAPP_URL
ENV NODE_ENV=production
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=30s --retries=5 \
CMD wget --spider http://localhost:3000 || exit 1
CMD wget --spider http://localhost:3000 || exit 1
CMD ["/calcom/scripts/start.sh"]
+15 -1
View File
@@ -174,6 +174,20 @@ Here is what you need to be able to run Cal.com.
yarn dx
```
**Default credentials created:**
| Email | Password | Role |
|-------|----------|------|
| `free@example.com` | `free` | Free user |
| `pro@example.com` | `pro` | Pro user |
| `trial@example.com` | `trial` | Trial user |
| `admin@example.com` | `ADMINadmin2022!` | Admin user |
| `onboarding@example.com` | `onboarding` | Onboarding incomplete |
You can use any of these credentials to sign in at [http://localhost:3000](http://localhost:3000)
> **Tip**: To view the full list of seeded users and their details, run `yarn db-studio` and visit [http://localhost:5555](http://localhost:5555)
#### Development tip
1. Add `export NODE_OPTIONS=“--max-old-space-size=16384”` to your shell script to increase the memory limit for the node process. Alternatively, you can run this in your terminal before running the app. Replace 16384 with the amount of RAM you want to allocate to the node process.
@@ -193,7 +207,7 @@ yarn dx
The logger will include all logs that are at the specified level or higher. For example: \
- If you set `NEXT_PUBLIC_LOGGER_LEVEL=2`, it will log from level 2 (debug) upwards, meaning levels 2 (debug), 3 (info), 4 (warn), 5 (error), and (fatal) will be logged. \
- If you set `NEXT_PUBLIC_LOGGER_LEVEL=2`, it will log from level 2 (debug) upwards, meaning levels 2 (debug), 3 (info), 4 (warn), 5 (error), and 6 (fatal) will be logged. \
- If you set `NEXT_PUBLIC_LOGGER_LEVEL=3`, it will log from level 3 (info) upwards, meaning levels 3 (info), 4 (warn), 5 (error), and 6 (fatal) will be logged, but level 2 (debug) and level 1 (trace) will be ignored. \
```sh
+4 -4
View File
@@ -16,11 +16,11 @@
## Lint & Type Check
- `yarn lint` - Run ESLint on codebase
- `yarn lint:fix` - Run ESLint and fix issues
- `yarn lint:report` - Generate lint report
- `yarn lint` - Run Biome across the codebase
- `yarn lint:fix` - Run Biome and apply safe fixes
- `yarn lint:report` - Generate Biome lint report
- `yarn type-check` - Run TypeScript type checking
- `yarn format` - Format code with Prettier
- `yarn format` - Format code with Biome
## Testing Commands
+71 -1
View File
@@ -255,7 +255,55 @@ import { TRPCError } from "@trpc/server";
### packages/features Import Restrictions
Files in `packages/features/**` should NOT import from `trpc`. This keeps the features package decoupled from the tRPC layer, making the code more reusable and testable. Use `ErrorWithCode` for error handling in these files, and let the tRPC middleware handle the conversion.
Files in `packages/features/**` should NOT import from `@calcom/trpc`. This keeps the features package decoupled from the tRPC layer, making the code more reusable and testable. Use `ErrorWithCode` for error handling in these files, and let the tRPC middleware handle the conversion.
**Architecture: packages/features vs apps/web/modules**
The `packages/features` package should contain only framework-agnostic code:
- Repositories (data access layer)
- Services (business logic)
- Core utilities and helpers
- Types and interfaces
Web-specific code, particularly anything that uses tRPC, should live in `apps/web/modules/...`. This includes:
- React hooks that use tRPC queries/mutations
- tRPC-specific utilities
- Web-only UI components that depend on tRPC
**Example:**
If you have a feature called `feature-opt-in`:
```
packages/features/feature-opt-in/
├── repository/
│ └── FeatureOptInRepository.ts # Data access - OK here
├── service/
│ └── FeatureOptInService.ts # Business logic - OK here
└── types.ts # Types - OK here
apps/web/modules/feature-opt-in/
└── hooks/
└── useFeatureOptIn.ts # tRPC hook - MUST be here, not in packages/features
```
```typescript
// ❌ Bad - tRPC hook in packages/features
// packages/features/feature-opt-in/hooks/useFeatureOptIn.ts
import { trpc } from "@calcom/trpc/react";
export function useFeatureOptIn() {
return trpc.viewer.featureOptIn.useQuery();
}
// ✅ Good - tRPC hook in apps/web/modules
// apps/web/modules/feature-opt-in/hooks/useFeatureOptIn.ts
import { trpc } from "@calcom/trpc/react";
export function useFeatureOptIn() {
return trpc.viewer.featureOptIn.useQuery();
}
```
This separation ensures that `packages/features` remains portable and can be used by other apps (like `apps/api/v2`) without pulling in web-specific dependencies like tRPC React hooks.
## Basic Performance Guidelines
@@ -372,6 +420,28 @@ export interface BookingDTO {
}
```
### DTO Location and Naming
**Location**: All DTOs go in `packages/lib/dto/`
**Naming conventions**:
- Base entity: `{Entity}Dto` (e.g., `BookingDto`)
- With relations: `{Entity}With{Relations}Dto` (e.g., `BookingWithAttendeesDto`)
- For specific projections: `{Entity}For{Purpose}Dto` (e.g., `BookingForConfirmationDto`)
- Avoid: `{Entity}Dto2`, `{Entity}DtoForHandler`, or other use-case-specific names
**Enum/union pattern** – use string literal unions to stay ORM-agnostic:
```typescript
// ✅ Good - ORM-agnostic string literal union
export type BookingStatusDto = "CANCELLED" | "ACCEPTED" | "REJECTED" | "PENDING";
// ❌ Bad - importing Prisma enum
import { BookingStatus } from "@calcom/prisma/client";
```
**Type safety** – never use `as any` in DTO mapping functions. If types don't align, fix the mapping explicitly.
### Prisma boundaries
- **Allowed**: `packages/prisma`, repository implementations (`packages/features/**/repositories/*Repository.ts`), and low-level data access infrastructure.
+1 -1
View File
@@ -1,4 +1,4 @@
const http = require("http");
const http = require("node:http");
const connect = require("connect");
const { createProxyMiddleware } = require("http-proxy-middleware");
+3 -6
View File
@@ -10,11 +10,8 @@
"author": "",
"license": "ISC",
"dependencies": {
"connect": "^3.7.0",
"http": "^0.0.1-security",
"http-proxy-middleware": "^2.0.6"
},
"devDependencies": {
"@calcom/eslint-config": "workspace:*"
"connect": "3.7.0",
"http": "0.0.1-security",
"http-proxy-middleware": "2.0.9"
}
}
-5
View File
@@ -1,5 +0,0 @@
.next/
coverage/
node_modules/
tests/
templates/
-3
View File
@@ -1,3 +0,0 @@
import { nextJsConfig } from "@calcom/eslint-config/next-js";
export default nextJsConfig;
+10 -7
View File
@@ -11,9 +11,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { ILicenseKeyService } from "@calcom/ee/common/server/LicenseKeyService";
import LicenseKeyService, { LicenseKeySingleton } from "@calcom/ee/common/server/LicenseKeyService";
import { PrismaApiKeyRepository } from "@calcom/lib/server/repository/PrismaApiKeyRepository";
import type { IDeploymentRepository } from "@calcom/lib/server/repository/deployment.interface";
import { ApiKeyService } from "@calcom/lib/server/service/ApiKeyService";
import { PrismaApiKeyRepository } from "@calcom/features/ee/api-keys/repositories/PrismaApiKeyRepository";
import { ApiKeyService } from "@calcom/features/ee/api-keys/services/ApiKeyService";
import type { IDeploymentRepository } from "@calcom/features/ee/deployment/repositories/IDeploymentRepository";
import { UserPermissionRole } from "@calcom/prisma/enums";
import { isAdminGuard } from "../utils/isAdmin";
@@ -21,11 +21,11 @@ import { isLockedOrBlocked } from "../utils/isLockedOrBlocked";
import { ScopeOfAdmin } from "../utils/scopeOfAdmin";
import { verifyApiKey } from "./verifyApiKey";
vi.mock("@calcom/lib/server/service/ApiKeyService", () => ({
vi.mock("@calcom/features/ee/api-keys/services/ApiKeyService", () => ({
ApiKeyService: vi.fn(),
}));
vi.mock("@calcom/lib/server/repository/PrismaApiKeyRepository", () => ({
vi.mock("@calcom/features/ee/api-keys/repositories/PrismaApiKeyRepository", () => ({
PrismaApiKeyRepository: vi.fn(),
}));
@@ -73,8 +73,8 @@ describe("Verify API key - Unit Tests", () => {
verifyKeyByHashedKey: vi.fn(),
} as unknown as ApiKeyService;
vi.mocked(ApiKeyService).mockImplementation(() => mockApiKeyService);
vi.mocked(PrismaApiKeyRepository).mockImplementation(() => ({} as unknown as PrismaApiKeyRepository));
vi.mocked(ApiKeyService).mockImplementation(function() { return mockApiKeyService; });
vi.mocked(PrismaApiKeyRepository).mockImplementation(function() { return {} as unknown as PrismaApiKeyRepository; });
vi.mocked(isAdminGuard).mockReset();
vi.mocked(isLockedOrBlocked).mockReset();
@@ -139,6 +139,7 @@ describe("Verify API key - Unit Tests", () => {
valid: true,
userId: 1,
user: {
uuid: "test-uuid-1",
role: UserPermissionRole.ADMIN,
locked: false,
email: "admin@example.com",
@@ -183,6 +184,7 @@ describe("Verify API key - Unit Tests", () => {
valid: true,
userId: 2,
user: {
uuid: "test-uuid-2",
role: UserPermissionRole.USER,
locked: false,
email: "org-admin@acme.com",
@@ -227,6 +229,7 @@ describe("Verify API key - Unit Tests", () => {
valid: true,
userId: 3,
user: {
uuid: "test-uuid-3",
role: UserPermissionRole.USER,
locked: true,
email: "locked@example.com",
+7 -6
View File
@@ -2,10 +2,10 @@ import type { NextMiddleware } from "next-api-middleware";
import { LicenseKeySingleton } from "@calcom/ee/common/server/LicenseKeyService";
import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys";
import { PrismaApiKeyRepository } from "@calcom/features/ee/api-keys/repositories/PrismaApiKeyRepository";
import { ApiKeyService } from "@calcom/features/ee/api-keys/services/ApiKeyService";
import { DeploymentRepository } from "@calcom/features/ee/deployment/repositories/DeploymentRepository";
import { IS_PRODUCTION } from "@calcom/lib/constants";
import { PrismaApiKeyRepository } from "@calcom/lib/server/repository/PrismaApiKeyRepository";
import { DeploymentRepository } from "@calcom/lib/server/repository/deployment";
import { ApiKeyService } from "@calcom/lib/server/service/ApiKeyService";
import { prisma } from "@calcom/prisma";
import { isAdminGuard } from "../utils/isAdmin";
@@ -36,9 +36,10 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => {
return res.status(401).json({ error: result.error });
}
// save the user id in the request for later use
req.userId = result.userId!;
req.user = result.user!;
// save the user id and uuid in the request for later use
req.userId = result.userId;
req.userUuid = result.user.uuid;
req.user = result.user;
const { isAdmin, scope } = await isAdminGuard(req);
const userIsLockedOrBlocked = await isLockedOrBlocked(req);
+1 -1
View File
@@ -128,7 +128,7 @@ export const schemaBookingReadPublic = Booking.extend({
title: true,
startTime: true,
endTime: true,
timeZone: true,
// Note: timeZone is not a field on Booking model - it's in nested attendees/user objects
attendees: true,
user: true,
eventType: true,
@@ -2,11 +2,11 @@ import { z } from "zod";
import { DestinationCalendarSchema } from "@calcom/prisma/zod/modelSchema/DestinationCalendarSchema";
// Note: bookingId is not a field on DestinationCalendar model in Prisma schema
export const schemaDestinationCalendarBaseBodyParams = DestinationCalendarSchema.pick({
integration: true,
externalId: true,
eventTypeId: true,
bookingId: true,
userId: true,
}).partial();
@@ -38,11 +38,11 @@ export const schemaDestinationCalendarEditBodyParams = schemaDestinationCalendar
schemaDestinationCalendarEditParams
);
// Note: bookingId is not a field on DestinationCalendar model in Prisma schema
export const schemaDestinationCalendarReadPublic = DestinationCalendarSchema.pick({
id: true,
integration: true,
externalId: true,
eventTypeId: true,
bookingId: true,
userId: true,
});
+5 -1
View File
@@ -151,6 +151,7 @@ export const schemaUserCreateBodyParams = schemaUserBaseBodyParams
.strict();
// @note: These are the values that are always returned when reading a user
// Note: We pick avatarUrl from the Prisma schema and extend with avatar for API v1 backward compatibility
export const schemaUserReadPublic = UserSchema.pick({
id: true,
username: true,
@@ -158,7 +159,7 @@ export const schemaUserReadPublic = UserSchema.pick({
email: true,
emailVerified: true,
bio: true,
avatar: true,
avatarUrl: true,
timeZone: true,
weekStart: true,
endTime: true,
@@ -176,6 +177,9 @@ export const schemaUserReadPublic = UserSchema.pick({
verified: true,
invitedTo: true,
role: true,
}).extend({
// API v1 backward compatibility: expose avatarUrl as avatar
avatar: UserSchema.shape.avatarUrl,
});
export const schemaUsersReadPublic = z.array(schemaUserReadPublic);
+4
View File
@@ -1,6 +1,7 @@
import { z } from "zod";
import { WEBHOOK_TRIGGER_EVENTS } from "@calcom/features/webhooks/lib/constants";
import { WebhookVersion } from "@calcom/features/webhooks/lib/interface/IWebhookRepository";
import { WebhookSchema } from "@calcom/prisma/zod/modelSchema/WebhookSchema";
const schemaWebhookBaseBodyParams = WebhookSchema.pick({
@@ -21,6 +22,7 @@ export const schemaWebhookCreateParams = z
eventTypeId: z.number().optional(),
userId: z.number().optional(),
secret: z.string().optional().nullable(),
version: z.nativeEnum(WebhookVersion).optional(),
// API shouldn't mess with Apps webhooks yet (ie. Zapier)
// appId: z.string().optional().nullable(),
})
@@ -33,6 +35,7 @@ export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams
z.object({
eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(),
secret: z.string().optional().nullable(),
version: z.nativeEnum(WebhookVersion).optional(),
})
)
.partial()
@@ -44,6 +47,7 @@ export const schemaWebhookReadPublic = WebhookSchema.pick({
eventTypeId: true,
payloadTemplate: true,
eventTriggers: true,
version: true,
// FIXME: We have some invalid urls saved in the DB
// subscriberUrl: true,
/** @todo: find out how to properly add back and validate those. */
+1 -1
View File
@@ -1,4 +1,4 @@
const path = require("path");
const path = require("node:path");
const i18nConfig = require("@calcom/config/next-i18next.config");
/** @type {import("next-i18next").UserConfig} */
+3 -1
View File
@@ -1,3 +1,4 @@
/* eslint-disable */
const { withAxiom } = require("next-axiom");
const { withSentryConfig } = require("@sentry/nextjs");
const { PrismaPlugin } = require("@prisma/nextjs-monorepo-workaround-plugin");
@@ -6,6 +7,7 @@ const plugins = [withAxiom];
/** @type {import("next").NextConfig} */
const nextConfig = {
turbopack: {},
transpilePackages: [
"@calcom/app-store",
"@calcom/dayjs",
@@ -94,7 +96,7 @@ const nextConfig = {
},
};
if (!!process.env.NEXT_PUBLIC_SENTRY_DSN) {
if (process.env.NEXT_PUBLIC_SENTRY_DSN) {
plugins.push((nextConfig) =>
withSentryConfig(nextConfig, {
autoInstrumentServerFunctions: true,
+1
View File
@@ -8,6 +8,7 @@ export declare module "next" {
session?: Session | null;
userId: number;
userUuid: string;
user?: { role: string; locked: boolean; email: string } | null;
method: string;
// session: { user: { id: number } };
+17 -17
View File
@@ -10,18 +10,19 @@
"build": "next build",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next",
"dev": "PORT=3003 next dev",
"lint": "eslint .",
"lint:fix": "eslint . --ext .ts,.js,.tsx,.jsx --fix",
"lint": "biome lint .",
"lint:fix": "biome lint --write .",
"start": "PORT=3003 next start",
"docker-start-api": "PORT=80 next start",
"type-check": "tsc --pretty --noEmit",
"type-check:ci": "tsc-absolute --pretty --noEmit"
},
"devDependencies": {
"@calcom/eslint-config": "workspace:*",
"@calcom/testing": "workspace:*",
"@calcom/tsconfig": "workspace:*",
"@calcom/types": "workspace:*",
"node-mocks-http": "^1.11.0"
"node-mocks-http": "1.16.2",
"typescript": "5.9.3"
},
"dependencies": {
"@calcom/app-store": "workspace:*",
@@ -31,18 +32,17 @@
"@calcom/lib": "workspace:*",
"@calcom/prisma": "workspace:*",
"@calcom/trpc": "workspace:*",
"@prisma/nextjs-monorepo-workaround-plugin": "^6.16.1",
"@sentry/nextjs": "^9.15.0",
"bcryptjs": "^2.4.3",
"memory-cache": "^0.2.0",
"next": "15.4.10",
"next-api-middleware": "^1.0.1",
"next-axiom": "^0.17.0",
"next-swagger-doc": "^0.3.6",
"next-validations": "^0.2.0",
"typescript": "^5.9.0-beta",
"tzdata": "^1.0.30",
"uuid": "^8.3.2",
"zod": "^3.22.4"
"@prisma/nextjs-monorepo-workaround-plugin": "6.16.1",
"@sentry/nextjs": "9.15.0",
"bcryptjs": "2.4.3",
"memory-cache": "0.2.0",
"next": "16.1.0",
"next-api-middleware": "1.0.1",
"next-axiom": "0.17.0",
"next-swagger-doc": "0.3.6",
"next-validations": "0.2.1",
"tzdata": "1.0.40",
"uuid": "8.3.2",
"zod": "3.25.76"
}
}
+16 -7
View File
@@ -8,6 +8,7 @@ import prisma from "@calcom/prisma";
import { availabilityUserSelect } from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import { stringOrNumber } from "@calcom/prisma/zod-utils";
import dayjs from "@calcom/dayjs";
/**
* @swagger
@@ -190,13 +191,21 @@ const availabilitySchema = z
async function handler(req: NextApiRequest) {
const { isSystemWideAdmin, userId: reqUserId } = req;
const { username, userId, eventTypeId, dateTo, dateFrom, teamId } = availabilitySchema.parse(req.query);
const { username, userId, eventTypeId, teamId, dateFrom, dateTo } = availabilitySchema.parse(req.query);
const dayjsDateFrom = dayjs(dateFrom);
const dayjsDateTo = dayjs(dateTo);
if (!dayjsDateFrom.isValid() || !dayjsDateTo.isValid()) {
throw new HttpError({ statusCode: 400, message: "Invalid date range" });
}
const userAvailabilityService = getUserAvailabilityService();
if (!teamId)
return userAvailabilityService.getUserAvailability({
username,
dateFrom,
dateTo,
dateFrom: dayjsDateFrom,
dateTo: dayjsDateTo,
eventTypeId,
userId,
returnDateOverrides: true,
@@ -224,8 +233,8 @@ async function handler(req: NextApiRequest) {
}, {} as MemberRoles);
// check if the user is a team Admin or Owner, if it is a team request, or a system Admin
const isUserAdminOrOwner =
memberRoles[reqUserId] == MembershipRole.ADMIN ||
memberRoles[reqUserId] == MembershipRole.OWNER ||
memberRoles[reqUserId] === MembershipRole.ADMIN ||
memberRoles[reqUserId] === MembershipRole.OWNER ||
isSystemWideAdmin;
if (!isUserAdminOrOwner) throw new HttpError({ statusCode: 403, message: "Forbidden" });
const availabilities = members.map(async (user) => {
@@ -233,8 +242,8 @@ async function handler(req: NextApiRequest) {
userId: user.id,
availability: await userAvailabilityService.getUserAvailability({
userId: user.id,
dateFrom,
dateTo,
dateFrom: dayjsDateFrom,
dateTo: dayjsDateTo,
eventTypeId,
returnDateOverrides: true,
bypassBusyCalendarTimes: false,
@@ -109,7 +109,7 @@ async function handler(req: NextApiRequest) {
// ^ Workaround for the select in `create` not working
if (createCalendarResources) {
const calendar = await getCalendar({ ...credential, delegatedTo: null });
const calendar = await getCalendar({ ...credential, delegatedTo: null }, "slots");
if (!calendar) throw new HttpError({ message: "Calendar missing for credential", statusCode: 500 });
const calendars = await calendar.listCalendars();
const calendarToCreate = calendars.find((calendar) => calendar.primary) || calendars[0];
+1
View File
@@ -22,6 +22,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
return {
user: {
id: req.userId,
uuid: req.userUuid,
username: "",
profile: {
id: null,
+1 -1
View File
@@ -1,4 +1,4 @@
import prismock from "../../../../../../tests/libs/__mocks__/prisma";
import prismock from "@calcom/testing/lib/__mocks__/prisma";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -22,6 +22,7 @@ const patchHandler = async (req: NextApiRequest, res: NextApiResponse) => {
return {
user: {
id: req.userId,
uuid: req.userUuid,
username: "" /* Not used in this context */,
role: req.isSystemWideAdmin ? UserPermissionRole.ADMIN : UserPermissionRole.USER,
profile: {
+64 -1
View File
@@ -1,5 +1,8 @@
import type { NextApiRequest } from "next";
import { sendChangeOfEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
import { UserRepository } from "@calcom/features/users/repositories/UserRepository";
import { HttpError } from "@calcom/lib/http-error";
import { uploadAvatar } from "@calcom/lib/server/avatar";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
@@ -130,10 +133,70 @@ export async function patchHandler(req: NextApiRequest) {
});
}
const userRepository = new UserRepository(prisma);
const currentUser = await userRepository.findById({ id: query.userId });
if (!currentUser) {
throw new HttpError({ statusCode: 404, message: "User not found" });
}
const featuresRepository = new FeaturesRepository(prisma);
const emailVerification = await featuresRepository.checkIfFeatureIsEnabledGlobally("email-verification");
const hasEmailBeenChanged = typeof body.email === "string" && currentUser.email !== body.email;
const newEmail = typeof body.email === "string" ? body.email : undefined;
const prismaData: Prisma.UserUpdateInput = { ...body };
if (hasEmailBeenChanged && newEmail) {
const secondaryEmail = await userRepository.findSecondaryEmailByUserIdAndEmail({
userId: query.userId,
email: newEmail,
});
if (emailVerification) {
if (secondaryEmail && secondaryEmail.emailVerified) {
const data = await userRepository.swapPrimaryEmailWithSecondaryEmail({
userId: query.userId,
secondaryEmailId: secondaryEmail.id,
oldPrimaryEmail: currentUser.email,
oldPrimaryEmailVerified: currentUser.emailVerified,
newPrimaryEmail: newEmail,
userUpdateData: prismaData,
});
const user = schemaUserReadPublic.parse(data);
return { user };
} else {
prismaData.metadata = {
...(currentUser.metadata as Prisma.JsonObject),
...(typeof prismaData.metadata === "object" && prismaData.metadata ? prismaData.metadata : {}),
emailChangeWaitingForVerification: newEmail.toLowerCase(),
};
delete prismaData.email;
}
}
}
const data = await prisma.user.update({
where: { id: query.userId },
data: body,
data: prismaData,
});
const shouldSendEmailVerification =
hasEmailBeenChanged && emailVerification && newEmail && !prismaData.email;
if (shouldSendEmailVerification) {
await sendChangeOfEmailVerification({
user: {
username: data.username ?? "Nameless User",
emailFrom: currentUser.email,
emailTo: newEmail,
},
});
}
const user = schemaUserReadPublic.parse(data);
return { user };
}
@@ -1,7 +1,7 @@
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
export function middleware(_request: NextRequest) {
function proxy(_request: NextRequest) {
// Matcher guarantees the last segment is one of the blocked segments, so we can
// immediately return a 403 without further path checks.
return NextResponse.json({ message: "Forbidden" }, { status: 403 });
@@ -17,3 +17,5 @@ export const config = {
"/:path*/_auth-middleware",
],
};
export default proxy;
+1 -1
View File
@@ -1,6 +1,6 @@
// This is a workaround for https://github.com/jsdom/jsdom/issues/2524#issuecomment-902027138
// See https://github.com/microsoft/accessibility-insights-web/blob/40416a4ae6b91baf43102f58e069eff787de4de2/src/tests/unit/jest-setup.ts
const { TextEncoder, TextDecoder } = require("util");
const { TextEncoder, TextDecoder } = require("node:util");
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
+1 -1
View File
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
+1 -1
View File
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
+35 -24
View File
@@ -1,5 +1,5 @@
// TODO: Fix tests (These test were never running due to the vitest workspace config)
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -67,15 +67,22 @@ vi.mock("@calcom/features/webhooks/lib/sendOrSchedulePayload", () => ({
const mockFindOriginalRescheduledBooking = vi.fn();
vi.mock("@calcom/features/bookings/repositories/BookingRepository", () => ({
BookingRepository: vi.fn().mockImplementation(() => ({
BookingRepository: vi.fn().mockImplementation(function() { return {
findOriginalRescheduledBooking: mockFindOriginalRescheduledBooking,
})),
}; }),
}));
vi.mock("@calcom/features/watchlist/operations/check-if-users-are-blocked.controller", () => ({
checkIfUsersAreBlocked: vi.fn().mockResolvedValue(false),
}));
vi.mock("@calcom/features/watchlist/operations/filter-blocked-users.controller", () => ({
filterBlockedUsers: vi.fn().mockImplementation(async (users) => ({
eligibleUsers: users,
blockedCount: 0,
})),
}));
vi.mock("@calcom/features/di/containers/QualifiedHosts", () => ({
getQualifiedHostsService: vi.fn().mockReturnValue({
findQualifiedHostsWithDelegationCredentials: vi.fn().mockResolvedValue({
@@ -87,23 +94,25 @@ vi.mock("@calcom/features/di/containers/QualifiedHosts", () => ({
}));
vi.mock("@calcom/features/bookings/lib/EventManager", () => ({
default: vi.fn().mockImplementation(() => ({
reschedule: vi.fn().mockResolvedValue({
results: [],
referencesToCreate: [],
}),
create: vi.fn().mockResolvedValue({
results: [],
referencesToCreate: [],
}),
update: vi.fn().mockResolvedValue({
results: [],
referencesToCreate: [],
}),
createAllCalendarEvents: vi.fn().mockResolvedValue([]),
updateAllCalendarEvents: vi.fn().mockResolvedValue([]),
deleteEventsAndMeetings: vi.fn().mockResolvedValue([]),
})),
default: vi.fn().mockImplementation(function() {
return {
reschedule: vi.fn().mockResolvedValue({
results: [],
referencesToCreate: [],
}),
create: vi.fn().mockResolvedValue({
results: [],
referencesToCreate: [],
}),
update: vi.fn().mockResolvedValue({
results: [],
referencesToCreate: [],
}),
createAllCalendarEvents: vi.fn().mockResolvedValue([]),
updateAllCalendarEvents: vi.fn().mockResolvedValue([]),
deleteEventsAndMeetings: vi.fn().mockResolvedValue([]),
};
}),
placeholderCreatedEvent: {
results: [],
referencesToCreate: [],
@@ -146,10 +155,10 @@ vi.mock("@calcom/features/profile/repositories/ProfileRepository", () => ({
},
}));
vi.mock("@calcom/features/flags/features.repository", () => ({
FeaturesRepository: vi.fn().mockImplementation(() => ({
FeaturesRepository: vi.fn().mockImplementation(function() { return {
checkIfFeatureIsEnabledGlobally: vi.fn().mockResolvedValue(false),
checkIfTeamHasFeature: vi.fn().mockResolvedValue(false),
})),
}; }),
}));
vi.mock("@calcom/features/webhooks/lib/getWebhooks", () => ({
@@ -161,7 +170,7 @@ vi.mock("@calcom/features/ee/workflows/lib/getAllWorkflows", () => ({
workflowSelect: {},
}));
vi.mock("@calcom/trpc/server/routers/viewer/workflows/util", () => ({
vi.mock("@calcom/features/ee/workflows/lib/getAllWorkflowsFromEventType", () => ({
getAllWorkflowsFromEventType: vi.fn().mockResolvedValue([]),
}));
@@ -245,7 +254,9 @@ describe("POST /api/bookings", () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
body: {
eventTypeId: 2,
},
});
await handler(req, res);
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
@@ -1,4 +1,4 @@
import prismaMock from "../../../../../../../tests/libs/__mocks__/prismaMock";
import prismaMock from "@calcom/testing/lib/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";

Some files were not shown because too many files have changed in this diff Show More