Skip to content

Comments

perf: implement quick app store loading optimizations#22450

Merged
emrysal merged 41 commits intomainfrom
devin/app-store-quick-optimizations-1752336742
Aug 26, 2025
Merged

perf: implement quick app store loading optimizations#22450
emrysal merged 41 commits intomainfrom
devin/app-store-quick-optimizations-1752336742

Conversation

@keithwillcode
Copy link
Contributor

@keithwillcode keithwillcode commented Jul 12, 2025

What does this PR do?

This PR optimizes the Cal.com app-store calendar service imports by converting from dynamic imports to static imports, improving performance and consistency across the codebase.

Key Changes:

  • Modified packages/app-store-cli/src/build.ts to generate static imports for CalendarServiceMap instead of dynamic imports
  • Updated getVariableName function to properly handle forward slashes in import paths (regex: /[-.]/g/[-.\/]/g)
  • Refactored packages/app-store/_utils/getCalendar.ts to work with static imports by removing async/await and .default property access
  • Regenerated packages/app-store/calendar.services.generated.ts with the new static import structure

Link to Devin run: https://app.devin.ai/sessions/8e0a5fbfba00485590fee40f95b84c11
Requested by: @joeauyeung

Visual Demo

Before (Dynamic Imports):

export const CalendarServiceMap = {
  applecalendar: import("./applecalendar/lib/CalendarService"),
  caldavcalendar: import("./caldavcalendar/lib/CalendarService"),
  // ... more dynamic imports
};

After (Static Imports):

import applecalendar_lib_CalendarService_ts from "./applecalendar/lib/CalendarService";
import caldavcalendar_lib_CalendarService_ts from "./caldavcalendar/lib/CalendarService";
// ... more static imports

export const CalendarServiceMap = {
  applecalendar: applecalendar_lib_CalendarService_ts,
  caldavcalendar: caldavcalendar_lib_CalendarService_ts,
  // ... references to imported variables
};

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox. N/A - Internal optimization, no user-facing changes
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

⚠️ Important: Due to environment setup issues during development, comprehensive automated testing was limited. Manual testing is crucial for this PR.

Critical Test Areas:

  1. Calendar Integration Testing:

    • Test creating events with different calendar services (Google, Apple, CalDAV, Exchange, etc.)
    • Verify calendar availability checking works correctly
    • Test calendar listing and selection functionality
  2. Performance Verification:

    • Measure calendar service initialization time (should be faster with static imports)
    • Check that calendar operations don't have unexpected delays
  3. Environment Setup:

    • Set up at least one calendar integration in your test environment
    • Ensure calendar credentials are properly configured
  4. Expected Behavior:

    • Calendar services should load immediately without async delays
    • All existing calendar functionality should work identically
    • No changes to user-facing behavior expected

Test Data Requirements:

  • Valid calendar service credentials (Google Calendar, Apple Calendar, etc.)
  • Test events and availability data
  • Multiple calendar types for comprehensive testing

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings

Human Review Focus Areas

🔍 Critical Review Points:

  1. Runtime Behavior: Verify that removing async/await from getCalendar doesn't break any dependent code that expects promises
  2. Import Variable Names: Check that the generated import variable names are valid JavaScript identifiers for all calendar services
  3. Circular Dependencies: Ensure static imports don't introduce circular dependency issues
  4. Performance Impact: Validate that the change actually improves performance as intended
  5. Calendar Service Coverage: Confirm all calendar services (Google, Apple, CalDAV, Exchange, Feishu, Lark, Office365, Zoho, ICS Feed) work correctly

⚠️ Risk Factors:

  • Core calendar functionality changes with limited automated test coverage during development
  • Transition from async to sync behavior in getCalendar function
  • Generated code changes affecting multiple calendar service integrations

🧪 Recommended Testing:

  • Manual testing of calendar event creation/deletion across different services
  • Performance benchmarking of calendar service initialization
  • Integration testing with real calendar providers

- Add conditional app store imports in videoClient and handlePayment
- Implement lazy calendar manager pattern in CalendarManager
- Enhance createCachedImport with better concurrency handling
- Create calendar-only registry for common calendar operations
- Add performance instrumentation for debugging

These optimizations reduce initial app store loading time by avoiding
module-level imports and creating smaller, focused registries for
calendar operations.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@vercel
Copy link

vercel bot commented Jul 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Preview Aug 26, 2025 0:49am
cal-eu Ignored Ignored Preview Aug 26, 2025 0:49am

@keithwillcode keithwillcode added core area: core, team members only foundation labels Jul 12, 2025
@delve-auditor
Copy link

delve-auditor bot commented Jul 12, 2025

No security or compliance issues detected. Reviewed everything up to 48a909e.

Security Overview
  • 🔎 Scanned files: 8 changed file(s)
Detected Code Changes
Change Type Relevant files
Enhancement ► slots.service.ts
    Add performance instrumentation
► getCalendar.ts
    Add performance monitoring for calendar loading
► calendar-registry.ts
    Create dedicated calendar registry with caching
► index.ts
    Add performance monitoring and improve import caching
► CalendarManager.ts
    Implement lazy calendar loading
► handlePayment.ts
    Add conditional app store import
► videoClient.ts
    Add conditional app store import
► util.ts
    Add performance instrumentation

Reply to this PR with @delve-auditor followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 12, 2025

E2E results are ready!

- Reverted getCalendar.ts to use main appStore instead of calendarStore
- This ensures test mocking system works properly with existing appStoreMock
- Fixes unit test failures where Google Calendar references were getting null values
- All collective scheduling tests now pass

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
- Add CalendarServiceMap generation following CrmServiceMap pattern
- Update getCalendar.ts to use generated calendar service map
- Remove manual calendar-registry.ts in favor of auto-generated approach
- Reduces calendar initialization from loading 48+ apps to ~10 calendar apps

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 17, 2025

Walkthrough

The PR generates and exports a CalendarServiceMap (packages/app-store/calendar.services.generated.ts, empty under NEXT_PUBLIC_IS_E2E), refactors runtime calendar resolution to use that map (getCalendar), and changes calendar test helpers to an async, map-driven mocking API (mockCalendar and wrappers now return Promises). Tests were updated to await calendar mocks and several expectations dropped meetingUrl. CalendarManager now stores calendars as thunks that call getCalendar and handles missing instances explicitly. Multiple modules switched from static to dynamic app-store imports and two location constants were centralized.

Possibly related PRs

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7cdf18f and dd2883b.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/app-store-quick-optimizations-1752336742

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

devin-ai-integration bot and others added 2 commits July 17, 2025 19:33
- Add missing SelectedCalendar fields (createdAt, updatedAt, lastErrorAt, watchAttempts, etc.)
- Fix CredentialPayload type errors by adding user.email and delegationCredentialId
- Mock CalendarServiceMap to use vi.importActual for real calendar services
- Ensure calendar service tests work with new lazy loading approach

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
- Update getCalendarsEvents.test.ts mocks to work with CalendarServiceMap dynamic imports
- Add missing SelectedCalendar fields (createdAt, updatedAt, lastErrorAt, watchAttempts, etc.)
- Fix CredentialPayload type errors by adding user.email and delegationCredentialId
- Use type assertion in getCalendar.ts to resolve credential type conflicts
- Ensure calendar service tests work with new lazy loading approach

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

- Resolve credential object merge conflicts keeping user email field
- Add missing SelectedCalendar fields (createdAt, updatedAt, etc.)
- Ensure CredentialPayload compatibility with delegationCredentialId
- Verify CalendarServiceMap mocking works with dynamic imports
- All 17 tests now passing locally with performance improvements

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
- Add comprehensive vi.mock for calendar.services.generated in delegation-credential tests
- Mock GoogleCalendarService and Office365CalendarService with proper return values
- Update all test files to use await with mockCalendarToHaveNoBusySlots
- Ensure calendar events return expected meetingId, meetingPassword, meetingUrl values
- Fix async/await compatibility issues in booking scenario test utilities

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
- Extract CalendarServiceMap promise to variable to fix 'always true' condition
- Ensure vi.mocked is called on Promise type for proper mockResolvedValue access
- Add await keywords to calendar mock calls in test files
- Maintain existing functionality while making code type-safe

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
@github-actions
Copy link
Contributor

github-actions bot commented Aug 2, 2025

This PR is being marked as stale due to inactivity.

keithwillcode and others added 3 commits August 26, 2025 08:48
…ub.com:calcom/cal.com into devin/app-store-quick-optimizations-1752336742
Revert the removal in app-store/index.ts also.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
packages/app-store/index.ts (4)

50-73: Streamline loader state: rely on a single promise, harden against sync-throws, and avoid state drift

Using both isLoading and loadingPromise is redundant and increases the chance of state drift. A single loadingPromise is sufficient for deduplication. Also, wrapping importFunc with Promise.resolve guards against a (rare) synchronous throw. The refactor below simplifies control flow, removes double writes to isLoading, and ensures we always return a non-undefined Promise reference.

-  let isLoading = false;
-  let loadingPromise: Promise<T> | undefined;
+  let loadingPromise: Promise<T> | undefined;

   return async () => {
-    if (cachedModule) return cachedModule;
-    if (isLoading && loadingPromise) return loadingPromise;
-
-    isLoading = true;
-    loadingPromise = importFunc()
-      .then((module) => {
-        cachedModule = module;
-        isLoading = false;
-        return module;
-      })
-      .catch((err) => {
-        throw err;
-      })
-      .finally(() => {
-        isLoading = false;
-        loadingPromise = undefined;
-      });
-
-    return loadingPromise;
+    if (cachedModule) return cachedModule;
+    if (loadingPromise) return loadingPromise;
+
+    const p = Promise.resolve(importFunc())
+      .then((module) => {
+        cachedModule = module;
+        return module;
+      })
+      .finally(() => {
+        // Clear to allow retries after failures and free the reference after success.
+        loadingPromise = undefined;
+      });
+    loadingPromise = p;
+    return p;
   };

57-71: Nit: duplicate state mutation; let finally handle cleanup

isLoading = false; is set in both .then and .finally. The .finally is sufficient and avoids double writes. Also consider wrapping the import with Promise.resolve(...) to catch any sync throws (rare but cheap to guard).

-    loadingPromise = importFunc()
+    loadingPromise = Promise.resolve(importFunc())
       .then((module) => {
         cachedModule = module;
-        isLoading = false;
         return module;
       })
       .catch((err) => {
         throw err;
       })
       .finally(() => {
         isLoading = false;
         loadingPromise = undefined;
       });

80-82: Make the mock app gate explicit: enable only on “true”

process.env.MOCK_PAYMENT_APP_ENABLED !== undefined will enable the mock even if set to an empty string. Prefer an explicit true check to prevent accidental activation across environments.

-if (process.env.MOCK_PAYMENT_APP_ENABLED !== undefined) {
+if (process.env.MOCK_PAYMENT_APP_ENABLED?.toLowerCase() === "true") {
   exportedAppStore["mock-payment-app"] = createCachedImport(() => import("./mock-payment-app/index"));
 }

If you’d like, I can open a follow-up to document the expected values for this env var across local/dev/prod.


84-84: Add a non-breaking named export for appStore

Per repository conventions, exposing a named export improves clarity and enables tree-shaking. We’ve audited all @calcom/app-store imports—there are numerous default imports and zero existing named imports of appStore, so this change is safe and conflict-free.

• In packages/app-store/index.ts (around line 84)

+export { exportedAppStore as appStore };
 export default exportedAppStore;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d624594 and bfa5d92.

📒 Files selected for processing (1)
  • packages/app-store/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/app-store/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/app-store/index.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/app-store/index.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: din-prajapati
PR: calcom/cal.com#21854
File: packages/app-store/office365calendar/__tests__/unit_tests/SubscriptionManager.test.ts:0-0
Timestamp: 2025-08-05T12:04:29.037Z
Learning: In packages/app-store/office365calendar/lib/CalendarService.ts, the fetcher method in Office365CalendarService class is public, not private. It was specifically changed from private to public in this PR to support proper testing and external access patterns.

loadingPromise = undefined;
});

return loadingPromise;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Type-safety: return value can be undefined under TS’s eyes

With let loadingPromise: Promise<T> | undefined, return loadingPromise; may fail type-checking (strictNullChecks) because TS can’t guarantee non-undefined here. Either use a non-null assertion or (preferably) adopt the refactor above that returns a local p.

Minimal fix if you keep the current structure:

-    return loadingPromise;
+    return loadingPromise!;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return loadingPromise;
return loadingPromise!;
🤖 Prompt for AI Agents
In packages/app-store/index.ts around line 72, TypeScript reports the return
value may be undefined because loadingPromise is declared as Promise<T> |
undefined and returned directly; either assert non-null when returning (e.g.,
return loadingPromise!;) or, preferably, refactor to assign the created promise
to a local const (const p = loadingPromise = new Promise<T>(...);) and return
that local p so the compiler can see a definite Promise<T> is returned.

…ub.com:calcom/cal.com into devin/app-store-quick-optimizations-1752336742
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (9)
packages/app-store/applecalendar/lib/CalendarService.ts (3)

1-1: Consider switching to a named import for the base class to avoid default exports.

Repo guideline discourages default exports. If/when @calcom/lib/CalendarService exposes a named export for the base class, prefer import { BaseCalendarService } from "@calcom/lib/CalendarService";. Not a blocker for this perf PR but worth planning to reduce refactor friction and improve tree-shaking.


4-8: Prefer named export for AppleCalendarService (avoid default exports).

To align with the repo guideline, consider exporting the class by name. This will also make static import sites cleaner and more consistent with the new generated map.

Apply in a follow-up PR (generator, mocks, and import sites likely assume default export today):

-export default class AppleCalendarService extends BaseCalendarService {
+export class AppleCalendarService extends BaseCalendarService {

5-7: De-duplicate service identifiers via a shared constant/enforced type.

Hardcoded "apple_calendar" risks drift with the generated CalendarServiceMap keys. Consider centralizing IDs (e.g., an enum or const object) and typing the constructor param to that union to prevent typos.

packages/app-store/caldavcalendar/lib/CalendarService.ts (3)

1-1: Prefer named import for BaseCalendarService (avoid default export).

Same note as in Apple: when feasible, switch to import { BaseCalendarService } ... to eliminate default exports in this module.


4-8: Avoid default export for CalDavCalendarService.

Prefer a named export to follow the repo guideline and keep generated/static imports consistent in the long term.

-export default class CalDavCalendarService extends BaseCalendarService {
+export class CalDavCalendarService extends BaseCalendarService {

6-6: Align service ID with a central constant/type.

"caldav_calendar" should likely come from a typed constant shared with the generator to prevent mismatches.

setupVitest.ts (3)

16-35: DRY up identical mock event payloads in create/update.

Both methods return the same object. Factor into a tiny helper to reduce duplication and cut future drift.

+const mockEvent = {
+  uid: "mock",
+  id: "mock",
+  password: "",
+  type: "",
+  url: "",
+  additionalInfo: {},
+} as const;

   async createEvent() {
-    return {
-      uid: "mock",
-      id: "mock",
-      password: "",
-      type: "",
-      url: "",
-      additionalInfo: {},
-    };
+    return { ...mockEvent };
   }
   async updateEvent() {
-    return {
-      uid: "mock",
-      id: "mock",
-      password: "",
-      type: "",
-      url: "",
-      additionalInfo: {},
-    };
+    return { ...mockEvent };
   }

37-42: Optional: tighten mock method signatures to catch breaking changes sooner.

If you import the relevant types (e.g., CalendarEvent, AvailabilitySlot), add explicit return/param types to mocks. This makes test mocks act as sentinels if signatures change in the services.


45-55: Consolidate repeated mocks for Exchange variants.

Minor cleanup: reduce repetition and avoid missing a variant in the future.

-vi.mock("@calcom/exchangecalendar/lib/CalendarService", () => ({
-  default: MockExchangeCalendarService,
-}));
-
-vi.mock("@calcom/exchange2013calendar/lib/CalendarService", () => ({
-  default: MockExchangeCalendarService,
-}));
-
-vi.mock("@calcom/exchange2016calendar/lib/CalendarService", () => ({
-  default: MockExchangeCalendarService,
-}));
+const exchangeModules = [
+  "@calcom/exchangecalendar/lib/CalendarService",
+  "@calcom/exchange2013calendar/lib/CalendarService",
+  "@calcom/exchange2016calendar/lib/CalendarService",
+] as const;
+for (const m of exchangeModules) {
+  vi.mock(m, () => ({ default: MockExchangeCalendarService }));
+}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bfa5d92 and 7cdf18f.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • packages/app-store/applecalendar/lib/CalendarService.ts (1 hunks)
  • packages/app-store/caldavcalendar/lib/CalendarService.ts (1 hunks)
  • setupVitest.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*Service.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Service files must include Service suffix, use PascalCase matching exported class, and avoid generic names (e.g., MembershipService.ts)

Files:

  • packages/app-store/caldavcalendar/lib/CalendarService.ts
  • packages/app-store/applecalendar/lib/CalendarService.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/app-store/caldavcalendar/lib/CalendarService.ts
  • packages/app-store/applecalendar/lib/CalendarService.ts
  • setupVitest.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/app-store/caldavcalendar/lib/CalendarService.ts
  • packages/app-store/applecalendar/lib/CalendarService.ts
  • setupVitest.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/app-store/caldavcalendar/lib/CalendarService.ts
  • packages/app-store/applecalendar/lib/CalendarService.ts
  • setupVitest.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: din-prajapati
PR: calcom/cal.com#21854
File: packages/app-store/office365calendar/__tests__/unit_tests/SubscriptionManager.test.ts:0-0
Timestamp: 2025-08-05T12:04:29.037Z
Learning: In packages/app-store/office365calendar/lib/CalendarService.ts, the fetcher method in Office365CalendarService class is public, not private. It was specifically changed from private to public in this PR to support proper testing and external access patterns.
📚 Learning: 2025-08-05T12:04:29.037Z
Learnt from: din-prajapati
PR: calcom/cal.com#21854
File: packages/app-store/office365calendar/__tests__/unit_tests/SubscriptionManager.test.ts:0-0
Timestamp: 2025-08-05T12:04:29.037Z
Learning: In packages/app-store/office365calendar/lib/CalendarService.ts, the fetcher method in Office365CalendarService class is public, not private. It was specifically changed from private to public in this PR to support proper testing and external access patterns.

Applied to files:

  • packages/app-store/caldavcalendar/lib/CalendarService.ts
  • packages/app-store/applecalendar/lib/CalendarService.ts
  • setupVitest.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache

Comment on lines +45 to +55
vi.mock("@calcom/exchangecalendar/lib/CalendarService", () => ({
default: MockExchangeCalendarService,
}));

vi.mock("@calcom/exchange2013calendar/lib/CalendarService", () => ({
default: MockExchangeCalendarService,
}));

vi.mock("@calcom/exchange2016calendar/lib/CalendarService", () => ({
default: MockExchangeCalendarService,
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure mocks are applied before static imports are evaluated.

With static imports replacing dynamic imports, it's critical that these vi.mock calls execute before any module imports the generated CalendarServiceMap or calendar services. Confirm setupVitest.ts is listed in setupFiles (or setupFilesAfterEnv) and runs before test modules load imports used by the generator.

If needed, verify Vitest config:


🏁 Script executed:

#!/bin/bash
# Show Vitest configs that declare setup files and workspace ordering
fd -t f -a 'vitest.config.*' | xargs -I{} sh -c 'echo "--- {} ---"; cat "{}"'

Length of output: 870


Add setupVitest.ts to Vitest’s setupFiles so mocks run before any imports

The current vitest.config.ts doesn’t include your setupVitest.ts in either setupFiles or setupFilesAfterEnv, so those vi.mock(...) calls will execute too late (after static imports). You need to ensure Vitest loads your setup file before any test modules are imported.

– In vitest.config.ts, under the test block, add a setupFiles entry pointing to your setup file. For example:

 export default defineConfig({
   test: {
+    // Ensure mocks are applied before any module import
+    setupFiles: ["./setupVitest.ts"],

     coverage: {
       provider: "v8",
     },
     passWithNoTests: true,
     testTimeout: 500000,
   },
 });

• Adjust the path in setupFiles as needed to correctly locate your setupVitest.ts.
• After this change, Vitest will invoke your mocks before evaluating any static imports (including the generated CalendarServiceMap).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
vi.mock("@calcom/exchangecalendar/lib/CalendarService", () => ({
default: MockExchangeCalendarService,
}));
vi.mock("@calcom/exchange2013calendar/lib/CalendarService", () => ({
default: MockExchangeCalendarService,
}));
vi.mock("@calcom/exchange2016calendar/lib/CalendarService", () => ({
default: MockExchangeCalendarService,
}));
export default defineConfig({
test: {
// Ensure mocks are applied before any module import
setupFiles: ["./setupVitest.ts"],
coverage: {
provider: "v8",
},
passWithNoTests: true,
testTimeout: 500000,
},
});
🤖 Prompt for AI Agents
In setupVitest.ts around lines 45 to 55, your vi.mock(...) calls will run too
late because vitest.config.ts does not include this file in setupFiles; update
vitest.config.ts's test block to add a setupFiles entry that points to the
setupVitest.ts path (adjust relative path as needed) so Vitest loads the setup
file before any test modules are imported and the mocks are applied before
static imports (no other code changes required).

Copy link
Contributor

@emrysal emrysal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🔥

@emrysal emrysal merged commit 6e09489 into main Aug 26, 2025
64 of 66 checks passed
@emrysal emrysal deleted the devin/app-store-quick-optimizations-1752336742 branch August 26, 2025 13:35
devin-ai-integration bot added a commit that referenced this pull request Aug 26, 2025
- Add analytics service generation to app-store-cli build process
- Generate analytics.services.generated.ts with only analytics apps (dub)
- Update getAnalytics.ts to use AnalyticsServiceMap instead of full appStore
- Add NEXT_PUBLIC_IS_E2E to turbo.json globalEnv for generated files
- Reduces import footprint from 100+ apps to only analytics apps with AnalyticsService
- Follows same pattern as calendar services optimization from PR #22450

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
keithwillcode added a commit that referenced this pull request Aug 26, 2025
#23372)

* perf: optimize analytics app imports to avoid loading entire app store

- Add analytics service generation to app-store-cli build process
- Generate analytics.services.generated.ts with only analytics apps (dub)
- Update getAnalytics.ts to use AnalyticsServiceMap instead of full appStore
- Add NEXT_PUBLIC_IS_E2E to turbo.json globalEnv for generated files
- Reduces import footprint from 100+ apps to only analytics apps with AnalyticsService
- Follows same pattern as calendar services optimization from PR #22450

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

* Reorder cli output

* fix: follow getCalendar pattern in getAnalytics and maintain alphabetical order in turbo.json

- Remove unnecessary object wrapping in getAnalytics.ts to match getCalendar.ts pattern
- Move NEXT_PUBLIC_IS_E2E to correct alphabetical position in turbo.json globalEnv
- Address PR feedback from keithwillcode

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

* chore: update yarn.lock after analytics optimization changes

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
emrysal added a commit that referenced this pull request Aug 26, 2025
* perf: implement quick app store loading optimizations

- Add conditional app store imports in videoClient and handlePayment
- Implement lazy calendar manager pattern in CalendarManager
- Enhance createCachedImport with better concurrency handling
- Create calendar-only registry for common calendar operations
- Add performance instrumentation for debugging

These optimizations reduce initial app store loading time by avoiding
module-level imports and creating smaller, focused registries for
calendar operations.

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

* fix: revert getCalendar to use appStore for proper test mocking

- Reverted getCalendar.ts to use main appStore instead of calendarStore
- This ensures test mocking system works properly with existing appStoreMock
- Fixes unit test failures where Google Calendar references were getting null values
- All collective scheduling tests now pass

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

* perf: implement CalendarServiceMap for optimized calendar loading

- Add CalendarServiceMap generation following CrmServiceMap pattern
- Update getCalendar.ts to use generated calendar service map
- Remove manual calendar-registry.ts in favor of auto-generated approach
- Reduces calendar initialization from loading 48+ apps to ~10 calendar apps

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

* fix: update test mocks for CalendarServiceMap compatibility

- Add missing SelectedCalendar fields (createdAt, updatedAt, lastErrorAt, watchAttempts, etc.)
- Fix CredentialPayload type errors by adding user.email and delegationCredentialId
- Mock CalendarServiceMap to use vi.importActual for real calendar services
- Ensure calendar service tests work with new lazy loading approach

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

* fix: resolve CalendarServiceMap test compatibility issues

- Update getCalendarsEvents.test.ts mocks to work with CalendarServiceMap dynamic imports
- Add missing SelectedCalendar fields (createdAt, updatedAt, lastErrorAt, watchAttempts, etc.)
- Fix CredentialPayload type errors by adding user.email and delegationCredentialId
- Use type assertion in getCalendar.ts to resolve credential type conflicts
- Ensure calendar service tests work with new lazy loading approach

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

* fix: update test mocking for CalendarServiceMap compatibility

- Add comprehensive vi.mock for calendar.services.generated in delegation-credential tests
- Mock GoogleCalendarService and Office365CalendarService with proper return values
- Update all test files to use await with mockCalendarToHaveNoBusySlots
- Ensure calendar events return expected meetingId, meetingPassword, meetingUrl values
- Fix async/await compatibility issues in booking scenario test utilities

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

* fix: resolve TypeScript errors in CalendarServiceMap mocking

- Extract CalendarServiceMap promise to variable to fix 'always true' condition
- Ensure vi.mocked is called on Promise type for proper mockResolvedValue access
- Add await keywords to calendar mock calls in test files
- Maintain existing functionality while making code type-safe

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

* Remove Exchange 2013 and 2016

* Mock Exchange in all tests

* Fix tests

* Remove exchange 2013 and 2016 from app store index

* Fix merge error

* Await when getting calendar service

* Fix selectedSlot test

* Add missing variable

* Update openapi.json

* Updated CalendarService imports

* try again

* WIP migrate calendar apps to ES6

* Revert "WIP migrate calendar apps to ES6"

This reverts commit 15bf2c8.

* Revert changes back to e239910

This reverts all calendar service changes that were causing circular dependency issues during builds and E2E tests.

* Remove circular dependency for location constants

* Update yarn.lock with removed package

* Add empty map when running E2E

* Type fies

* Fix merge conflict

* Remove logging statements

* Throw error and reset state if failing to load app

* Revert "Remove Exchange 2013 and 2016"

This reverts commit fedaf63.

* Re-introduce exchange{2013,2016}

Revert the removal in app-store/index.ts also.

* Trying to fix tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
devin-ai-integration bot added a commit that referenced this pull request Aug 27, 2025
- Remove obsolete appStoreMock line from bookingScenario.ts since handlePayment now uses PaymentServiceMap
- Update setupVitest.ts to import prismaMock from correct PrismockClient instance
- Add PaymentServiceMap mock following PR #22450 pattern for calendar services
- Ensure MockPaymentService uses consistent externalId across test files
- Fix webhook handler to return 200 status by ensuring payment records are found correctly

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
keithwillcode added a commit that referenced this pull request Aug 28, 2025
…23408)

* perf: optimize payment app imports to avoid loading entire app store

- Add PaymentServiceMap generation to app-store-cli build process
- Generate payment.services.generated.ts with lazy imports for 6 payment services
- Update handlePayment.ts, deletePayment.ts, handlePaymentRefund.ts to use PaymentServiceMap
- Update getConnectedApps.ts and tRPC payment routers to use PaymentServiceMap
- Follow same pattern as analytics optimization in PR #23372
- Reduces bundle size by avoiding import of 100+ apps when only payment functionality needed

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

* Update build.ts

* fix: update payment service test mocking to work with PaymentServiceMap

- Remove obsolete appStoreMock line from bookingScenario.ts since handlePayment now uses PaymentServiceMap
- Update setupVitest.ts to import prismaMock from correct PrismockClient instance
- Add PaymentServiceMap mock following PR #22450 pattern for calendar services
- Ensure MockPaymentService uses consistent externalId across test files
- Fix webhook handler to return 200 status by ensuring payment records are found correctly

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

* fix: revert prismaMock import to avoid interfering with other tests' vi.spyOn() calls

- Remove global prismaMock import from setupVitest.ts that was causing 'is not a spy' errors
- Update MockPaymentService to import prismaMock locally to maintain payment test functionality
- Fixes organization and outOfOffice tests while preserving payment service optimization

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

* fix: remove E2E conditional check from payment services map generation

- Payment services map now always includes all payment apps regardless of E2E environment
- Ensures payment functionality is consistently available across all environments
- Addresses CI failures caused by conditional payment service loading

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

* refactor: use direct PaymentService imports instead of .lib structure

- Update app-store-cli to import directly from lib/PaymentService.ts files
- Modify all payment handlers to access PaymentService directly
- Update test mocks to match new direct import structure
- Remove .lib property access pattern across payment system
- Maintain backward compatibility while improving import efficiency

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

* fix: revert chargeCard booking.id parameter additions

- Remove booking.id parameter from chargeCard calls in chargeCard.handler.ts and payments.tsx
- Addresses GitHub feedback to investigate chargeCard signature changes in separate PR
- Keeps all other direct PaymentService import refactor changes intact

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
BenraouaneSoufiane added a commit to BenraouaneSoufiane/cal.com that referenced this pull request Aug 28, 2025
…gacy fallback

- Move non-calendar map generation (payment, CRM, video) into packages/app-store-cli build/watch
- Ensure maps regenerate on both `yarn build` and during `yarn dev` via CLI watcher
- Update videoClient.ts to use VIDEO_ADAPTERS with lazy legacy fallback
- Update handlePayment.ts to use PAYMENT_APPS with lazy legacy fallback
- Remove eager @calcom/app-store imports (legacy loaded only if needed)

Follows naming convention from calcom#22450 (calendar handled separately).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app-store area: app store, apps, calendar integrations, google calendar, outlook, lark, apple calendar core area: core, team members only foundation ready-for-e2e self-hosted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants