Commit Graph
1131 Commits
Author SHA1 Message Date
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
77c8e34073 fix: api v2 get event-types non org users (#26896)
* fix: get event-types non org users

* fix: add excludeOrgUsers parameter to findByUsername for targeted filtering

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

* fix: create dedicated findByUsernameExcludingOrgUsers function

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

* test: add e2e test for same username org vs non-org user event types

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

* test: move e2e test for same username org vs non-org to 2024_06_14

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

* fix: add organizationId to orgUser in e2e test

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

* fix: reorder afterAll cleanup to delete users before team

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

* fix: add organizationId null check to findByUsernameExcludingOrgUsers

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

* Revert "fix: add organizationId null check to findByUsernameExcludingOrgUsers"

This reverts commit 0d31e3d5d7c0eaa408939d697ea790521e520a3c.

* fixup! fix: add organizationId null check to findByUsernameExcludingOrgUsers

* fix: restore /public suffix in e2e test URL

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

* fix: use findByUsernameExcludingOrgUsers in getEventTypeByUsernameAndSlug when no org context

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

* fixup! fix: use findByUsernameExcludingOrgUsers in getEventTypeByUsernameAndSlug when no org context

* refactor: remove unused getEventTypesPublicByUsername from 2024_06_14 service

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

* fix: test user creation

* chore: add test for org event-types

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-15 19:26:51 +00:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f5085af396 docs: improve beforeEventBuffer and afterEventBuffer descriptions in API v2 (#26899)
* docs: improve beforeEventBuffer and afterEventBuffer descriptions in API v2

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

* fixup! docs: improve beforeEventBuffer and afterEventBuffer descriptions in API v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-15 15:27:13 -03:00
Rajiv SahalandGitHub 568d9de160 chore: better error messages (#26890) 2026-01-15 18:28:54 +02:00
Keith WilliamsGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
3a8fe8c7af perf: convert services to factory functions and add TypeScript project references (#26117)
* perf(app-store): convert services to factory functions to narrow SDK type exports

This change converts CRM, Calendar, Payment, and Analytics services from
exporting classes to exporting factory functions that return interface types.
This prevents SDK types (HubSpot, Stripe, etc.) from leaking into the type
system when TypeScript emits .d.ts files.

Services modified:
- CRM: hubspot, salesforce, closecom, pipedrive-crm, zoho-bigin, zohocrm
- Calendar: all 13 calendar services
- Payment: stripe, paypal, alby, btcpayserver, hitpay, mock-payment-app
- Analytics: dub

Video adapters were audited and already use factory pattern.

WIP: Salesforce CRM service has a type error that needs fixing.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>

* fix(salesforce): add type assertion for appOptions in factory function

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

* fix: update remaining consumers to use factory functions

- getAnalytics.ts: call factory function instead of new
- getConnectedApps.ts: call factory function instead of new
- salesforce/CrmService.ts: fix type assertion with default value
- salesforce/routingForm/incompleteBookingAction.ts: use factory function
- salesforce/routingFormBookingFormHandler.ts: use factory function

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

* fix(salesforce): add SalesforceCRM interface for Salesforce-specific methods

- Create SalesforceCRM interface extending CRM with findUserEmailFromLookupField and incompleteBookingWriteToRecord methods
- Add createSalesforceCrmServiceWithSalesforceType factory function for internal Salesforce modules
- Update routing form files to use the new factory function with proper typing

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

* fix(salesforce): correct return type in SalesforceCRM interface

The findUserEmailFromLookupField method returns { email: string; recordType: RoutingReasons } | undefined,
not string | undefined. Updated the interface to match the actual implementation.

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

* fix: update all call sites to use factory functions

- Update calendar API add files to use factory functions (7 files)
- Update Google Calendar test files to use factory functions (3 files)
- Update Salesforce test files to use SalesforceCRM interface
- Add testMode parameter to createSalesforceCrmServiceWithSalesforceType
- Remove unused @ts-expect-error directive in bookingScenario.ts

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

* fix: add GoogleCalendar interface and update factory functions for service-specific methods

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

* fix: add type annotation to attendee parameter in google-calendar.e2e.ts

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

* fix: update selected-calendars/route.ts to use GoogleCalendar factory function

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

* fix: update remaining GoogleCalendarService call sites to use factory function

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

* fix: remove explicit type annotation in google-calendar.e2e.ts to fix type error

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

* fix: update test mocks to use factory function pattern for calendar and payment services

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

* fix: convert MockPaymentService to factory function in setupVitest.ts

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

* fix(api-v2): call calendar service factory functions instead of using new

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

* perf(trpc): add TypeScript project references to reduce build file count

- Add tsconfig.build.json to app-store with composite settings for declaration emit
- Add tsconfig.server.build.json to trpc with project references
- Add types and typesVersions to app-store package.json to redirect type resolution to dist-types
- Add build:types script to app-store for generating declarations
- Add dist-types to .gitignore

This reduces the tRPC build file count from 7,733 to 5,618 files (27% reduction)
by having TypeScript resolve to prebuilt .d.ts files instead of source files.

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

* fix(app-store): add fallback to typesVersions for CI compatibility

The typesVersions now prefers dist-types but falls back to source files
when dist-types don't exist. This fixes CI type-check failures while
still allowing the optimization when dist-types are built.

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

* Added build dependency for tRPC on app-store

* fix(app-store): exclude test directories from tsconfig.build.json

Exclude __tests__, __mocks__, and tests directories from the build
config to prevent test utility files (which import from outside rootDir)
from being included in the declaration emit.

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

* fix(turbo): add build:types task definition for app-store

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

* fix(turbo): remove circular build dependency between trpc and app-store

The build:types task for app-store transitively imports from @calcom/features,
which imports from @calcom/trpc. This creates a circular build dependency when
@calcom/trpc#build depends on @calcom/app-store#build:types.

Solution: Remove the turbo dependency. The typesVersions fallback pattern
['./dist-types/*', './*'] will use source files when dist-types/ doesn't exist,
and use prebuilt declarations when they do exist (for faster builds).

Also exclude dist-types from regular tsconfig.json to prevent 'Cannot write file'
errors when dist-types/ exists.

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

* refactor(app-store): rename dist-types to types for consistency

Rename the prebuilt TypeScript declarations folder from dist-types to types
to match the convention used by @calcom/trpc and other packages in the monorepo.

Updated files:
- tsconfig.build.json: declarationDir and exclude
- tsconfig.json: exclude
- package.json: typesVersions paths
- turbo.json: build:types outputs
- .gitignore: ignore path

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

* fix(api-v2): update ICS calendar test to mock factory function instead of class prototype

The IcsFeedCalendarService is now a factory function, not a class, so
jest.spyOn(IcsFeedCalendarService.prototype, 'listCalendars') no longer works.

Updated to use jest.spyOn(appStore, 'IcsFeedCalendarService').mockImplementation()
to mock the factory function return value instead.

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

* refactor(app-store): rename factory functions to Build* naming convention

- Rename Calendar factory functions from create*CalendarService to BuildCalendarService
- Rename CRM factory functions from create*CrmService to BuildCrmService
- Rename Payment factory functions from PaymentService to BuildPaymentService
- Rename Analytics factory function from createDubAnalyticsService to BuildAnalyticsService
- Update all index.ts re-exports to use new names
- Update all call sites throughout the codebase
- Update test mocks to use new factory function names

This makes it clear that these are factory functions, not class constructors.

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

* fix(app-store): update remaining CalendarService and PaymentService imports to Build* names

- Update api/add.ts files for applecalendar, caldavcalendar, exchange2013calendar, exchange2016calendar, exchangecalendar, ics-feedcalendar
- Update mock-payment-app index.ts to export BuildPaymentService
- Fix googlecalendar test import alias for createInMemoryDelegationCredentialForBuildCalendarService

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

* fix(tests): update payment service mocks to use BuildPaymentService

- Update setupVitest.ts to use BuildPaymentService instead of PaymentService
- Update handlePayment.test.ts mock to use BuildPaymentService

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

* refactor: address PR review comments - rename to Build* and remove unused code

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

* refactor: remove explanatory comments and fix indentation

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

* chore: update .gitignore to use *.tsbuildinfo pattern

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

* fix(api-v2): update IcsFeedCalendarService to BuildIcsFeedCalendarService in e2e test

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

* style: format CalendarService.test.ts

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

* Delete apps/ui-playground/next-env.d.ts

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-15 11:28:05 -03:00
MorganandGitHub eee31d6e9e chore: tag deprecated platform oauth endpoints in api v2 (#26873)
* chore: tag deprecated platform oauth endpoints in api v2

* fixup! chore: tag deprecated platform oauth endpoints in api v2

* fixup! fixup! chore: tag deprecated platform oauth endpoints in api v2

* chore: fix docs.json mintlify

* chore: fix docs.json mintlify
2026-01-15 12:39:55 +00:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
dd7b647715 feat(api-v2): ensure default calendars for delegation credentials when user added to org (#26800)
* feat(api-v2): ensure default calendars for delegation credentials when user added to org

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

* fix: make calendars queue optional in OrganizationsMembershipService

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

* fix: make delegation credential repository and users repository optional

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

* refactor: move calendar setup logic to delegation credential service

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

* fix: make usersRepository optional for E2E tests

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

* fix: module deps

* Update apps/api/v2/src/modules/organizations/delegation-credentials/services/organizations-delegation-credential.service.ts

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

* test: add unit tests for ensureDefaultCalendarsForUser method

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

* fix: address Cubic AI feedback (confidence 9/10)

- Repository query now uses select: { id: true } for existence check
- Add job removal before adding new job (consistent with ensureDefaultCalendars)
- Fix test spy reuse issue

Co-Authored-By: morgan@cal.com <morgan@cal.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-14 16:13:25 -03:00
MorganandGitHub ecaf24d9a2 chore: sync vercel env var with trigger.dev and deploy (#25610)
* chore: sync vercel env var with trigger.dev

* chore: get trigger version from .env.production

* chore: deploy trigger dev tasks in draft release

* fixup! chore: deploy trigger dev tasks in draft release

* fixup! Merge branch 'main' into sync-trigger-dev-env-vercel

* remove trigger version from commit message it's already in .env.production

* chore: use generated token instead of GITHUB_TOKEN in draft release

* fix: code review
2026-01-14 13:34:58 +00:00
Dhairyashil ShindeandGitHub b94e522dd1 fix(api): use public username and correct base URL for platform orgs (#26830)
- Use public  instead of internal profile username for platform orgs
- Use  base URL instead of
2026-01-14 12:32:10 +00:00
Volnei MunhozGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
cfbcd0f95b chore: upgrade sentry and start using metrics for Calendar Cache (#26827)
* upgrade sentry and start using metrics

* format changes

* format changes

* format changes

* type error

* type error

* format changes

* format changes

* fix: add updateSyncStatus call on API error and mock Sentry metrics in tests

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-14 12:29:09 +00:00
2881961859 feat: add custom calendar reminder for Google Calendar events (#26078)
* feat: add custom calendar reminder for Google Calendar events

Allows users to set default reminder notifications (10, 30, or 60 minutes)
for events created via Cal.com bookings in Google Calendar. This addresses
the issue where Google Calendar's default reminders don't apply to
API-created events.

- Add customCalendarReminder field to DestinationCalendar model
- Create reminder selector UI in destination calendar settings
- Update GoogleCalendarService to apply custom reminders (popup + email)
- Add TRPC endpoint for updating reminder settings

* fix: address code review feedback

- Use z.union with literal values (10, 30, 60) for stricter schema validation
- Add localization for toast messages using t()
- Fix test data to use null for customCalendarReminder to match test intent

* fix: add customCalendarReminder to DestinationCalendar types

Update manually-defined DestinationCalendar types to include the new
customCalendarReminder field added in the previous commit. This fixes
type mismatches when passing Prisma-persisted destination calendars to
functions using these local type definitions.

* fix: update customCalendarReminder type in test to match Prisma schema

The customCalendarReminder field is defined as a non-nullable Int with
default value of 10 in the Prisma schema. Changed test value from null
to 10 to fix TS2345 type error.

* feat: add 'just in time' reminder option for Google Calendar events

- Add 0 (just in time) as a valid reminder option alongside 10, 30, 60 minutes
- Update TRPC schema to accept 0 as valid reminder value
- Add 'Just in time' option to reminder dropdown selector UI
- Add translation for 'just_in_time' key in English locale
- Include comprehensive test case for 0-minute (just in time) reminders
- Remove unused import from test file

This addresses reviewer feedback to provide flexible 'just in time' option that allows reminders to fire at exact event start time.

🤖 Generated with Claude Code

* fix: add customCalendarReminder to calendars service mock

- Add missing customCalendarReminder field to destination calendar mock
- Matches the Prisma schema requirement
- Fixes type error in calendars controller e2e test

* fix: add customCalendarReminder to destination calendars controller test

- Add missing customCalendarReminder field to mock destination calendar
- Matches Prisma schema requirement
- Fixes type error in destination-calendars controller e2e test

* fix: cast customCalendarReminder to ReminderMinutes type

- Add type cast for reminderValue to ensure type safety
- Use nullish coalescing (??) to preserve 0 as valid reminder value
- Ensures database number type is properly cast to ReminderMinutes union

* refactor: simplify translation logic in DestinationReminderSelector

- Remove conditional check for 'just_in_time' label
- Pass count parameter to all translations uniformly
- Translation function handles unused parameters gracefully

Addresses review feedback from @Khaan25

* refactor: make custom calendar reminder opt-in and use repository pattern

- Change default from 10 to null (opt-in feature)
- Add DestinationCalendarRepository to avoid direct Prisma usage
- Add 'Use default reminders' option to UI

* refactor: remove redundant migration file

The original migration already creates customCalendarReminder as nullable,
so this second migration to make it nullable is not needed.

* fix: type error for customCalendarReminder in destination calendar settings

* refactor: validate customCalendarReminder with Zod schema instead of type casting

* refactor: use instance methods in DestinationCalendarRepository

Changed from static to instance methods with getInstance() pattern as requested in review.

* refactor: replace singleton with DI for DestinationCalendarRepository

- Remove getInstance() singleton pattern
- Add DI tokens, module, and container
- Update GoogleCalendarService and tRPC handler to use DI

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
2026-01-14 12:32:00 +01:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
0b37520f0d fix: translate location dropdown group labels and options in event-type settings (#26784)
* fix: translate location dropdown group labels in event-type settings

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

* fix: use requesting user's locale for team event type translations

For team event types, the current user might not be in eventType.users,
causing translations to default to English. This fix queries the user's
locale directly from the database when not found in the event type users.

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

* refactor: pass userLocale as parameter instead of database call

Per PR feedback, pass the authenticated user's locale as an optional
parameter to getEventTypeById instead of making an extra database call.
The locale is passed from ctx.user.locale in the tRPC handler.

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

* fix: provide userLocale in apiv2 getEventTypeById

* fix: remove unused ts comments

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-14 08:28:31 -03:00
+47 a7a8c78494 chore: [Booking Cancellation Refactor - 2] Inject repositories and use them instead of Prisma in cancellation flow (#24159)
* chore: Inject repositories instead of Prisma in canellation flow

* simplify

* simplify

* fix formatting issue

* chore: resolve merge conflicts for PR #24159 (#26820)

* matched colour of icons across website (#26394)

* 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

* chore: release v6.0.7

* fix: Custom time input for availability (#26373)

* add custom time input

* add unit test

* add validation logic

* 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

* chore: add logging in next-auth (#26404)

* Add logging in next-auth
* Add logging at other return

* fix: Make incomplete booking form mobile-responsive (#26413)

* fix: update bundle identifier (#26402)

* 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

* 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

* fix: add vertical spacing when hovered (#26419)

* fix(seed): add missing Host entries for seeded round‑robin team events (#26426)

* 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

* fix(auth): enhance SAML login handling by introducing userId field and updating JWT token structure (#26428)

* 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>

* 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>

* 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.

* 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>

* 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>

* 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>

* 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)

* 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>

* 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

* 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>

* feat: update translations via @LingoDotDev (#26445)

Co-authored-by: Lingo.dev <support@lingo.dev>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>

* 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>

* 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>

* 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

* 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>

* Disable noReactSpecificProps as we use react (#26479)

* 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)

* fix: atoms build by updating import paths (#26489)

* fix build

* fix build

* 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

* 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>

* 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

* perf: improve cal video webhook (#26495)

* perf: improve cal video webhook

* save format

* refactor: use errorMs

* chore: change API codeowner to Foundation (#26504)

* 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

* 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>

* 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>

* feat: update translations via @LingoDotDev (#26497)

Co-authored-by: Lingo.dev <support@lingo.dev>

* 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>

* feat: add organization banner to user profile page (#26514)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* 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>

* 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>

* 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>

* 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

* chore: release v6.0.8

* 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>

* fix(ci): use env vars for input interpolation in workflow run steps (#26520)

Co-authored-by: Alex van Andel <me@alexvanandel.com>

* 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)

* 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

* 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>

* Make booking-audit integration test utils reusable (#26526)

* 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>

* 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.

* 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

* 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)

* 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 declaratio…

* fix: remove duplicate onBookingCancelled call

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

---------

Signed-off-by: Bandhan Majumder <bandhanmajumder16@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Ram Shukla <codewithrex@gmail.com>
Co-authored-by: Pedro Castro <pedro@cal.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Manas Kenge <man.kng02@gmail.com>
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Eesh Midha <72607015+eeshm@users.noreply.github.com>
Co-authored-by: Beto <43630417+betomoedano@users.noreply.github.com>
Co-authored-by: shashank-100 <shashank.telkhade@gmail.com>
Co-authored-by: Kartik Labhshetwar <kartik.labhshetwar@gmail.com>
Co-authored-by: Abhay Mishra <grabhaymishra@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
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>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: cal-com-ci[bot] <247290566+cal-com-ci[bot]@users.noreply.github.com>
Co-authored-by: Lingo.dev <support@lingo.dev>
Co-authored-by: Benny Joo <sldisek783@gmail.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
Co-authored-by: Anshumancanrock <109489361+Anshumancanrock@users.noreply.github.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Kartik <103111467+kartik-212004@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
Co-authored-by: Volnei Munhoz <volnei.munhoz@gmail.com>
Co-authored-by: Adarsh Tiwari <adarshtiwari797023@gmail.com>
Co-authored-by: Dylan Tarre <timecreepsby@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Amin Jaoui <101276751+aminjaoui@users.noreply.github.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Anik Dhabal Babu <adhabal2002@gmail.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: Mehmet Sungur <mehmetsungurmutlu@gmail.com>
Co-authored-by: xDipzz <155362028+xDipzz@users.noreply.github.com>
Co-authored-by: Pasquale Vitiello <pasqualevitiello@gmail.com>
Co-authored-by: pasquale@cal.com <pasquale@cal.com>
Co-authored-by: cal.com <morgan@cal.com>
Co-authored-by: Anas Najam <129951478+anzz14@users.noreply.github.com>
Co-authored-by: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com>
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
Co-authored-by: Kartik Saini <41051387+kart1ka@users.noreply.github.com>
Co-authored-by: Abhishek <abhiifour@gmail.com>
Co-authored-by: susan@cal.com <susan@cal.com>
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
Co-authored-by: simiondolha <34995943+simiondolha@users.noreply.github.com>
Co-authored-by: simiondolha <simiondolha@users.noreply.github.com>
Co-authored-by: Kirankumar Ambati <kiran.chinna12520@gmail.com>
2026-01-14 08:20:37 -03:00
c0017114ef fix(api): return empty bookingUrl for managed users in API v2 (#26826)
Managed users (isPlatformManaged: true) don't have public booking pages -
their scheduling is handled through the platform's app.

- Fetch isPlatformManaged in event-types repository
- Return empty string for managed users in buildBookingUrl
- Added unit test for managed users case

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2026-01-14 15:28:25 +05:30
821dce6a04 fix(api): skip platform org subdomain in bookingUrl for API v2 (#26812)
Platform organizations don't have public-facing subdomains, so non-managed
users in platform orgs should get cal.com URLs instead of the platform
org subdomain.

- Updated EventTypeUser type to include isPlatform field
- Modified buildBookingUrl to check isPlatform before using org slug
- Added unit test for platform org users

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2026-01-14 09:04:45 +00:00
Pedro CastroandGitHub 4226231b8a perf: batch user queries in schedules output service (#25901)
Replace N sequential queries with single batch query for fetching
user default schedule IDs

Changes:
- Add getUsersScheduleDefaultIds batch method to UsersRepository
- Add getResponseSchedules batch method to OutputSchedulesService
- Extract transformScheduleToOutput for reuse
- Simplify OrganizationsSchedulesService and TeamsSchedulesService
- Remove dead code (formatInput no-op method)

Reduces database round-trips from O(n) to O(1) for schedule lookups
2026-01-13 19:21:17 +00:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
9ad8aa981a chore: deploy api v2 on vercel (#26735)
* chore: deploy api v2 on vercel

* fix: replace console.log with logger.log in Vercel handler

Address Cubic AI review feedback to use the logging framework
consistently instead of console.log in the serverless handler.

Co-Authored-By: unknown <>

* chore: enable esModuleInterop

* chore: deploy api v2 on vercel

* chore: deploy api v2 on vercel

* Update apps/api/v2/src/bootstrap.ts

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

* fixup! Merge branch 'main' into deploy-api-v2-vercel

* Revert "chore: deploy api v2 on vercel"

This reverts commit 45c704a48e8396c46118069e1a25d8d7a5ee84be.

* chore: deploy api v2 on vercel

* fix: address Cubic AI review feedback in main.ts

- Replace console.log with logger.log for consistent logging
- Replace console.error with logger.error for consistent error logging
- Restore comma: true option in qs.parse to support comma-separated arrays

Co-Authored-By: unknown <>

* fix: remove comma: true from qs.parse to maintain backward compatibility

The main branch does not have comma: true in the query parser, so adding
it would be a breaking change for existing API consumers. Removing it to
maintain consistency with the current production behavior.

Co-Authored-By: unknown <>

* chore: deploy api v2 on vercel

* small fixes

* chore: add try catch around bootstrap.ts

* fix: use NestJS Logger and throw error instead of process.exit in bootstrap

- Replace console.error with logger.error for consistent logging
- Replace process.exit(1) with throw error to avoid breaking Vercel serverless instance reuse

Addresses Cubic AI review feedback (confidence 10/10 for both issues)

Co-Authored-By: unknown <>

* chore: try log redis url

* fix: sanitize REDIS_URL logging to avoid exposing credentials

Replace full REDIS_URL logging with a boolean check that only indicates
whether Redis is configured, without exposing the connection string.

Addresses Cubic AI review feedback (confidence 9/10)

Co-Authored-By: unknown <>

* chore: remove unnecessary logs

* fix: prisma adapter

* chore: handle USE_POOL platform libraries

* fix: use JSON.stringify for Vite define value

Wrap usePool with JSON.stringify() to properly serialize the string value.
Without this, Vite injects the raw value as an identifier instead of a
string literal, breaking runtime behavior.

Addresses Cubic AI review feedback (confidence 9/10)

Co-Authored-By: unknown <>

* fix: docker file builds

* fix: correct Dockerfile build order for platform packages

Reorder builds to match the dependency graph from dev:build script:
constants → enums → utils → types → libraries → trpc → api-v2

platform-libraries depends on the other platform packages, so they
must be built first.

Addresses Cubic AI review feedback (confidence 9/10)

Co-Authored-By: unknown <>

* fix: docker file builds

* chore: add docker build

* chore: upgrade nest/bull

---------

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-13 11:31:21 -03:00
Hariom BalharaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
75d611c2e8 chore: Integrate creation/rescheduling booking audit for Recurring/regular booking/seated bookings (#26046)
* Integrate creation/rescheduling booking audit

* fix: add missing hostUserUuid to booking audit test data

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

* fix-ci

* feat: enhance booking audit with seat reference

- Added support for seat reference in booking audit actions.
- Updated localization for booking creation to include seat information.
- Modified relevant services to pass attendee seat ID during booking creation.

* fix: update test data to match schema requirements

- Add seatReferenceUid: null to default mock audit log data
- Add seatReferenceUid: null to multiple audit logs test case
- Convert SEAT_RESCHEDULED test data to use numeric timestamps instead of ISO strings

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

* Allow nullish seatReferenceUid

* feat: enhance booking audit to support rescheduledBy information

- Updated booking audit actions to include rescheduledBy details, allowing tracking of who rescheduled a booking.
- Refactored related services to accommodate the new rescheduledBy parameter in booking events.
- Adjusted type definitions and function signatures to reflect the changes in the booking audit context.

* Avoid possible run time issue

* Fix imoport path

* fix failing test due to merge from main\

* Pass useruuid

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-13 13:16:16 +00:00
5818da414b feat: update recording, transcript endpoint and add tests (#25771)
* feat: add tests and update endpoint

* chore: undo

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-13 09:54:23 -03:00
Anik Dhabal BabuGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
9202028ab6 fix: resolve API v2 test flakes with cleanup and simplified slug (#26766)
* fix: resolve API v2 test flakes by using UUID-only slug

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

* fix: add beforeAll cleanup to prevent test flakes from leftover data

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-12 18:54:29 -03:00
Dhairyashil ShindeandGitHub e879c923ea feat(api): add bookingUrl field to event types API v2 response (#26195)
* feat(api): add bookingUrl field to event types API v2 response

Add a new bookingUrl field to EventTypeOutput_2024_06_14 that contains
the full, correct booking URL for each event type. This fixes the issue
where companion app and Chrome extension were hardcoding cal.com URLs
instead of using organization subdomains.

Changes:
- Add bookingUrl field to EventTypeOutput_2024_06_14 type definition
- Update repository to include organization data when fetching users
- Add buildBookingUrl method to compute URL using getOrgFullOrigin
- Include bookingUrl in getResponseEventType return object

The booking URL is computed using the first user's organization slug
(if any) to generate the correct subdomain URL (e.g., i.cal.com/keith/30min
for organization users instead of cal.com/keith/30min).

* fix: include organization data in getEventTypeByIdWithHosts

Update getEventTypeByIdWithHosts to use usersInclude to fetch
organization slug data, ensuring bookingUrl is computed correctly
for the GET /v2/event-types/{eventTypeId} endpoint.

* test: add unit tests and E2E assertions for bookingUrl field

* fix(api-v2): correct bookingUrl format for org users and fix double slashes

Fix issues with bookingUrl field in event types API v2 response:
- Remove trailing slashes from base URLs to prevent double slashes
- Use profile.username instead of user.username for organization users
  (profile contains clean username without org suffix)
- Include user profiles in repository queries to access profile data
- Create local org-domains utility to replace @calcom/features dependency
  which isn't available in API v2 runtime

Changes:
- Add apps/api/v2/src/lib/org-domains.ts with getOrgFullOrigin function
  adapted from @calcom/features/ee/organizations/lib/orgDomains
- Update event-types.repository.ts to include profiles in usersInclude
- Update buildBookingUrl() to prioritize profile data when available
- Update unit tests to cover organization user profile scenarios

Fixes:
- Double slashes in URLs (e.g., http://localhost:3000//user/slug)
- Incorrect username format for org users (e.g., owner1-acme instead
  of owner1)
- Missing organization subdomain in booking URLs (e.g., should be
  http://acme.localhost:3000/owner1/30min not
  http://localhost:3000/owner1-acme/30min)

* deslop ai code

* handle empty username in both code and write test for it, use select instead of include

* feat(api-v2): reuse core org domain logic for event type bookingUrl

Export getOrgFullOrigin and subdomainSuffix from @calcom/platform-libraries/organizations
to reuse existing core logic instead of duplicating it in API v2. This ensures consistency
across the codebase and reduces maintenance burden.

- Export getOrgFullOrigin and subdomainSuffix from platform-libraries/organizations
- Update output-event-types.service to import from @calcom/platform-libraries/organizations
- Remove duplicate org-domains.ts file from API v2
- Update test mocks to use platform-libraries import path
- buildBookingUrl method now uses core getOrgFullOrigin function

This addresses feedback to reuse core code rather than introducing duplicate logic.

* test(api-v2): exclude bookingUrl from output comparison in e2e test

* refactor(api-v2): reuse core logic for event type bookingUrl

Replace duplicated username/org extraction logic in buildBookingUrl with
core functions. Use getBookerBaseUrlSync from @calcom/platform-libraries/organizations
for base URL generation, and add enrichUserWithProfile method that follows
the same pattern as core's UserRepository.enrichUsersWithTheirProfiles.

The enrichment logic is applied synchronously since profiles are already
fetched by the repository, avoiding the need to make the service async.
This ensures consistency with core patterns while maintaining the existing
synchronous API contract.

- Replace getOrgFullOrigin with getBookerBaseUrlSync
- Add enrichUserWithProfile method following core enrichment pattern
- Simplify buildBookingUrl to use enriched user data
- Update tests to mock getBookerBaseUrlSync and verify enrichment flow

* trailing slash cubic comment

* address review comments

* address review comments 2

* better code

* Updated the test to give the user an organization

* address review comments again

* Revert "address review comments again"

This reverts commit 622ea3fc8dcd7f5c3113614afcfc86beadecca0e.

* allow both the full UserWithProfile and the partial EventTypeUser (from select queries) to use the same getUserMainProfile() method, eliminating code duplication without changing the performance-optimized repository queries.

* reveiw points
2026-01-12 14:57:17 -03:00
MorganandGitHub c7cd25b7d5 chore: api v2 esModuleInterop more imports (#26755) 2026-01-12 11:39:01 -03:00
MorganandGitHub 6840642cb7 chore: esModuleInterop: true api v2 tsconfig (#26752)
* chore: api v2 esModuleInterop

* chore: api v2 esModuleInterop
2026-01-12 11:24:08 -03:00
Dhairyashil ShindeandGitHub dd4e1ba11b fix: api v2 dev server error (#26748) 2026-01-12 13:33:48 +00:00
Alex van AndelGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>keith@cal.com <keithwillcode@gmail.com>
6fb42b63e0 feat: add comprehensive validation tests for event-types/[id] GET endpoint (#23809)
* feat: add comprehensive validation tests for event-types/[id] GET endpoint

- Add integration tests for complex validation scenarios
- Test locations, booking fields, metadata, and seats validation
- Test edge cases that could cause validation mismatches between validators and DB results
- Ensure API response structure matches schemaEventTypeReadPublic schema
- Successfully catch validation discrepancies like missing displayLocationPublicly and assignAllTeamMembers fields

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: add explicit type annotations for booking fields find callbacks

- Fix TypeScript errors on lines 388 and 395
- Provide proper type annotations for find method callback parameters
- Replace any[] with specific { label: string; value: string }[] type
- Ensure CI type checking passes

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* feat: convert event-types integration test to use real database

- Replace prismaMock with real Prisma client operations
- Create actual database records for comprehensive test scenarios
- Add proper setup/teardown with unique timestamps for test isolation
- Maintain all existing validation test coverage
- Follow Cal.com integration test patterns for database operations

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* feat: restore original mock-based test alongside integration test

- Restored original _get.test.ts with prismaMock for unit testing
- Kept _get.integration.test.ts with real database for integration testing
- Both tests provide complementary coverage: mocks for fast unit tests, real DB for validation testing
- Fixed type annotations in find callbacks to maintain type safety

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: rename integration test to use proper naming convention

- Rename _get.integration.test.ts to _get.integration-test.ts
- Follows Cal.com vitest workspace pattern for integration tests
- Ensures integration test runs in proper CI workflow with database setup

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: update tests to use handler return value instead of res._getData()

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

* fix: add proper type assertions for locations and bookingFields in tests

Co-Authored-By: unknown <>

* fix: create schedule for test user to fix foreign key constraint in integration tests

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: keith@cal.com <keithwillcode@gmail.com>
2026-01-12 12:01:43 +00:00
Hariom BalharaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
77f59b1e4d chore: Integrate confirmation booking audit (#26523)
* chore: Integrate booking confirmation booking audit

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

* fix: Use BookingStatus type instead of string for booking.status

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

* Make booking-audit integration test utils reusable

* refactor: enhance handlePaymentSuccess to accept appSlug and actor identification

- Updated handlePaymentSuccess function to accept an object with paymentId, bookingId, appSlug, and traceContext.
- Introduced getActor function to determine the actor based on appSlug and credentialId.
- Modified webhook handlers for Alby, BTCPayServer, HitPay, PayPal, and Stripe to pass the new parameters.
- Improved logging for missing credentialId in payment processing.
- Adjusted related schemas to ensure proper type handling for booking status and actor identification.

* fix: Correct import paths and getActor function call

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

* fix: Use ActorIdentification type instead of AuditActor in getActor

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

* fix: Add guard clause for undefined actor in fireBookingAcceptedEvent

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

* fix: Add actionSource to all confirm calls

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

* refactor: Integrate actor identification and action source updates across booking services

- Added `makeUserActor` to various booking service files to enhance actor identification.
- Updated action source handling in booking confirmation and related functions to include "MAGIC_LINK".
- Refactored schemas to accommodate new actor and action source requirements, ensuring consistent type handling.
- Improved error handling and logging for booking actions to enhance traceability.

* Remvoe formatting changes

* Add test

* refactor: Enhance booking confirmation tests and event handling

- Updated `confirm.handler.test.ts` to improve test coverage for booking acceptance and rejection scenarios, including bulk bookings.
- Refactored the mock implementation of `BookingEventHandlerService` to streamline event handling for accepted and rejected bookings.
- Adjusted the `handleConfirmation` function to utilize `acceptedBookings` for better clarity and maintainability.
- Added tests to ensure correct invocation of event handler methods for both single and bulk booking confirmations and rejections.

* fix tests

* refactor: Use confirmHandler directly in link and verify-booking-token routes

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: hariom@cal.com <hariombalhara@gmail.com>

* fix ts errors due to merge frommain

* feat: introduce getAppActor utility for actor creation

This commit adds a new utility function, getAppActor, to streamline the process of creating actor objects for apps based on their slug and credential ID. The function is integrated into handlePaymentSuccess and handleStripePaymentSuccess, replacing the previous inline actor creation logic. This refactor enhances code maintainability and readability by centralizing actor creation logic.

Changes:
- New file: packages/app-store/_utils/getAppActor.ts
- Updated handlePaymentSuccess and handleStripePaymentSuccess to use getAppActor
- Removed redundant actor creation code from these functions

* refactor: Update appSlug in payment success handlers to use appConfig.slug

This commit modifies the appSlug parameter in the handlePaymentSuccess function across multiple payment webhook handlers to utilize the appConfig.slug value instead of hardcoded strings. This change enhances consistency and maintainability of the code.

Changes:
- Updated appSlug in handlePaymentSuccess for btcpayserver, hitpay, and paypal webhooks.
- Adjusted a test case to reflect the new appSlug value for consistency.

* test: Enhance booking token verification and audit action tests

This commit adds additional assertions to the booking token verification tests to ensure that the confirmHandler is not called when an error occurs. It also introduces a mechanism to clean up additional booking UIDs after each test in the accepted action integration tests, improving test reliability. Furthermore, it updates the action source schema comment for clarity.

Changes:
- Updated tests in `verify-booking-token` to check that `mockConfirmHandler` is not called on error.
- Implemented cleanup logic for additional booking UIDs in `accepted-action.integration-test.ts`.
- Clarified comment in `actionSource.ts` regarding the schema for action sources.
- Refactored `handleConfirmation.ts` and `confirm.handler.ts` to include tracing logger for error handling in booking events.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-12 08:17:26 -03:00
Hariom BalharaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c9bb03b602 chore: Integrate add guests booking audit (#26568)
* chore: Integrate add guests booking audit

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

* chore: Add actionSource parameter to support API_V2 audit logging

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

* refactor: update attendee audit action service to use new email schema

- Modified the `AttendeeAddedAuditActionService` to replace the old attendees schema with a new `emailSchema` for better validation.
- Adjusted the `addGuestsHandler` to pass the action source explicitly and updated the audit logging to reflect the new structure.
- Cleaned up the code for better readability and consistency.

* test: add happy path integration test for attendee added action

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-12 11:11:33 +00:00
Rajiv SahalandGitHub f7dee536d7 fix: dont import directly from @calcom/trpc or @calom/features (#26734) 2026-01-12 10:05:39 +00:00
0994050b0f fix(api): return original email without OAuth suffix in bookings (#25593)
* fix(api): remove OAuth client ID suffix from email in booking API responses

Fixes #25494 | Linear: CAL-6843

When managed users create or receive bookings, their emails were being returned with an internal OAuth client ID suffix (e.g., bob+cuid123@example.com). This suffix is used internally for user identification but should not be exposed in API responses.

Changes:
- Add cleanOAuthEmailSuffix() helper using CUID regex pattern
- Clean email suffix in hosts[], attendees[], bookingFieldsResponses.email, bookingFieldsResponses.guests[], and reassignedTo.email
- Pattern consistent with google-calendar.service.ts implementation

Affected output methods:
- getOutputBooking
- getOutputRecurringBooking
- getOutputSeatedBooking
- getOutputRecurringSeatedBooking
- getOutputReassignedBooking
- getHost

* refactor(api): preserve original email, add displayEmail field

Per team discussion, keep original email unchanged to avoid breaking changes for platform customers.
Add displayEmail field with CUID suffix removed for display purposes

* feat(api): add displayEmail to booking output DTOs

Add displayEmail property to BookingAttendee, BookingHost and ReassignedToDto for API documentation and type safety

* test(api): add e2e tests for displayEmail fields in managed user bookings

Add tests to verify that displayEmail fields correctly strip CUID suffix from OAuth managed user emails in booking API responses:

- Test host displayEmail returns email without CUID suffix
- Test attendee displayEmail returns email without CUID suffix
- Test bookingFieldsResponses.displayEmail returns clean email
- Test displayGuests array returns emails without CUID suffix

* false positive breaking change

* false positive breaking change

* test(api): update existing e2e tests to expect displayEmail field

* fix(api): add missing displayEmail to seated booking test assertions

The seated booking tests were missing displayEmail in the attendee
assertions for the second booking test and cancel-as-host test,
causing CI test failures

---------

Co-authored-by: cal.com <morgan@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2026-01-12 07:48:37 +00:00
3e7e376100 chore: Some minor fixes and follow up to #26446 (#26587)
* init

* DI and other improvements

* type fix

---------

Co-authored-by: Volnei Munhoz <volnei@cal.com>
2026-01-12 04:32:55 +00:00
MorganandGitHub 32ecb924d7 chore: USE_POOL env var for api v2 prisma pooling (#26622) 2026-01-10 09:10:38 +00:00
cal.com 71729813a9 Revert "chore: USE_POOL env var for api v2 prisma pooling"
This reverts commit a97092619f.
2026-01-09 17:59:10 +02:00
cal.com a97092619f chore: USE_POOL env var for api v2 prisma pooling 2026-01-09 17:55:25 +02:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
8666efa29d chore: enable/disable slots workers via env (#26621)
* chore: enable/disable slots workers via env

* fix: address Cubic AI review feedback

- Fix incorrect JSDoc comment for getSerializableContext method
- Remove debug console.log statement from slots controller
- Fix port suffix condition to preserve original behavior

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-09 15:03:13 +00:00
MorganandGitHub 02a334e072 chore: api v2 generate swagger only in dev (#26617) 2026-01-09 15:12:42 +02:00
MorganandGitHub 56b29b5df6 chore: rename app.ts to bootstrap.ts on api-v2 (#26604) 2026-01-09 09:56:27 +00:00
Anik Dhabal BabuGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
b6c243f1dd fix: improve cleanup for managed event types and fix flaky api v2 e2e test (#26602)
* fix: improve cleanup for managed event types in e2e tests

- Add deleteAllUserEventTypes method to EventTypesRepositoryFixture
- Update afterAll cleanup to delete user event types before deleting users
- This ensures child event types of managed event types are properly cleaned up
- Fixes flaky tests caused by incomplete cleanup between test runs
- Add explicit return types to fixture methods to satisfy lint rules
- Replace @ts-ignore with @ts-expect-error for better type safety

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

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-09 06:16:59 -03:00
Pedro CastroandGitHub 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
Anik Dhabal BabuGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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
Alex van AndelandGitHub 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
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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
Volnei MunhozGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
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
Syed Ali ShahbazGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
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
Benny JooGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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
Udit TakkarandGitHub 0d905a6c11 fix: add arrayLimit (#26542) 2026-01-07 14:23:38 +00:00
Dhairyashil ShindeandGitHub 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
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>Peer RichelsenVolnei MunhozVolnei Munhoz
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 BalharaandGitHub 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
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
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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