* refactor(companion): split calcom.ts into modular service files
Split the monolithic 1692-line calcom.ts file into focused modules:
- auth.ts: Authentication configuration and token management
- bookings.ts: Booking CRUD operations and actions
- conferencing.ts: Conferencing options
- event-types.ts: Event type CRUD operations
- private-links.ts: Private link management for event types
- request.ts: Core HTTP request functionality
- schedules.ts: Schedule CRUD operations
- user.ts: User profile management
- utils.ts: JSON parsing and payload sanitization utilities
- webhooks.ts: Webhook management (global and event type specific)
- index.ts: Re-exports all functions and maintains backward compatibility
This improves code organization, maintainability, and makes it easier
to understand and modify specific functionality.
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix(companion): avoid logging sensitive booking response data
Replace logging of full responseText (which may contain PII like attendee
emails and names) with responseLength for safer debugging.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: move booking-audit client components from packages/features to apps/web/modules
This is part of the larger effort to move tRPC-dependent UI components from packages/features to apps/web/modules to eliminate circular dependencies.
Changes:
- Move BookingHistory.tsx and BookingHistoryPage.tsx to apps/web/modules/booking-audit/components/
- Update imports in apps/web to use the new location
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
* refactor: move formbricks client from packages/features to apps/web/modules
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
* refactor: move hooks and stores from packages/features to apps/web/modules
- Move useAppsData hook from packages/features/apps/hooks to apps/web/modules/apps/hooks
- Move onboardingStore from packages/features/ee/organizations/lib to apps/web/modules/ee/organizations/lib
- Move useWelcomeModal hook from packages/features/ee/organizations/hooks to apps/web/modules/ee/organizations/hooks
- Move useAgentsData hook from packages/features/ee/workflows/hooks to apps/web/modules/ee/workflows/hooks
- Update all import paths in consuming files
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
* refactor: move onboardingStore test file to apps/web/modules
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: return 400 instead of 500 for invalid email in iCal generation
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
* test: add unit tests for error handling in generateIcsString
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat(companion): add app store rating prompts for iOS and Android
- Add useAppStoreRating hook with generalized requestRating(trigger) function
- Add RatingTrigger const for extensible trigger types (EVENT_TYPE_SAVED, BOOKING_CONFIRMED, BOOKING_REJECTED)
- Integrate rating prompt into useCreateEventType and useUpdateEventType hooks
- Integrate rating prompt into useConfirmBooking and useDeclineBooking hooks
- Add expo-store-review package dependency
- Rating prompts only show once per trigger type (tracked via AsyncStorage)
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix(companion): correct expo-store-review version to 9.0.10
Co-Authored-By: peer@cal.com <peer@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* chore: save progress
* chore:
* feat: add input dialog
* fix: type error
* feat: mass apply dialog
* test: per host location
* test: fix test
* fix: address Cubic AI review feedback (confidence >= 9/10)
- Remove PII (address, phone number) from tracing logs in RegularBookingService.ts
- Constrain HostLocation.type to EventLocationType["type"] for compile-time validation
Co-Authored-By: unknown <>
* fix: translation
* refactor: improvements
* fix: correct grammar in custom host locations tooltip
Change 'custom host locations is enabled' to 'custom host locations are enabled' (plural subject requires plural verb).
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
* refactor: improvements
* fix: auth
* fix: check
* refactor: improvements
* fix: address Cubic AI review feedback (confidence >= 9/10)
- Add scheduleId to newly created hosts in update.handler.ts to persist
host-specific schedules during create operations
- Change host location deletion filter from !host.location to
host.location === null to only delete when explicitly set to null
- Fix static-link per-host locations to use actual link instead of type
in locationBodyString for bookingLocationService.ts
Co-Authored-By: unknown <>
* fix: preserve existing host scheduleId when not explicitly provided
Change scheduleId handling for existing hosts from 'host.scheduleId ?? null'
to 'host.scheduleId === undefined ? undefined : host.scheduleId' so that
when the client doesn't provide a scheduleId, the existing value is preserved
instead of being cleared to null.
Co-Authored-By: unknown <>
* fix; type erro
* fix; type erro
* fix; type erro
* refactor: move repository
* refactor: move repository
* fix: add singular/plural translations for location_applied_to_hosts
Addresses Cubic AI review feedback (confidence 9/10) to fix '1 hosts' rendering as '1 host' by using i18next plural format with _one and _other suffixes.
Co-Authored-By: unknown <>
* refactor: feedback
* fix: type err
* fix: use uuid in schema and remove attendee locaiton
* fix: type err
* fix: type err
* fix: validate eventTypeId as integer in massApplyHostLocation schema
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(coss-ui): convert /settings/my-account/general to coss-ui
* update guide
* fix: add menuPosition fixed to TimezoneSelect in TravelScheduleModal
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: use menuPortalTarget to render TimezoneSelect dropdown above dialog footer
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: use Object.assign for type-safe styles in TimezoneSelect
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* revert comment
* fix: guard document access for SSR in TravelScheduleModal
Addresses Cubic AI review feedback: menuPortalTarget={document.body} will
throw during server rendering where document is undefined. Added typeof
check to guard against SSR.
Co-Authored-By: unknown <>
* change dialog backdrop from blur to dim
* fix: add menuPlacement auto to open dropdown upward on mobile
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: use menuPlacement top on mobile for TimezoneSelect dropdown
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: make timezone button stack vertically on mobile to prevent overflow
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: make timezone select and button 50/50 width on larger viewports
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix date range picker issue on mobile
* prevent travel schedule dialog dismissal with date picker
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: allow normal users to see userId filter with only themselves as option
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: return empty map when canReadOthersBookings is false and currentUser doesn't exist
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: use generic type parameter for Table to fix type compatibility
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* perf: disable listSimpleMembers query when canReadOthersBookings is false
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add seat tracking infrastructure for monthly proration
Add seat change logging infrastructure with operationId for idempotency.
This PR adds the foundation for monthly proration billing by tracking
seat additions and removals, gated behind the monthly-proration feature flag.
- Add operationId field to SeatChangeLog for idempotency
- Update SeatChangeLogRepository to support upsert with operationId
- Add feature flag guard in SeatChangeTrackingService
- Integrate seat tracking in team member invites
- Integrate seat tracking in bulk user deletions
- Integrate seat tracking in team service operations
- Integrate seat tracking in DSYNC user creation
When monthly-proration feature flag is disabled, seat logging is skipped
and behavior remains unchanged.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: add monthly proration processing
Add monthly proration billing processing that works on top of the seat
tracking infrastructure. This PR implements the core proration logic,
webhook handlers, and integration with Stripe billing.
- Enhance MonthlyProrationService to process seat change logs
- Add payment webhook handlers (invoice.payment_succeeded, invoice.payment_failed)
- Update subscription webhook to sync billing period on renewals
- Update TeamBillingService to skip real-time updates when proration enabled
- Enhance StripeBillingService with proration capabilities
- Add Tasker enhancements for processing queues
- Update team creation/upgrade routes
Depends on: feat/monthly-proration-seat-tracking
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: remove unused logger from SeatChangeTrackingService
* fix: description for calculation
* fix null check on trial
* feat: add scheduled trigger.dev task for monthly proration
* feat: add custom month key support and use batchTrigger
* feat: add isValidMonthKey and return result from batch task
* fix merge artifact
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add graceful error handling for audit log enrichment
- Add hasError field to EnrichedAuditLog type
- Create buildFallbackAuditLog() method for failed enrichments
- Wrap enrichAuditLog() in try-catch to handle errors gracefully
- Add booking_audit_action.error_processing translation key
- Update BookingHistory.tsx to show warning icon for error logs
- Hide 'Show details' button for logs with hasError
- Add comprehensive test cases for error handling scenarios
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: include actionType in error_processing translation and allow expanded content for error logs
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Implements booking audit logging for round-robin reassignment events (both manual and automatic). This is part of the booking audit integration plan (PR 7).
Changes:
- Added audit logging to `roundRobinManualReassignment.ts` for manual host reassignments
- Added audit logging to `roundRobinReassignment.ts` for automatic round-robin reassignments
- Updated tRPC handlers to pass `actionSource: "WEBAPP"` and `reassignedByUuid`
- Updated API v2 bookings service to pass `actionSource: "API_V2"` and `reassignedByUuid`
- Updated `ReassignmentAuditActionService.ts` with proper field schemas and translation keys
The audit logging uses `BookingEventHandlerService.onReassignment()` with proper actor identification and action source tracking.
## Updates since last revision
Addressed review feedback:
- Renamed `title` field to `hostName` for semantic clarity (tracks host name changes, not booking titles)
- Fixed `assignedById` schema: changed from `NumberChangeSchema` to `z.number()` (no old/new pattern needed - it's always the user who performed the reassignment)
- Fixed `reassignmentReason` schema: changed from `StringChangeSchema` to `z.string().nullable()` (no old/new pattern needed)
- Added `ValidActionSource` type that excludes `UNKNOWN` - clients must pass explicit action sources
- Made `actionSource` required in both reassignment functions (no longer optional)
- Added integration tests for `ReassignmentAuditActionService` (15 tests covering all methods)
- Updated `roundRobinManualReassign.handler.ts` to pass required `actionSource` and `reassignedByUuid` params
**Latest fixes:**
- Fixed `hasAttendeeUpdated` check in `ReassignmentAuditActionService.ts`: changed from `!== null` to `!= null` to properly handle undefined values
- Updated test expectations in `ReassignmentAuditActionService.test.ts` to match the new display JSON field names (`hostAttendeeUserUuidNew`/`hostAttendeeUserUuidOld` instead of `newAssignedRRHostUuid`/`previousAssignedRRHostUuid`)
- Fixed async `getDisplayFields` tests to properly await the Promise and include the `previous_assignee` field
- Fixed `hasAttendeeUpdated` to check for `hostAttendeeUpdated` object presence instead of optional `id` field - host changes with only `withUserUuid` populated were being ignored (identified by Cubic AI, confidence 9/10)
- Fixed test expectation in `getDisplayJson` test: removed incorrect null expectations for `hostAttendeeIdUpdated`, `hostAttendeeUserUuidNew`, `hostAttendeeUserUuidOld` - the implementation uses conditional spreading to omit these fields when `hostAttendeeUpdated` is not present, rather than setting them to null
## 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. Trigger a manual round-robin reassignment via the webapp and verify audit logs are created with `actionSource: "WEBAPP"`
2. Trigger an automatic round-robin reassignment and verify audit logs are created
3. Use API v2 to reassign a booking and verify audit logs are created with `actionSource: "API_V2"`
4. Verify the audit data contains correct values for `organizerUuid`, `hostAttendeeUpdated`, `reassignmentReason`, and `reassignmentType`
## Checklist
- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings
## Human Review Checklist
- [x] Verify the `hasAttendeeUpdated` fix is correct: now checks `fields.hostAttendeeUpdated != null` to detect any host attendee update regardless of whether `id` is populated
- [x] Verify `getDisplayJson` test fix: fields are correctly omitted (not set to null) when `hostAttendeeUpdated` is not present, matching the conditional spreading implementation
- [ ] Verify all callers of reassignment functions pass required `actionSource` and `reassignedByUuid`
- [ ] Confirm `getDisplayFields` is properly awaited in all call sites (it's now async)
- [ ] Check that `ValidActionSource` type properly excludes `UNKNOWN` for client-side validation
## Important Notes for Reviewer
1. **Dependency on base PR**: The translation key changes use the format from base PR (#26046). This PR should be merged after the base PR.
2. **Schema changes**: The `organizerUuid` and `hostAttendeeUpdated` fields track both organizer changes and round-robin host attendee changes separately for complete audit trail.
---
Link to Devin run: https://app.devin.ai/sessions/e4353e2ec6ea4a51ab33313bdc630aba
Requested by: @hariombalhara
* refactor: move organization members page from /settings/organizations/members to /members
- Create new /members route under main-nav with same functionality
- Add permanent redirect from /settings/organizations/members to /members
- Include loading skeleton and server actions for the new route
Co-Authored-By: peer@cal.com <peer@cal.com>
* refactor: Deduplicate organization members page logic (#27168)
* refactor(web): extract shared org members data fetching logic
- Extract data fetching, coaching, and permission logic into [getOrgMembersPageData.ts](cci:7://file:///Users/dhairyashilshinde/work/cal.com/apps/web/modules/members/getOrgMembersPageData.ts:0:0-0:0)
- Deduplicate logic between [/members](cci:7://file:///Users/dhairyashilshinde/work/cal.com/apps/web/app/%28use-page-wrapper%29/%28main-nav%29/members:0:0-0:0) and pages
- Reduce page component size and improve maintainability
* safe guard for org id null
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
* fixed text issue
* matched style of api keys page
* made changes to the upgradetip
* made changes to the upgradetip
* made changes to the upgradetip
* Refactor TextField component properties
---------
Co-authored-by: Pallav <90088723+pallava-joshi@users.noreply.github.com>
* perf: optimize getEventTypeIdsFromTeamIdsFilter with raw SQL query
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: use prisma singleton for raw queries to fix runtime error
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: use context prisma for raw queries and update test mocks
- Changed getEventTypeIdsFromTeamIdsFilter to use the context-passed prisma parameter instead of importing the singleton
- Added $queryRaw mock to test file to support raw SQL queries
- Updated test assertion to check for $queryRaw call instead of eventType.findMany
The context prisma IS the same singleton at runtime (passed via tRPC context in createContext.ts). The test was failing because the mock didn't include $queryRaw.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Removed extra subquery where not needed
* fix: restore subquery optimization for better query performance
Restores the subquery structure that allows PostgreSQL to use the composite
index on EventType(parentId, teamId) efficiently via Nested Loop joins,
resulting in ~66x faster execution (2.46ms vs 164ms in production benchmarks).
Identified by Cubic AI (confidence 9/10).
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Fighting with AI
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Follow-up to #27085 and #27092 - creates the database migration to drop the deprecated `startTime` and `endTime` columns from the `users` table.
These columns were marked as `// DEPRECATED - TO BE REMOVED` in the Prisma schema. The prerequisite PRs removed all code references to these columns, making it safe to now drop them from the database.
**Changes:**
- Remove `startTime` and `endTime` fields from the `User` model in `schema.prisma`
- Add migration to drop both columns from the `users` table
- Remove `startTime` and `endTime` from test builder (`packages/lib/test/builder.ts`)
## 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 schema cleanup
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. N/A - schema migration only, existing tests should continue to pass
## How should this be tested?
1. Verify PRs #27085 and #27092 have been merged (prerequisite)
2. Run `yarn prisma generate` - should complete without errors
3. Run `yarn type-check:ci --force` - should pass (no code references these columns anymore)
4. Apply migration to a test database and verify columns are dropped
## Checklist
- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings
## Human Review Checklist
- [ ] Confirm PRs #27085 and #27092 are merged before merging this PR
- [ ] Verify no remaining code references to `user.startTime` or `user.endTime` in the codebase
- [ ] ⚠️ **Breaking change**: This permanently drops data from the `users` table. Ensure no external systems depend on these columns.
---
Link to Devin run: https://app.devin.ai/sessions/c5a10684d905496fbce66a0b464a73a5
Requested by: @emrysal
* feat(flags): add @Memoize and @Unmemoize decorators for declarative caching
- Add @Memoize decorator for caching method results with Zod validation
- Add @Unmemoize decorator for cache invalidation on mutations
- Create UserFeatureRepository using decorators as example implementation
- Add comprehensive tests with 80%+ coverage (19 tests)
- Add DI module and tokens for UserFeatureRepository
- Enable experimentalDecorators in packages/features/tsconfig.json
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(cache): use lazy Redis lookup in decorators
- Decorators now access Redis via getRedisService() instead of this.redis
- UserFeatureRepository no longer has redis property or direct redis calls
- findByUserIdAndFeatureIds now uses decorated findByUserIdAndFeatureId
- DI module simplified to only pass prisma dependency
- Tests updated to call setRedisService() in beforeEach
This ensures the repository only knows about Prisma, with all caching
handled transparently by the decorators.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat(flags): add FeatureRepository and TeamFeatureRepository with decorator-based caching
- Add FeatureRepository with @Memoize decorators for findAll, findBySlug, getFeatureFlagMap
- Add TeamFeatureRepository with @Memoize/@Unmemoize decorators for all CRUD operations
- Add comprehensive Zod schemas for Feature, TeamFeatures, and AppFlags validation
- Add DI modules and tokens for both repositories
- Add comprehensive test coverage (33 tests) for both repositories
- Maintain backward compatibility with existing FEATURES_REPOSITORY tokens
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(cache): use DI container pattern for Redis service
- Create packages/features/di/containers/Redis.ts with getRedisService()
- Update Memoize and Unmemoize decorators to import from DI container
- Remove setRedisService() and IRedisService from types.ts exports
- Update all tests to mock the container's getRedisService
- Fix import ordering issues from biome
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(cache): remove barrel import and add root-level cache export
- Remove packages/features/cache/decorators/index.ts barrel file
- Add packages/features/cache/index.ts as root-level export for cache feature
- Update repository imports to use direct imports from source files
- Follows the pattern: avoid barrel imports at nested levels, keep at feature root
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(flags): minimize repository methods and address PR feedback
- Remove unnecessary methods from FeatureRepository, TeamFeatureRepository, and UserFeatureRepository
- Keep only methods needed by FeatureOptInService
- Update imports to use @calcom/features/cache public API instead of relative paths
- Handle redis.del() errors gracefully in Unmemoize decorator
- Update tests to match simplified repositories
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(cache): use Promise.allSettled for cache invalidation
Cleaner approach than Promise.all with individual .catch() handlers
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat(flags): add setAutoOptIn methods and replace featuresRepository usage in _router.ts
- Add setAutoOptIn method to TeamFeatureRepository with @Unmemoize decorator
- Add setAutoOptIn method to UserFeatureRepository with @Unmemoize decorator
- Replace featuresRepository usage in featureOptIn/_router.ts with new repositories
- TeamFeatureRepository.setAutoOptIn unmemoizes KEY.autoOptInByTeamId(teamId)
- UserFeatureRepository.setAutoOptIn unmemoizes KEY.autoOptInByUserId(userId)
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(flags): use DI containers for TeamFeatureRepository and UserFeatureRepository
- Create TeamFeatureRepository.ts container with getTeamFeatureRepository()
- Create UserFeatureRepository.ts container with getUserFeatureRepository()
- Update _router.ts to use DI containers instead of direct instantiation
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(feature-opt-in): use DI containers for FeatureOptInService dependencies
- Update FeatureOptInService to use IFeatureOptInServiceDeps with 3 repositories
- Add helper functions teamFeatureToState() and userFeatureToState()
- Update DI module to use depsMap pattern with featureRepo, teamFeatureRepo, userFeatureRepo
- Create FeatureRepository container file
- Replace all FeaturesRepository method calls with new repository methods
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* test(feature-opt-in): update FeatureOptInService tests for new IFeatureOptInServiceDeps interface
- Update mock structure to use featureRepo, teamFeatureRepo, userFeatureRepo
- Add helper functions createMockTeamFeature and createMockUserFeature
- Update all test cases to use new repository method names
- Add explicit types to satisfy biome lint rules
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor(flags): use DTOs at repository boundaries to prevent Prisma type leakage
- Create FeatureDto, TeamFeaturesDto, UserFeaturesDto in packages/lib/dto/
- Update repository interfaces to return DTOs instead of Prisma types
- Add toDto() transformation methods in repository implementations
- Update FeatureOptInService to use DTOs instead of Prisma types
- Follow data-dto-boundaries.md guidelines for architectural boundaries
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix(flags): update TeamFeatureRepository tests to match DTO structure
Remove assignedAt from test mock data since TeamFeaturesDto only includes:
teamId, featureId, enabled, assignedBy, and updatedAt
Co-Authored-By: unknown <>
* fix(cache): make Redis failures non-blocking in @Memoize decorator
Wrap Redis get and set operations in try-catch blocks to ensure
Redis failures don't break the application flow. If cache read fails,
proceed to fetch from source. If cache write fails, silently ignore
and return the result.
Co-Authored-By: unknown <>
* fix(cache): add logging for Redis failures and remove barrel import
- Add warning logs for Redis failures in @Memoize and @Unmemoize decorators
- Remove packages/lib/dto/index.ts barrel import file
- Update all imports to use direct file paths instead of barrel imports
Co-Authored-By: unknown <>
* fix(cache): sanitize log messages to avoid exposing sensitive data
- Remove cacheKey from log messages (may contain PII like user/team IDs)
- Log only error.message instead of raw error objects
- Addresses Cubic AI feedback (confidence 9/10)
Co-Authored-By: unknown <>
* sanitize log
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
Follow-up to #27085 - removes the remaining code references to the
deprecated user.startTime and user.endTime columns that were missed
in the initial PR.
Changes:
- Remove startTime/endTime from availabilityUserSelect in prisma selects
- Remove startTime/endTime from GetUserAvailabilityInitialData type
- Remove startTime/endTime from defaultEvents user mock object
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* --INIT
* fixes
* better comments and some clean up
* test and type fix
* clean up
* address feedback
* fix erroneous booking_confirmed to booking_rescheduled
* feat: add seat tracking infrastructure for monthly proration
Add seat change logging infrastructure with operationId for idempotency.
This PR adds the foundation for monthly proration billing by tracking
seat additions and removals, gated behind the monthly-proration feature flag.
- Add operationId field to SeatChangeLog for idempotency
- Update SeatChangeLogRepository to support upsert with operationId
- Add feature flag guard in SeatChangeTrackingService
- Integrate seat tracking in team member invites
- Integrate seat tracking in bulk user deletions
- Integrate seat tracking in team service operations
- Integrate seat tracking in DSYNC user creation
When monthly-proration feature flag is disabled, seat logging is skipped
and behavior remains unchanged.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: add monthly proration processing
Add monthly proration billing processing that works on top of the seat
tracking infrastructure. This PR implements the core proration logic,
webhook handlers, and integration with Stripe billing.
- Enhance MonthlyProrationService to process seat change logs
- Add payment webhook handlers (invoice.payment_succeeded, invoice.payment_failed)
- Update subscription webhook to sync billing period on renewals
- Update TeamBillingService to skip real-time updates when proration enabled
- Enhance StripeBillingService with proration capabilities
- Add Tasker enhancements for processing queues
- Update team creation/upgrade routes
Depends on: feat/monthly-proration-seat-tracking
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: remove unused logger from SeatChangeTrackingService
* fix: description for calculation
* fix null check on trial
* chore: no more prisma calls
* add feature flag check
* fix stub
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: store utm params in stripe on signup
* fix: fallback to cookie when query params don't contain valid UTM data
Changed from else-if to separate if statement so that when query
params exist but don't contain valid UTM data, the cookie fallback
is still tried. Previously, any request with non-UTM query params
would skip the stored cookie data entirely.
Co-Authored-By: unknown <>
* fix: e2e
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Adds an end-to-end test for the Feature Opt-In banner flow. This test verifies the complete user journey from seeing the banner to enabling a feature.
Currently `OPT_IN_FEATURES` in `packages/features/feature-opt-in/config.ts` is empty, so this e2e test skips. Once we uncomment the `bookings-v3` item from the config, this e2e test will run and pass. This is a preparation for when we enable the feature.
**Changes:**
- Creates a new e2e test file (`feature-opt-in-banner.e2e.ts`) that tests the complete opt-in flow
- Adds `data-testid` attributes to banner and dialog components for reliable test selectors
## 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 - test only.
- [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. Add the `ready-for-e2e` label to run e2e tests in CI
2. The test should pass when run with `PLAYWRIGHT_HEADLESS=1 yarn e2e feature-opt-in-banner.e2e.ts`
**Test requirements:**
- The `bookings-v3` feature flag must exist in the Features table (the test uses `prisma.feature.upsert` to ensure this)
- The test will skip if `bookings-v3` is not in `OPT_IN_FEATURES`
## Checklist
- [x] I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- [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
## Updates since last revision
- Replaced text-based locators (`getByText`, `getByRole`) with `data-testid` selectors for more reliable element targeting
- Added `data-testid` attributes to `FeatureOptInBanner`, `FeatureOptInConfirmDialog`, and `FeatureOptInSuccessDialog` components
## Human Review Checklist
- [ ] Verify the `data-testid` attributes don't conflict with existing test IDs in the codebase
- [ ] Confirm the test correctly skips when `bookings-v3` is not in `OPT_IN_FEATURES`
- [ ] Check that the added `data-testid` attributes follow the project's naming conventions
---
Link to Devin run: https://app.devin.ai/sessions/97158ab1b7414e3988ba803b30d95b3e
Requested by: @eunjae-lee
* fix: prevent CalDAV duplicate invitations with RFC-compliant SCHEDULE-AGENT
Fixes#9485
Adds SCHEDULE-AGENT=CLIENT to ATTENDEE lines in CalDAV createEvent and
updateEvent operations per RFC 6638 Section 7.1. This tells CalDAV servers
(Fastmail, NextCloud, etc.) that the client handles scheduling, preventing
duplicate invitation emails.
Implementation includes:
- RFC 5545 compliant line folding (max 75 octets per line)
- UTF-8 aware byte counting for international names
- Proper handling of :mailto: format in ATTENDEE lines
- Skips lines that already have SCHEDULE-AGENT parameter
* fix: address Cubic review - unfold lines and case-insensitive matching
- Add unfoldLines() to handle RFC 5545 folded lines before processing
- Use case-insensitive regex (gim flag) per RFC 5545 spec
- Simplify regex to properly capture params and value separately
* fix: only unfold/refold ATTENDEE lines, preserve other lines
- Match ATTENDEE lines including folded continuations
- Unfold only the matched ATTENDEE line
- Re-fold after adding SCHEDULE-AGENT=CLIENT
- Other iCal lines remain untouched (no RFC 5545 violation)
* fix: check SCHEDULE-AGENT only in params, not value
Only check for existing SCHEDULE-AGENT in the params portion,
not the value (which contains email/CN). This prevents false
positives when email contains "schedule-agent" substring.
* fix: handle quoted colons and exact SCHEDULE-AGENT matching
1. Colon parsing: Match :mailto:/:http:/:urn: patterns, or fallback
to finding colon not inside quotes
2. SCHEDULE-AGENT check: Use regex to match exact parameter name
(preceded by ; or at start), not substring match
* add tests
* Update .env.example
---------
Co-authored-by: Anik Dhabal Babu <adhabal2002@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
* perf: add composite index on EventType(parentId, teamId)
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Apply suggestion from @keithwillcode
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add assigned badge to team event types
Add an 'Assigned' badge to Round Robin and Collective event types
when the current user is a host/participant of the event type.
This provides visibility to users without edit permissions that
they are included in the rotation.
Changes:
- Add isCurrentUserHost flag in getEventTypesFromGroup handler
- Display blue 'Assigned' badge in event types listing view
- Add i18n translation for 'assigned' text
Co-Authored-By: ali@cal.com <ali@cal.com>
* refactor: remove redundant isTeamEvent check for assigned badge
Co-Authored-By: ali@cal.com <ali@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
* chore: add new view for two step slot selection for embed
* fix: make sure two step slot selection is false by default
* chore: update embed playground to showcase two step slot selection
* chore: add tests
* chore: update embed snippet generator code to include two step slot selection
* chore: update docs
* fix: back button styling
* chore: implement feedback from cubic
* fix: add missing isEnableTwoStepSlotSelectionVisible properties to test mock store
Co-Authored-By: unknown <>
* chore: implement PR feedback
* chore: update slot selection modal
* chore: add prop to hide available times header
* fix: scope two-step slot selection visibility to mobile only
Restores the isMobile check in the timeslot visibility guard to ensure
desktop embeds continue to show the booking UI when two-step slot
selection is enabled. The feature should only hide the timeslot list
on mobile devices.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
* fixup: use translations for loading instead of actual word
* fix: type check
* fix: add window.matchMedia mock for jsdom test environment
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: add window.matchMedia mock to packages/testing/src/setupVitest.ts
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: unit tests failing
* add a width style to the two-step slot selection embed container.
* refactor: rename enableTwoStepSlotSelection to useSlotsViewOnSmallScreen
- Rename external-facing embed config option from enableTwoStepSlotSelection to useSlotsViewOnSmallScreen
- Update URL parameter parsing in embed-iframe.ts
- Update type definitions in types.ts and index.d.ts
- Update internal variable names to slotsViewOnSmallScreen for consistency
- Update documentation, playground examples, and tests
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* Add config to prefill all booking fields so that slot has confirm button along with it
* chore: implement PR feedback
* fix: move twoStepSlotSelection embed outside misc-embeds div to fix e2e test
The e2e test was failing because the misc-embeds div content was
intercepting pointer events on mobile viewport. This follows the same
pattern used for skeletonDemo - the embed is now outside misc-embeds
and the div is hidden when testing this namespace.
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: prevent pointer event interception in twoStepSlotSelection embed
Hide heading and note elements and set pointer-events: none on container
elements while keeping pointer-events: auto on the iframe container.
This prevents the container from intercepting clicks on the iframe
during mobile viewport e2e tests.
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: hide all non-essential content for twoStepSlotSelection e2e test
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: disable pointer-events on body for twoStepSlotSelection e2e test
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: remove pointer-events: auto on container to let clicks pass through to iframe
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: explicitly set pointer-events: none on container and inline-embed-container
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: also set pointer-events: none on html element to prevent interception
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: make .place div fill viewport for twoStepSlotSelection e2e test
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: failing embed tests
* fixup
* fixup fixup
* fix: failing tests
* fix: update checks for verifying prefilled date
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
* refactor: remove redundant filtering and return filtered users from service
* Simplify user retrieval by returning users directly
* Fix formatting issue in users.service.ts
* Filter out null users in getDynamicEventType
---------
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
* fix: make linting required for CI
- Remove continue-on-error from lint workflow so CI fails on lint errors
- Fix 2 lint errors: avoid importing from @trpc/server in lib package
- Add trpcErrorUtils.ts to handle TRPC errors without circular dependencies
- Update lint-staged to show warnings but not block commits
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
* fix: add message field validation to isTRPCErrorLike type guard
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add Cloudflare URL Scanner integration for malicious URL detection
- Add MALICIOUS_URL_IN_WORKFLOW to LockReason enum
- Add URL_SCANNING_ENABLED constant for feature flag
- Create urlScanner.ts utility for Cloudflare Radar URL Scanner API
- Create scanWorkflowUrls task for async URL scanning with polling
- Integrate URL scanning into scanWorkflowBody task
- Add URL scanning for event type redirect URLs
- Lock user accounts when malicious URLs are detected
- Fix pre-existing lint issues (parseInt radix, optional chaining)
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address biome lint warnings and TypeScript iterator errors
- Wrap iterators with Array.from() to fix TS2802 errors
- Add biome-ignore comments for process.env usage
- Extract helper functions to reduce function length
- Move exports to end of file per useExportsLast rule
- Remove problematic imports that cause TypeScript errors
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address cubic-dev-ai review comments for URL scanning
- Fix P0: Re-fetch workflow steps before scheduling notifications to use actual verifiedAt values from database instead of overriding with new Date()
- Fix P1: Mark workflow step as verified in submitWorkflowStepForUrlScanning when URL scanning is disabled or no URLs found
- Fix P1: Add whitelistWorkflows parameter to submitUrlForUrlScanning for consistency
- Fix P2: Preserve URL context in error results in urlScanner.ts scanUrls function
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: add select clause to Prisma query for workflow steps
Address cubic-dev-ai P2 comment: Use select to fetch only the required
fields (id, action, sendTo, emailSubject, reminderBody, template, sender,
verifiedAt) instead of fetching all columns from workflowStep table.
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: add select clause to Prisma query in scanWorkflowBody.ts
Address cubic-dev-ai P2 review comment: Use select to fetch only the
required fields (id, action, sendTo, emailSubject, reminderBody,
template, sender, verifiedAt) instead of fetching all columns.
Co-Authored-By: peer@cal.com <peer@cal.com>
* test: add unit tests for URL scanning functionality
- Add tests for urlScanner.ts (extractUrlsFromHtml, isUrlScanningEnabled)
- Add tests for scanWorkflowUrls.ts (happy/unhappy paths for URL scanning task)
- Add tests for scanWorkflowBody.ts (happy/unhappy paths for workflow body scanning)
Tests cover:
- URL extraction from HTML content
- URL normalization and deduplication
- Handling of malicious URLs and user locking
- Fail-open behavior for API errors
- Whitelisted user handling
- Iffy spam detection integration
Co-Authored-By: peer@cal.com <peer@cal.com>
* test: remove incomplete test that provides no value
Removed the 'should mark all steps as verified when neither Iffy nor URL scanning is enabled' test as it used vi.doMock() which doesn't work after module import, had no assertions, and gave false confidence in test coverage.
Co-Authored-By: peer@cal.com <peer@cal.com>
* refactor: use Cloudflare bulk scanning endpoint to reduce API quota usage
- Added submitUrlsForBulkScanning function that uses /urlscanner/v2/bulk endpoint
- Updated scanUrls to use bulk submission instead of individual URL submissions
- Bulk endpoint accepts up to 100 URLs per request, batching is handled automatically
- Reduces API quota usage as suggested by keithwillcode
Co-Authored-By: peer@cal.com <peer@cal.com>
* Update packages/features/tasker/tasks/scanWorkflowUrls.ts
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* fix: address cubic-dev-ai review comments
- P1: Sanitize URLs before logging to prevent exposing sensitive query parameters
- P2: Extract handleUrlScanningForStep helper function to reduce code duplication
- P2: Use vi.stubGlobal for fetch mock in tests for proper cleanup
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address volnei review comments on PR #26387
- Move vi.unstubAllGlobals() to afterEach hook in iffyScanBody tests
- Restore updateMany optimization when URL scanning is disabled
Co-Authored-By: peer@cal.com <peer@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* feat: add OAuth client developer settings page with approval workflow
- Add new developer OAuth page at /settings/developer/oAuth for users to submit OAuth client requests
- Transform admin OAuth page into management dashboard for reviewing/approving submissions
- Add OAuthClientApprovalStatus enum (PENDING, APPROVED, REJECTED) to track submission status
- Add userId and createdAt fields to OAuthClient model for tracking submissions
- Create email notifications for admin (new submission) and user (approval)
- Add sidebar navigation link in developer section below API keys
- Add comprehensive translations for new UI strings
- Create OAuthClientRepository for data access following repository pattern
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: re-export generateSecret for backward compatibility
Co-Authored-By: peer@cal.com <peer@cal.com>
* feat: make logo mandatory and list items clickable for OAuth clients
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: add missing translation keys and remove client secret from details dialog
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address cubic AI reviewer comments
- Remove duplicate 'there' JSON key in common.json
- Add select clause to findByUserId to avoid exposing clientSecret
- Add @@index([userId]) to OAuthClient model for query performance
- Update migration to include the index
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address PR review comments - fix indentation and use useCopy hook
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: change react-dom/server import to fix Turbopack compatibility
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* Revert "fix: change react-dom/server import to fix Turbopack compatibility"
This reverts commit c3e0b709c2d88fd221143cb4ce9cd25bb8c94277.
* fix: use email service pattern for OAuth client notifications
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add try-catch around email sending to handle Turbopack react-dom/server issue
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* Revert "fix: add try-catch around email sending to handle Turbopack react-dom/server issue"
This reverts commit fc9d47cd773505ebc5ee2696718aad4a8a98be77.
* fix: improve OAuth client UI with skeleton loaders and smaller dialog styling
- Replace 'Loading...' text with proper skeleton loaders in both developer and admin OAuth client views
- Make client_id and copy button smaller in dialogs using size='sm' and text-sm styling
- Add 'client_id' translation key to common.json for proper i18n
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: improve skeleton loader to match actual OAuth client list structure
- Remove divide-y from container and use conditional border-b on rows
- Match the exact structure from oauth-clients-view.tsx L126-160
- Use proper spacing for text elements (mt-1 instead of space-y-2)
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix skeleton
* rename the selected oauth client dialog
* fix: address PR feedback - admin auth, dropdown styling, sidebar label
- Add defense-in-depth admin authorization check in updateClientStatus handler
- Fix broken dropdown menu by using DropdownItem with StartIcon prop
- Fix sidebar menu label from 'oAuth' to 'oauth_clients' to match developer view
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* update common.json
* feat: show client secret in approval email for confidential OAuth clients
- Add regenerateSecret method to OAuthClientRepository
- Regenerate secret when admin approves a PENDING confidential client
- Include client secret in approval notification email
- Add one-time warning message about storing the secret securely
- Only regenerate on first approval (not re-approvals)
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: add Website URL field, fix logo styling, show client secret after approval
- Add Website URL field to OAuth client forms (admin and developer views)
- Fix Upload Logo section styling by wrapping in Label div with proper gap
- Display client secret in dialog after admin approves a confidential OAuth client
- Add websiteUrl field to Prisma schema with migration
- Update tRPC handlers and repository to support websiteUrl
- Add translation keys for new UI elements
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: move clientSecret variable declaration outside if block for proper scoping
Co-Authored-By: peer@cal.com <peer@cal.com>
* refactor: dont expose client secret in emails
* refactor: dont regenerate secret upon status change
* refactor: reuse existing hash function
* refactor: rename admin/oAuth to admin/oauth page
* refactor: deduplicate oauth repositories
* refactor: remove withGlobalPrisma from oauth repository
* refactor: developer oauth page
* refactor: oauth status by default accepted
* refactor: request oauth status when creating
* refactor ux
* fix: address Cubic AI code review feedback
- Add purpose field to plain text email body for accessibility
- Convert NewOAuthClientButton to inline JSX to avoid React anti-pattern
- Trigger re-approval when redirectUri changes for security
- Add e.preventDefault() for Space key to prevent page scroll
- Change default approvalStatus to PENDING for defense-in-depth
- Use oauth_clients translation key for consistency
- Add meaningful alt text to Avatar for accessibility
- Remove onClick from DialogClose to prevent double-run close effects
- Return NOT_FOUND for non-owner delete to prevent resource enumeration
Co-Authored-By: unknown <>
* common.json file
* refactor: delete all prisma migrations
* refactor: have just 1 prisma migration
* revert: some devin changes
* fix: typecheck
* test: owner OAuth crud
* test: admin OAuth approval / rejection
* fix: address Cubic AI review feedback (confidence 9/10 issues)
- schema.prisma: Remove @default("") from purpose field to make it required
- schema.prisma: Use UTC-aware timezone expression for createdAt default
- OAuthClientFormFields.tsx: Localize redirect URI placeholder using t()
- common.json: Add redirect_uri_placeholder translation key
Co-Authored-By: unknown <>
* cubic changes
* refactor: dont log sensitive info and rethrow error
* cubic feedback
* refactor: make oauth client purpose optional
* refactor: admin/oauth not allowed if not logged in
* refactor: admin view skeleton
* refactor: rename state
* refactor: get rid of redundant mapping
* refactor: remove redundant handler
* refactor: remove redundant handler
* refactor: re-usable new oauth client button
* refactor: dialogs
* refactor: modals
* refactor: handler names, dialog, skeleton
* fix: purpose being null
* refactor: rename handler and delete old oauth admin page
* fix: purpose in submission
* refactor: handler names
* refactor: rename
* refactor: update handler
* refactor: rename approvalStatus -> status
* refactor: simplify modal
* refactor: name
* dont require repproval if redirectUri changes
* fix: remove integration sync index creation
* refactor: require re-approval if redirectUri updated
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: remove duplicate common.json keys
* refactor: replace team@cal.com with SUPPORT_MAIL_ADDRESS
* refactor: generate client secret on handler level
* fix: authorization code only available to approved clients
* refactor: cubic review dont display exclamation
* refactor: cubic review website_url in common json
* fix: dont default in ui to approved status
* refactor: optiona logo in schema create handler
* fix: tests
* fix: tests
* fix: /authorize redirect if client not approved or show error
* test: authorize page with invalid client id
* refactor: dont allow refreshing tokens unless approved client
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* chore: warn that pending client is not usable
* fix: approve and reject buttons
* fix: /authorize show error if client not approved
* refactor: info message about editing oauth client and status
* change info alert to warning
* try to fix ci test
* debug: failing e2e test
* fix: improve session propagation in oauth-client-admin E2E test
- Add navigateToAdminOAuthPage helper that waits for listClients API call
- If the API call doesn't arrive (session issue), reload page to force session refresh
- This fixes the CI flakiness where admin page wasn't loading due to session not having ADMIN role
Co-Authored-By: lauris@cal.com <lauris@cal.com>
* fix: register waitForResponse before navigating in E2E test
- Register the listClients waitForResponse promise BEFORE page.goto()
- This ensures the response isn't missed during page load
- Also register the promise before reload in the catch block
Co-Authored-By: lauris@cal.com <lauris@cal.com>
* fix: rename oAuth folder to oauth for case-sensitive filesystems
The admin OAuth page route was at /settings/admin/oAuth (capital A) but the
code references /settings/admin/oauth (lowercase). This caused 404 errors
on case-sensitive filesystems (Linux).
Also improved the E2E test navigation helper to retry with delays if the
admin page doesn't load immediately, handling session propagation timing.
Co-Authored-By: lauris@cal.com <lauris@cal.com>
* test style
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: eunjae@cal.com <hey@eunjae.dev>
Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
Co-authored-by: supalarry <laurisskraucis@gmail.com>
Co-authored-by: cubic-dev-ai[bot] <1082092+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: lauris@cal.com <lauris@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
These columns are marked as deprecated in the Prisma schema and will be
removed in a follow-up migration. This PR removes all code references to
prepare for the column removal.
Changes:
- Remove startTime/endTime from ProfileRepository userSelect and methods
- Remove startTime/endTime from UserRepository userSelect and methods
- Remove startTime/endTime from me/get.handler.ts API response
- Remove endTime from API v1 user validation schema
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: remove Object.freeze hack in getConnectedCalendars
The previous implementation used Object.freeze to prevent the destinationCalendar
object from being mutated when looping through multiple calendar credentials.
This was a workaround for a bug where the wrong calendar's primaryEmail and
integrationTitle would be set when multiple credentials existed.
This refactor properly fixes the issue by:
1. Only setting destinationCalendar once (when first found)
2. Using a flag to track when the destination calendar is found in the current credential
3. Only setting primaryEmail and integrationTitle for the credential that contains
the destination calendar
Fixes the hack mentioned in: https://github.com/calcom/cal.com/pull/7644
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* refactor: move destinationCalendar enrichment outside the loop
Per feedback, moved the destinationCalendar finding and enrichment
completely outside the Promise.all loop. After all connected calendars
are fetched, we search through the results to find and enrich the
destination calendar with primaryEmail and integrationTitle.
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* chore: ensure default calendars with trigger.dev apiv2
* test: add unit and e2e tests for CalendarsTasker integration
- Add unit tests for CalendarsTasker.dispatch when enableAsyncTasker is true
- Add e2e test to verify ensureDefaultCalendarsForUser is called when creating membership
- Mock CalendarsTasker and ConfigService in unit tests
- Test both async (Trigger.dev) and sync (Bull queue) paths
- Fix missing return types on helper functions in e2e tests
- Add *.spec.ts to biome test file exceptions for noExcessiveLinesPerFunction rule
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: filter out Google system calendars from calendar list
Google system calendars (holidays, birthdays) don't return proper
free/busy information, making them useless for availability checking.
This change filters them out from the listCalendars() method so users
won't see these calendars as selectable options.
Filtered calendar types:
- Holiday calendars (#holiday@group.v.calendar.google.com)
- Birthdays/contacts calendar (#contacts@group.v.calendar.google.com)
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
* test: add tests for Google system calendar filtering
Tests verify that listCalendars() correctly filters out:
- Holiday calendars (#holiday@group.v.calendar.google.com)
- Birthdays/contacts calendar (#contacts@group.v.calendar.google.com)
Test cases cover:
- Filtering holiday calendars
- Filtering birthdays calendar
- Mixed calendars (keeping regular, filtering system)
- All system calendars (returns empty array)
- Null/undefined calendar IDs
- Various international holiday calendar formats
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Refactor duplicate UI components (SettingsGroup, SettingRow, NavigationRow) into [SettingsUI.tsx]
- Centralize showNotAvailableAlert in utils/alerts.ts
- Replace in-app browser links with Feature not available alerts for iOS on:
- More tab items (Apps, Routing, Workflows, Insights, Support)
- Event Type Other tab (Apps, Workflows, Webhooks)
- Event Type Advanced tab (Private Links)
- Remove View public page from Profile Sheet on iOS
- Remove Preview actions from Event Type (List menu and Detail quick actions) on iOS
- Add Learn More links to Advanced Tab settings
* feat: add option to hide duration selector in booking page for multiple durations
- Add 'hideDurationSelectorInBookingPage' field to event type metadata schema
- Add checkbox under Default Duration select in event type settings
- Modify Duration component to hide selector when setting is enabled
- URL params can still set duration when selector is hidden
- Add i18n translation for the new checkbox label
- Add e2e tests for the new functionality
Co-Authored-By: ali@cal.com <ali@cal.com>
* fix: rename checkbox label to 'Hide duration selector'
Co-Authored-By: ali@cal.com <ali@cal.com>
* fix: replace text locator with data-testid in E2E test
Replace `text=Multiple duration` locator with `page.getByTestId("event-types").locator('a[title="Multiple duration"]')` to follow E2E test best practices.
Co-Authored-By: unknown <>
* fix: add data-testid to hide duration selector checkbox for E2E tests
Co-Authored-By: ali@cal.com <ali@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
* feat: remove Revert.dev dependency from Pipedrive integration
- Replace Revert API calls with direct Pipedrive OAuth2 and REST API
- Update OAuth flow to use Pipedrive's authorization endpoint
- Implement token exchange in callback handler
- Map Revert's unified API format to Pipedrive's native API structure
- Remove REVERT_* environment variables from configuration
- Update app config to reflect direct Pipedrive integration
- Follow patterns from other CRM integrations like HubSpot
Breaking change: Requires PIPEDRIVE_CLIENT_ID and PIPEDRIVE_CLIENT_SECRET
environment variables instead of REVERT_* variables
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* feat: implement proper token refresh logic for Pipedrive OAuth
- Add token refresh implementation following Pipedrive OAuth2 specification
- Use proper Basic Auth for token refresh requests
- Handle token refresh errors with appropriate logging
- Update access token and expiry date after successful refresh
- Add note about database credential update requirement
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* feat: add database credential updates for Pipedrive token refresh
- Import updateTokenObjectInDb utility for proper credential management
- Store credentialId in constructor for database updates
- Update token refresh logic to persist refreshed tokens to database
- Follow Cal.com patterns for OAuth credential management
- Ensure tokens are properly updated after successful refresh
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* refactor: use OAuthManager for Pipedrive token management
- Refactor CrmService.ts to use OAuthManager instead of manual token refresh
- Create getPipedriveAppKeys helper function for client credentials
- Update callback.ts to use the new helper function
- Add requestPipedrive helper method for all API calls
- Implement proper token refresh callbacks (isTokenObjectUnusable, isAccessTokenUnusable)
This addresses the review comments from hariom and cubic on PR #22492.
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* fix: validate token endpoint response before storing Pipedrive credentials
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: handle invalid timezones gracefully in getLuckyUser
Co-Authored-By: benny@cal.com <sldisek783@gmail.com>
* refactor: move timezone validation to getCalendarsEvents with offset conversion
- Move invalid timezone handling from getLuckyUser.ts to getCalendarsEvents.ts
- Add convertOffsetToEtcGmt() to convert offset formats (GMT-05:00, UTC+08:00) to valid IANA Etc/GMT timezones
- Preserves timezone precision for fairness calculations instead of falling back to UTC
- Add unit tests for timezone conversion scenarios
* refactor: extract timezone conversion to dedicated file
- Create timezone-conversion.ts with concise convertOffsetToIanaTimezone and normalizeTimezone functions
- Update getCalendarsEvents.ts to import from the new file
- Follow kebab-case naming convention for utility files
* test: add unit tests for timezone conversion proving Intl.DateTimeFormat behavior
- Add tests proving Intl.DateTimeFormat throws RangeError for offset formats (GMT-05:00, UTC+08:00)
- Add tests for convertOffsetToIanaTimezone function
- Add tests for normalizeTimezone function
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Early return if date range is empty
* test: add tests for empty workingHours early return optimization
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
PR #27012 introduced logic to disable apps without valid keys during seeding.
This caused the alby payment app tests to fail because the alby app was
disabled in the App table when its environment keys weren't configured.
This fix adds an ensureAppEnabled helper function that enables the app
in the App table before running the tests, treating it as a mock/test
setup step.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Integrates booking audit logging for the edit location functionality, following the pattern established in PR #26046 (booking creation/rescheduling audit).
This PR adds audit logging when a booking's location is changed through:
1. **Web app** (tRPC handler): `packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts`
2. **API v2**: `apps/api/v2/src/ee/bookings/2024-08-13/services/booking-location.service.ts`
### Changes:
- Added `actionSource` as a **required** parameter to `editLocationHandler` (no fallback)
- Added optional `userUuid` parameter (defaults to logged-in user's uuid)
- Added `ValidActionSource` type that excludes "UNKNOWN" for client-facing APIs
- Captures old location before update for audit data
- Calls `BookingEventHandlerService.onLocationChanged()` after successful location update
- Web app uses `actionSource: "WEBAPP"`, API v2 uses `actionSource: "API_V2"`
- Updated router to explicitly pass `actionSource: "WEBAPP"`
- Updated test to pass `actionSource: "WEBAPP"`
- **API v2**: Uses NestJS dependency injection pattern with `BookingEventHandlerService` injected via constructor
### Updates since last revision:
- **Created `BookingEventHandlerModule`** (`apps/api/v2/src/lib/modules/booking-event-handler.module.ts`) to encapsulate `BookingEventHandlerService` and its dependencies (Logger, TaskerService, HashedLinkService, BookingAuditProducerService)
- Updated both bookings modules (2024-04-15 and 2024-08-13) to import `BookingEventHandlerModule` instead of listing individual providers
- This reduces code duplication and makes dependency management cleaner
## 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. N/A - using existing audit infrastructure that is already tested.
## How should this be tested?
1. Update a booking's location through the web app
2. Update a booking's location through API v2
3. Verify audit logs are created with:
- Correct `bookingUid`
- Correct `actor` (user who made the change)
- Correct `source` ("WEBAPP" or "API_V2")
- Correct `auditData.location.old` and `auditData.location.new` values
## 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
## Human Review Checklist
- [ ] Verify all callers of `editLocationHandler` pass `actionSource` (router updated, test updated)
- [ ] Verify `organizationId` derivation is correct in both handlers (tRPC uses `booking.user?.profiles?.[0]?.organizationId`, API v2 uses `existingBookingHost.organizationId`)
- [ ] Confirm audit call placement after location update is intentional (audit failures would fail the operation even though location was already updated)
- [ ] Note: API v2 has its own implementation and does NOT reuse `editLocationHandler` - this is correct
- [ ] Verify `BookingEventHandlerModule` properly exports `BookingEventHandlerService` and is imported in both bookings modules
- [ ] Verify the `updateBookingLocationInDb` return value (`{ updatedLocation }`) is destructured and used correctly for audit data
- [ ] Verify API v2 uses `bookingLocation` for audit `new` value, while tRPC uses `updatedLocation` from DB update
---
Link to Devin run: https://app.devin.ai/sessions/fd1d439779674050a26ea3fa7d799943
Requested by: @hariombalhara
## What does this PR do?
Adds auto-accept logic to the `/v2/teams/{teamId}/memberships` endpoint, similar to what exists in the `/v2/organizations/{orgId}/teams/{teamId}/memberships` endpoint.
When a user is added to a sub-team of an organization, the system now checks if the user's email domain matches the organization's `orgAutoAcceptEmail` setting. If it matches and the organization is verified, the membership is automatically accepted (overriding any `accepted: false` in the request).
### Changes:
- Modified `TeamsMembershipsService.createTeamMembership()` to check if the team has a parent organization and apply auto-accept logic using the existing `OrganizationMembershipService.shouldAutoAccept()` method
- Exported `OrganizationMembershipService` from `OrganizationsModule` for dependency injection
- Added `TeamsModule` and `UsersModule` imports to `TeamsMembershipsModule`
- Added required dependencies (`OrganizationMembershipService`, `OAuthClientRepository`, etc.) to `TeamsModule` and `TeamsSchedulesModule` since they provide `TeamsMembershipsService` directly
- Added comprehensive E2E tests for auto-accept scenarios
- Added `createOrgSettings` and `deleteOrgSettings` helper methods to test fixtures
## 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?
The E2E tests cover the following scenarios:
1. **Auto-accept when email matches** - User with `@acme.com` email is auto-accepted when org has `orgAutoAcceptEmail: "acme.com"`
2. **Case-insensitive matching** - User with `@ACME.COM` email matches `orgAutoAcceptEmail: "acme.com"`
3. **Override accepted:false** - Even if `accepted: false` is passed, it's overridden to `true` when email matches
4. **No auto-accept for non-matching emails** - User with `@external.com` email is NOT auto-accepted
5. **EventTypes assignment** - Verifies user is added to event types with `assignAllTeamMembers: true`
To run the tests:
```bash
TZ=UTC yarn test:e2e --testPathPattern="teams-memberships.controller.e2e-spec"
```
## Human Review Checklist
- [ ] Verify the auto-accept logic matches the existing implementation in `organizations-teams-memberships.controller.ts`
- [ ] Confirm all modules that provide `TeamsMembershipsService` directly (`TeamsModule`, `TeamsSchedulesModule`, `OrganizationsModule`) have the required dependencies
- [ ] Verify `updateNewTeamMemberEventTypes` is called when auto-accept triggers (controller checks `membership.accepted` after service returns)
- [ ] Consider if organization membership creation is needed when a user is auto-accepted into a sub-team but doesn't have org membership yet (not implemented in this PR)
## Checklist
- [x] I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- [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
---
Link to Devin run: https://app.devin.ai/sessions/578b8904a5a94385b59031f9616379cc
Requested by: @hariombalhara
* fix: use WEBAPP_URL for booking URLs when domains differ
For EU deployments where WEBAPP_URL (app.cal.eu) differs from
WEBSITE_URL (cal.com), use WEBAPP_URL for non-org booking URLs.
This fixes incorrect bookingUrl in API responses for EU instance.
* Created new shared utility getTldPlus1 and updated code to use shared function instead of inline copy
* use same comment
* feat: integrate DateTimePickerAndroid for date/time selection
- Added @react-native-community/datetimepicker dependency for native date/time picker functionality.
- Replaced modal-based date/time picker implementation with DateTimePickerAndroid for improved user experience.
- Updated RescheduleScreen to utilize the new date/time picker methods, enhancing the selection process and ensuring better styling consistency.
* feat: add LimitsTabDatePicker component for date selection
- Introduced a new LimitsTabDatePicker component utilizing DateTimePickerAndroid for improved date selection on Android.
- Implemented date parsing and formatting for user-friendly display.
- Enhanced user interaction with a pressable element to open the date picker.
* feat: add EditAvailabilityOverrideScreen for managing schedule overrides
- Introduced EditAvailabilityOverrideScreen component to allow users to create and edit availability overrides.
- Implemented date and time selection using DateTimePickerAndroid for improved user experience.
- Added functionality to handle existing overrides, including editing and deleting options.
- Enhanced user interaction with clear alerts for success and error states during save operations.
* fixed lint warnings, info
* address cubics comments
---------
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
* chore: update teams schedules module
* chore: update schedules and team events repository
* chore: input for teams schedules
* feat: add logic to filter schedules based on event type id
* fix: bad import
* chore: add input for get user schedules
* feat: add logic in user schedule to filter schedules based on event type id
* chore: update e2e tests
* fix: add EventTypesModule_2024_06_14 import to SchedulesModule_2024_06_11
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: import path
* chore: implement cubic feedback
* fix: replace .finally() with try/finally in E2E tests
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* chore: implement PR feedback
* fix: correct schedule precedence order for team hosts
Fix the effective schedule resolution to follow the intended precedence:
host schedule > user default schedule > event type schedule
This addresses Cubic AI review feedback with confidence 9/10:
- schedules.service.ts: Fix precedence in getUserSchedulesForEventType
- teams-schedules.service.ts: Fix precedence in getTeamSchedulesForEventType
Co-Authored-By: unknown <>
* fixup
---------
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Converts a `console.log` statement to use the proper `@calcom/lib/logger` with debug level in the raqbUtils.server.ts file. This ensures the log message only appears when debug logging is enabled, reducing noise in production logs.
## 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. N/A - logging change only.
## How should this be tested?
This is a simple logging change. No specific testing required beyond CI passing.
The log message "A group option found. Using all its sub-options instead" will now only appear when the logger level is set to debug (level 2 or lower via `NEXT_PUBLIC_LOGGER_LEVEL`).
## Checklist
- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings
<!-- Link to Devin run: https://app.devin.ai/sessions/45d95cd7127541ffac96764f251ae1c9 -->
<!-- Requested by: @hariombalhara -->
- Add 40 minutes to the multipleDurationOptions array in EventSetupTab
- Add comprehensive tests for 40-minute slot generation including:
- Full day slot generation
- Correct time intervals
- Default duration handling
- Same day booking with time constraints
- Multiple date ranges
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
* feat: add PlatformOrganizationBillingTasker with sync and trigger.dev versions
- Create PlatformOrganizationBillingTasker extending Tasker base class
- Add sync tasker (PlatformOrganizationBillingSyncTasker) for synchronous execution
- Add trigger.dev tasker (PlatformOrganizationBillingTriggerTasker) for async execution
- Create trigger.dev task for incrementing subscription usage
- Add PlatformOrganizationBillingTaskService with business logic
- Add PlatformOrganizationBillingRepository for data access
- Add createSubscriptionUsageRecord method to StripeBillingService
- Follow BookingEmailAndSmsTasker pattern for consistency
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* refactor: move repository methods per PR feedback
- Move findPlatformOrgByUserId to OrganizationRepository
- Create new PlatformBillingRepository for billing queries
- Remove PlatformOrganizationBillingRepository (consolidated)
- Update task service and trigger.dev task to use new repositories
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* feat: add DI using @evyweb/ioctopus for platform billing tasker
- Create di/tasker/ directory following BookingEmailAndSmsTasker pattern
- Add tokens.ts with DI tokens for all billing tasker classes
- Add module files for PlatformBillingRepository, TaskService, SyncTasker, TriggerTasker, Tasker
- Add container files with getter functions
- Update trigger.dev task to use DI container instead of manual instantiation
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* refactor: add select statement to PlatformBillingRepository.findByTeamId
Only select subscriptionId field since that's the only field used by the task service
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* feat: add NestJS DI modules for platform billing tasker in API v2
- Add platform billing tasker exports to platform-libraries/organizations.ts
- Export IBillingProviderService type from platform-libraries
- Create StripeBillingProviderService wrapper implementing IBillingProviderService
- Create PrismaPlatformBillingRepository extending PlatformBillingRepository
- Create NestJS service wrappers for all platform billing tasker classes
- Create PlatformBillingTaskerModule with all providers and exports
- Update PlatformOrganizationBillingTaskService to use Pick<IBillingProviderService>
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* feat: handle cancel and reschedule usage
* fix: restore IsUserInBillingOrg to billing module providers
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* chore: add idempotency key
* fix: just log error]
* fix: logger and typo
* fix: address Cubic AI review feedback (high confidence issues)
- Fix grammar error: 'Delayed task are' -> 'Delayed tasks are' in PlatformOrganizationBillingSyncTasker.ts (3 occurrences)
- Re-throw error after logging in increment-usage.ts to enable trigger.dev retry mechanism
Co-Authored-By: unknown <>
* fix: remove duplicate code and use DI instead
* fix: remove orThrow on find first in findPlatformOrgByUserId
* refactor: prevent usage increment task from re-throwing errors
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Fixes a bug where the UI shows team members who match segment criteria even when they don't have host entries in the database. When `assignAllTeamMembers` is `true` and segment filtering is enabled, members would appear in the Assignment tab but wouldn't actually be assigned during booking because they lack host entries.
**The Problem:**
- The filtering logic in `EditWeightsForAllTeamMembers` short-circuited when `assignAllTeamMembers` was true, showing all segment-matching members regardless of whether they had host entries
- The `handleSave` function only updates hosts that already exist in the `value` array, filtering out members without host entries
- This created a misleading UI where members appeared but wouldn't be assigned
**The Fix:**
- Removed the `assignAllTeamMembers` prop from `EditWeightsForAllTeamMembers` component entirely since the filtering should always check for existing host entries
- Updated the filter in `EditWeightsForAllTeamMembers.tsx` to always check for existing host entries in the `value` array
- Added `filterMemberIds` prop to `Segment` component to filter matching team members to only show those who are hosts of the event-type
- `AddMembersWithSwitch` now passes the list of non-fixed host user IDs to the Segment component via `filterMemberIds`
## 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. Create a team event type with round-robin scheduling
2. Enable "Assign all team members" toggle
3. Enable segment filtering with criteria that matches some team members
4. Verify that only members who have host entries (are actually assigned to the event type) appear in the "Edit team member weights" sheet
5. Members matching segment criteria but without host entries should NOT be displayed
## Checklist
- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings
---
### Human Review Checklist
- [ ] Verify the filtering logic correctly shows only members with host entries in both `EditWeightsForAllTeamMembers` and `Segment` components
- [ ] Confirm this aligns with the actual booking behavior (members without host entries won't be assigned)
- [ ] Check that `filterMemberIds` prop is correctly passed through `AddMembersWithSwitch` → `MembersSegmentWithToggle` → `Segment` → `MatchingTeamMembers`
- [ ] Verify the filter `value.filter((host) => !host.isFixed).map((host) => host.userId)` correctly extracts non-fixed host IDs
---
Link to Devin run: https://app.devin.ai/sessions/3333b41226d0452e98ef7ac358511f5b
Requested by: @hariombalhara
* ci(companion): add separate typecheck workflow to catch type errors
This adds a new companion-typecheck.yml workflow that runs TypeScript type
checking for the companion app. This would have caught the missing useEffect
import issue in PR #26931.
Changes:
- Add new companion-typecheck.yml workflow file
- Update pr.yml to call the new workflow when companion files change
- Add typecheck-companion to the required jobs list
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* add lint checks
* test
* remove
* update typecheck
* address review
* chore:- hide apps with missing required keys from app store
* update
* Delete packages/app-store/_utils/hasRequiredAppKeys.test.ts
* Update validateAppKeys.ts
* Update validateAppKeys.ts
* Update validateAppKeys.test.ts
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: hide navigation when ?standalone=true URL parameter is present
Co-Authored-By: peer@cal.com <peer@cal.com>
* feat: standalone page config to use in companion
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: peer@cal.com <peer@cal.com>
* docs: add feature opt-in banner system plan
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* docs: iterate on feature opt-in banner plan based on feedback
- Use config.ts for feature metadata instead of TRPC response
- Consolidate localStorage dismissal into single key to avoid bloat
- Replace separate success dialog with in-dialog success state for smoother UX
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: implement feature opt-in banner system
- Add checkFeatureOptInEligibility TRPC procedure to check if user can opt-in
- Create useFeatureOptInBanner hook with localStorage dismissal state
- Create FeatureOptInBanner floating component for bottom-right display
- Create FeatureOptInConfirmDialog with role-based options and success state
- Integrate banner into bookings-view.tsx as example usage
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: add i18n translation keys for feature opt-in banner
* refactor: create FeatureOptInBannerWrapper for simpler consumer integration
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: use @calcom/lib/webstorage and add Zod schema for localStorage
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: address PR review comments - use PBAC, move logic to service, improve typing
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
# Conflicts:
# packages/features/feature-opt-in/services/FeatureOptInService.ts
* test: add comprehensive tests for checkFeatureOptInEligibility method
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: correct import and Checkbox type errors
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* update message
* invalidate after dialog dismiss
* feat: simulate user opt-in to determine banner eligibility
When a feature has a strict policy and org/team hasn't explicitly
enabled it, user opt-in alone won't enable the feature. This change
simulates what would happen if the user opts in and only shows the
banner if opting in would actually enable the feature.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add early return for missing featureConfig and clarify simulation comment
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix repository usage
* refactor: simplify FeatureOptInConfirmDialog UI and remove unused translation
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: replace radio buttons with multi-select dropdown in FeatureOptInConfirmDialog
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* resize banner
* refactor: use AnimatedPopover pattern for team selection and rename titleI18nKey to nameI18nKey
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: change 'Just for me' to 'For me', fix width clipping, remove divider
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* update style
* feat: make 'Just for me' mutually exclusive with teams/org and store opt-ins in localStorage
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: remove barrel imports and update to direct imports
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add modal prop to AnimatedPopover to fix scroll lock conflict in dialogs
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: wrap Popover.Content with Portal to prevent layout interference in dialogs
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: use flexbox gap instead of space-y to prevent popover wrapper from affecting layout
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* Revert "fix: use flexbox gap instead of space-y to prevent popover wrapper from affecting layout"
This reverts commit 8385adafa890c2f2674aa3ae3b10ca6e0c55ba5c.
* Revert "fix: wrap Popover.Content with Portal to prevent layout interference in dialogs"
This reverts commit e84301a35a99b3559d47c2d37316af290834ca2d.
* Revert "fix: add modal prop to AnimatedPopover to fix scroll lock conflict in dialogs"
This reverts commit b015af2f1cf31ef7087c02cb8535d96cc4a34125.
* feat: replace Radix Dialog and AnimatedPopover with coss-ui components
This migration uses @coss/ui Dialog and Popover components which are built on
Base UI instead of Radix. Base UI handles scroll locking and positioning
differently, which should fix the gap issue when opening the popover inside
the dialog.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: replace remaining @calcom/ui components with coss-ui
- Replace Divider with Separator from @coss/ui
- Replace Label with Label from @coss/ui
- Replace CheckboxField with Checkbox + Label from @coss/ui
- Replace Icon with direct lucide-react icons (UserIcon, BuildingIcon, UsersIcon, CheckIcon)
- Replace showToast with toastManager.add() from @coss/ui
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: replace Popover with Menu component from coss-ui
- Replace Popover + FilterCheckboxField with Menu + MenuCheckboxItem
- MenuCheckboxItem provides built-in checkbox indicator and styling
- MenuSeparator provides proper menu separators
- Cleaner API with onCheckedChange callback
- Better keyboard navigation support
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: align icon and text on same line in MenuCheckboxItem, widen dialog
- Wrap icon and text in flex container with items-center gap-2
- Change dialog width from sm:max-w-md to sm:max-w-lg to prevent text wrapping
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* use dimmed bg for coss dialog title
* refactor: change nameI18nKey/descriptionI18nKey to nested i18n object
- Change OptInFeatureConfig interface to use i18n: { name, description }
- Update all component usages to use featureConfig.i18n.name and featureConfig.i18n.description
- Update test mocks to use new structure
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: add i18n.title to OptInFeatureConfig type definition
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* update texts
* use title instead of name
* update banner style
* refactor: split FeatureOptInConfirmDialog into separate success and confirmation dialogs
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: don't record dismissed info in local storage after successful opt-in
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add checkFeatureOptInEligibility to IFeatureOptInService interface
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* update common.json
* refactor: move tRPC usage from features package to apps/web/modules
Addresses Cubic AI review feedback (confidence 9/10):
- Remove @calcom/trpc import from FeatureOptInConfirmDialog.tsx
- Add FeatureOptInMutations type for passing mutation functions via props
- Move tRPC hooks to useFeatureOptInBanner hook in apps/web/modules
- Pass mutations through FeatureOptInBannerWrapper to dialog component
This maintains the architectural constraint that packages/features
should not import from @calcom/trpc to prevent circular dependencies.
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Change 'Booking not found' to throw NOT_FOUND (404) instead of plain Error
- Preserve ErrorWithCode for ChargeCardFailure to properly map to BAD_REQUEST (400)
- Add specific error handling for 'User is not a member of the team' -> FORBIDDEN (403)
- Add specific error handling for 'User ID is required' and 'No payment credential found' -> BAD_REQUEST (400)
- Keep INTERNAL_SERVER_ERROR (500) only for actual server errors like 'Payment app not implemented'
- Update test to expect ErrorWithCode to be re-thrown instead of wrapped in translated Error
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: update transaction timeout for large managed event-types
* test: add findMany mock for batch update optimization in handleChildrenEventTypes tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: reduce batch size to 50 and use skipDuplicates for workflow linkage
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* test: add comprehensive tests for batch execution and retry behavior
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: use logger instead of console.log and fix type error
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* test: update test file to mock logger instead of console.log
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: type issues
* fixup! fix: type issues
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: keith@cal.com <keithwillcode@gmail.com>
* feat: redesign team creation flow to match onboarding-v3 design
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* feat: skip invite options and go directly to email invite step
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* feat: invalidate teams query on submit to refresh teams list
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use server action to invalidate server-side teams cache
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: conditionally render avatar in browser view to remove extra padding
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix browser view
* test: update team creation E2E tests to use new onboarding-v3 flow
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* test: update auth-index.e2e.ts to use new team creation flow
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* test: update team-management.e2e.ts to use new team creation flow
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: add error handling for createTeam and improve CSV parsing for quoted fields
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* ci(companion): add separate typecheck workflow to catch type errors
This adds a new companion-typecheck.yml workflow that runs TypeScript type
checking for the companion app. This would have caught the missing useEffect
import issue in PR #26931.
Changes:
- Add new companion-typecheck.yml workflow file
- Update pr.yml to call the new workflow when companion files change
- Add typecheck-companion to the required jobs list
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* add lint checks
* test
* remove
* update typecheck
* address review
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor(teams): improve membership validation for org admins
- Add organization scope validation to removeMember handler
- Ensure team operations are scoped to users organization context
- Update related tests
* test(teams): align removeMember tests with updated interface
- Add organizationId to test contexts
- Add team.findMany mock for org validation
- Add test cases for org scope validation
* refactor(teams): use TeamRepository for org validation in LegacyRemoveMemberService
- Add findByIdsAndOrgId method to TeamRepository
- Inject TeamRepository into LegacyRemoveMemberService via constructor
- Update RemoveMemberServiceFactory to instantiate and inject TeamRepository
- Update tests to mock TeamRepository instead of direct prisma calls
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: keith@cal.com <keithwillcode@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add CalendarsTasker with sync and trigger.dev versions
This PR implements a CalendarsTasker following the same pattern as
PlatformOrganizationBillingTasker to replace the logic in
apps/api/v2/src/ee/calendars/processors/calendars.processor.ts
New files created:
- CalendarsTasker main orchestrator extending Tasker base class
- CalendarsSyncTasker for sync execution
- CalendarsTriggerTasker for async execution via trigger.dev
- CalendarsTaskService with business logic for ensuring default calendars
- trigger.dev task with queue config and retry settings
- DI modules using @evyweb/ioctopus
- NestJS DI modules for API v2
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: import and deasync
* style: format trigger.config.ts dirs array
Co-Authored-By: unknown <>
* refactor: move prisma query to UserRepository and set onboarding to true
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* refactor: remove credential.key from UserRepository method
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Part 1 of monthly proration feature.
Adds seat change tracking infrastructure with operationId for idempotency.
**Dependency chain:**
- This PR (seat tracking)
- PR #27002 depends on this
* fix(ui): update coss ui components
* fix(sidebar): remove redundant overflow-auto from SidebarContent
ScrollArea already provides the scroll container, so keeping overflow-auto
on the child creates a nested scroll area and prevents scrollFade from
reflecting actual overflow.
Addresses Cubic AI review feedback with confidence 9/10.
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: replace loggedInUsersTz with timeZone in busy-times API
- Add new timeZone parameter to CalendarBusyTimesInput
- Mark loggedInUsersTz as deprecated
- Update getBusyTimes endpoint to prioritize timeZone parameter
- Maintain backward compatibility with loggedInUsersTz
- Add validation to ensure at least one timezone parameter is provided
- Update API documentation with new parameter example
Fixes#25423
* fix: improve timezone validation in CalendarBusyTimesInput
- Use custom ValidatorConstraint instead of problematic ValidateIf
- Properly validate that at least one timezone parameter is provided
- Improve code quality and clarity
* fix: update DTOs for getBusyTimes
* cleanup
* fix: abstract normalize timezone logic into platform types util function
* chore: update e2e tests
* fixup
* fixup
---------
Co-authored-by: Ryukemeister <sahalrajiv6900@gmail.com>
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
* fix init
* remove comment
* fix to v2
* type fix
* edge case
* test fix to suit the date storage method
* fix for atoms
* backward compatibility
* fix test mock
* test fix?
* testing a theory
* address cubic
* fix: pass seatUid when rescheduling seated booking from booking limit error
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* test: add test case for seatUid in booking limit reschedule error for seated events
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* chore: ensure default selected calendars handleEnsureDefaultCalendars
* fix: bypass cache when ensureDefaultSelectedCalendars is true
When ensureDefaultSelectedCalendars is true, the cache should be bypassed
to ensure the defaults logic actually runs. Previously, cached data would
be returned before the ensure-defaults logic could execute.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* perf: timezone select component
* fix: type error
* fix: type error
* fix: use object assign
* fix: use data. length
* fix: use props.data reference instead of length for memoization
The useMemo dependency on props.data?.length could return stale timezone
options when the array contents change but the length stays the same.
Using the full props.data reference ensures updates propagate correctly.
Fix identified by Cubic AI (confidence 9/10)
Co-Authored-By: unknown <>
* fix: use data. length
* fix: use props.data reference instead of length for memoization
The useMemo dependency on props.data?.length could return stale timezone
options when the array contents change but the length stays the same.
Using the full props.data reference ensures updates propagate correctly.
Fix identified by Cubic AI (confidence 9/10)
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Test that params are properly passed to async tasker methods
- Test that params are passed in correct order
- Test fallback to sync tasker when async tasker fails
- Test params are passed correctly to sync tasker fallback
- Test error handling when both taskers fail
- Test logging of dispatch information with args
- Test behavior when async tasker is disabled (missing env vars)
- Test error details logging
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* init: team invite link endpoint
* chore: add e2e tests
* fix: use SUCCESS_STATUS and ERROR_STATUS constants in invite output DTO
Address Cubic AI review feedback by using proper enum typing with
SUCCESS_STATUS and ERROR_STATUS constants from @calcom/platform-constants
for consistency with other API v2 output DTOs.
Co-Authored-By: unknown <>
* fixup: add missing memberships module
* fixup: revert previous change, not needed
* chore: use createInvite from teams service
* chore: remove unused value
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: calEventParser CalendarEvent ISP
* update
* fix: complete CalEventParser ISP refactoring - update call sites and fix type errors
- Update getUid call sites to pass only uid instead of whole CalendarEvent
- Update getLocation call sites to pass narrow shape with videoCallData, additionalInformation, location, uid
- Update narrow input shapes to accept null for location (matching CalendarEvent type)
- Update recurringEvent type to accept RecurringEvent | null instead of boolean
- Update videoCallData type to be more flexible ({ type?: string; url?: string })
- Fix ManageLink.tsx to pass recurringEvent directly instead of converting to boolean
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* test: update CalEventParser tests to use narrow input shapes
- Update getPublicVideoCallUrl test to pass uid instead of calEvent
- Update getVideoCallPassword tests to pass videoCallData instead of calEvent
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* few fix
* fix type error
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
- Add interpolation: { escapeValue: false } to AttendeeRequestEmail.tsx
- Add interpolation: { escapeValue: false } to attendee-request-email.ts
- Add interpolation: { escapeValue: false } to bookings-single-view.tsx
This prevents special characters like '/' from being HTML-encoded to '/'
in booking confirmation emails and success page dialogs.
Fixes#26938
* fix: validate hosts belong to team in managed event type create/update
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* test: add e2e tests for managed event type host validation
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: move update test after get team event-types test to fix ordering
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The UpdateInputAddressLocation_2024_08_13 and related location types were
referenced via getSchemaPath() but not registered with @ApiExtraModels,
causing them to be missing from the generated OpenAPI spec.
This fix adds @ApiExtraModels decorator to the BookingLocationController
to register all location types used in the UpdateBookingLocationInput.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat(companion): add optimistic updates to EditAvailabilityNameScreen
- Refactor useUpdateSchedule hook with optimistic updates
- Update EditAvailabilityNameScreen to use mutation hook instead of direct API call
- Update EditAvailabilityNameScreen.ios.tsx with same pattern
- Cache is updated immediately on save, then synced with server
- On error, cache is rolled back to previous state
* fix(companion): fix cache update for schedule list when detail cache is empty
- Update list cache in onMutate even when detail cache doesn't exist
- Remove onSettled invalidation that was causing issues with staleTime: Infinity
- Add fallback invalidation in onSuccess when list cache doesn't exist
* fix(companion): fix AvailabilityDetailScreen not reflecting cache updates
The previous optimistic updates implementation in EditAvailabilityNameScreen
correctly updated the React Query cache, but AvailabilityDetailScreen was
still using direct CalComAPIService.getScheduleById() calls with local
useState, completely bypassing the cache.
The disconnect:
- EditAvailabilityNameScreen → useUpdateSchedule → Updates React Query Cache ✓
- AvailabilityDetailScreen → CalComAPIService.getScheduleById → Local state ✗
This meant when a user saved changes to a schedule's name/timezone, the
cache was updated but the detail screen (and subsequently the list screen)
never saw those updates because they weren't reading from the cache.
Changes:
- Refactor AvailabilityDetailScreen.tsx to use useScheduleById hook
- Refactor AvailabilityDetailScreen.ios.tsx to use useScheduleById hook
- Replace direct API calls with React Query for cache synchronization
- Add RefreshControl for pull-to-refresh support
- Use mutation hooks (useSetScheduleAsDefault, useDeleteSchedule) for actions
- Derive availability/overrides data using useMemo from query result
Now when EditAvailabilityNameScreen updates the cache, AvailabilityDetailScreen
automatically reflects those changes because both read from the same cache.
* feat(companion): refactor EditAvailabilityOverrideScreen to use mutation hook
- Replace direct CalComAPIService.updateSchedule calls with useUpdateSchedule hook
- Remove local isSaving state, use isPending from mutation hook instead
- Cache is now updated automatically via the mutation hook's optimistic updates
- Consistent pattern with EditAvailabilityNameScreen refactoring
* feat(companion): refactor EditAvailabilityDayScreen to use mutation hook
- Replace direct CalComAPIService.updateSchedule calls with useUpdateSchedule hook
- Remove local isSaving state, use isPending from mutation hook instead
- Cache is now updated automatically via the mutation hook's optimistic updates
- Consistent pattern with EditAvailabilityNameScreen and EditAvailabilityOverrideScreen
* fix(companion): refactor edit-availability-hours routes to use useScheduleById hook
The working hours page (page 2 in the flow) was showing stale data because
it used direct CalComAPIService.getScheduleById() calls with local useState,
bypassing the React Query cache.
The disconnect:
- EditAvailabilityDayScreen → useUpdateSchedule → Updates React Query Cache ✓
- edit-availability-hours route → CalComAPIService.getScheduleById → Local state ✗
This meant when a user saved changes to a day's availability, the cache was
updated but the working hours page never saw those updates because it wasn't
reading from the cache.
Changes:
- Refactor edit-availability-hours.tsx to use useScheduleById hook
- Refactor edit-availability-hours.ios.tsx to use useScheduleById hook
- Replace direct API calls with React Query for cache synchronization
- Now all 3 pages in the flow read from the same cache
* fix(companion): make Date Overrides section clickable when empty
Previously, when there were no date overrides, the Date Overrides section
was just a plain View without any press handler, making it impossible for
users to navigate to the edit override page to add new overrides.
This follows the same pattern as other sections (Weekly Schedule, Timezone)
which are always clickable regardless of their content state.
Changes:
- Wrap the 'No Overrides' section in AppPressable with navigation handler
- Add chevron-forward icon to indicate it's tappable
- Apply fix to both AvailabilityDetailScreen.tsx and .ios.tsx
* fix(companion): use useEffect instead of useMemo for side effects
- Change useMemo to useEffect for onActionsReady callback (side effect)
- Move error handling (showErrorAlert, router.back) to useEffect
- Keep early return for error state after useEffect hooks
Fixes Cubic AI review feedback (confidence 9/10)
* feat(companion): add optimistic updates to EventTypeDetail screen
- Enhance useUpdateEventType hook with full optimistic update support
- Add onMutate callback to update cache immediately
- Add onSuccess callback to sync with server response
- Add onError callback to rollback on failure
- Update both eventTypes.detail(id) and eventTypes.lists() caches
- Refactor handleSave in event-type-detail.tsx
- Replace direct CalComAPIService.updateEventType() with useUpdateEventType hook
- Replace direct CalComAPIService.createEventType() with useCreateEventType hook
- Remove manual fetchEventTypeData() call after save (cache updates automatically)
- Replace local saving state with mutation hooks' isPending states
- Refactor handleDelete in event-type-detail.tsx
- Replace direct CalComAPIService.deleteEventType() with useDeleteEventType hook
This ensures the event types list updates immediately after save/delete
without requiring manual refresh.
* feat: monthly-proration-taskerh
* remove cronjob from tasker implementation
* feat: add DI for MonthlyProrationService and TriggerDevLoggerServiceModule
- Create TriggerDevLoggerServiceModule for DI injection of TriggerDevLogger
- Add tokens for TriggerDevLogger in shared.tokens.ts
- Create MonthlyProrationService DI module and container
- Update processMonthlyProrationBatch.ts to use DI container
- Use redactError in Tasker.ts to avoid logging sensitive information
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat(companion): add optimistic updates to EditAvailabilityNameScreen
- Refactor useUpdateSchedule hook with optimistic updates
- Update EditAvailabilityNameScreen to use mutation hook instead of direct API call
- Update EditAvailabilityNameScreen.ios.tsx with same pattern
- Cache is updated immediately on save, then synced with server
- On error, cache is rolled back to previous state
* fix(companion): fix cache update for schedule list when detail cache is empty
- Update list cache in onMutate even when detail cache doesn't exist
- Remove onSettled invalidation that was causing issues with staleTime: Infinity
- Add fallback invalidation in onSuccess when list cache doesn't exist
* fix(companion): fix AvailabilityDetailScreen not reflecting cache updates
The previous optimistic updates implementation in EditAvailabilityNameScreen
correctly updated the React Query cache, but AvailabilityDetailScreen was
still using direct CalComAPIService.getScheduleById() calls with local
useState, completely bypassing the cache.
The disconnect:
- EditAvailabilityNameScreen → useUpdateSchedule → Updates React Query Cache ✓
- AvailabilityDetailScreen → CalComAPIService.getScheduleById → Local state ✗
This meant when a user saved changes to a schedule's name/timezone, the
cache was updated but the detail screen (and subsequently the list screen)
never saw those updates because they weren't reading from the cache.
Changes:
- Refactor AvailabilityDetailScreen.tsx to use useScheduleById hook
- Refactor AvailabilityDetailScreen.ios.tsx to use useScheduleById hook
- Replace direct API calls with React Query for cache synchronization
- Add RefreshControl for pull-to-refresh support
- Use mutation hooks (useSetScheduleAsDefault, useDeleteSchedule) for actions
- Derive availability/overrides data using useMemo from query result
Now when EditAvailabilityNameScreen updates the cache, AvailabilityDetailScreen
automatically reflects those changes because both read from the same cache.
* feat(companion): refactor EditAvailabilityOverrideScreen to use mutation hook
- Replace direct CalComAPIService.updateSchedule calls with useUpdateSchedule hook
- Remove local isSaving state, use isPending from mutation hook instead
- Cache is now updated automatically via the mutation hook's optimistic updates
- Consistent pattern with EditAvailabilityNameScreen refactoring
* feat(companion): refactor EditAvailabilityDayScreen to use mutation hook
- Replace direct CalComAPIService.updateSchedule calls with useUpdateSchedule hook
- Remove local isSaving state, use isPending from mutation hook instead
- Cache is now updated automatically via the mutation hook's optimistic updates
- Consistent pattern with EditAvailabilityNameScreen and EditAvailabilityOverrideScreen
* fix(companion): refactor edit-availability-hours routes to use useScheduleById hook
The working hours page (page 2 in the flow) was showing stale data because
it used direct CalComAPIService.getScheduleById() calls with local useState,
bypassing the React Query cache.
The disconnect:
- EditAvailabilityDayScreen → useUpdateSchedule → Updates React Query Cache ✓
- edit-availability-hours route → CalComAPIService.getScheduleById → Local state ✗
This meant when a user saved changes to a day's availability, the cache was
updated but the working hours page never saw those updates because it wasn't
reading from the cache.
Changes:
- Refactor edit-availability-hours.tsx to use useScheduleById hook
- Refactor edit-availability-hours.ios.tsx to use useScheduleById hook
- Replace direct API calls with React Query for cache synchronization
- Now all 3 pages in the flow read from the same cache
* fix(companion): make Date Overrides section clickable when empty
Previously, when there were no date overrides, the Date Overrides section
was just a plain View without any press handler, making it impossible for
users to navigate to the edit override page to add new overrides.
This follows the same pattern as other sections (Weekly Schedule, Timezone)
which are always clickable regardless of their content state.
Changes:
- Wrap the 'No Overrides' section in AppPressable with navigation handler
- Add chevron-forward icon to indicate it's tappable
- Apply fix to both AvailabilityDetailScreen.tsx and .ios.tsx
* fix(companion): use useEffect instead of useMemo for side effects
- Change useMemo to useEffect for onActionsReady callback (side effect)
- Move error handling (showErrorAlert, router.back) to useEffect
- Keep early return for error state after useEffect hooks
Fixes Cubic AI review feedback (confidence 9/10)
* fix(event-types): keep slug in sync with title until manually edited
Changed from checking `touchedFields` to `dirtyFields` when deciding
whether to sync the slug with the title. This fixes the issue where
merely focusing on the slug field would stop the sync, even if the
user didn't actually edit it.
Now the slug stays in sync with the title until the user actually
modifies the slug value.
Note: The hardcoded "Slug" label for platform users was preserved from
the original code. Localizing it would be a separate enhancement.
Fixes#26265
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: add ensureProtocol helper to handle URLs without protocol
Some container orchestration tools (like Coolify) strip the protocol
from URL environment variables. This causes `new URL()` to throw
`ERR_INVALID_URL` because strings like "sub.domain.com" are invalid
without a protocol prefix.
This fix adds an `ensureProtocol` helper function that:
- Returns empty string for null/undefined URLs
- Preserves URLs that already have http:// or https://
- Prepends https:// to URLs missing the protocol
Applied to WEBAPP_URL, WEBSITE_URL, and CAL_URL env var parsing.
Fixes#25774
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Clarify URL protocol handling in comments
Updated comment to clarify handling of URLs.
* Refactor slug handling in CreateEventTypeForm
---------
Co-authored-by: simiondolha <simiondolha@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
* feat: add GitHub Action to check Prisma migrations match schema
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: use CI_DATABASE_URL secret instead of hardcoded URL
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* test: add test field to verify prisma migration check workflow
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: use git-based check for prisma changes to bypass paths-filter issue
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add migration for test field to verify prisma migration check workflow
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* chore: revert test field and migration after verifying workflow
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: split paths-filter into two actions to fix predicate-quantifier issue
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: rename has_companion to has-companion for consistent naming
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: update steps.filter references to steps.filter-exclusions
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: make sure we dont implement directly from @calcom/features
* fix: preserve the original booking duration instead of using the default event type length
* chore: update tests
* fix: merge conflicts
* chore: revert linting changes
* chore: implement PR feedback
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
This PR adds https://vercel.com/blog/introducing-react-best-practices for your coding agent using `npx add-skill vercel-labs/agent-skills` command
The skills are added to `.claude/`, `.cursor/`, and `.opencode/` directories to provide React and Next.js performance optimization guidance for AI-assisted workflows.
## Updates since last revision
Addressed Cubic AI review feedback for issues with confidence >= 9/10:
- **rerender-dependencies.md** - Replaced `console.log(user.id)` with `fetchUserDetails(user.id)` to avoid logging sensitive information
- **server-after-nonblocking.md** - Removed `sessionCookie` from `logUserAction` call to avoid logging sensitive authentication data, added `await` to async call
- **bundle-conditional.md** - Added `loadError` state and `setLoadError` setter to fix undefined `setEnabled` reference
- **advanced-event-handler-refs.md** - Updated `useWindowEvent` handler signature to accept `Event` parameter and forward it to the stored handler
- **rerender-derived-state.md** - Closed `<nav>` elements in both examples for valid JSX
Fixes applied to both `.claude` and `.cursor` skill directories for consistency.
## Mandatory Tasks (DO NOT REMOVE)
- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] N/A I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). If N/A, write N/A here and check the checkbox.
- [x] N/A, I confirm automated tests are in place that prove my fix is effective or that my feature works.
## How should this be tested?
These are documentation files for AI coding agents. No runtime testing required - review the markdown files to verify the example code snippets are correct.
## Checklist for human review
- [ ] Verify example code snippets in the skill files are syntactically correct
- [ ] Confirm the fixes don't introduce new issues in the documentation examples
- [ ] Check that `.claude` and `.cursor` directories have consistent content
---
Link to Devin run: https://app.devin.ai/sessions/f7f7e67fdeea4b22a4817d63ed9e1759
Requested by: unknown ()
## What does this PR do?
When a filter segment is selected and the user clicks it again to deselect, this PR now clears all active filters in addition to deselecting the segment.
Previously, deselecting a segment only called `setSegmentId(null)`, which removed the segment selection but left the filters in place. Now it calls `clearAll()` which clears both the segment selection and all active filters.
## 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. Go to a page with DataTable and filter segments (e.g., Bookings page or Organization Members page)
2. Select a filter segment (e.g., "My Bookings" system segment or a user-created segment)
3. Verify filters are applied (URL contains `activeFilters`)
4. Click the same segment again to deselect it
5. Verify the segment is deselected AND all filters are cleared (URL should no longer contain `activeFilters`)
An e2e test has been added to `filter-segment.e2e.ts`:
- `Deselecting a segment clears all active filters`
## Checklist
- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings
## Human Review Checklist
- [ ] Verify that calling `clearAll()` instead of `setSegmentId(null)` is the intended behavior (clears both segment selection and all active filters)
- [ ] Consider if there are use cases where users might want to keep filters when deselecting a segment
---
> **Link to Devin run**: https://app.devin.ai/sessions/44f22b80d9c442bdb334d04dac2b476d
> **Requested by**: @eunjae-lee
* feat(agents): add modular engineering rules from 2026 standards
Add a rules directory with individual rule files derived from the
Cal.com Engineering in 2026 and Beyond blog post. Rules are organized
by section (architecture, quality, data, api, performance, testing,
patterns, culture) following the Vercel agent-skills structure.
Includes:
- _sections.md defining rule categories and impact levels
- _template.md for creating new rules
- 14 individual rule files covering key engineering standards
- README documenting the rules structure and usage
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat(agents): consolidate DI and Repository+DTO docs into rules
- Move di-pattern.md content to rules/patterns-di-pattern.md
- Extract Repository + DTO section from knowledge-base.md into:
- rules/data-repository-methods.md (method naming conventions)
- rules/data-dto-boundaries.md (DTO location and naming)
- Update knowledge-base.md to reference the new rule files
- Delete old di-pattern.md file
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* chore(agents): remove stub reference sections from knowledge-base.md
The rules directory is self-contained with its own README, so these
redirect sections are unnecessary clutter.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor(agents): combine DI pattern rules into single file
Merged patterns-di-pattern.md into patterns-dependency-injection.md
to eliminate overlap and create one comprehensive DI guide.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(user-dropdown): make SSR-safe and fix ESLint warning for Beacon
* fix: added ssr guard in second useEffect and added type for beacon instead of ts-ignoring
* fix: add dependency array to Beacon useEffect
Address review feedback by adding [user?.username] dependency array
to the Beacon session-data useEffect, improving performance by
preventing unnecessary re-runs on every render.
Co-authored-by: albin-baby-2002 <albinbaby2002@gmail.com>
Co-Authored-By: unknown <>
* test: add automated tests for UserDropdown Beacon functionality
Add comprehensive tests for:
- Beacon session-data calls with correct payload
- Handling of undefined Beacon (no errors)
- Username change triggering useEffect re-run
- SSR safety (window undefined check)
- Component rendering states (loading, user available, no user)
Co-authored-by: albin-baby-2002 <albinbaby2002@gmail.com>
Co-Authored-By: unknown <>
* refactor: remove useless comments and misleading SSR test
- Remove redundant comments above vi.mock calls (per keithwillcode feedback)
- Remove SSR safety test that provided false coverage since jsdom always has window defined (per Cubic feedback)
- The 'should not throw error when Beacon is undefined' test already covers graceful handling
Co-Authored-By: unknown <>
* fix: remove unused @ts-expect-error directives
The Window interface is augmented with optional Beacon and Support properties,
so TypeScript allows deleting them without errors.
Co-Authored-By: unknown <>
* fix: handle lazy-loaded Beacon with polling
When Beacon loads lazily after component mount, the useEffect now polls
every second until Beacon becomes available, then sends session data
and clears the interval. This ensures session info is always sent even
when HelpScout loads asynchronously.
Added test to verify lazy loading behavior works correctly.
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: albin-baby-2002 <albinbaby2002@gmail.com>
* fix: remove Stale label when Devin starts completing a stale PR
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: update Devin prompt to remove Stale label after pushing changes
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: use lowercase 'stale' label to match repository label
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Update stale-pr-devin-completion.yml
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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>
* 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>
* introduce a dependsOn permission string
* fix permissions toggle
* add DFS to allow permission chains
* Update packages/features/pbac/utils/permissionTraversal.ts
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
* fix splitPerms to work with attributes or dotted resources
* CodeRabbit Generated Unit Tests: Add unit tests for permissions hooks, registry, and traversal
* Fix UTG issues (iteration 1)
---------
Co-authored-by: Sean Brydon <sean@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
* Documentation edits made through Mintlify web editor
* Documentation edits made through Mintlify web editor
---------
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
* clean-up nav
* Documentation edits made through Mintlify web editor
* Documentation edits made through Mintlify web editor
* further clean up
* add oauth in sidebar
* --
* land in v2
* land in v2
* Documentation edits made through Mintlify web editor
* Documentation edits made through Mintlify web editor
* cleanup
* Documentation edits made through Mintlify web editor
* deprecated v1
---------
Co-authored-by: Syed Ali Shahbaz <alishahbaz7@gmail.com>
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
* refactor: migrate MembershipRole usages to PBAC permission checks
- Refactor get.handler.ts to use PermissionCheckService for canUpdateTeams
- Refactor checkForInvalidAppCredentials.ts to use getTeamIdsWithPermission
- Refactor outOfOffice.utils.ts to use checkPermission for ooo.update
- Refactor checkIfOrgNeedsUpgrade.handler.ts to use organization.manageBilling
- Refactor getActiveOnOptions.handler.ts to use eventType.update permission
- Refactor WorkflowRepository.ts to use workflow.update permission
- Refactor organization.tsx to use team.update permission
- Refactor getEventTypesByViewer.ts to use eventType.update permission
- Refactor getPublicEvent.ts to use team.read permission for private teams
- Update CreateNewOutOfOfficeEntryButton.tsx to use canUpdateOOO prop
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use organization.update permission instead of team.update for org management
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: rename teamsWithEventTypeManagePermission to teamsWithEventTypeUpdatePermission
Renamed variable to match the permission string being used (eventType.update)
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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>
* Add db schema
* Add `CredentialRepository.findByTeamIdAndSlugs`
* Add enabled app slugs for attribute syncing
* Create repository for `IntegrationAttributeSync`
* Create zod schemas
* Create `AttributeSyncUserRuleOutputMapper`
* Create `IntegrationAttributeSyncService`
* Create DI contianer
* Create trpc endpoints
* Create page
* Include team name in `CredentialRepository.findByTeamIdAndSlugs`
* Update schema and relations
* Update types and schemas
* Add more methods to IntegrationAttributeSyncRepository
* Add more services to `IntegrationAttributeSyncService`
- getById
- Init updateIncludeRulesAndMappings
* Refactor `getTeams.handler` to use repository
* Create `createAttributeSync` trpc endpoint
* Create `updateAttributeSync` trpc endpoint
* Add router to trpc
* Create attribute sync child components
* Pass custom actions to `FormCard`
* Create `IntegrationAttributeSyncCard`
* Pass inital props via server side
* Fix prop
* Only refetch on mutation
* Fixes
* Add form error when duplicate field and attribute combo
* Add `updateTransactionWithRUleAndMappings` logic
* Adjust zod schemas
* Service add `updateIncludeRulesAndMappings`
* Pass orgId from server to component
* Rename types
* Add deleteById method to repository
* Add name to integrationAttributeSync
* Add deleteById method to service
* Rename method
* Add deleteAttributeSync trpc endpoint
* Make the IntegrationAttributeSyncCard a dummy component
* test: add tests for IntegrationAttributeSync feature
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Move creating a attribute sync record to the service
* Add i18n strings
* Safe select credential in find by id and team
* Fix default credentialId value in form
* Update repository return types
* Add i18n string
* Make credentialId optional for form schema
* Fix label
* Add cascade deletes
* Add verification that syncs belong to org
* Create mapper for repository output
* Type fixes
* Remove old test file
* Pass `attributeOptions` from parent to children
* Infer types from zod schema
* Type fixes
* Type fix
* Clean up
* Add i18n strings
* Remove unused file
* Address feedback
* Add migration file
* Address feedback
* Add validation for new integration values
* Remove unused router
* Move away from z.infer to z.ZodType
* Clean up comments
* Type fix
* Type fixes
* Type fix
* fix: add passthrough to syncFormDataSchema to preserve extra fields
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove incorrect test that expected extra fields to pass through syncFormDataSchema
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Add endpoint for SF to call
* Create scratch org config
* Create sf cli scripts
* Create package logic
* Update README
* Remove unused file
* Add indexes
* Add aria label
* Address feedback - consistent validation
* Fix import paths for attribute types
* Add `CredentialRepository.findByAppIdAndKeyValue`
* Get credential by instance URL
* Verify incoming sfdc orgId matches credential sfdc orgId
* Rename method
* Get user name integration syncs
* refactor: change attributeSyncRules array to singular attributeSyncRule
The database schema enforces a one-to-one relationship between
IntegrationAttributeSync and AttributeSyncRule (via @unique constraint),
and the UI only supports a single rule. This change makes the TypeScript
type match the database schema and UI behavior.
Changes:
- Update IntegrationAttributeSync interface to use attributeSyncRule: AttributeSyncRule | null
- Update mapper to return singular rule instead of wrapping in array
- Update UI component to access sync.attributeSyncRule directly
- Update IIntegrationAttributeSyncUpdateParams Omit type
- Update tests to use attributeSyncRule: null instead of attributeSyncRules: []
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Convert `membershipRepository.findAllByUserId` to a normal method
* Add temp files to git ignore
* Init and process team conditions
* Biome formatting
* Add `AttributeService` to get user attributes
* Add DI container for AttributeService
* AttributeSyncService evaluate attribute conditions
* Create DI container for attributeSyncService
* Return result for full condition
* Evaluate if attribute sync should apply to user
* Add method
* Change PrismaAttributeOptionRepository to instance methods
* Init AttributeSyncFieldMappingsService and process attribute syncs
* Add AttributeSyncFieldMappingService DI container
* Refactor orgId to organizationId
* Add membership validation to sync field service
* AttributeSYncFieldMappingService use repository methods
* AttributeSyncFieldMappingService.processMappings add mapping logic
* Add DI tokens
* user-sync endpoint to implement attribute syncing
* Validate team belongs to org for rule
* test: add tests for AttributeSyncRuleService, AttributeSyncFieldMappingService, and AttributeService
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Remove duplicate migration file
* Fix merge conflict
* fix: resolve type errors in attribute sync feature (#26814)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Rename variable
* Fix log typo
* Fix file name
* Add error logging
* Use credential teamId
* fix: add missing mockTeamRepository and team validation to tests
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Fix naming
* Fix file import
* Type fix
* Pass MembershipRepository as a dep in AttributeSyncFieldMappingService
* Type fix
* fix: add mockMembershipRepository to AttributeSyncFieldMappingService tests
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Update packages/app-store/salesforce/api/user-sync.ts
Add error handling when getting orgId from stored salesforce id
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* fix: address Cubic code review comments
- PrismaAttributeRepository: use nested select instead of include: true for options
- CredentialRepository: use this.primaClient instead of global prisma, use select instead of include for relations
- AttributeSyncFieldMappingService: optimize O(n*m) complexity with Map lookup for O(1) access
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Fix typo in CredentialRepository
* Update README
* Update sfdx-project
* Add SFDC package tests
* fix: improve Salesforce Apex test assertions to verify actual behavior
- Enhanced CalComHttpMock to track HTTP callout invocations and capture requests
- Updated UserUpdateHandlerTest to verify HTTP callouts are made with correct data
- Updated CalComCalloutQueueableTest to verify HTTP callouts are made correctly
- Replaced System.assert(true, ...) with meaningful assertions that verify:
- Correct number of HTTP callouts
- Request body contains expected fields
- Request method is POST
Addresses Cubic AI review feedback (confidence 9/10 issues only)
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* 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
* fix: detect OOM errors in type-check CI workflow
Turborepo has a known bug where tasks killed by signals (like OOM)
are incorrectly marked as successful because the exit code is -1,
and Turborepo takes max(-1, 0) = 0.
This fix captures the type-check output and explicitly checks for
OOM error patterns, failing the job if detected.
See: https://github.com/vercel/turbo/issues/4227
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
* fix: increase type-check memory limit to 6144MB and add OOM detection
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
* fix: increase type-check memory limit to 12GB
Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(companion): iOS event type detail fixes
- Fix#1: Weekly schedule now shows multiple time slots per day in AvailabilityTab
- Fix#2: Allow numeric input fields to be empty with proper validation
- Fix#3: Add native iOS date picker for date range in Limits tab
- Fix#4: Change 'Email verification' to 'Booker email verification' in Advanced tab
- Fix#5: Fix Requires confirmation comparison logic in buildPartialUpdatePayload
- Fix#6: Forward parameters toggle already working, verified wiring
- Fix#7: Add toggles for redirect booking URL and interface language in Advanced tab
- Fix#8: Increase scroll padding at bottom from 200 to 350 for better keyboard access
* fix(companion): conditional scroll padding for limits and advanced tabs only
* fix(companion): remove static date text from iOS date picker, keep only picker
* fix(companion): simplify iOS date picker to match RescheduleScreen pattern
* update code
* fix: make flaky E2E tests more stable
- Add waitForFunction for localStorage check in change-theme test to wait for app-theme to be set before asserting
- Use waitUntil: 'domcontentloaded' for waitForURL calls in routing-forms tests to handle client-side navigation more reliably
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <adhabal2002@gmail.com>
* fix: reuse existing Devin sessions in stale PR completion workflow
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: consolidate Devin session logic into reusable action
- Create .github/actions/devin-session composite action for session checking
- Update stale-pr-devin-completion.yml to use the new action
- Update cubic-devin-review.yml to use the new action
- Update devin-conflict-resolver.yml to use the new action
- Rename workflows to 'PR Labeled' with descriptive job names
The new action checks for existing Devin sessions by:
1. Looking for session URLs in PR body (for PRs created by Devin)
2. Searching PR comments for known Devin session patterns
3. Verifying session is active (working, blocked, or resumed status)
This eliminates duplicated session checking logic across all three workflows.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* revert: restore original workflow names
Reverted workflow names back to descriptive names:
- 'Stale Community PR Devin Completion' (was 'PR Labeled')
- 'Devin PR Conflict Resolver' (was 'PR Labeled')
Descriptive names are the recommended convention as they appear in
GitHub Actions tab, status checks, and notifications.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: add active status check for PR body sessions
Addresses Cubic AI feedback (confidence 9/10): PR body sessions
now verify the session is active (working, blocked, or resumed)
before reusing, matching the behavior of comment-based session checks.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: remove fork restriction from Stale Community PR Devin Completion workflow
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add back request maintainer access step for fork PRs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace ESLint fixAll with Biome codeActionsOnSave settings:
- source.fixAll.biome: applies safe lint fixes (e.g., removing unused imports)
- source.organizeImports.biome: sorts and organizes imports/exports
Both are needed separately because they serve different purposes:
- fixAll handles lint rule auto-fixes
- organizeImports handles import sorting/ordering
This aligns with Biome being the default formatter in this repo.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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
* docs: update integration test commands for Vitest 4.0
Vitest 4.0 no longer supports custom CLI flags like --integrationTestsOnly.
Updated documentation to use the new VITEST_MODE=integration environment
variable syntax instead.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: load .env file in vitest config for integration tests
Vitest 4.0 doesn't automatically load .env files into process.env.
This caused integration tests to fail with ECONNREFUSED errors because
DATABASE_URL was not available.
Added loadEnv from Vite to load .env file at the start of vitest config.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* chore: remove unnecessary comment
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: only load .env vars if not already set
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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>
* fix: add server-side redirect for users with pending invites on onboarding page
When users sign up with an invite token, they were being redirected to
/onboarding/getting-started (plan selection page) instead of going
directly to /onboarding/personal/settings. This caused users to see
the payment prompt for team/org plans before being redirected.
This fix adds a server-side check in the /onboarding/getting-started
page to redirect users with pending invites directly to the personal
onboarding flow, preventing them from seeing the plan selection page.
Also refactored onboardingUtils.ts to use MembershipRepository instead
of direct prisma access.
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* test: add integration tests for hasPendingInviteByUserId method
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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>
* 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>
* 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>
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>
* feat: add scope configuration for feature opt-in
Add scope field to OptInFeatureConfig that allows features to be scoped
to specific levels (org, team, user). This enables features to be shown
only at certain settings pages rather than all three.
Changes:
- Add OptInFeatureScope type with values 'org', 'team', 'user'
- Add optional scope field to OptInFeatureConfig interface
- Add getOptInFeaturesForScope helper function to filter features by scope
- Update FeatureOptInService to filter features based on scope
- Update tRPC router to pass scope parameter for org/team endpoints
Features without a scope field default to all scopes for backward compatibility.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: add scope validation to setUserFeatureState and setTeamFeatureState
- Add isFeatureAllowedForScope helper function to check if a feature is allowed for a scope
- Update setUserFeatureState to reject if feature is not scoped to 'user'
- Update setTeamFeatureState to accept scope parameter and reject if feature is not allowed
- Update tRPC router to pass scope parameter for team and org endpoints
- Fix unit test mock to include new config exports
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: use ErrorWithCode for scope validation and add tests
- Replace raw Error with ErrorWithCode using ErrorCode.BadRequest
- Add comprehensive tests for setUserFeatureState scope validation
- Add comprehensive tests for setTeamFeatureState scope validation
- Test both enabled/disabled and inherit state scenarios
- Test error messages include feature ID and scope name
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: improve Features menu visibility to use scope configuration
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: remove unused hasOptInFeaturesForScope function
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: allow features not in config at all scopes (permissive default)
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: revert permissive default and mock scope validation in integration tests
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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>
* fix: workflow locale
* fix: workflow locale
* fix: check if tmeplate is changed
* fix: regression
* fix: also check subject when determining if template is customized
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* refactor: extract template matching logic into testable function
- Create detectMatchedTemplate function in separate file
- Add comprehensive unit tests (20 test cases)
- Refactor EmailWorkflowService to use the new function
Addresses review comment from hariombalhara requesting
abstraction and tests for the template matching logic.
Co-Authored-By: udit@cal.com <udit222001@gmail.com>
---------
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: morgan@cal.com <morgan@cal.com>
Add hideCalendarNotes support to reschedule flow
The hideCalendarNotes flag was only handled in CalendarManager.createEvent(), not in updateEvent(). This caused notes to become visible again in ICS files after rescheduling.
Changes:
- Add hideCalendarNotes handling to CalendarManager.updateEvent()
- Add hideCalendarNotes checks to reschedule email functions
- Move description reset before reschedule call (required for cloned event)
* Add db schema
* Add `CredentialRepository.findByTeamIdAndSlugs`
* Add enabled app slugs for attribute syncing
* Create repository for `IntegrationAttributeSync`
* Create zod schemas
* Create `AttributeSyncUserRuleOutputMapper`
* Create `IntegrationAttributeSyncService`
* Create DI contianer
* Create trpc endpoints
* Create page
* Include team name in `CredentialRepository.findByTeamIdAndSlugs`
* Update schema and relations
* Update types and schemas
* Add more methods to IntegrationAttributeSyncRepository
* Add more services to `IntegrationAttributeSyncService`
- getById
- Init updateIncludeRulesAndMappings
* Refactor `getTeams.handler` to use repository
* Create `createAttributeSync` trpc endpoint
* Create `updateAttributeSync` trpc endpoint
* Add router to trpc
* Create attribute sync child components
* Pass custom actions to `FormCard`
* Create `IntegrationAttributeSyncCard`
* Pass inital props via server side
* Fix prop
* Only refetch on mutation
* Fixes
* Add form error when duplicate field and attribute combo
* Add `updateTransactionWithRUleAndMappings` logic
* Adjust zod schemas
* Service add `updateIncludeRulesAndMappings`
* Pass orgId from server to component
* Rename types
* Add deleteById method to repository
* Add name to integrationAttributeSync
* Add deleteById method to service
* Rename method
* Add deleteAttributeSync trpc endpoint
* Make the IntegrationAttributeSyncCard a dummy component
* test: add tests for IntegrationAttributeSync feature
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Move creating a attribute sync record to the service
* Add i18n strings
* Safe select credential in find by id and team
* Fix default credentialId value in form
* Update repository return types
* Add i18n string
* Make credentialId optional for form schema
* Fix label
* Add cascade deletes
* Add verification that syncs belong to org
* Create mapper for repository output
* Type fixes
* Remove old test file
* Pass `attributeOptions` from parent to children
* Infer types from zod schema
* Type fixes
* Type fix
* Clean up
* Add i18n strings
* Remove unused file
* Address feedback
* Add migration file
* Address feedback
* Add validation for new integration values
* Remove unused router
* Move away from z.infer to z.ZodType
* Clean up comments
* Type fix
* Type fixes
* Type fix
* fix: add passthrough to syncFormDataSchema to preserve extra fields
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove incorrect test that expected extra fields to pass through syncFormDataSchema
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Add endpoint for SF to call
* Create scratch org config
* Create sf cli scripts
* Create package logic
* Update README
* Remove unused file
* Add indexes
* Add aria label
* Address feedback - consistent validation
* Fix import paths for attribute types
* refactor: change attributeSyncRules array to singular attributeSyncRule
The database schema enforces a one-to-one relationship between
IntegrationAttributeSync and AttributeSyncRule (via @unique constraint),
and the UI only supports a single rule. This change makes the TypeScript
type match the database schema and UI behavior.
Changes:
- Update IntegrationAttributeSync interface to use attributeSyncRule: AttributeSyncRule | null
- Update mapper to return singular rule instead of wrapping in array
- Update UI component to access sync.attributeSyncRule directly
- Update IIntegrationAttributeSyncUpdateParams Omit type
- Update tests to use attributeSyncRule: null instead of attributeSyncRules: []
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* 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>
* Prevent duplicate field and attribute mappings
* Add validation that attribute belongs to the org
* fix: address Cubic AI review feedback
- Add @@index([credentialId]) to IntegrationAttributeSync model for efficient cascade deletes and credential-based queries (confidence: 9/10)
- Fix translation key from 'credential_required' to 'attribute_sync_credential_required' to match existing locale definition (confidence: 10/10)
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: address remaining cubic review feedback
- RuleBuilder.tsx: Use unique IDs for React keys instead of array index to prevent reconciliation bugs when removing conditions
- updateAttributeSync.handler.ts: Add early organization check before service calls for consistency
- createAttributeSync.handler.ts: Add CredentialNotFoundError class for type-safe error handling instead of string matching
- IntegrationAttributeSyncService.test.ts: Replace expect.fail() with proper Vitest rejects.toSatisfy() pattern
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Pull test file from main
* fix: address Cubic AI review feedback (confidence >= 9/10)
- Remove sensitive fields (email, changedFields) from logging in user-sync.ts
- Rename scratch-org:open to scratch-org:start in package.json to match README
Co-Authored-By: unknown <>
* Update README
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
* fix(bookings): fix email exclusion validation for full emails and @-prefixed domains
* NIT
* make case insensitive
* fix: make domain matching case-insensitive in doesEmailMatchEntry
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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
* fix: Yarn installation fails in windows due to mixed path separators in app-store-cli
* fix: normalize paths for cross-platform Biome compatibility in app-store-cli
* fix(ui): improve Variables Dropdown styling consistency
- Change focus ring from brand-800 to subtle for consistent design
- Add rounded-md to dropdown container for visual consistency
- Add rounded-md to DropdownMenuItem for rounded corners
- Remove redundant hover:bg-muted and conditional bg-muted styling
Fixes#25848
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: restore keyboard navigation active state indicator
Keep the conditional bg-muted styling for the selected item during
keyboard navigation, while still removing the redundant hover:bg-muted
since DropdownMenuItem already handles hover styling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: simiondolha <simiondolha@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
* refactor: split large org creation transaction into smaller batches
The prisma.team.create call at L418 was creating the organization along with
all orgProfiles and memberships in a single large transaction, which could
timeout when there are many members.
This change splits the operation into smaller, separate transactions:
1. Create the organization (team) with just metadata and organizationSettings
2. Create org profiles in batches of 50 using Promise.all
3. Create memberships in batches of 100 using createMany
4. Fetch created profiles to rebuild the member-profile mapping
This approach avoids transaction timeouts while maintaining the same
functionality and data integrity.
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* Apply suggestion from @cubic-dev-ai[bot]
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>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
The AES256 encryption used for 2FA requires exactly 32 bytes.
The previous command `openssl rand -base64 32` generates a 44-character
base64 string (32 bytes encoded in base64), which is too long.
Changed to `openssl rand -base64 24` which generates exactly 32
characters (24 bytes encoded in base64 = 32 characters).
This was causing 2FA setup failures with "Something went wrong" errors
and RangeError: Invalid key length in self-hosted Docker installations.
Fixes#22365
Co-authored-by: simiondolha <simiondolha@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
* feat: add tri-state UI settings pages and auto opt-in preference
TASK 5: Tri-state UI with ToggleGroup
- Create shared TeamOrgFeaturesSettings component
- Create user features settings page (features-view.tsx)
- Create team features settings page
- Create org features settings page
TASK 6: Add auto opt-in preference
- Add autoOptInExperimentalFeatures field to User and Team models
- Add migration for new fields
- Add TRPC endpoints for auto opt-in preference (using repository pattern)
- Add auto opt-in checkboxes to settings pages
Also adds i18n keys for feature opt-in UI.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
refactor: rename autoOptInExperimentalFeatures to autoOptInFeatures
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
refactor: apply PBAC procedure pattern to featureOptIn router
- Create createTeamPbacProcedure for team-scoped endpoints
- Create createOrgPbacProcedure for organization-scoped endpoints
- Refactor all team/org endpoints to use the new PBAC procedures
- Significantly reduces boilerplate code for permission checks
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
add features pages
implement hooks
update style
update style
rename slug to featureId
show Features page on the side bar only if OPT_IN_FEATURES.length > 0
revert unncessary renaming
revert some changes
remove some changes
* fix repository usage
* test: add unit tests for PBAC utility procedures
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: add 'disabled by organization' badge for Team Level Features page
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* a little clean up
* feat: add effectiveReason to computeEffectiveStateAcrossTeams for better UI feedback
- Update computeEffectiveStateAcrossTeams to return both enabled state and reason
- Add EffectiveStateReason type with 6 possible values
- Update FeatureOptInService to include effectiveReason in resolved state
- Simplify useUserFeatureOptIn.getBlockedWarning to use effectiveReason directly
- Add feature_no_explicit_enablement_warning translation
- Invalidate feature list when auto-opt-in setting changes in all hooks
* test: add tests for FeatureOptInService.listFeaturesForTeam and refactor router to use TeamRepository
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* make it clearer about auto opt in
* move hooks to apps/web/module
* fix
* fix: move types to packages/features/feature-opt-in, fix imports and test mocks
- Move types.ts from apps/web/modules/feature-opt-in/hooks to packages/features/feature-opt-in
- Update FeaturesSettings.tsx to import types from new location
- Update hooks to import types from @calcom/features/feature-opt-in/types
- Fix organization features-view import path (~/settings/organizations -> ~/ee/organizations)
- Fix PermissionCheckService mock in util.test.ts to use class syntax
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add validation for team ID and remove isPublic from featureOptIn handler
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: resolve biome lint errors in feature-opt-in files
- Add explicit return types to functions and methods
- Replace ternary operators with if-else statements
- Replace forEach with for...of loops to avoid useIterableCallbackReturn
- Extract helper functions to reduce function complexity
- Add explicit type annotations to variables
- Move exports to end of file to satisfy useExportsLast rule
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: resolve type errors in featureOptIn router
- Replace ctx.organizationId with ctx.user.organization.id
- Add null checks for organizationId in org procedures
- Remove incorrect type annotation from featureOptInRouter
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: address PR feedback on feature opt-in implementation
- Refactor createMutationCallbacks to useMutationCallbacks hook with useLocale internally
- Restore comment on featureOptIn prop in FeaturesSettings.tsx
- Revert getAllTeamIds helper, use ternary operator instead
- Use ctx.user.organizationId with proper guard clauses
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix type error
* feat: disable toggle when feature is blocked by higher level
- Add isBlockedByHigherLevel function to UseFeatureOptInResult interface
- Implement blocking detection for user level (org/team disabled)
- Implement blocking detection for team level (org disabled)
- Organization level never blocked (top level)
- Update FeaturesSettings to disable ToggleGroup when blocked
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* change order of toggle buttons
* feat: add policy field (permissive/strict) to feature opt-in config
- Add OptInFeaturePolicy type with 'permissive' and 'strict' modes
- Update computeEffectiveStateAcrossTeams to handle both policies:
- Permissive: user opt-in can activate; disables only win if ALL teams disable
- Strict: user opt-in alone not enough; ANY explicit disable blocks
- Add new EffectiveStateReason values for strict policy
- Update FeatureOptInService to read policy from config
- Add unit tests for all 9 policy scenarios from spec
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: rewrite test file with scenario tables and make policy required
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix type
* fix types
* make policy required
* disable toggle group if blocked by higher level
* refactor: move PBAC procedures to packages/trpc/server/procedures
- Move util.ts to pbacProcedures.ts in procedures folder for better reusability
- Move util.test.ts to pbacProcedures.test.ts alongside the main file
- Update imports in _router.ts to use new location
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: remove redundant null checks in featureOptIn router
The createOrgPbacProcedure middleware already validates organizationId
and throws if null. Use non-null assertion (!) instead of redundant
runtime checks since the middleware guarantees the value exists.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: improve middleware typing to avoid non-null assertions
Remove explicit return type from createOrgPbacProcedure to let TypeScript
infer the extended context type. This allows handlers to use ctx.organizationId
directly (typed as number) instead of ctx.user.organizationId! assertions.
The middleware validates organizationId and adds it to the context, so
downstream handlers can safely access ctx.organizationId as a number.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat(pbac): use featureOptIn permissions instead of generic team/org permissions
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat(pbac): add PBAC to team features page and pass canEdit to views
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add effectiveReason to IFeatureOptInService and update listFeaturesForTeam interface
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add feature_any_team_disabled to isUserBlockedByHigherLevel check
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add strict-policy reasons to warning helper function
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* 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>
* 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>
* remove header and add standard pagination
* Remove unused props from OutOfOfficeEntriesList
Removed unnecessary props from the data table component.
* removed standard pagination
* fix
* Update OutOfOfficeEntriesList.tsx
* remove unnecessary padding
---------
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
- Create unified date/time formatter with Intl-first approach and dayjs fallback
- Add support for is/lt/nb locales in Booker components
- Unify date formatting across Booker (Header, dates, weekdays)
- Update translation pipeline to include is, lt, nb
- Add tests for new locales and formatter
- Add timezone support in dayjs fallback
- Add formatter caching with circuit breaker
- Use unified formatDateTime in Header.tsx
* fix integration test
* fix: enable DI for FeatureOptInService
* create containers/FeaturesRepository.ts
* refactor: convert FeatureOptInService and FeaturesRepository to moduleLoader pattern
- Create feature-specific tokens in feature-opt-in/di/tokens.ts and flags/di/tokens.ts
- Update modules to use bindModuleToClassOnToken for type-safe dependency injection
- Simplify containers to use moduleLoader.loadModule() for automatic dependency loading
- Import feature-specific tokens in central tokens.ts using spread operator
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: rename FeatureOptInServiceInterface to IFeatureOptInService
Follow the codebase convention of using 'I' prefix for interface files and names.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: export featuresRepositoryModule for backward compatibility
The FeaturesRepository module was refactored to use moduleLoader pattern but
AvailableSlots.ts still imports featuresRepositoryModule. This adds the export
to maintain backward compatibility.
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add skip trial feature for teams/orgs billing page
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* feat: add translation strings for skip trial feature and fix lint-staged config
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use IS_TEAM_BILLING_ENABLED instead of IS_SELF_HOSTED
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use correct DialogHeader props in billing-view.tsx
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* restore lint staged config file
* invalidate trpc cache
* fix: update role filter and error message in skipTrialForTeam handler
- Changed role filter to include both OWNER and ADMIN roles to match authorization logic
- Updated error message to reflect that both owners and admins can skip the trial
Addresses Cubic AI review feedback on PR #26584
Co-Authored-By: unknown <>
* fix: optimize skipTrialForTeam to query only specific team by ID
Address Cubic AI review feedback: Replace findAllAcceptedTeamMemberships
(which fetches all teams) with TeamRepository.findById (which fetches
only the specific team needed). Authorization is already validated
earlier in the handler, so this redundant query was inefficient.
Co-Authored-By: unknown <>
* fix static methods
* feat: use pbac
* fix: remove redundant team query in getSubscriptionStatus handler
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* add pbac to skip team handler
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: optimize routing form mutation to avoid costly name update triggers
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* Add load test script for form responses
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Copy changes
* Move search bar inline with new button
* Get rid of no more results message
* Change hidden badge to (hidden)
* Remove Cal.ai badge from sidebar
* Add dropdown to create button when there is multiple options
* Fix delete dialog
* Saved filters updates
* More string fixes
* Switch members table to use names
* Fix member spacing
* Fix routing form identifier field
* Fix routing forms stuff
* Only show SMS hint on SMS options
* Make workflow delete button minimal
* Fix padding on workflow steps
* Remove min width on workflow title
* Fix delete workflow PR
* Fix org profile buttons
* Fix org profile screen partially scrolled down
* Improve logos & banner uploads
* Personal profile fixes
* Fix settings general view stuff
* Sentence case consistency
* Fix stuff I broke
* Fix fab
* Fix hidden translation string
* Fix text fields
* Make button small for solo users too
* fix: update E2E tests to match sentence case labels in routing forms
* fix: update tests to match sentence case label changes
- insights.e2e.ts: chart titles (14 strings)
- event-types.e2e.ts: Organizer phone number location
- EditLocationDialog.test.tsx: phone number labels
* fix: address Cubic AI review feedback (confidence 9+)
- Replace hardcoded text-gray-500 with text-muted in TextField.tsx hint section
- Replace text locator with data-testid in E2E test for location select
Co-Authored-By: unknown <>
* fix: update E2E tests for sentence case label changes
- Use data-testid selectors for location options (more reliable than text)
- Update field identifiers in routing-forms tests to match new labels
- Fix Long text selector in manage-booking-questions test
* fix: replace text locator with data-testid in manage-booking-questions E2E test
Replace fragile text="Long text" locator with resilient
page.getByTestId("select-option-textarea") selector per E2E best practices.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
* fix: use .last() for multiple location select items
---------
Co-authored-by: Pedro Castro <pedro@cal.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add filtering to SelectedCalendarRepository.findNextSubscriptionBatch to
exclude generic calendars (holidays, contacts, shared, imported, resources)
based on their externalId suffixes.
Changes:
- Add GENERIC_CALENDAR_SUFFIXES constant mapping providers to their
generic calendar suffixes in AdaptersFactory
- Add getGenericCalendarSuffixes method to AdapterFactory interface
- Update findNextSubscriptionBatch to accept and use genericCalendarSuffixes
parameter to filter out calendars with matching externalId suffixes
- Update CalendarSubscriptionService.checkForNewSubscriptions to pass
generic calendar suffixes from the adapter factory
- Update tests to cover the new filtering logic
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* checkpoint 1
* checkpoint 2
* update extension header
* fix some minor ios ui bugs
* fix(companion): restore username fetching for URL fallback display
Addresses Cubic AI review feedback (confidence 9/10): The username was
hardcoded to 'username' but still used by BasicsTab as a fallback for
URL display when bookingUrl is unavailable. This restores the useEffect
that fetches the actual username from CalComAPIService.getUsername().
Co-Authored-By: unknown <>
* complete devins code change
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Add db schema
* Add `CredentialRepository.findByTeamIdAndSlugs`
* Add enabled app slugs for attribute syncing
* Create repository for `IntegrationAttributeSync`
* Create zod schemas
* Create `AttributeSyncUserRuleOutputMapper`
* Create `IntegrationAttributeSyncService`
* Create DI contianer
* Create trpc endpoints
* Create page
* Include team name in `CredentialRepository.findByTeamIdAndSlugs`
* Update schema and relations
* Update types and schemas
* Add more methods to IntegrationAttributeSyncRepository
* Add more services to `IntegrationAttributeSyncService`
- getById
- Init updateIncludeRulesAndMappings
* Refactor `getTeams.handler` to use repository
* Create `createAttributeSync` trpc endpoint
* Create `updateAttributeSync` trpc endpoint
* Add router to trpc
* Create attribute sync child components
* Pass custom actions to `FormCard`
* Create `IntegrationAttributeSyncCard`
* Pass inital props via server side
* Fix prop
* Only refetch on mutation
* Fixes
* Add form error when duplicate field and attribute combo
* Add `updateTransactionWithRUleAndMappings` logic
* Adjust zod schemas
* Service add `updateIncludeRulesAndMappings`
* Pass orgId from server to component
* Rename types
* Add deleteById method to repository
* Add name to integrationAttributeSync
* Add deleteById method to service
* Rename method
* Add deleteAttributeSync trpc endpoint
* Make the IntegrationAttributeSyncCard a dummy component
* test: add tests for IntegrationAttributeSync feature
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Move creating a attribute sync record to the service
* Add i18n strings
* Safe select credential in find by id and team
* Fix default credentialId value in form
* Update repository return types
* Add i18n string
* Make credentialId optional for form schema
* Fix label
* Add cascade deletes
* Add verification that syncs belong to org
* Create mapper for repository output
* Type fixes
* Remove old test file
* Pass `attributeOptions` from parent to children
* Infer types from zod schema
* Type fixes
* Type fix
* Clean up
* Add i18n strings
* Remove unused file
* Address feedback
* Add migration file
* Address feedback
* Add validation for new integration values
* Remove unused router
* Move away from z.infer to z.ZodType
* Clean up comments
* Type fix
* Type fixes
* Type fix
* fix: add passthrough to syncFormDataSchema to preserve extra fields
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove incorrect test that expected extra fields to pass through syncFormDataSchema
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Add indexes
* Add aria label
* Address feedback - consistent validation
* Fix import paths for attribute types
* refactor: change attributeSyncRules array to singular attributeSyncRule
The database schema enforces a one-to-one relationship between
IntegrationAttributeSync and AttributeSyncRule (via @unique constraint),
and the UI only supports a single rule. This change makes the TypeScript
type match the database schema and UI behavior.
Changes:
- Update IntegrationAttributeSync interface to use attributeSyncRule: AttributeSyncRule | null
- Update mapper to return singular rule instead of wrapping in array
- Update UI component to access sync.attributeSyncRule directly
- Update IIntegrationAttributeSyncUpdateParams Omit type
- Update tests to use attributeSyncRule: null instead of attributeSyncRules: []
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* 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>
* Prevent duplicate field and attribute mappings
* Add validation that attribute belongs to the org
* fix: address Cubic AI review feedback
- Add @@index([credentialId]) to IntegrationAttributeSync model for efficient cascade deletes and credential-based queries (confidence: 9/10)
- Fix translation key from 'credential_required' to 'attribute_sync_credential_required' to match existing locale definition (confidence: 10/10)
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: address remaining cubic review feedback
- RuleBuilder.tsx: Use unique IDs for React keys instead of array index to prevent reconciliation bugs when removing conditions
- updateAttributeSync.handler.ts: Add early organization check before service calls for consistency
- createAttributeSync.handler.ts: Add CredentialNotFoundError class for type-safe error handling instead of string matching
- IntegrationAttributeSyncService.test.ts: Replace expect.fail() with proper Vitest rejects.toSatisfy() pattern
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Pull test file from main
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
* 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>
* 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
* feat: add DEVIN_ACTIONS_PAT instructions for pushing to forked PRs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: simplify PAT instructions to be high-level
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: allow workflow_dispatch to run on draft PRs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: only process targeted PR when pr_number is provided
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add critical fork PR error handling instruction to stale PR workflow
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* use cross-platform rimraf for build scripts
* fix: use cross-platform rimraf for build scripts
* fix: replace cp with npx shx cp for cross-platform compatibility
* Update schema.prisma
* fix: use pull_request_target for conflict resolver label trigger
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: update if condition to check for pull_request_target event name
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
resolver validation
- Change git diff from HEAD^1 to HEAD^2 to show PRs contribution
(matches GitHubs Files changed view) instead of what main brought in
- Replace fixed 50-file threshold with relative threshold (original PR files + 10)
- A 20-file PR with 100 files in merge = bad
- A 100-file PR with 108 files in merge = fine
* docs: add moduleLoader pattern documentation to knowledge-base
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* docs: rewrite DI section to use moduleLoader pattern as primary approach
- Replace manual module loading examples with moduleLoader pattern
- Add Mistake 4 about manual module loading being not type-safe
- Update Core Concepts to explain moduleLoader components
- Show both depsMap (multiple deps) and dep (single dep) usage
- Emphasize build-time type safety throughout
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* docs: extract DI pattern to separate file
- Move DI documentation from knowledge-base.md to di-pattern.md
- Add brief reference in knowledge-base.md pointing to the new file
- Keeps knowledge-base.md focused on quick notes while DI gets its own detailed guide
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: make OOO team member select close after selection
Replace the custom always-visible scrollable list with a proper Select
component that closes after selection like a normal dropdown. The Select
component uses onMenuScrollToBottom for infinite scroll and onInputChange
for search functionality.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: also convert Team OOO member select to use Select component
Both 'Select team member' sections now use the proper Select component
that closes after selection. Removed unused useInViewObserver import.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: add menuPlacement='bottom' to Team OOO member select
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Update devin-conflict-resolver.yml to check maintainerCanModify for fork PRs
- Instead of skipping fork PRs entirely, now checks if maintainer access is enabled
- Posts friendly comment asking contributors to enable 'Allow edits from maintainers'
- Adds 'maintainer-access-requested' label to track which PRs have been notified
- Update stale-pr-devin-completion.yml to post similar comment when triggered
- Both workflows avoid duplicate comments by checking for existing requests
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: only auto-fix Cubic suggestions with confidence >= 9/10
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Apply suggestion from @keithwillcode
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This adds the withSentryConfig wrapper to the Next.js configuration,
which is required for Sentry tracing to work properly. The wrapper is
only applied in production when both NEXT_PUBLIC_SENTRY_DSN and
SENTRY_TRACES_SAMPLE_RATE environment variables are set.
Without this wrapper, Sentry cannot properly instrument the build for
performance monitoring, causing spans (including calendar telemetry)
to not be recorded despite the SDK being initialized.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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>
* 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>
* 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>
* feat(billing): add database schema for monthly proration tracking
add new database models and migration for tracking seat changes and monthly proration on annual subscriptions
- new models: SeatChangeLog, MonthlyProration
- new enums: SeatChangeType, ProrationStatus
- extend TeamBilling and OrganizationBilling with billingPeriod, pricePerSeat, paidSeats fields
- add feature flag 'monthly-proration' (disabled by default)
- squashed migration: 20260106093811_add_monthly_proration_tracking
the schema supports:
- tracking seat additions/removals per month with metadata
- storing proration calculations and stripe invoice details
- high-water mark billing via paidSeats field
- proper foreign key relationships and indexes for query performance
* feat(billing): add repository layer for monthly proration
add repository pattern for proration data access
- MonthlyProrationRepository: crud operations for proration records
- create, update, and query proration records
- status management (pending, invoice_created, charged, failed)
- retry count tracking
- MonthlyProrationTeamRepository: team-specific queries with billing context
- fetch teams with billing information
- query annual teams with unprocessed seat changes
- update billing info and paidSeats
- metadata fallback for legacy teams without billing records
- update IBillingRepository interface to include proration fields
these repositories provide clean data access layer without business logic
* feat(billing): add seat change tracking service
add service for logging and querying seat changes per month
- SeatChangeTrackingService: track seat additions and removals
- log seat additions with user and metadata context
- log seat removals with optional triggered-by info
- calculate monthly changes (additions, removals, net change)
- retrieve unprocessed changes for a given month
- mark changes as processed after proration calculation
- auto-detect billing entity (team vs organization)
- stripe-subscription-utils: extract billing data from stripe subscriptions
- determine billing period (monthly vs annually)
- extract price per seat and quantity
includes comprehensive unit tests
* feat(billing): add billing period service
add service to determine billing period and proration eligibility
- BillingPeriodService: query and manage billing period information
- check if team is on annual vs monthly plan
- check if team is in trial period
- determine if monthly proration should apply (annual + not in trial + feature flag)
- lazy load billing data from stripe if missing in database
- backfill missing billing data automatically
supports both TeamBilling and OrganizationBilling models
includes comprehensive unit tests with stripe mocking
* feat(billing): add monthly proration service
add core service for calculating and processing monthly seat prorations
- MonthlyProrationService: orchestrate monthly proration workflow
- process monthly prorations for teams with seat changes
- calculate prorated amounts based on remaining subscription days
- create stripe invoice items for seat additions
- handle payment success and failure webhooks
- track high-water mark (paidSeats) for billing
- update stripe subscription quantities after payment
- lazy load and backfill missing billing data from stripe
- support retry logic for failed payments
calculation logic:
- only charge for net seat increases (additions - removals, capped at 0)
- prorate based on remaining days in annual subscription
- track separately from stripe's built-in proration to aggregate monthly
includes unit tests and integration tests with stripe mocking
* refactor(billing): extract prisma logic from services to repositories
move database access logic from services to repository layer for better separation of concerns
- add SeatChangeLogRepository for seat change log data access
- add BillingPeriodRepository for billing period queries and updates
- refactor SeatChangeTrackingService to use SeatChangeLogRepository
- refactor BillingPeriodService to use BillingPeriodRepository
- add create methods to MonthlyProrationTeamRepository for billing records
- refactor MonthlyProrationService to use repository for billing creation
- remove direct prisma calls from services (except FeaturesRepository dependency)
services now focus on business logic while repositories handle data access
* refactor(billing): inject prisma via constructor in repositories
make repositories more testable by accepting prisma client via constructor
- SeatChangeLogRepository: accept optional prisma in constructor
- BillingPeriodRepository: accept optional prisma in constructor
- MonthlyProrationRepository: accept optional prisma in constructor
- MonthlyProrationTeamRepository: accept optional prisma in constructor
all repositories default to global prisma instance when not provided
enables easier mocking in tests by injecting test prisma instances
* refactor: remove verbose comments and unnecessary try-catch
* refactor: change pricePerSeat and proratedAmount to cents (Int)
store monetary values as integers in cents instead of floats for precision
remove unnecessary schema comments
* fix tests and add back try catch error handlign
* Update packages/features/ee/billing/service/proration/__tests__/MonthlyProrationService.integration-test.ts
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* add faeture flag to config.ts
* Update packages/features/ee/billing/service/proration/__tests__/MonthlyProrationService.integration-test.ts
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* restore schema
* add hooks types for flag
* fix: correct pricePerSeat calculations for cents-based storage
MonthlyProrationService now correctly handles pricePerSeat stored as
cents (INTEGER) instead of dollars (DOUBLE PRECISION). Removed duplicate
conversions to cents that were causing 100x price inflation.
* Use cents for money values
* fix type error
* Move integration to test to use cents value
* fix integration import
* mock subscription
* include paid seats tracking in proration service
* add mocks for invoice creation
* feat: use stripebilling service instead of using stripe directly
* fix validation erorr handler in proration service
* fix: fix sub
* use correct seat value
* fix(billing): mark seat changes as processed when netChange is zero
When a team has additions and removals that net to zero, the function
was returning null without calling markAsProcessed(). This left seat
change logs in an unprocessed state indefinitely, causing subsequent
proration runs to re-query the same changes repeatedly.
Changed the early return condition from checking netChange === 0 to
checking if there are no changes at all (additions === 0 && removals === 0).
This ensures that when there are actual seat changes that net to zero,
a proration record is still created and seat changes are marked as processed.
Co-Authored-By: unknown <>
* update test to reflect new return type of proration
---------
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
description:React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
license:MIT
metadata:
author:vercel
version:"1.0.0"
---
# Vercel React Best Practices
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
## When to Apply
Reference these guidelines when:
- Writing new React components or Next.js pages
- Implementing data fetching (client or server-side)
`useEffectEvent` provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.
Import directly from source files instead of barrel files to avoid loading thousands of unused modules. **Barrel files** are entry points that re-export multiple modules (e.g., `index.js` that does `export * from './module'`).
Popular icon and component libraries can have **up to 10,000 re-exports** in their entry file. For many React packages, **it takes 200-800ms just to import them**, affecting both development speed and production cold starts.
**Why tree-shaking doesn't help:** When a library is marked as external (not bundled), the bundler can't optimize it. If you bundle it to enable tree-shaking, builds become substantially slower analyzing the entire module graph.
When comparing arrays with expensive operations (sorting, deep equality, serialization), check lengths first. If lengths differ, the arrays cannot be equal.
In real-world applications, this optimization is especially valuable when the comparison runs in hot paths (event handlers, render loops).
Two O(n log n) sorts run even when `current.length` is 5 and `original.length` is 100. There is also overhead of joining the arrays and comparing the strings.
## Use toSorted() Instead of sort() for Immutability
`.sort()` mutates the array in place, which can cause bugs with React state and props. Use `.toSorted()` to create a new sorted array without mutation.
This applies to all CSS transforms and transitions (`transform`, `opacity`, `translate`, `scale`, `rotate`). The wrapper div allows browsers to use GPU acceleration for smoother animations.
Use explicit ternary operators (`? :`) instead of `&&` for conditional rendering when the condition can be `0`, `NaN`, or other falsy values that render.
**Incorrect (renders "0" when count is 0):**
```tsx
functionBadge({count}:{count: number}){
return(
<div>
{count&&<spanclassName="badge">{count}</span>}
</div>
)
}
// When count = 0, renders: <div>0</div>
// When count = 5, renders: <div><span class="badge">5</span></div>
This is especially helpful for large and static SVG nodes, which can be expensive to recreate on every render.
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler automatically hoists static JSX elements and optimizes component re-renders, making manual hoisting unnecessary.
When rendering content that depends on client-side storage (localStorage, cookies), avoid both SSR breakage and post-hydration flickering by injecting a synchronous script that updates the DOM before React hydrates.
var theme = localStorage.getItem('theme') || 'light';
var el = document.getElementById('theme-wrapper');
if (el) el.className = theme;
} catch (e) {}
})();
`,
}}
/>
</>
)
}
```
The inline script executes synchronously before showing the element, ensuring the DOM already has the correct value. No flickering, no hydration mismatch.
This pattern is especially useful for theme toggles, user preferences, authentication states, and any client-only data that should render immediately without flashing default values.
Reduce SVG coordinate precision to decrease file size. The optimal precision depends on the viewBox size, but in general reducing precision should be considered.
**Incorrect (excessive precision):**
```svg
<pathd="M 10.293847 20.847362 L 30.938472 40.192837"/>
When updating state based on the current state value, use the functional update form of setState instead of directly referencing the state variable. This prevents stale closures, eliminates unnecessary dependencies, and creates stable callback references.
**Incorrect (requires state as dependency):**
```tsx
functionTodoList() {
const[items,setItems]=useState(initialItems)
// Callback must depend on items, recreated on every items change
The first callback is recreated every time `items` changes, which can cause child components to re-render unnecessarily. The second callback has a stale closure bug—it will always reference the initial `items` value.
**Correct (stable callbacks, no stale closures):**
```tsx
functionTodoList() {
const[items,setItems]=useState(initialItems)
// Stable callback, never recreated
constaddItems=useCallback((newItems: Item[])=>{
setItems(curr=>[...curr,...newItems])
},[])// ✅ No dependencies needed
// Always uses latest state, no stale closure risk
1.**Stable callback references** - Callbacks don't need to be recreated when state changes
2.**No stale closures** - Always operates on the latest state value
3.**Fewer dependencies** - Simplifies dependency arrays and reduces memory leaks
4.**Prevents bugs** - Eliminates the most common source of React closure bugs
**When to use functional updates:**
- Any setState that depends on the current state value
- Inside useCallback/useMemo when state is needed
- Event handlers that reference state
- Async operations that update state
**When direct updates are fine:**
- Setting state to a static value: `setCount(0)`
- Setting state from props/arguments only: `setName(newName)`
- State doesn't depend on previous value
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler can automatically optimize some cases, but functional updates are still recommended for correctness and to prevent stale closure bugs.
Pass a function to `useState` for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once.
**Incorrect (runs on every render):**
```tsx
functionFilteredList({items}:{items: Item[]}){
// buildSearchIndex() runs on EVERY render, even after initialization
Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations.
For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary.
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders.
Use Next.js's `after()` to schedule work that should execute after a response is sent. This prevents logging, analytics, and other side effects from blocking the response.
`React.cache()` only works within one request. For data shared across sequential requests (user clicks button A then button B), use an LRU cache.
**Implementation:**
```typescript
import{LRUCache}from'lru-cache'
constcache=newLRUCache<string,any>({
max: 1000,
ttl: 5*60*1000// 5 minutes
})
exportasyncfunctiongetUser(id: string){
constcached=cache.get(id)
if(cached)returncached
constuser=awaitdb.user.findUnique({where:{id}})
cache.set(id,user)
returnuser
}
// Request 1: DB query, result cached
// Request 2: cache hit, no DB query
```
Use when sequential user actions hit multiple endpoints needing the same data within seconds.
**With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** LRU caching is especially effective because multiple concurrent requests can share the same function instance and cache. This means the cache persists across requests without needing external storage like Redis.
**In traditional serverless:** Each invocation runs in isolation, so consider Redis for cross-process caching.
The React Server/Client boundary serializes all object properties into strings and embeds them in the HTML response and subsequent RSC requests. This serialized data directly impacts page weight and load time, so **size matters a lot**. Only pass fields that the client actually uses.
description:Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
argument-hint:<file-or-pattern>
metadata:
author:vercel
version:"1.0.0"
---
# Web Interface Guidelines
Review files for compliance with Web Interface Guidelines.
## How It Works
1. Fetch the latest guidelines from the source URL below
2. Read the specified files (or prompt user for files/pattern)
3. Check against all rules in the fetched guidelines
4. Output findings in the terse `file:line` format
description:React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
license:MIT
metadata:
author:vercel
version:"1.0.0"
---
# Vercel React Best Practices
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
## When to Apply
Reference these guidelines when:
- Writing new React components or Next.js pages
- Implementing data fetching (client or server-side)
`useEffectEvent` provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.
Import directly from source files instead of barrel files to avoid loading thousands of unused modules. **Barrel files** are entry points that re-export multiple modules (e.g., `index.js` that does `export * from './module'`).
Popular icon and component libraries can have **up to 10,000 re-exports** in their entry file. For many React packages, **it takes 200-800ms just to import them**, affecting both development speed and production cold starts.
**Why tree-shaking doesn't help:** When a library is marked as external (not bundled), the bundler can't optimize it. If you bundle it to enable tree-shaking, builds become substantially slower analyzing the entire module graph.
When comparing arrays with expensive operations (sorting, deep equality, serialization), check lengths first. If lengths differ, the arrays cannot be equal.
In real-world applications, this optimization is especially valuable when the comparison runs in hot paths (event handlers, render loops).
Two O(n log n) sorts run even when `current.length` is 5 and `original.length` is 100. There is also overhead of joining the arrays and comparing the strings.
## Use toSorted() Instead of sort() for Immutability
`.sort()` mutates the array in place, which can cause bugs with React state and props. Use `.toSorted()` to create a new sorted array without mutation.
This applies to all CSS transforms and transitions (`transform`, `opacity`, `translate`, `scale`, `rotate`). The wrapper div allows browsers to use GPU acceleration for smoother animations.
Use explicit ternary operators (`? :`) instead of `&&` for conditional rendering when the condition can be `0`, `NaN`, or other falsy values that render.
**Incorrect (renders "0" when count is 0):**
```tsx
functionBadge({count}:{count: number}){
return(
<div>
{count&&<spanclassName="badge">{count}</span>}
</div>
)
}
// When count = 0, renders: <div>0</div>
// When count = 5, renders: <div><span class="badge">5</span></div>
This is especially helpful for large and static SVG nodes, which can be expensive to recreate on every render.
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler automatically hoists static JSX elements and optimizes component re-renders, making manual hoisting unnecessary.
When rendering content that depends on client-side storage (localStorage, cookies), avoid both SSR breakage and post-hydration flickering by injecting a synchronous script that updates the DOM before React hydrates.
var theme = localStorage.getItem('theme') || 'light';
var el = document.getElementById('theme-wrapper');
if (el) el.className = theme;
} catch (e) {}
})();
`,
}}
/>
</>
)
}
```
The inline script executes synchronously before showing the element, ensuring the DOM already has the correct value. No flickering, no hydration mismatch.
This pattern is especially useful for theme toggles, user preferences, authentication states, and any client-only data that should render immediately without flashing default values.
Reduce SVG coordinate precision to decrease file size. The optimal precision depends on the viewBox size, but in general reducing precision should be considered.
**Incorrect (excessive precision):**
```svg
<pathd="M 10.293847 20.847362 L 30.938472 40.192837"/>
When updating state based on the current state value, use the functional update form of setState instead of directly referencing the state variable. This prevents stale closures, eliminates unnecessary dependencies, and creates stable callback references.
**Incorrect (requires state as dependency):**
```tsx
functionTodoList() {
const[items,setItems]=useState(initialItems)
// Callback must depend on items, recreated on every items change
The first callback is recreated every time `items` changes, which can cause child components to re-render unnecessarily. The second callback has a stale closure bug—it will always reference the initial `items` value.
**Correct (stable callbacks, no stale closures):**
```tsx
functionTodoList() {
const[items,setItems]=useState(initialItems)
// Stable callback, never recreated
constaddItems=useCallback((newItems: Item[])=>{
setItems(curr=>[...curr,...newItems])
},[])// ✅ No dependencies needed
// Always uses latest state, no stale closure risk
1.**Stable callback references** - Callbacks don't need to be recreated when state changes
2.**No stale closures** - Always operates on the latest state value
3.**Fewer dependencies** - Simplifies dependency arrays and reduces memory leaks
4.**Prevents bugs** - Eliminates the most common source of React closure bugs
**When to use functional updates:**
- Any setState that depends on the current state value
- Inside useCallback/useMemo when state is needed
- Event handlers that reference state
- Async operations that update state
**When direct updates are fine:**
- Setting state to a static value: `setCount(0)`
- Setting state from props/arguments only: `setName(newName)`
- State doesn't depend on previous value
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler can automatically optimize some cases, but functional updates are still recommended for correctness and to prevent stale closure bugs.
Pass a function to `useState` for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once.
**Incorrect (runs on every render):**
```tsx
functionFilteredList({items}:{items: Item[]}){
// buildSearchIndex() runs on EVERY render, even after initialization
Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations.
For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary.
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders.
Use Next.js's `after()` to schedule work that should execute after a response is sent. This prevents logging, analytics, and other side effects from blocking the response.
`React.cache()` only works within one request. For data shared across sequential requests (user clicks button A then button B), use an LRU cache.
**Implementation:**
```typescript
import{LRUCache}from'lru-cache'
constcache=newLRUCache<string,any>({
max: 1000,
ttl: 5*60*1000// 5 minutes
})
exportasyncfunctiongetUser(id: string){
constcached=cache.get(id)
if(cached)returncached
constuser=awaitdb.user.findUnique({where:{id}})
cache.set(id,user)
returnuser
}
// Request 1: DB query, result cached
// Request 2: cache hit, no DB query
```
Use when sequential user actions hit multiple endpoints needing the same data within seconds.
**With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** LRU caching is especially effective because multiple concurrent requests can share the same function instance and cache. This means the cache persists across requests without needing external storage like Redis.
**In traditional serverless:** Each invocation runs in isolation, so consider Redis for cross-process caching.
The React Server/Client boundary serializes all object properties into strings and embeds them in the HTML response and subsequent RSC requests. This serialized data directly impacts page weight and load time, so **size matters a lot**. Only pass fields that the client actually uses.
description:Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
argument-hint:<file-or-pattern>
metadata:
author:vercel
version:"1.0.0"
---
# Web Interface Guidelines
Review files for compliance with Web Interface Guidelines.
## How It Works
1. Fetch the latest guidelines from the source URL below
2. Read the specified files (or prompt user for files/pattern)
3. Check against all rules in the fetched guidelines
4. Output findings in the terse `file:line` format
Provide a clear and concise description of the issue or feature.
-->
(Write your description here.)
### Steps to Reproduce (Bug Reports Only)
<!--
If this is a bug report, provide steps to reproduce the issue.
Delete this section for feature requests.
-->
1. Go to...
2. Click on...
3. See error...
### Expected Behavior
<!--
What did you expect to happen?
-->
(Describe what you expected.)
### Actual Behavior (Bug Reports Only)
<!--
What actually happened? Delete this section for feature requests.
-->
(Describe what actually happened.)
### Proposed Solution (Feature Requests Only)
<!--
If this is a feature request, describe your proposed solution.
Delete this section for bug reports.
-->
(Describe your proposed solution.)
### Screenshots / Evidence
<!--
Add screenshots, screen recordings, or console logs if applicable.
You can use tools like Bird Eats Bug for recordings.
-->
(Attach evidence here.)
### Additional Context
<!--
Any other information that might be helpful.
-->
(Add any additional context here.)
---
##### House rules
- If this issue has a `🚨 needs approval` label, don't start coding yet. Wait until a core member approves the request by removing this label.
- Your ideas are invaluable! However, they undergo review to ensure alignment with the product's direction.
- Follow best practices in our [Contributor Docs](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.